ADR-0175 Phase 3 splits wrong=0-first: build the gate (3a) and PROVE invariant #2 before the bounded search (3b) that could exploit gaps. generate/derivation/: - model.py: Quantity / Step / GroundedDerivation. A derivation is a left-fold over text-sourced quantities; each Step carries its licensing cue (the lexeme the search claims licenses the op). - verify.py: self_verifies() — grounded operands ∧ grounded operation cues ∧ unit consistency ∧ no divide-by-zero. Grounding REUSES the canonical primitives from math_roundtrip (_tokens/_token_in/_value_grounds) so the gate cannot drift from the round-trip contract. select_self_verified() adds the uniqueness rule: unique self-verifying answer resolves; zero or disagreeing refuse (wrong=0). INVARIANT #2 proven (TestInvariant2_NoSpuriousSelfVerification): the gate refuses to self-verify a derivation that is not grounded+unit-consistent+unique even when its value coincides with gold — the 20/5==4 class: - invented operand not in text -> refused - operation cue not in text -> refused (division not licensed by any present cue) - value coincidence (20/5=4) with ungrounded op -> still refused - add across units (pounds + reps) -> refused - divide-by-zero -> refused Plus uniqueness: disagreeing grounded derivations -> refuse; agreeing -> resolve. Phase 3a is inert (nothing wires generate.derivation into serving). 3b is the bounded search that produces derivations for this gate + measures the flip-curve in the practice lane under perturbation. Verified: 16/16; ruff clean; smoke 67/67; no serving import. |
||
|---|---|---|
| .. | ||
| __init__.py | ||
| model.py | ||
| verify.py | ||