CLOSE the autonomous-loop spine: when idle, the engine consolidates each soundly-derived determination back into the held self, so the next determine() reaches it directly and can chain one hop further. The directly-answerable set climbs monotonically across idle ticks to the deductive-closure fixed point. Mechanism — generate/determine/consolidate.py::consolidate_once runs ONE semi-naive layer of the member/subset deductive closure (member∘subset → member, subset∘subset → subset; NEVER member∘member — instance-of is not transitive). Each one-hop conclusion not yet realized is VERIFIED by the sound+complete proof_chain ROBDD (reusing C's single verifier _verify_subsumption) and written back via generate/realize::realize_derived as a SPECULATIVE realized record carrying derived-provenance (premise structure_keys + rule + the ENTAILED verdict). idle_tick gains a consolidation pass gated by the new config.consolidate_determinations (default OFF); IdleTickResult.facts_consolidated reports the layer. Invariants held: - wrong=0 — every consolidated fact is a sound-rule conclusion confirmed by the sound+complete decider; member∘member is structurally unreachable (a member fact is only ever extended by a subset edge). _verify_subsumption now refuses a mislabeled/wrong-arity path (belt-and-suspenders now that consolidation is a second caller), so the fallacy cannot be laundered through a corrupted chain. - honesty — a fact derived from SPECULATIVE premises stays SPECULATIVE / as-told; the soundness of the inference never upgrades the standing of the premises. COHERENT is never minted. - teaching-safety — SESSION memory (immediate), an extension of the realize path; NOT corpus mutation and NOT coupled to proposals. The HITL path is untouched. - determinism/replay — pure function of the realized set; sorted write order; derived structure_key identical to a told fact's; provenance round-trips through the Shape B+ snapshot (consolidated facts resume the SAME life across reboot). - no new normalization — writes reuse the INV-21-allowed vault writer; algebra/versor.py keeps closure. Falsification — evals/determination_closure: a frozen replay seeds a deep is-a chain and runs idle ticks; asserts the closure climbs monotonically to a complete fixed point (no-op final tick), wrong=0 (member∘member canary never derived, no fabricated membership), all derived facts SPECULATIVE, and every derived record re-verifies ENTAILED from its recorded premises. Verified green: smoke, runtime, cognition, architectural invariants, plus the new D unit + lane tests and the determine/realize/persistence regression net. Five-lens adversarial review: 4 lenses held; the 5th (normalization) was a misattribution (pre-existing vault reproject, triggered identically by the merged realize path, on sanctioned null-vector storage). Design + findings: docs/analysis/ D-close-consolidation-design-2026-06-06.md.
55 lines
2 KiB
Python
55 lines
2 KiB
Python
"""Step D falsification lane — ``evals.determination_closure``.
|
|
|
|
The lane is the deterministic, falsifiable proof that idle consolidation makes the
|
|
engine learn from its determined facts: the directly-answerable set climbs monotonically
|
|
across idle ticks to the deductive-closure fixed point, with wrong=0 (the member ∘
|
|
member fallacy is never derived), honesty (derived facts stay SPECULATIVE), and a
|
|
provenance replay obligation (every derived record re-verifies ENTAILED).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from evals.determination_closure import run
|
|
|
|
|
|
def test_falsification_met() -> None:
|
|
report = run(depth=9)
|
|
assert report["falsification_met"] is True, report["verdicts"]
|
|
|
|
|
|
def test_each_verdict_holds() -> None:
|
|
v = run(depth=9)["verdicts"]
|
|
assert v["monotone"]
|
|
assert v["strict_increase_on_consolidating_tick"]
|
|
assert v["converged_to_fixed_point"]
|
|
assert v["closure_complete"]
|
|
assert v["canary_member_member_never_derived"]
|
|
assert v["no_fabricated_membership"]
|
|
assert v["provenance_replay_ok"]
|
|
assert v["all_derived_speculative"]
|
|
|
|
|
|
def test_closure_climbs_strictly_then_plateaus() -> None:
|
|
sizes = run(depth=9)["member_closure_sizes"]
|
|
# Non-decreasing throughout.
|
|
assert all(b >= a for a, b in zip(sizes, sizes[1:]))
|
|
# Starts at 1 (the single told membership) and ends at the full chain (10 classes).
|
|
assert sizes[0] == 1
|
|
assert sizes[-1] == 10
|
|
# The final transition is a no-op (the converged fixed point repeats the size).
|
|
assert sizes[-1] == sizes[-2]
|
|
|
|
|
|
def test_run_is_deterministic() -> None:
|
|
a = run(depth=7)
|
|
b = run(depth=7)
|
|
assert a["member_closure_sizes"] == b["member_closure_sizes"]
|
|
assert a["final_member_closure"] == b["final_member_closure"]
|
|
assert a["derived_record_count"] == b["derived_record_count"]
|
|
|
|
|
|
def test_depth_is_clamped_to_chain_length() -> None:
|
|
# Asking for more depth than the chain provides clamps, never errors.
|
|
report = run(depth=999)
|
|
assert report["depth"] == 9
|
|
assert report["falsification_met"] is True
|