core/tests/test_determination_closure_lane.py
Shay 8edafd04ac feat(determine): idle deductive consolidation — the loop learns from determined facts (Step D)
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.
2026-06-06 12:28:09 -07:00

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