Review/ratification pass over the 6-phase afferent environment-falsification
roadmap (rebased onto D-inclusive main). The roadmap validated green: smoke (90),
architectural invariants (56), the full sensorium suite, all phase tests, and the
four eval lanes (environment-falsification / event-vision / vision / sensorimotor)
report failed:0. A five-lens adversarial review found the efferent gate
fail-closed (default-deny, conjunctive safety∧ethics∧tool_scope, refuses before
the decoder, hash-only traces, no real decoder, no overclaim), the afferent
Phases 1-5 read-only (runtime import-guards + frozen dataclasses), and the
expected-artifact obligations deterministic + meaningfully-failing. Two
reconciliations from that review:
1. Witness-log importer trust boundary (sensorium/logs/importer.py). The offline
JSONL importer now rejects malformed input with a deterministic ValueError
instead of a raw JSONDecodeError/KeyError, names the 1-based line on a bad
JSON line, rejects non-object records and non-integer ticks, and size-caps the
file (8 MiB) so an oversized log is refused rather than read whole. The trust
boundary is now stated in the module + function docstrings. Behavior for VALID
logs is byte-identical (the environment-falsification lane hashes are
unchanged). New rejection-path tests added.
2. ADR-0198 reconciliation. The §3 verdict-enforcing GATE mechanism
(VerdictEnforcingEfferentGate + MotorActionIntent) has now landed, so the
Implementation Status is amended to say so — while being explicit that the §3
lowering itself (deriving verdicts from the ADR-0029/0033/0036/0037 governance
packs), the motor decoder (every adapter is decoder=None), and ratification by
the dedicated motor governance ADR (now drafted as ADR-0216, Proposed) all
remain deferred. No physical motor decode is authorized.
Disjoint from the GSM8K serving path and from Step D (generate/determine|realize,
chat/runtime, core/config) — clean rebase, no overlap.
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.
DETERMINE was one-hop. C answers a member/subset query that holds by SOUND transitive
subsumption when direct entailment misses: member∘subset* and subset∘subset (the
Description-Logic is-a rules). 'Socrates is a man. All men are mortal. Is Socrates
mortal?' -> yes, as told.
wrong=0 hazard surfaced and closed: member∘member is NOT transitive (instance-of vs
subclass-of) — 'Socrates is a man. Man is a species.' does NOT entail 'Socrates is a
species'. That rule is NEVER an edge, so the fallacy is unreachable (bite-tested). The
reader's member/subset split (X is a Y vs all Xs are Ys) is exactly the instance-of/
subclass-of distinction that makes the included rules sound.
Mechanism: SEARCH-then-VERIFY. Reachability over the sound edges finds the chain, then
the proof_chain ROBDD verifies that chain's propositional entailment (O(path) premises).
Full O(n³) grounding into proof_chain was tried and rejected: it overruns the
canonicalizer's per-conjunct recursion, and transitive closure is reachability, not
general SAT. Search-then-verify scales (11-hop chain determines in ~2ms) and keeps the
sound+complete decider as the wrong=0 verifier + proof artifact.
subset is now a supported direct-entailment predicate (a told subset(a,b) answers it);
the other categoricals (disjoint/intersects/some_not) stay excluded. Two existing tests
updated accordingly (subset->ungrounded, disjoint stays unsupported_query).
When accrue_realized_knowledge is on and a question turn is Determined over realized
knowledge, the user-facing surface IS that answer (generate.determine.render_determination):
'Yes — as I was told, truth is a concept.' The realizer's articulation_surface is
RETAINED as evidence — the determination is a user-facing SELECTION (like the
unknown-domain gate), not a rewrite. An Undetermined turn keeps the default
articulation surface (the honest 'I don't know'); flag-off never takes this path.
Basis is rendered honestly: SPECULATIVE grounds read 'as I was told', never 'verified'
(D0 only asserts answer=True, so the surface is an affirmation — no fabricated or
asserted-False string). Selection only: no field op, no normalization, proposes no
learning (HITL untouched).
Updates docs/runtime_contracts.md selection policy + adds the contract test in the
same PR (per the surface-contract discipline).
Wires comprehend->realize/determine into the live turn loop: a declarative turn
REALIZES a fact into the held self (session vault, SPECULATIVE/as-told); a question
turn is DETERMINED over realized knowledge (answered as-told, or refused open-world).
The first time a CORE conversation actually accumulates knowledge it can recall and
reason over — the 'one continuous life' telos made real, including across reboot
(the accrued fact is in the Shape B+ snapshot, so it survives the process ending).
Seam: all chat() returns funnel through _checkpointed_response; accrual runs there
BEFORE the checkpoint (so the fact persists this turn), gated by a new
accrue_realized_knowledge flag (default OFF — one-shot/eval runtimes don't accrue;
the production L10 process enables it with persist_session_state).
Discipline: SESSION memory, not ratified learning — proposes nothing, HITL untouched.
Realization writes go through generate.realize (INV-21 allowed writer). Additive: a
failure is a clean no-op, never crashes a turn. Slice B-1 RECORDS the outcome
(last_turn_accrual(), introspectable) and leaves the ChatResponse/surface contract
UNCHANGED; surfacing the determination is the B-2 follow-up (needs runtime_contracts
+ contract-test updates).
Tests: declarative accrues; question determines as_told; untold refuses open-world;
idempotent retell not recreated; flag-off no-ops with identical surface; and the
lived-spine proof — accrued knowledge survives reboot (determined as_told after a
fresh runtime over the same checkpoint).
A2 of the refined sequencing. Proves (deterministically, not by assertion) what a
long-running CORE life costs to persist per turn on a constrained offline device.
Measures the Shape B+ checkpoint BYTES per turn (session_state.json) over the real
turn loop — bytes, not wall-clock latency (machine-dependent → flaky). Reuses the L10
continuity corpus.
Measured cliff: save_session_state re-serializes the FULL snapshot every turn, so
per-turn bytes are O(n) in the accumulated life — 3,811 → 88,189 bytes (23x) over 24
turns, ~1.3KB/vault-entry re-written every turn. That blocks continuous-life at the edge.
The gate encodes the edge REQUIREMENT (≤16 KiB/turn regardless of session length) as
xfail(strict): it fails today (documenting the cliff), runs green in CI, and flips to
a hard failure the moment incremental/append-only persistence (O(Δ)/turn) lands —
forcing us to retire it. Plus a regression ceiling (passes today) and a determinism
check (the byte metric is reproducible → a valid gate).
The fix is algorithmic (incremental persistence, Python/Ring-2), NOT a language
rewrite. Tagged core/array_codec.py as the locked reference contract for a future
gated Ring-1 Zig byte-exact codec (ADR-0196 G0-G8) — step 3, only after the O(Δ) fix
and only if this gate proves the codec is still the bottleneck. See contract.md.
A1 of the refined sequencing — the binary-relation reader was inert w.r.t. the
yardstick (contributing 0). This adds a comprehension_relational_predicate domain:
binary-relation prose scored against hand-authored independent gold (predicate,
subject, object) triples — INV-25 independent / INV-27 reader-disjoint (the reader
never produced the gold). Index breadth 8->9, capability_score 0.937258->0.944030,
wrong_total still 0; baseline.json re-frozen to digest 1ea91c1e.
Rigor split: the index lane is POSITIVE-ONLY (clean coverage, consistent with the
other 8 lanes — mixing adversarial refuse-cases into the coverage denominator would
make 'added capability' read as a score drop). The #596 fabrication-catch lives in a
dedicated falsification test (evals/relational/v1/refusals.jsonl): the trailing-
qualifier / dangling-copula / negation / verb-form cases MUST refuse — bites if the
reader ever fabricates. Honest coverage gap recorded: overlaps_event has no copular
surface form (verb-form 'A overlaps B' refuses), so 17 positives cover 15/16 predicates.
Lookback (adversarial verify) found a comprehension-layer wrong=0 hole: an argument
slot only refused on reader._RESERVED tokens, so connective heads leaked through —
'Carol is the sibling of Dan during school.' fabricated sibling_of(carol,
dan_during_school) and realized it, while the asymmetric twin '… during the trip.'
refused (article leaked). The fabricated compound entity entered realized memory,
breaching the never-fabricate floor.
Fix: (1) argument slots must be FREE of connective tokens (a leaked connective head =
unparsed relational structure -> refuse 'extra_relational_structure'); (2) the copula
must sit STRUCTURALLY adjacent to the connective, so a dangling copula ('Monday before
Friday is.') and a period-question-as-statement ('Is Monday before Friday.') refuse
instead of fabricating a fact. determine stays sound by construction; this closes the
reader-layer hole. Bite tests added for both classes + a 'no fabricated entity enters
realized memory' assertion.
First consumer of en_core_relational_predicates_v1: a fail-closed sibling reader
that maps '<A> is [the] <connective> <B>' onto the pack's closed predicate
vocabulary (parent_of, less_than, left_of, before_event, ...), producing a standard
Comprehension. realize_comprehension consumes it unchanged; determine's guard widens
from the single 'member' predicate to a CLOSED direct-entailment set (member + the
ground binary relational predicates), keeping categorical/propositional predicates
soundly excluded.
Direct entailment only — no transitive/symmetric/rule inference (symmetric-converse
questions are a sound-but-incomplete refusal, never a faked assertion). Only the
predicate is closed-vocabulary; arguments may be OOV. The pack is loaded explicitly,
not default-mounted.
wrong=0 bites: reader refuses non-template/negated/pack-absent surfaces; determine
asserts only on direct entailment and excludes categorical predicates.
From the mandated lookback audit: three D0 refusal branches were asserted-but-unproven.
Now they bite:
- not_single_query: reachable from REAL input — a two-question prompt yields two queries.
- malformed_query: a unary `member` query (hand-built; the reader only emits arity-2).
- not_a_comprehension: a non-Comprehension/Refusal input.
No code change — determine.py already refused all three; this closes the
schema-proof-obligation gap (each would now fail if its guard were removed).
From the mandated lookback audit of the composed R0→R1→R1c→OOV surface:
- wrong=0 HAZARD (medium): realize_quantitative trusted equation admissibility it
never checked. `comprehend_quantitative` runs real check_admissibility, but the
type does not enforce it, so a future non-reader constructor could slip a
dimensionally-incoherent 'pending'/'refused' equation into the held self (then
surfaced as-told by DETERMINE). Now RE-ASSERTS admitted-status defensively ->
NotRealized("unadmitted_equation"); docstring corrected to match (no longer claims
the type guarantees it). Bite test via a hand-built pending-equation graph.
- Defensive: wrap binding_graph hashing -> NotRealized("unhashable_structure") so a
future numeric field is a clean refusal, not an uncaught TypeError mid-write.
- Coverage (the obligations now bite, not decoration): unadmitted_equation,
not_a_quant_comprehension, no_bound_fact, grounding_failed (monkeypatched probe),
cross-substrate coexistence (meaning_graph + binding_graph in one vault — recall
isolates, structure_keys differ), and the negated_relation refusal (hand-built,
since the reader encodes declarative negation in the PREDICATE not rel.negated).
- Drift: R0 idempotency test now names the actual dedup key (structure_key, not
content_hash); scope doc notes #591 made OOV placement injective (the §0/§1
non-injectivity finding describes the pre-#591 substrate).
Note: the lookback flagged negated_relation as a high reachable-untested hazard, but
verification showed the reader never sets rel.negated=True for declaratives (it
refuses "X is not a Y" or uses some_not/disjoint predicates) — so it is a defensive
branch, tested via a hand-built graph. Green: 35 realize + ruff clean.
The honest gear (roadmap Step 4). `determine(question: Comprehension | Refusal, ctx)`
answers a membership question ("Is X a Y?") ONLY from what the held self has already
REALIZED (R1a structural recall) — never from the field, an LLM, or absence.
Honesty (from the design review): every realizable record is SPECULATIVE, and
ADMISSIBLE_AS_EVIDENCE = {COHERENT}, so a determination grounded in SPECULATIVE records
carries `basis="as_told"` — "based on what I was told (unverified)", NEVER "verified".
Until COHERENT promotion exists (out of scope), D0 produces only as-told assertions or
typed `Undetermined` refusals. No estimation; no corpus mutation (teaching stays HITL
proposal-only).
Soundness (open-world, wrong=0): D0 asserts an answer ONLY on DIRECT structural
entailment by a realized fact; absence never refutes (so it never asserts a positive
answer from missing knowledge — it refuses). It asserts only `answer=True` on a direct
hit; it never asserts False. Negated questions and non-`member` queries are an explicit
`Undetermined` — D0 ships no entailment path the reader cannot exercise.
Tests (test_determine_d0.py, 8) BITE: present-but-non-entailing (a record about the
subject exists but not the asked relation) MUST refuse; the same question against a
fresh context with no realized fact flips Determined→Undetermined (the verdict is
entailment, not mere presence); the negated + unsupported-query refusals are exercised
via hand-built queries (the reader refuses them upstream, so a comprehend-based test
would pass vacuously). Independent of #593: reasons over R0/R1 `member` facts only.
Generalizes what REALIZE accepts, on the structural-key foundation from #592.
R1c — binding_graph / arithmetic realize:
- `realize_quantitative(QuantComprehension | Refusal, ctx)` realizes a comprehended
arithmetic structure (its admissibility-checked binding_graph) as a SPECULATIVE
record with `structure_kind="binding_graph"` and a span-free `structure_key` over
symbols/facts/equations. The only wrong=0 guard needed is the `Refusal` check —
factless input is already a Refusal upstream (the fact-count gate would be vacuous).
- Extracts the shared `_realize_structured` write path so meaning_graph and
binding_graph share ONE wrong=0 dedup/store point (the `.store` call stays in the
INV-21-allowlisted realize.py).
OOV — lift the in-vocab subject gate:
- R0 declined OOV subjects on the mistaken belief that OOV grounding is
non-deterministic. It is deterministic and reboot-stable, and #591 makes it
injective. Correctness rests on the structural key, not the versor, so OOV subjects
now realize normally. The "side-effect-free" comment is corrected: probe_ingest of
an OOV token mutates the shared vocab via a session-scoped `insert_transient` that
is NOT serialized into the snapshot, so reboot-stability rests on the vault record.
Honesty: the binding_graph entities (alice, the synthesized `total`) are symbolic/OOV
so the placement versor is deterministic-GIVEN-session-state, NOT subject-determined;
reboot-stability is carried by the Shape B+ snapshot of the exact bytes, and
distinctness by structural recall — never the (possibly colliding) metric. SPECULATIVE
always; versor_condition<1e-6 + exact CGA recall preserved; no parallel learning path.
Tests: test_realize_r1c_binding_graph.py (8) + test_realize_oov.py (6, incl. a
fresh-vocab reboot proving stability rests on the vault record not the transient) +
test_realize_r0.py oov test flipped to realize. Green: 35 realize + smoke locally.
R0 keyed a realized fact by its subject's field versor, which is NOT injective:
two facts about one subject embed to byte-identical versors and collide at inf on
metric recall (proven). R1 adds the missing structural key.
- RealizedRecord/metadata carry ordered `relation_arguments` (the relation-space
key R0's sorted `entity_names` discards) and a span-free `structure_key`.
- `recall_realized(ctx, subject=/predicate=/content_hash=/structure_key=/
structure_kind=/entity=)` retrieves realized facts by EXACT structural metadata
(no metric / ANN), via a new read-only `VaultStore.iter_metadata()` accessor.
- Idempotency now dedups on the span-free `structure_key`, so the same proposition
told from a different source/offset collapses (R0's span-inclusive content_hash
could not). Guarded by an ambiguous-entity-name refusal — a wrong=0 defense,
since `Entity.name` is non-unique in the model (only `entity_id` is enforced).
- `content_hash` retained for provenance + replay_hash; `vault_index` pinned to the
live deque position.
Design adversarially verified (docs/analysis/REALIZE-R1-DETERMINE-scope-2026-06-06.md);
the false "established pattern" private-access comment is removed in favor of the
public accessor. wrong=0 + versor_condition<1e-6 + exact CGA recall preserved;
vault/store.py adds only a read-only accessor (no normalization). Green: 23 realize
+ 110 invariant/vault + 90 smoke; ruff check clean.
REALIZE roadmap Step 3, slice R0: the boundary that turns comprehension from an
EVAL ARTIFACT into accumulating living knowledge. A comprehended declarative fact is
integrated into the held self as a structured vault entry (versor, metadata) — NOT a
new store — so it inherits exact cga_inner recall, EpistemicStatus stamping, and
bit-exact Shape B+ persistence for free. Scope: docs/analysis/REALIZE-scope-2026-06-06.md.
generate/realize/realize.py — realize_comprehension(Comprehension|Refusal, ctx) ->
Realized(record, created) | NotRealized(reason):
- eligibility: a Comprehension (not Refusal) with NO queries and EXACTLY ONE
non-negated relation whose subject grounds IN-VOCABULARY. Everything else is a
typed NotRealized with zero vault writes (wrong=0).
- in-vocab-subject only: OOV grounding is non-deterministic across reboots (an
empirically-confirmed substrate gap), so OOV subjects are declined in R0.
- SPECULATIVE always (COHERENT is never a default — ADR-0021); provenance via
MeaningSpan source_span + structure_canonical; content_hash + replay_hash via
canonical-JSON SHA-256 (floats forbidden).
- idempotency: dedup by content_hash within the session (exact-canonical,
span-inclusive — safe direction only, never drops a distinct fact).
- durable schema admits a 2nd substrate later via structure_kind/structure_canonical.
- stores via the existing VaultStore.store path: no new embedder, no normalization
(closure stays algebra/versor.py), no parallel learning path.
Explicitly OUT of R0: COHERENT promotion, teaching-loop proposals, trace-folding,
relation-space recall, the arithmetic/binding_graph path.
tests/test_realize_r0.py (10) — eligibility (refusal/query/multi-relation/OOV all
write nothing); record fields; idempotency (re-told fact doesn't grow the vault);
SPECULATIVE status firewall (recall(min_status=COHERENT) excludes it); the
falsifiable exit gate (told -> realize -> snapshot -> reboot -> recall: byte-exact
content_hash + score + versor bytes, speculative, versor_condition<1e-6); and
replay_hash re-derivable after reboot. Gate verified to BITE (COHERENT default,
refusal-writes, reprojection-on-load all fail it).
INV-21: generate/realize/realize.py added to ALLOWED_VAULT_WRITERS — a sanctioned
writer (same VaultStore.store path, SPECULATIVE default, nothing on Refusal).
Adversarially reviewed (3 lenses: invariants/wrong0/honesty, determinism/boundary,
scope/adjustments) — no critical/high/medium findings; low/nit honesty wrinkles
folded (state-dependent-placement wording, span-inclusive-dedup note, direct
versor-bytes gate assert, replay_hash re-derivation test). 10 R0 + 90 smoke green;
lane SHAs 8/9 (sole miss = public_demo env flake; deductive_logic + math_teaching
unchanged -> no GSM8K coupling).
Scopes REALIZE (comprehended/told structure -> the held self with an
EpistemicStatus, persisted via Shape B+, recalled exactly) — roadmap Step 3, the
boundary that turns comprehension from an eval artifact into accumulating living
knowledge; intake ("being told") lands here.
Produced by a reconnaissance -> design -> adversarial-verification pass over the
real substrate (vault, EpistemicStatus, Shape B+ persistence, teaching/intake,
comprehension output, determinism/replay). Central finding: a realized record is a
structured vault entry (versor, metadata), NOT a new store — so it inherits exact
cga_inner recall, EpistemicStatus stamping (teaching/epistemic.py already exists),
and bit-exact snapshot/restore for free.
Defines the realized-knowledge record, the told->realize->recall->survives-reboot
contract, the composition seams (verified APIs), the obligations (wrong=0,
provenance, EpistemicStatus honesty, no forbidden normalization, no parallel
learning path, determinism), slice R0 + a falsifiable exit gate, and the design
forks/risks/open-questions.
Adversarially corrected: R0 must catch embedding KeyError/empty-decomposition ->
no-op (+ OOV grounding determinism); determinism is state-restore-based not
input-pure (versor/score are session-state-dependent); MeaningSpan (not
SourceSpanLink) is the provenance API; sharpened gate arms (history-dependence +
idempotency/placement re-run).
The binding-graph's FIRST comprehension consumer (doctrine-aligned: quantities live
in binding_graph, NOT the MeaningGraph). generate/quantitative_comprehension.py
reads arithmetic prose into SymbolBinding/BoundFact/BoundEquation and runs the REAL
check_admissibility (shell -> verify -> rebuild with the actual UnitProof) — there
is NO stamped "admitted": an equation is admitted only if its operand units verify.
Then to_relational_metric projects the binding-graph to the independent
relational_metric oracle for the verdict.
Templates (digits only; non-digit quantity REFUSES):
"<X> has <N> <unit>" -> BoundFact(X = N)
"<Y> has <N> more <unit> than <X>" -> BoundEquation(Y = X + N) op=add
"<Y> has <N> fewer <unit> than <X>" -> BoundEquation(Y = X - N) op=subtract
"How many <unit> does <Y> have" -> ask Y
"How many <unit> do <X> and <Y> have"-> total = X + Y; ask total
Unit modelling (honest, not faked): a noun the closed en_units_v1 pack knows is
used verbatim (dollars -> dollar/money); an UNKNOWN sortal noun (stickers, coins)
is a count of discrete objects -> the existing 'item' lemma (dimension count). So
admissibility stays a REAL check: count+count admits, count+money (a mixed-unit
sum) REFUSES with unit_mismatch — verified to bite.
comprehension_relational_metric: 15/15 wrong=0 (full coverage). Located OUTSIDE
generate/meaning_graph (it targets binding_graph, not the MeaningGraph) so INV-28
neutrality stays intact; oracle imports none of the SUT (new INV-25 lane).
Capability index breadth 7->8, score 0.928622 -> 0.937258, wrong_total 0, digest
50e0675b…
Tests: reader templates + count/known-unit modelling + admissibility-bite (mixed
unit refuses) + non-digit refusal; end-to-end full-coverage wrong=0; arithmetic
added to the structure-preservation generative panel (projected relations+query ==
ground truth); capability breadth 7->8; INV-25 arithmetic lane. 93 targeted + 90
smoke green; lane SHAs 8/9 (sole miss = public_demo env flake; deductive_logic +
math_teaching unchanged -> no GSM8K coupling).
Addresses the review's hygiene point: the comprehension lanes deserve the same
repo-wide independent-gold + neutrality discipline as the older reasoning lanes.
INV-25 (independent gold): register the four comprehension lanes
(set_membership / syllogism / total_ordering / propositional) so their domain
oracles are statically proven to import NONE of the comprehension organ
(generate.meaning_graph reader + projectors). The gold the reader is scored
against is thereby independent of the reader — the anti-overfit firewall now covers
comprehension, not just the structured-input lanes. All four oracles are clean
(stdlib-only), so the firewall passes.
INV-28 (MeaningGraph neutrality): a new repo-wide invariant mirroring INV-26's
binding-graph neutrality — no generate/meaning_graph module imports
field/algebra/evals/vault/chat/core/sensorium or numpy. The MeaningGraph is the new
neutral meeting point where prose-read structure projects into independent oracles;
it earns the same firewall. numpy is forbidden too: Path β reads structure
SYMBOLICALLY and quantities are the binding-graph's domain, not the MeaningGraph's.
Non-vacuity test included (the predicate flags a module known to import the field
engine).
Tests-only. 56 architectural-invariant tests pass (was 53 + 3 new INV-28 +
4 INV-25 lanes wired into the existing oracle-firewall test).
Addresses the central review finding: the generative wrong=0 tests compared oracle
VERDICTS, so a misread graph that coincidentally yields the same verdict passed
silently (coincidental correctness in cleaner clothes). This adds the conjugate
check — the reader must recover the EXACT structure the prose encodes, not merely a
verdict-equivalent one.
tests/test_comprehension_structure_preserving.py:
- Structure preservation (all 4 domains): over randomly generated structures
rendered to prose that FULLY determines them, assert projected structure AND
query == ground truth exactly (order-insensitive canonicalization), or refuse.
Empirically this is strictly stronger: under a subject<->predicate premise swap,
361/400 reads are structurally wrong and 307 of those (85%) coincide in verdict
— the answer test misses all 307; the structure test catches all 361.
- Perturbation invariance: meaning-preserving surface changes (premise/clause
reordering, capitalization, extra whitespace) yield the SAME structure.
The existing answer-preservation property tests stay (verdict agreement is still a
valid, separate check — exactly the "assert structure, then separately assert
oracle agreement" the review recommends). Tests-only; no source change; capability
index unchanged. 7 new + 86 comprehension/capability targeted green.
Execution-ready brief for the next comprehension increment (user-chosen,
doctrine-aligned): read arithmetic word-problem prose into the binding_graph
quantity substrate -> project to the independent relational_metric oracle ->
wrong=0. Reuses the existing 15-case relational_metric gold lane (no gold
authoring).
Captures the full scope from this session: the oracle grammar (fact/more_than/
fewer_than/sum_of), the new number-parsing reader capability, binding_graph
construction (SymbolBinding/BoundFact/BoundEquation with REAL admissibility — a
proof obligation, not a stamp), the direct-construction recommendation (keep the
comprehension organ disjoint from the GSM8K MathProblemGraph / serving path), the
projector, wiring, the generative round-trip anti-overfit test, and the
validation gates.
Briefed rather than rushed: this is binding_graph's first comprehension consumer,
a load-bearing integration whose correctness hinges on real equation
admissibility — it deserves fresh context, per "no shortcuts on architectural
gaps".