Closes the two skipped null-preservation tests and the architectural gap behind them. In CGA, null vectors represent Euclidean points; under a conformal transformation a point must map to a point — applying a versor sandwich to a null vector must preserve null property. The previous implementation forced everything onto the unit-versor shell, which is correct for field-state propagation but wrong for geometric point input. Implementation - algebra/versor.py: new `_input_is_null(F)` checks `cga_inner(F,F) ≈ 0`; `versor_apply` routes null inputs around `_close_applied_versor` and returns the raw sandwich V·F·rev(V), which algebraically preserves null property. Non-null inputs unchanged. - core-rs/src/versor.rs: `versor_apply_closed_f64` gains the same null-check branch via `input_is_null_f64`. ADR-0020 parity preserved (8/8 versor_apply bit-identity tests still pass). Test changes - tests/test_architectural_invariants.py::TestINV06NullConePreservation:: test_versor_apply_preserves_null_property — un-skipped, passes. - tests/test_rust_backend.py::test_rust_versor_apply_preserves_null_vectors — un-skipped, passes. - tests/test_versor_closure.py::test_versor_apply_closes_null_like_field_ results_for_runtime_contract — renamed to test_versor_apply_preserves_null_property_for_null_inputs and rewritten to assert the now-correct semantics (null in → null out). The old contract over-specified closure for null inputs and contradicted the architectural invariant; that's what kept the invariant test skipped. Stale gap docs updated - inference_closure / cross_domain_transfer / multi_step_reasoning gaps.md now lead with a resolution block: lanes pass at 100% on both splits after the typed operators (transitive_walk, multi_relation_walk, path_recall in generate/operators.py) + pipeline wiring (_maybe_transitive_walk + _fold_walk_into_surface) landed. The historic findings are preserved below for traceability. - compositionality gaps.md: partial resolution — recall up from 6.25% to 68.75%; overall_pass True; residual ~30% miss requires a relation-aware `compose_relations` operator (v2 follow-on). Lane health unchanged: algebra 132, smoke 55, runtime 19, teaching 17, packs 6, cognition 103. Cognition eval 100%. Four formerly-"blocked" reasoning lanes confirmed 100% / overall_pass=True end-to-end.
5.4 KiB
inference-closure lane — architectural findings (v1)
Resolution — 2026-05-17 lane re-run
After the typed deterministic operators (ADR-0018: transitive_walk,
multi_relation_walk, path_recall in generate/operators.py) and
their pipeline wiring (_maybe_transitive_walk + _fold_walk_into_surface
in core/cognition/pipeline.py) landed, this lane passes:
| Split | n | derived_recall_rate | premises_stored | replay | overall |
|---|---|---|---|---|---|
| public/v1 | 20 | 1.0 | 1.0 | 1.0 | ✓ |
| holdouts/v1 | 12 | 1.0 | 1.0 | 1.0 | ✓ |
Gap 1 (no transitive composition) and Gap 2 (no path-recall) are both
closed. The probe for wisdom is light, light is truth,
What is wisdom? now produces
wisdom is defined as ... — wisdom is truth (via wisdom light truth),
and the chain endpoint truth is folded into the user-facing surface.
Historic finding preserved below.
Original v1 result (now superseded)
| Split | n | derived_recall_rate | premises_stored_rate | replay_determinism | overall_pass |
|---|---|---|---|---|---|
| public/v1 | 20 | 0.0 | 1.0 | 1.0 | False |
| holdouts/v1 | 12 | 0.0 | 1.0 | 1.0 | False |
This is the expected v1 outcome documented in
docs/capability_roadmap.md Phase 3: lanes may fail v1 honestly, and
each failure becomes either a closed engineering gap or a documented
architectural deferral.
What v1 confirms
- Foundation intact. Every premise emits a
PackMutationProposal(M3 = 1.0); every (premises, probe) sequence is replay-deterministic by trace_hash (M4 = 1.0). The work that landed in Phase 2 (symbolic-logic v1+v2) — storage and replay — holds at this depth. - No inference operator. Across all 32 cases (20 public + 12
holdouts) covering five relation families (
is,precedes,grounds,causes,belongs_to), the probe response surface never references the derived entailment token. Bothsurfaceandwalk_surfaceare template-driven definitions/disclaimers, not derivations.
Concrete probe trace
For INF-DEV-001 — premises wisdom is light, light is truth,
probe What is wisdom? — the runtime produces:
PREMISE 'What is wisdom?' surface='wisdom is defined as ...' vault=0
PREMISE 'Actually wisdom is light' surface='Light write.' vault=9
PREMISE 'What is light?' surface='light is defined as ...' vault=5
PREMISE 'Actually light is truth.' surface='Truth thought — λαμβάνω…' vault=9
PROBE 'What is wisdom?'
surface = 'wisdom is defined as ...'
articulation_surface = 'wisdom is defined as ...'
walk_surface = 'Wisdom does not with.'
vault_hits = 9
The probe retrieves 9 vault entries (so the premises are in
recall reach) but the realizer template emits a generic definition
stub. The transitive entailment (truth) appears in neither
surface nor walk_surface.
Architectural gaps (where the inference closure step is missing)
The roadmap pre-identified two suspects. v1 evidence narrows it to both:
Gap 1 — generate/graph_planner.py has no transitive composition
When the premise wisdom is light is taught, a proposition-graph
node is created. When light is truth is taught, a second node is
created. No edge composition step runs that would emit a derived
node wisdom is truth. The articulation target planner picks a
single node to articulate; it has no mechanism for chained traversal.
Engineering shape (out of scope for v1, in scope for v2):
- Extend
graph_from_intent()to detect a probe whose form is "what does A R?" / "what is A?" and walk outgoing R-edges of A. - Extend
plan_articulation()to optionally compose a multi-node surface when the walk produces a single deterministic chain.
Gap 2 — field/propagate.py has no derivable-but-not-asserted recall path
Vault retrieval scores cga_inner(query, stored_versor) and returns
the top-K direct matches. There is no path-based recall that says
"return X if there is a relation-chain from the query entity to X."
The 9 vault hits for the probe include the premise versors but not a
derivation versor (none exists).
Engineering shape (also v2 candidate, may overlap with Gap 1):
- A path-recall operator over the relation-typed edges of vault entries. Preserves exact-CGA semantics: the chain composition is deterministic, not approximate.
Pass criterion review
The pass thresholds in contract.md (derived_recall_rate >= 0.50,
premises_stored_rate >= 0.95, replay_determinism >= 0.95) are
unchanged. v1's failure is uniform on the derived-recall metric —
exactly what the contract was built to detect.
What stands today
- The lane exists as a permanent regression and progress signal.
- Foundation guarantees (storage, replay) are independently scored and remain at 1.0 — closing the inference gap will not cost them.
- Structural-zero frontier baseline recorded
(
baselines/v1_structural_zero.json): frontier LLMs do not emit the typed signals these sub-metrics score by construction.
Phase 3 exit posture
This lane satisfies the roadmap's v1 expectation: "v1 results with honest scores (which may be failing — that's acceptable for v1)." Phase 3 exit requires at least two lanes passing v1 by phase exit; inference-closure's gap-1 / gap-2 engineering work, if undertaken, flips this lane from failing v1 to passing v2 and contributes to that count. Until then it stands as load-bearing evidence of the specific engineering work needed.