Plan of record for the generalization arc lands here
(docs/plans/generalization-arc-2026-07-24.md) with the risk-tiered
handoff pack (docs/handoff/generalization-2026-07/); Phase 0.1 executed.
Root-caused the three stale lane pins (docs/research/lane-drift-
investigation-2026-07-24.md):
- miner/curriculum: 5c69b741 (ADR-0244 §2.7) widened content digests
16→64 hex; intentional, pins were simply never updated. Re-pinned
surgically; SHAs triple-run deterministic.
- demo_composition: a REAL serving regression. #76's canonical-first
base precedence in resolve_surface, activated when #96 routed pipeline
turns through the resolver, served the pre-R6 canonical — the register
axis (ADR-0077 R6 substantive + ADR-0071 R4 decoration) was silently
stripped from every pipeline-served turn. T13's back-stamp then made
telemetry mirror the stripped bytes; register-tour claims went red and
the e2e tests pinning the axis (outside smoke) were failing on main.
Fix: response-first base precedence (served bytes = post-guard, post-R6,
post-R4) + new SurfaceResolution.hash_surface carrying the truth-path
canonical-precedence bytes through substrate overrides, folds, hedge,
logos-morph, and the speculative marker. compute_trace_hash folds
hash_surface, so the register axis varies the served surface ONLY and
trace_hash stays register-invariant (ADR-0069 inv C). _prior_surface
(correction binding) stays on the truth path. Dead FailureClass import
and _assessment_residual removed.
Also: generate_claims.py had raised on every run since the
deduction_serve_v1 pin landed without a _LANE_ADR entry — mapping added
(ADR-0256), CLAIMS.md regenerated, --check green.
[Verification]: register tour 6/6 claims (substantive-differs restored,
all_trace_hashes_identical held); 88 tests green in-worktree
(test_surface_resolution incl. 2 new fallback tests,
test_register_substantive_consumption incl. previously-red e2e tests,
test_grounded_open_hedge_arm, test_cognitive_turn_pipeline,
test_warmed_session_lane 10/10 T13 consistency); miner/curriculum lane
SHAs byte-identical across three runs; deduction_serve + deductive_logic
lane reports byte-identical to their unchanged pins; smoke suite via
pre-push gate.
6.3 KiB
Lane-Pin Drift Investigation — miner / curriculum / demo_composition
Date: 2026-07-24 · Worktree: core-wt-gen off main @ 5224b5e0
Verdict: two distinct causes; no determinism bug; one real serving
regression found and fixed (register axis stripped from pipeline-served
turns).
Context: during the Band v4-CM arc (2026-07-23), a verify_lane_shas.py --update dry run showed three lanes' pins stale. This investigation
root-causes all three before any re-pin (generalization-arc Phase 0.1).
Determinism check
Each drifted lane was run twice in a fresh worktree (fresh
uv sync --locked venv, hermetic CORE_ENGINE_STATE_DIR): byte-identical
SHAs across runs for miner_loop_closure (537094fe…) and
curriculum_loop_closure (cb94ca00…). Not a determinism bug.
Cause 1 — content-digest widening (miner + curriculum): benign, stale pins
Commit 5c69b741 (2026-07-17, ADR-0244 Phase 5a "§2.7 content-id
semantic rigor") widened core/contemplation/schema.py::_content_digest
from 16-hex truncation to the full 64-hex sha256 (birthday-collision
rigor). Both lanes' reports embed finding_id / derived proposal_id
values from that digest: the fresh finding_id is the 64-hex extension
of the exact pinned 16-hex prefix (4d6b8b5e1d46eb60 →
4d6b8b5e1d46eb60ea7a…), and every downstream proposal_id cascades.
The commit re-pinned nothing. Intentional, ADR-tracked, benign → both
pins re-pinned surgically in this branch (single-line edits; never
--update, which rewrites every lane and silently drops erroring
lanes' pins).
Cause 2 — demo_composition: a REAL serving regression (found via the drift)
The fresh lane report flipped register-tour all_claims_supported
true→false (plus composite_supported, which is audit ∧ register).
Isolation showed the register tour's two substantive-differentiation
claims failing while the three invariance claims held: terse/convivial
registers no longer differed from neutral on pack-grounded definitions
— the entire register axis (ADR-0077 R6 substantive + ADR-0071 R4
decoration) was missing from pipeline-served surfaces.
Mechanism (three commits, each individually defensible):
ff1dcb25(2026-05-20, #76) introducedresolve_surfacewith a_base_runtime_surfaceprecedence of canonical-first — the trace-hash identity capture preferred over the runtime's served bytes. Dormant at first.e0d1b475(2026-07-20, #96 fail-closed linguistic governance) routed pipeline turns through the resolver withcanonical_surfacepopulated → pipeline-served turns began serving the pre-R6 canonical. The runtime's ownchat()path stayed correct;warmed_sessiontelemetry-consistency went red (0.9444) because TurnEvent (correct bytes) disagreed with pipeline (stripped bytes).5a343b49(2026-07-22, T13) "fixed" the telemetry red by back-stamping the pipeline's (stripped) surface onto TurnEvent — making telemetry consistent with the regressed serving. The register tour's claims — the falsifiable contract for the register axis — then failed, which is exactly the byte drift the lane pin caught.
Why no gate caught it: the e2e tests that pin this behavior
(tests/test_register_substantive_consumption.py::test_e2e_terse_*)
are red on main but are not in the curated smoke suite; the lane-shas CI
job is the only gate that runs the demo lanes, and its failures were
conflated with the known public_demo env flake.
Fix (this branch)
core/cognition/surface_resolution.py + core/cognition/pipeline.py:
_base_runtime_surfaceprecedence corrected to response-first (served bytes = post-guard, post-R6, post-R4), canonical demoted to last-resort fallback.- New
SurfaceResolution.hash_surface: the truth-path (canonical-precedence) bytes, kept in lockstep through substrate overrides, folds, hedge prefix, logos-morph override, and the speculative marker.compute_trace_hashnow foldshash_surface, so trace_hash stays register-invariant (ADR-0069 inv C) while the served surface carries the register._prior_surface(correction binding) also stays on the truth path so register packs cannot perturb teaching. - Removed dead
FailureClassimport +_assessment_residual(repo-wide unreferenced).
Verification: register tour 6/6 claims (both substantive-differs
claims restored AND all_trace_hashes_identical held);
tests/test_surface_resolution.py (updated precedence tests + 2 new
fallback tests), test_register_substantive_consumption.py (previously
red e2e tests now green), test_grounded_open_hedge_arm.py,
test_cognitive_turn_pipeline.py, test_warmed_session_lane.py (T13
consistency) — all green; smoke suite via pre-push gate.
demo_composition pin disposition (measured)
After the fix, every claims-supported flag in the lane report matches
the committed report again (all_claims_supported_a/b true,
composite_supported true). The only residual delta vs the 2026-07-14
pin is the two tours' inner payload sha256 values — those payloads
embed per-prompt trace_hash values whose format legitimately changed
post-pin (e7d116c9, 2026-07-20: Phase-B graph-topology inclusion in
compute_trace_hash). Semantics restored, embedded hash format
evolved → re-pinned to f0611a2c… with this diff as the audit trail.
public_demo (not one of the three, for completeness)
Unchanged: its known failure mode is the env-timeout flake
(all_claims_supported=False under cold/slow runs), documented in
memory and the lane-shas remediation text. Do not re-pin from a laptop
run; adjudicate on the Act runner.
Bonus latent break found while re-pinning
scripts/generate_claims.py raised on every run since the
deduction_serve_v1 pin landed (2026-07-23): the pin was added to
PINNED_SHAS without the required _LANE_ADR entry, so the lane-shas
CI's generate_claims.py --check step has been red since then. Fixed
here (ADR-0256 row added; CLAIMS.md regenerated, check green).
Follow-ups (assigned in the generalization-arc plan)
- Tier S: add
tests/test_register_substantive_consumption.pye2e tests to the curated smoke suite so this axis can never silently regress again (small, mechanical). - Tier S: document the lane-shas CI expectation that a red lane job is triaged per-lane, never assumed to be the public_demo flake.