§9.8 of the plan — "every card carries a verified_at no older than the last arc
that touched its layer" — is a maintenance contract this directory holds itself
to, and today's arc moved MV, M3, M4, M2, M6 and three component cards. A card
whose stamp falls behind a load-bearing arc is testimony, not evidence, which is
the failure mode the directory exists to replace.
Each card gains a Re-verified stamp at 39331dbc plus an arc note saying what
actually changed under it, not merely that something did:
MV PR-4 + PR-6 landed; G-7/G-9 closed. The layer's finding is sharper than
the card stated: the recurring defect is not ABSENT pins but PINS THAT
EXIST AND DO NOT RUN — four found this arc, each indistinguishable from
coverage in any document.
M3 §5 run to NO-GO, settling the successor-path question. New measurement
G-21: the reader decides 5 of 500 holdout_dev/v1 cases. H-8e corrected.
M4 H-13 fixed — the served-marker honesty contract held where it leaked.
M2 PR-7's table: two boundaries already met, THREE CLOSED as category
differences, one real delta (no audit record per rejection).
M6 PR-9 — the accrual backstop counts and names what it absorbs.
realize-phase / always-on-process / surface-selection — the component-level
versions of the same three.
Plan §Status replaced with the actual board: what landed, what each remaining
item is blocked on, and the six findings this arc added that the assessment did
not have (N-8, N-9, G-21, H-13, H-14, H-8e). README carries the same summary at
the directory's entry point.
The status block says plainly what has NOT moved: comprehension breadth and
proof-of-life. The reader is still 19 constructions wide and decides 1.0% of the
held-out corpus; the 5000-beat soak is still prose with no pinned digest.
Everything landed this arc is enforcement and evidence machinery. Capability
moves in PR-11/PR-12/PR-14/Track B, all four ruling-gated.
Docs only.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wcw2pnMBwyvmNyQg4uPEt4
11 KiB
M4 — Expression & Serving
Kind: layer · Parent: CORE · Assessor: Opus 5 (Phase 2)
Re-verified: 39331dbc (2026-07-28) — see the arc note below.
Verified at: 8927c563 (2026-07-27)
Liveness: live-serving · Fitness: strained · Topology role: runtime boundary
Field → world. M4 owns the only bytes a user ever sees, which makes it the layer where the project's central discipline —
wrong=0or refuse — either holds or fails. Everything upstream can be correct and M4 can still serve a falsehood by selecting the wrong surface; everything upstream can refuse and M4 must render that refusal honestly rather than filling it. Its philosophical charge is that saying is a distinct act from knowing, governed separately.
Telos stages: articulate (primary); replay/determinism (trace emission) Macro role: Selects, governs, decorates, and emits the served surface; emits the telemetry that makes the turn auditable.
Arc note — 2026-07-28 (39331dbc). H-13 fixed: the speculative-marker cache un-marked a sibling proposal's still-unreviewed material on promotion, serving it without the (speculative, not yet reviewed) prefix. Claimant-tracked now; the served-surface honesty contract holds where it previously leaked.
What it is / What it does
chat/runtime.py (3364 lines) is the layer's centre of mass, with core/cognition/pipeline.py (1381) wrapping it for the full cognitive turn, and generate/realizer.py + generate/surface.py producing the articulation. Around them: the register axis (chat/register_variation.py, chat/register_substantive.py), response governance (core/response_governance/: govern_response, shape_surface), grounding composers (chat/pack_grounding.py, chat/teaching_grounding.py, chat/deduction_surface.py, chat/curriculum_surface.py), the refusal surface (chat/refusal.py), safety and ethics checks, and telemetry (chat/telemetry.py, chat/verdicts.py).
The load-bearing behavior is surface selection, contracted in runtime_contracts.md: surface = determination_surface when a turn determined an answer over realized knowledge; = [approximate] estimate under a genuine SERVE license; = _UNKNOWN_DOMAIN_SURFACE when the unknown-domain gate fires; = articulation_surface otherwise. walk_surface and articulation_surface are both always retained as evidence — a determination or a gate is a selection, never a rewrite. This is the layer's best design property: the honest artifact survives even when it is not what was served.
Three distinct surfaces exist for three distinct invariants, and conflating them is a documented hazard: surface (what the user read), walk_surface (manifold/token-walk evidence), and hash_surface (the register-invariant truth-path capture that compute_trace_hash folds). Because TurnEvent carries the served surface but never hash_surface, trace_hash is not reconstructable from telemetry — a contract, not a defect. Verify a hash by replaying the pipeline, never by rebuilding it from a turn record.
Contract
- Inputs:
ArticulationTarget/PropositionGraphfrom M3, determination or entailment results, mounted register/safety/ethics/identity packs (M1, MG), session context. - Outputs:
ChatResponse(surface,walk_surface,articulation_surface),TurnEvent,TurnVerdicts,trace_hash,CognitivePipelineRecord,grounding_source,epistemic_state. - Invariants:
- Register must not move
trace_hash(ADR-0069 inv C) — pin: register lane tests — status: running (register suites present). - Unknown-domain gate honoured — the realizer's fallback must not override the gate's stub — pin: contract tests in the cognition suite.
- Realizer slot-type guard / C1 coherence floor (ADR-0075), with a documented exemption for deduction's quoted templates at both guard sites (
chat/runtime.py:2371-2375,:3007-3010). - Grounding-source registration is a three-part atomic change (enum +
enum-snapshot.json+ UI badge contract) — pin:workbench-ui/enumCoverage.test.tsfails the build on divergence;tests/test_workbench_deduction_provenance.py. - A live
/chat/turnwith a trace hash but nostatus="recorded"pipeline record fails before journal append; pre-widening rows must showmissing_evidence, never a synthesized green pipeline.
- Register must not move
Design vs build
- Design:
docs/specs/runtime_contracts.md(the frozen surface-selection policy, thetrace_hashcontract, audit-ledger R7); ADR-0069/0071/0075/0077 (register axis and guards); ADR-0206 (response-governance bridge); ADR-0039 (audit completeness); ADR-0153 (trace-hash back-stamp); ADR-0254 (grounded-open hedge arm); ADR-0265 (negation reaches the surface); ADR-0024/0025/0026 (typed refusal, rotor and margin admissibility). - Build:
live-serving. - Evidence:
- Deduction serving is ratified ON and reaches served output — measurement —
core/config.py:397 deduction_serving_enabled=True; verified by execution 2026-07-25 (_run_chat_turnon a modus-ponens prompt returns the entailment surface) — would-fail-if-absent: yes. - Surface selection honours the unknown-domain gate — contract + pin —
runtime_contracts.md§"Unknown-domain gate honour" — would-fail-if-absent: yes. - Provenance falsification (a proved deduction answer recorded as
grounding_source='none') is closed — the registration requirement and its pin are now documented inruntime_contracts.md§"Grounding-source registration" — would-fail-if-absent: yes. - Negation reaches the surface (ADR-0265, merged
8927c563): underrealizer_grounded_authority, "evidence does not support truth" and "evidence supports truth" previously served byte-identical surfaces — would-fail-if-absent: yes. - Register decoration does not move
trace_hash— pin — would-fail-if-absent: yes.
- Deduction serving is ratified ON and reaches served output — measurement —
Capacity
- Designed: every served surface is either grounded, disclosed, or an honest refusal;
wrong=0or refuse. - Measured:
wrong=0holds across every ratified serving lane (deduction 18,000 cases / 25 bands; curriculum physics 32/32; deductive logic 716/716). Writer-side construction inventory: 1739 constructions emitted. Refusal is typed and carries a machine-readable reason plus per-step rejection evidence. - Ceilings: a real refusing turn still returns
surface == ""withrefusal_reason == ""throughChatRuntime.respond()'sstrcontract — the typed evidence is unread between the raise site and the public return. The plumbing exists onCognitiveTurnResultandcompute_trace_hash; materialisation awaits a future ADR. Curriculum serving is OFF;askandverifiedserving are OFF.
Dependencies & provenance
receives ← M3; reads → M1 (packs, register, lexicon), MG (safety, ethics, identity); feeds → M5 (correction capture), MV (telemetry, trace, pipeline record), M6 (checkpoint at turn boundary); governed-by → MG (safety is fail-closed and never swappable).
Stage coverage
| Stage | Verdict | Evidence |
|---|---|---|
| articulate | covered | Live serving with ratified wrong=0 lanes; typed refusal; disclosed estimates; negation now representable |
| replay/determinism (emission side) | covered, with a known asymmetry | trace_hash is deliberately register-invariant and deliberately not reconstructable from TurnEvent; audit-ledger R7 closed by deferred emission at the serve boundary |
Zone roster: L6-chat-runtime (partial-wiring-debt per map → revised to live-serving at layer level: the serving path demonstrably executes end-to-end), L9-epistemic-verdicts ✱ (straddles MG; owned here, cross-referenced there).
Rollup note: the map's partial-wiring-debt label on L6-chat-runtime reflects internal wiring debt (dormant modules, unmaterialised refusal strings), not a non-serving path. The layer serves; parts of it are unwired. Weakest-link rollup again understating the serving reality.
Judgment
Phase 3 refinement (C-3,
05-phase3-findings.md): "no single place states the precedence order" is half-wrong —core/cognition/surface_resolution.py::resolve_surface(494 lines) is a declared-precedence resolver for the pipeline seam. The accretion concern survives only for the upstream composer arms inchat/runtime.py; the Third-Door candidate refines to extending the existing resolver's pattern upstream. Full arm inventory:20-component-cards/surface-selection.md.
Fitness: strained. M4's architecture is among the strongest in CORE — the selection-not-rewrite discipline, the three-surface separation, the fail-closed typing, the atomic enum/UI coupling. The strain is that its surface-selection policy has accreted one arm per capability (determination, estimate, unknown-domain, deduction, curriculum, hedge, register decoration, logos-morph override), each individually contracted, with no single place that states the precedence order as an executable rule. runtime_contracts.md documents it in prose across several sections; chat/runtime.py implements it across 3364 lines. That is the classic shape of a trade-off being split rather than dissolved — and a Third Door candidate for Phase 4 (a declarative resolution table with the precedence pinned, rather than ordered branches).
Honest wrinkles:
- A refusing turn serves the empty string.
respond()/arespond()convert anyValueErrorto""for their publicstrcontract, so the typed refusal — reason code, blocking region, per-step evidence — is constructed and then discarded before the caller sees it. The system's honesty machinery is real and, on this path, unread. - The layer that owns
wrong=0is also the layer where the PR #138 fabrications surface: the reader's fabricatedmember(every_dog, mammal)and the recitedfurthermorepremise reach served output. The defect is M3's; the blast radius is M4's. Measured and pinned, held for ADR + ratification — recorded, not fixed. epistemic_statedegrades honestly (epistemic_state_needed) where hand-copied whitelists degraded dishonestly (none). The asymmetry is a reusable design lesson: a coercion that asserts a falsehood is strictly worse than doing nothing.- Surface selection is documented as "current policy… future realizer work may change it" — a standing invitation to accrete another arm.
Open questions:
- Materialise the typed refusal into
ChatResponse.refusal_reason(→ ruling; ADR already anticipated) - Should surface precedence become a declarative table? (→ Phase 4 hindrance audit)
- Whether
TurnEventshould carryhash_surfaceremains an open ruling recorded inruntime_contracts.md(→ ruling)