diff --git a/CLAIMS.md b/CLAIMS.md index a11598ad..4b8315c5 100644 --- a/CLAIMS.md +++ b/CLAIMS.md @@ -36,13 +36,14 @@ is a CI failure (`.github/workflows/lane-shas.yml`). | --- | --- | --- | --- | --- | | ADR-0092 | `reviewer_registry` | Reviewer registry schema validates + bootstrap entry self-seals | `evals/reviewer_registry/results/v1_dev.json` | `681a2aab5aa4ffd58cd837ce5673c8b2a9545b570117aec3c02726a12f6876e6` | | ADR-0093 | `domain_contract_validation` | All ratified packs satisfy the 9 ADR-0091 contract predicates | `evals/domain_contract_validation/results/v1_dev.json` | `98ace04e3f02bbc5a8ad655bb6593c3f1ee64cb67014f1122fe6c3c85f48d22f` | -| ADR-0095 | `miner_loop_closure` | Miner-sourced proposals route through single reviewed teaching path | `evals/miner_loop_closure/results/v1_dev.json` | `9f071733abe7dcacf759f928548ce738fb639af3fd6e4c621a651b306d7e77ce` | +| ADR-0095 | `miner_loop_closure` | Miner-sourced proposals route through single reviewed teaching path | `evals/miner_loop_closure/results/v1_dev.json` | `537094fe21d7e6cfbaf42bfc32b82d669fa9bb05a132d2bc93c72b3ceb7762a6` | | ADR-0096 | `fabrication_control_summary` | Phantom endpoints / cross-pack non-bridges / sibling collapses refuse | `evals/fabrication_control/results/v1_summary.json` | `01e1b6b711141f2b4a14551d7df3ea482d8d6dd7b364a25c509f4f8d08cda8a8` | -| ADR-0098 | `demo_composition` | Demos compose from shipped modules; no parallel mechanism | `evals/demo_composition/results/v1_dev.json` | `e2ba2314d8768459fb6a8db082a4bbcf4107b5161d869804a4b2a33c3724081a` | +| ADR-0098 | `demo_composition` | Demos compose from shipped modules; no parallel mechanism | `evals/demo_composition/results/v1_dev.json` | `f0611a2ce41721dd40767fc6a83a08470d3c7fd7fc8f1ae8ba003abf8a25ec97` | | ADR-0099 | `public_demo` | Public showcase runs deterministically under 30s; all claims supported | `evals/public_demo/results/v1_dev.json` | `7d8ba0dbae9287cfe0bf15d231fa78a75abc627121c14900439293e01e1cc1d3` | -| ADR-0104 | `curriculum_loop_closure` | Curriculum-sourced proposals route through single reviewed teaching path | `evals/curriculum_loop_closure/results/v1_dev.json` | `b46d56b2d209172cc3ffaf3776dc8dcfe55093f13587c5cb67372be6dfa23e8d` | +| ADR-0104 | `curriculum_loop_closure` | Curriculum-sourced proposals route through single reviewed teaching path | `evals/curriculum_loop_closure/results/v1_dev.json` | `cb94ca0042d78ec2624129ff6493d52e767b69feea32d2997b85d88f1c0883af` | | ADR-0131 | `math_teaching_corpus_v1` | Math teaching corpus replays deterministically; all chains pass exit criterion (correct_rate=1.0, wrong=0) | `evals/math_teaching_corpus/v1/report.json` | `eaf160d145da29f9050ede8d58bf111b0f651dd40aeae9201857d0b97e014dd4` | | ADR-0206 | `deductive_logic_v1` | Propositional entailment scored against an independent truth-table oracle; dev+holdout+external 716/716 correct, wrong=0, refused=0 | `evals/deductive_logic/report.json` | `97a230949016e38d5e3f37a69e4245b320575ee70e5af92ff7607f7b05f74b5f` | +| ADR-0256 | `deduction_serve_v1` | Flag-gated deduction serving decides real English/member/fused arguments end-to-end under earned SERVE licenses; wrong=0 across all splits | `evals/deduction_serve/report.json` | `b530ed99c414a6d1bdd239752b0e1c6c8c03893f402198def29122b9c2a8a8be` | ## Verification diff --git a/core/cognition/pipeline.py b/core/cognition/pipeline.py index e4e6ccd5..6e3a3bc9 100644 --- a/core/cognition/pipeline.py +++ b/core/cognition/pipeline.py @@ -486,6 +486,11 @@ class CognitiveTurnPipeline: grounding_provenance=grounding_src, ) surface = resolved.surface + # Truth-path bytes for trace_hash (ADR-0069 inv C): the served + # surface carries register R6/R4 transforms and MUST NOT move the + # hash; hash_surface is the register-invariant canonical-precedence + # capture, kept in lockstep with every served-surface mutation below. + hash_surface = resolved.hash_surface or resolved.surface articulation_surface = resolved.articulation_surface authority_source = resolved.authority @@ -518,6 +523,7 @@ class CognitiveTurnPipeline: if logos_blocks_certified_answer(logos_decision): refusal = decision_as_coherence_refusal(logos_decision) surface = refusal.surface_message or refusal.message + hash_surface = surface articulation_surface = surface authority_source = "logos_morph_constraint" except Exception: @@ -667,6 +673,7 @@ class CognitiveTurnPipeline: # proposal (if any) is added below for FUTURE turns to see. if self._speculative_subjects and surface and self._should_mark_speculative(text, surface): surface = _SPECULATIVE_SURFACE_MARKER + surface + hash_surface = _SPECULATIVE_SURFACE_MARKER + hash_surface articulation_surface = _SPECULATIVE_SURFACE_MARKER + articulation_surface # 10. TEACHING — correction capture, review, and store @@ -705,9 +712,11 @@ class CognitiveTurnPipeline: if len(tok) >= 4 and tok not in _SUBJECT_STOPWORDS: self._forget_speculative_subject(tok) - # Advance turn counter and remember surface for next correction binding + # Advance turn counter and remember surface for next correction binding. + # The truth-path surface (not the served, register-decorated bytes) + # feeds correction binding so register packs cannot perturb teaching. self._turn_number += 1 - self._prior_surface = surface + self._prior_surface = hash_surface # 11. TRACE — deterministic hash (includes teaching IDs and any # typed-operator invocation per ADR-0018). @@ -787,7 +796,7 @@ class CognitiveTurnPipeline: trace_hash = compute_trace_hash( input_text=text, filtered_tokens=filtered_tokens, - surface=surface, + surface=hash_surface, walk_surface=response.walk_surface, articulation_surface=articulation_surface, dialogue_role=str(response.dialogue_role), diff --git a/core/cognition/surface_resolution.py b/core/cognition/surface_resolution.py index 96009397..84affc4b 100644 --- a/core/cognition/surface_resolution.py +++ b/core/cognition/surface_resolution.py @@ -24,8 +24,6 @@ from typing import TYPE_CHECKING from core.cognition.fail_closed import ( CoherenceRefusal, ContractViolation, - FailureClass, - ResidualState, contract_assessment_none_violation, open_geometry_refusal, ) @@ -86,6 +84,15 @@ class SurfaceResolution: refusal: CoherenceRefusal | None = None contract_violation: ContractViolation | None = None proof_trace: ProofTrace | None = None + hash_surface: str = "" + """Truth-path surface for ``trace_hash`` folding (ADR-0069 inv C). + + ``surface`` carries the *served* bytes (post register R6/R4); + ``hash_surface`` carries the register-invariant truth-path bytes + (canonical-precedence base plus the same substrate/fold suffixes). + Empty means the served surface IS the truth-path surface (refusal, + abstention, and legacy callers) — the pipeline falls back to + ``surface`` when folding the trace.""" def _base_runtime_surface( @@ -95,25 +102,44 @@ def _base_runtime_surface( response_surface: str, response_articulation_surface: str, ) -> tuple[str, str, str]: - """Select the runtime-owned base surface by declared precedence.""" + """Select the runtime-owned base surface by declared precedence. - if canonical_surface: - return canonical_surface, response_articulation_surface, "runtime_canonical" + ``response_surface`` is the runtime's final *served* bytes — post + realizer-guard, post substantive register (ADR-0077 R6), post seeded + decoration (ADR-0071 R4) — and always wins when present. + ``canonical_surface`` / ``pre_decoration_surface`` are truth-path + identity captures the pipeline folds into ``trace_hash``; they are + fallbacks for callers that never sealed a response surface, never a + substitute for served bytes. Preferring canonical here strips the + entire register axis from pipeline-served turns (terse/convivial + stop differing from neutral) while trace_hash stays green — the + register-tour claims are the falsifiable contract that catches it. + """ + + if response_surface: + return response_surface, response_articulation_surface, "runtime" if pre_decoration_surface: return pre_decoration_surface, response_articulation_surface, "runtime_pre_decoration" - return response_surface, response_articulation_surface, "runtime" + if canonical_surface: + return canonical_surface, response_articulation_surface, "runtime_canonical" + return "", response_articulation_surface, "runtime" -def _assessment_residual( - contract_assessment: "ContractAssessment | None", -) -> ResidualState | None: - if contract_assessment is None: - return ResidualState(detail="contract_assessment is None") - return ResidualState( - missing_bindings=tuple(contract_assessment.missing_bindings), - unresolved_hazards=tuple(contract_assessment.unresolved_hazards), - detail=str(contract_assessment.explanation or ""), - ) +def _truth_path_base( + *, + canonical_surface: str, + pre_decoration_surface: str, + response_surface: str, +) -> str: + """Register-invariant base folded into ``trace_hash``. + + Canonical-first: the composer's pre-R6 capture is the truth-path + identity field, byte-identical across register packs (ADR-0069 + inv C / ADR-0077). Falls through to pre-decoration, then the + response itself for turns that never captured a canonical surface. + """ + + return canonical_surface or pre_decoration_surface or response_surface def _abstention_resolution( @@ -211,9 +237,17 @@ def _grounded_open_hedge_resolution( response_surface=response_surface, response_articulation_surface=response_articulation_surface, ) + truth_base = _truth_path_base( + canonical_surface=canonical_surface, + pre_decoration_surface=pre_decoration_surface, + response_surface=response_surface, + ) surface = ( f"{_GROUNDED_OPEN_HEDGE_PREFIX} {base_surface}" if base_surface else base_surface ) + hash_surface = ( + f"{_GROUNDED_OPEN_HEDGE_PREFIX} {truth_base}" if truth_base else truth_base + ) articulation = ( f"{_GROUNDED_OPEN_HEDGE_PREFIX} {base_articulation}" if base_articulation @@ -229,6 +263,7 @@ def _grounded_open_hedge_resolution( refusal=None, contract_violation=None, proof_trace=None, + hash_surface=hash_surface, ) @@ -322,6 +357,11 @@ def resolve_surface( response_surface=response_surface or "", response_articulation_surface=response_articulation_surface or "", ) + hash_surface = _truth_path_base( + canonical_surface=canonical_surface or "", + pre_decoration_surface=pre_decoration_surface or "", + response_surface=response_surface or "", + ) # === DUAL-COMPETING SHADOW COHERENCE GATE === # Forward and conjugate evaluated as independent competitors; commit @@ -340,6 +380,7 @@ def resolve_surface( if not gate_blocks and realized_surface and forward_ok and conjugate_ok: surface = realized_surface + hash_surface = realized_surface articulation_surface = realized_surface authority = "substrate_realizer" elif ( @@ -352,12 +393,16 @@ def resolve_surface( # Transitional shim: geometric coherence holds, but graph not yet # fully grounded. Never used when conjugate residual fails. surface = realized_surface + hash_surface = realized_surface articulation_surface = realized_surface authority = "realizer" fold_sources: list[str] = [] if walk_surface: surface = f"{surface} — {walk_surface}" if surface else walk_surface + hash_surface = ( + f"{hash_surface} — {walk_surface}" if hash_surface else walk_surface + ) articulation_surface = ( f"{articulation_surface} — {walk_surface}" if articulation_surface @@ -367,6 +412,9 @@ def resolve_surface( if compose_surface: surface = f"{surface} — {compose_surface}" if surface else compose_surface + hash_surface = ( + f"{hash_surface} — {compose_surface}" if hash_surface else compose_surface + ) articulation_surface = ( f"{articulation_surface} — {compose_surface}" if articulation_surface @@ -392,6 +440,7 @@ def resolve_surface( refusal=None, contract_violation=None, proof_trace=proof, + hash_surface=hash_surface, ) diff --git a/docs/handoff/generalization-2026-07/BRIEF-O-opus-medium-tier.md b/docs/handoff/generalization-2026-07/BRIEF-O-opus-medium-tier.md new file mode 100644 index 00000000..c58f5e07 --- /dev/null +++ b/docs/handoff/generalization-2026-07/BRIEF-O-opus-medium-tier.md @@ -0,0 +1,52 @@ +# Handoff Brief — Tier O (Opus 5, MEDIUM risk) + +**Read first:** `docs/plans/generalization-arc-2026-07-24.md` (the plan of +record — §4 gold contract and §6 constraint set are binding), then +`AGENTS.md`. Reference ADRs on demand: 0256–0259 (band recipe), +0175/0199 (license doctrine), 0251/0252 (math-reader guardrails). + +**You own, in order:** + +1. **O1 — Band v6-EX (existential `some` witnesses).** Follow the band + recipe exactly as ADR-0258/0259 executed it: reader module in + `generate/proof_chain/`, shape bands in `shape.py`, surface wiring in + `chat/deduction_surface.py`, arena templates ≥720/band in + `evals/deduction_serve/practice/gold.py`, hand-authored lane split, + ledger reseal, tests, ADR, research doc. Gotchas that bit before: + cross-module `_Reject` identity (catch both classes); band-N swallows + band-N+1 test texts (verify the prior band really refuses your + declined cases); surgical single-line pin edits only (never + `verify_lane_shas.py --update`). +2. **O2 — Phase 2 physics serve lane** per the §4 curriculum-entailment + contract. Premises come ONLY from ratified domain chains + (`teaching/domain_chains/physics_chains_v1.jsonl` + pack mounts); + anti-recall probes (gold=UNKNOWN for true-but-untaught) are mandatory + or the lane must not ship. Independent closed-world oracle first, + then the lane. Biology second, only after O3 lands. +3. **O3 — generic consumption bridge**: extract the seal→ratify→ + SHA-verified-license→serve-gate pattern (models: + `chat/deduction_serve_license.py`, + `generate/determine/estimation_license.py`) into a reusable ADR-0175 + Phase-5 bridge so subject arenas plug in without bespoke wiring. +4. **O4 — math reader: seeding-sentence injection** (standing ruling + #77 — the 75% "no injection" wall). Then compare unblock (4.2). + Hard guardrails: no bespoke-per-case regex growth (ADR-0251); check + every new pattern against + `docs/research/reader-arc-overfit-inventory-2026-07-19.md`; measure + on the frozen tune/measure split; wrong=0 on the full 500 is the + gate, parse-rate gain is the goal. + +**Constraints (non-negotiable):** wrong=0; all flags stay default-off — +flips are Shay's ratification only; Forgejo-primary (no `gh`); worktree +per unit off `forgejo-https/main`; fresh venv per worktree +(`rm -rf .venv && uv sync --locked --offline`, then `uv run --no-sync`); +pre-push hook runs smoke+warmed_session (~4.5 min — budget timeouts); +PRs opened by Shay via the compare URL the push prints (push PAT 403s +the PR API); Shay merges — never you; branch+worktree deleted after +merge; no timelines in any doc. + +**Your exit checkpoint (O→S):** v6-EX merged; ≥1 subject lane serving +wrong=0 with earned licenses; bridge merged; math increment measured and +documented (a null result is a valid checkpoint). Then update +`BRIEF-S-sonnet-low-tier.md` with actual state, update memory, and stop +for the Sonnet handoff. diff --git a/docs/handoff/generalization-2026-07/BRIEF-S-sonnet-low-tier.md b/docs/handoff/generalization-2026-07/BRIEF-S-sonnet-low-tier.md new file mode 100644 index 00000000..c28170bc --- /dev/null +++ b/docs/handoff/generalization-2026-07/BRIEF-S-sonnet-low-tier.md @@ -0,0 +1,47 @@ +# Handoff Brief — Tier S (Sonnet 5, LOW risk) + +**Read first:** `docs/plans/generalization-arc-2026-07-24.md` §6 +(constraint set is binding) and the Tier-O brief's constraints block — +they apply verbatim. Opus will have updated this brief with actual state +at its exit checkpoint; trust that update over anything stale below. + +**You own (independent items, any order unless noted):** + +1. **S1 — ratification packet for `deduction_serving_enabled`.** + Evidence collation only — the flip is Shay's decision, never yours. + Contents: 17+-band sealed ledger stats + (`chat/data/deduction_serve_ledger.json`), serve-lane results + (`evals/deduction_serve/report.json`), byte-identical-when-off proof + (cite ADR-0256 + `tests/test_deduction_surface.py` flag tests), blast + radius (exact dispatch point `chat/runtime.py` deduction branch), and + rollback (flip back, zero residue). One markdown doc in + `docs/research/`, PR'd. +2. **S2 — lane re-pins + flake documentation.** Only AFTER the Phase-0.1 + drift findings doc exists and says re-pin is safe. Surgical + single-line edits in `scripts/verify_lane_shas.py` — NEVER `--update` + (it rewrites every lane and silently drops erroring lanes' pins). + Document the `public_demo` env-timeout flake where the findings doc + says. +3. **S3 — vocab-trigger instrument.** Implement the measurable test + specified in `docs/handoffs/COMPREHENSION-READER-AUDIT.md` + (§measurable-test, lines ~163–166 and ~231–238): refusal histogram + split mechanism-vs-coverage + Phase-2-admissions-per-lexicon-batch + counter. CLI or lane runner per the spec; do not invent policy — the + spec decides, you implement. +4. **S4 — HITL proposal-queue CLI.** A `core` CLI surface listing + + reviewing pending proposals from the existing sinks + (`teaching/proposals/`, contemplation/idle sinks). Read + review-state + transitions only; NO ratification automation, NO corpus mutation, NO + flag flips. +5. **S5 — housekeeping.** Promotion sweeps Opus's checkpoint notes call + for; capability-index entries for new subject lanes; docs/memory + updates; dead-code removal only when unambiguous. + +**Constraints:** identical to Tier O (worktrees, fresh venv, pre-push +gate, compare-URL PRs, Shay merges, wrong=0, flags stay off, no +timelines). When any item's scope turns out larger than described here — +stop and flag it in the PR/handoff notes rather than improvising. + +**Arc close:** all Tier-S PRs pushed; memory updated; note whether the +Phase-5 articulation trigger (multi-step decided content exists) has +fired, for the next arc's scoping. diff --git a/docs/plans/generalization-arc-2026-07-24.md b/docs/plans/generalization-arc-2026-07-24.md new file mode 100644 index 00000000..ff51cebf --- /dev/null +++ b/docs/plans/generalization-arc-2026-07-24.md @@ -0,0 +1,238 @@ +# Generalization Arc — GSM8K-Level Capability Across Core Subjects + +**Date:** 2026-07-24 · **Status:** ACTIVE · **Base:** main @ `5224b5e0` (post ADR-0259 / Band v4-CM) + +This is the ratified plan of record for the arc that takes CORE from "one +fully-closed cognitive lifecycle (deduction-serve)" to "the same lifecycle +running across core subjects at GSM8K-exam level" — articulated answers, +problem solving, comprehension, all under wrong=0 discipline. + +Execution is **risk-tiered across three operators** (§6): Fable 5 does the +high-risk design + build, Opus 5 the medium tier, Sonnet 5 the low tier. +Handoff briefs live in `docs/handoff/generalization-2026-07/`. + +--- + +## 1. Ground truth at arc start + +- Exactly one lifecycle is closed end-to-end: **deduction-serve** + (comprehend → 5 band readers → ROBDD decide → sealed practice arena, + 17 bands × 720, θ_SERVE=0.99 → SHA-verified ratified ledger → license + gate → render → register chain). Dark behind + `deduction_serving_enabled=False`, awaiting ratification. +- Cross-subject substrate exists but is idle: 16 unmounted domain seed + packs, 5 domain chain corpora, 6 OOD fluency lanes, five-layer + teaching-order doctrine (`docs/teaching_order.md`), capability index. +- Learning-loop organs exist but are write-only or dark: 19 default-off + flags; proposal/contemplation/promotion paths emit into review sinks + with no runtime consumer. Three real ratified-artifact consumers exist + (deduction ledger, estimation license, recognizer registry) — the + pattern to generalize. +- Math is reader-gated, not solver-gated: compiler holds 50/50 wrong=0 on + dev-1 but the reader parses ~1% of real GSM8K; the ~30-band bet was + falsified; standing ruling #77 selects **seeding-sentence injection** + as the next math move. +- ADR-0246 §3.7 identity calibration is explicitly OFF this critical + path (blocked on §11 research evidence; doctrine order: + capability → practice → calibration → serve). + +## 2. Phases + +### Phase 0 — Truth-substrate hygiene + first live serve *(Small)* +- **0.1** Root-cause the 3-lane pin drift (`miner_loop_closure`, + `curriculum_loop_closure`, `demo_composition`). Classify: determinism + bug (stop-the-line) vs stale pins vs local/CI byte divergence. + Re-pin surgically only after root-cause. Findings doc in + `docs/research/`. +- **0.2** Ratification packet for `deduction_serving_enabled` (evidence + collation only; the flip is Shay's decision). + +**Done when:** drift explained + resolved; packet delivered. + +### Phase 1 — Reading generalization: verb predicates + existentials *(Large)* +The band cascade reads only copula sentences; every other subject states +facts as verb sentences. Ordered by leverage: + +- **1.1 Band v5-VP — verb predicates**: predicate atoms keyed by + (verb lemma, argument tuple); intransitive + transitive with + named/classed arguments ONLY; closed morphology; typed refusal for + everything else (voice, tense shifts, ditransitives, PP-arguments). + This band gates Phase 2. +- **1.2 Band v6-EX — existential (`some`) witnesses**: completes the + all/no/some square; witness-based lowering. +- Deferred (unchanged from ADR-0259 §5): universal-nested-in-connective + (bound-variable tracking), identity/co-reference, tense. + +Recipe per band (proven 3×): reader module → shape bands → arena +templates (≥720/band) → hand-authored lane split (content-disjoint from +practice lexicon) → ledger reseal → tests → ADR → research doc. + +**Done when:** verb-predicate and existential arguments decided at SERVE +wrong=0; ledger resealed; promotion sweep of previously-declined cases +done honestly (promotion = *decided correctly*, not *decided favorably*). + +### Phase 2 — Port the lifecycle to two non-math subjects *(Medium-Large)* +Physics and biology first (OOD lanes, seed packs, and domain chains +already exist). Implemented strictly to the **curriculum-entailment gold +contract** (§4 — the load-bearing design of this arc): + +- Mount subject packs; wire domain chains through the teaching corridor + per the five-layer order. +- Exam-shaped serve lanes: question → read (v5-VP reading) → decide + **from ratified curriculum premises only** → licensed articulated + answer. +- Per-subject band ledgers via the same arena; capability-index + coverage entries; 3-domain anti-overfit panel discipline + (independence must be in the READING). + +**Done when:** two subjects serve wrong=0 on hand-authored exam-shaped +lanes with earned licenses, zero subject-specific engine code. + +### Phase 3 — Close the discovery→learning loop *(Medium)* +- **3.1** Vocab-expansion trigger as code (the COMPREHENSION-READER-AUDIT + §measurable-test, made a standing instrument: refusal histogram split + mechanism-vs-coverage; admissions-per-lexicon-batch). +- **3.2** HITL proposal-queue surface (review CLI over the existing + sinks). +- **3.3** Generic consumption bridge: extract the seal → ratify → + SHA-verified license → serve-gate pattern (deduction ledger is the + model; estimation license the second instance) into the ADR-0175 + Phase-5 bridge so each subject arena plugs in without bespoke wiring. +- **3.4** Feed discovery-yield with real traffic (post 0.2 flip). + +**Done when:** a serve-time gap flows discovery → proposal → +ratification → runtime consumption with no manual file surgery. + +### Phase 4 — Math problem-solving reader *(Medium-Large, parallel lane)* +Independent of Phases 1–3 (no shared files; production-line pattern): + +- **4.1** Seeding-sentence injection (ruling #77; the 75% "no injection" + wall). +- **4.2** Compare unblock (summation-question reader + inverse compare), + queued behind 4.1 per the same ruling. +- **4.3** q:complex decomposition study (increment-1 band plan §9; 101 + cases behind one label). +- Guardrails pinned: `docs/research/reader-arc-overfit-inventory-2026-07-19.md`, + ADR-0251 recalibration (no bespoke-per-case regex growth), + ADR-0252. + +**Done when:** real-GSM8K parse floor materially above ~1% with wrong=0 +held on the full 500; ceiling revised with evidence. + +### Phase 5 — Articulation depth (`generate/` "core_logos") *(trigger-gated)* +Not queued by order. Trigger: Phases 1–2 produce multi-step decided +content (proof chains, multi-fact answers) — the evidence of where +articulation quality binds that the intelligence-loop plan's Phase 6 +deferral was waiting for. Scope the arc from that evidence. + +## 3. Dependencies + +- Phase 1.1 gates Phase 2. Phase 0 first. +- Phase 3.3 lands before the *second* subject arena (avoid copy-paste + wiring). 3.1/3.2 interleave freely. +- Phase 4 fully parallel. Phase 5 trigger-gated on 1–2. +- §3.7 identity calibration stays downstream of the whole arc (its + calibration data comes *from* this arc's practice volume). + +## 4. Curriculum-entailment gold contract (Phase-2 design, decided here) + +This section is the HIGH-risk design, fixed now so the medium tier can +implement without re-litigating epistemology. + +1. **Verdict domain** — every exam item resolves to + {entailed, refuted, unknown, declined}, identical to deduction-serve. + UNKNOWN is the honest verdict for untaught facts. No open-world + recall, ever. +2. **Two question shapes** — (a) self-contained arguments (premises in + the text): already owned by bands v2–v6; (b) **curriculum-grounded + questions** (the new Phase-2 shape): question text supplies only the + query; the premise set is compiled from the RATIFIED domain chain + corpus for that subject. Gold is a function of (curriculum, question) + — never of case-local hidden text. This is the decoding-not-generating + line in mechanical form. +3. **Premise provenance** — each lane case pins the chain IDs it draws + on; the runner reconstructs premises from the ratified corpus and + MUST fail the case if a pinned chain is absent or unratified. +4. **Independent oracle** — per subject, a closed-world reachability + oracle over the chain corpus (sharing no code with the serving path) + validates every gold verdict; the lane asserts corpus soundness + before any case runs (the `assert_corpus_sound()` pattern). +5. **License granularity** — bands keyed by (subject × relation family × + chain depth), earned in the ADR-0199 arena: θ_SERVE=0.99, n≥720, + wrong=0, sealed + SHA-verified ledger per subject. +6. **Typed refusals, lifecycle-mapped** — `untaught_vocabulary`, + `unratified_chain`, `out_of_curriculum`, `ambiguous_reading`; the + OOV refusal feeds the Phase-3 proposal queue (refusals become + discovery, not dead ends). +7. **Anti-recall probes (mandatory per lane)** — cases whose answer is + true in the world but absent from the curriculum; gold = UNKNOWN. + A lane without these probes cannot prove the system decodes rather + than recalls, and MUST NOT ship. + +## 5. Risks + +- **HIGH — subject-gold epistemology drift**: mitigated by §4 (contract + fixed before implementation; anti-recall probes mandatory). +- **HIGH — v5-VP scope creep**: argument structure/voice/agreement are a + real jump from copula. Mitigation: two argument shapes only, closed + morphology, typed refusal for the rest — the same discipline that made + v2–v4 land clean. +- **MEDIUM — arena scale**: 720/band × growing band count on local + hardware; linear sealing time; watch, don't block. +- **MEDIUM — synthetic-overfit trap**: practice templates and lane cases + stay content-disjoint per subject (standing doctrine). +- **MEDIUM — q:complex may not decompose**: nothing gates on Phase 4. +- **LOW — drift root-cause escalates**: if Phase 0.1 finds a determinism + bug, the arc pauses until it is fixed (stop-the-line). + +## 6. Risk-tiered operator assignment + +Constraint set for every tier: wrong=0; flags stay default-off (flips +are Shay's ratification only); Forgejo-primary, no GitHub/`gh`; local +smoke + warmed_session gate before every push (pre-push hook); `uv` +always; branch + worktree per unit; no merge automation; one PR per +coherent solution; attribution disabled. + +### Tier F — Fable 5 (HIGH risk; this session) +- F1: Phase 0.1 drift root-cause (+ surgical re-pin if benign). +- F2: this plan doc + handoff briefs. +- F3: §4 gold contract (done — it is this document). +- F4: Band v5-VP (Phase 1.1), full recipe, PR. + +**Checkpoint F→O:** F1/F2/F4 PRs pushed with compare URLs; memory +updated; briefs current. Opus starts at O1 with no open design +questions. + +### Tier O — Opus 5 (MEDIUM risk) +- O1: Band v6-EX existentials (Phase 1.2) — recipe + ADR-0257/0258/0259 + as references. +- O2: Phase 2 physics + biology serve lanes per §4 (mount packs, wire + chains, arena, ledgers, lanes). Physics first; biology second only + after the generic bridge (O3) lands. +- O3: Phase 3.3 generic consumption bridge. +- O4: Phase 4.1 seeding-sentence injection, then 4.2; 4.3 as analysis. + Guardrail docs pinned in §2/Phase 4. + +**Checkpoint O→S:** v6-EX merged; ≥1 subject lane serving wrong=0 with +earned licenses; bridge merged; math increment measured + documented +(whatever its outcome — a null result is a valid checkpoint). + +### Tier S — Sonnet 5 (LOW risk) +- S1: Phase 0.2 ratification packet (evidence collation). +- S2: Post-fix lane re-pins; public_demo flake documentation. +- S3: Phase 3.1 vocab-trigger instrument (spec is pinned in + `docs/handoffs/COMPREHENSION-READER-AUDIT.md` §measurable-test). +- S4: Phase 3.2 HITL proposal-queue CLI surface. +- S5: Promotion sweeps, capability-index entries, docs/memory + housekeeping. + +**Arc close:** all three tiers merged; Phase 5 trigger evaluated with +evidence in hand; next arc scoped from it. + +## 7. Non-goals (this arc) + +- ADR-0246 §3.7 / identity-gate calibration (evidence-blocked). +- `core/ports/` Ring-2/3 consumption (own future flag-gated units). +- Universal-nested-in-connective, co-reference, tense bands. +- Any serving-flag flip without explicit ratification. +- Zig substrate work. diff --git a/docs/research/lane-drift-investigation-2026-07-24.md b/docs/research/lane-drift-investigation-2026-07-24.md new file mode 100644 index 00000000..0e203863 --- /dev/null +++ b/docs/research/lane-drift-investigation-2026-07-24.md @@ -0,0 +1,125 @@ +# 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): + +1. `ff1dcb25` (2026-05-20, #76) introduced `resolve_surface` with a + `_base_runtime_surface` precedence of **canonical-first** — the + trace-hash identity capture preferred over the runtime's served bytes. + Dormant at first. +2. `e0d1b475` (2026-07-20, #96 fail-closed linguistic governance) routed + pipeline turns through the resolver with `canonical_surface` populated + → pipeline-served turns began serving the pre-R6 canonical. The + runtime's own `chat()` path stayed correct; `warmed_session` + telemetry-consistency went red (0.9444) because TurnEvent (correct + bytes) disagreed with pipeline (stripped bytes). +3. `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_surface` precedence 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_hash` now folds `hash_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 `FailureClass` import + `_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.py` e2e + 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. diff --git a/scripts/generate_claims.py b/scripts/generate_claims.py index ec86a63b..14e7008d 100644 --- a/scripts/generate_claims.py +++ b/scripts/generate_claims.py @@ -74,6 +74,10 @@ _LANE_ADR: dict[str, tuple[str, str]] = { "ADR-0206", "Propositional entailment scored against an independent truth-table oracle; dev+holdout+external 716/716 correct, wrong=0, refused=0", ), + "deduction_serve_v1": ( + "ADR-0256", + "Flag-gated deduction serving decides real English/member/fused arguments end-to-end under earned SERVE licenses; wrong=0 across all splits", + ), } diff --git a/scripts/verify_lane_shas.py b/scripts/verify_lane_shas.py index 735f1ad9..e2c9826c 100644 --- a/scripts/verify_lane_shas.py +++ b/scripts/verify_lane_shas.py @@ -43,11 +43,11 @@ LANE_TIMEOUT_S = int(os.environ.get("CORE_LANE_VERIFY_TIMEOUT_S", "900")) PINNED_SHAS: dict[str, str] = { "reviewer_registry": "681a2aab5aa4ffd58cd837ce5673c8b2a9545b570117aec3c02726a12f6876e6", - "miner_loop_closure": "9f071733abe7dcacf759f928548ce738fb639af3fd6e4c621a651b306d7e77ce", - "curriculum_loop_closure": "b46d56b2d209172cc3ffaf3776dc8dcfe55093f13587c5cb67372be6dfa23e8d", + "miner_loop_closure": "537094fe21d7e6cfbaf42bfc32b82d669fa9bb05a132d2bc93c72b3ceb7762a6", + "curriculum_loop_closure": "cb94ca0042d78ec2624129ff6493d52e767b69feea32d2997b85d88f1c0883af", "domain_contract_validation": "98ace04e3f02bbc5a8ad655bb6593c3f1ee64cb67014f1122fe6c3c85f48d22f", "fabrication_control_summary": "01e1b6b711141f2b4a14551d7df3ea482d8d6dd7b364a25c509f4f8d08cda8a8", - "demo_composition": "e2ba2314d8768459fb6a8db082a4bbcf4107b5161d869804a4b2a33c3724081a", + "demo_composition": "f0611a2ce41721dd40767fc6a83a08470d3c7fd7fc8f1ae8ba003abf8a25ec97", "public_demo": "7d8ba0dbae9287cfe0bf15d231fa78a75abc627121c14900439293e01e1cc1d3", "math_teaching_corpus_v1": "eaf160d145da29f9050ede8d58bf111b0f651dd40aeae9201857d0b97e014dd4", "deductive_logic_v1": "97a230949016e38d5e3f37a69e4245b320575ee70e5af92ff7607f7b05f74b5f", diff --git a/tests/test_surface_resolution.py b/tests/test_surface_resolution.py index c53eb6f4..6600112f 100644 --- a/tests/test_surface_resolution.py +++ b/tests/test_surface_resolution.py @@ -32,7 +32,10 @@ def _open_assessment() -> ContractAssessment: ) -def test_runtime_canonical_surface_has_base_precedence() -> None: +def test_runtime_response_surface_has_base_precedence() -> None: + # response_surface is the served bytes (post register R6/R4 — + # ADR-0077/ADR-0071); canonical is the trace-hash identity capture + # and must never displace served bytes when a response exists. resolved = resolve_surface( canonical_surface="canonical", pre_decoration_surface="pre-decoration", @@ -41,13 +44,39 @@ def test_runtime_canonical_surface_has_base_precedence() -> None: contract_assessment=_closed_assessment(), ) - assert resolved.surface == "canonical" + assert resolved.surface == "runtime" assert resolved.articulation_surface == "articulation" - assert resolved.authority == "runtime_canonical" + assert resolved.authority == "runtime" assert resolved.fold_sources == () assert resolved.authoritative is True +def test_canonical_surface_is_last_resort_fallback() -> None: + resolved = resolve_surface( + canonical_surface="canonical", + pre_decoration_surface="", + response_surface="", + response_articulation_surface="articulation", + contract_assessment=_closed_assessment(), + ) + + assert resolved.surface == "canonical" + assert resolved.authority == "runtime_canonical" + + +def test_pre_decoration_outranks_canonical_when_response_absent() -> None: + resolved = resolve_surface( + canonical_surface="canonical", + pre_decoration_surface="pre-decoration", + response_surface="", + response_articulation_surface="articulation", + contract_assessment=_closed_assessment(), + ) + + assert resolved.surface == "pre-decoration" + assert resolved.authority == "runtime_pre_decoration" + + def test_useful_realizer_requires_conjugate_coherence() -> None: """Realizer shim only when conjugate geometric contract is closed.""" resolved = resolve_surface(