diff --git a/chat/runtime.py b/chat/runtime.py index eec25ced..b652ecc5 100644 --- a/chat/runtime.py +++ b/chat/runtime.py @@ -1195,6 +1195,53 @@ class ChatRuntime: cand, source_turn_trace=trace_hash ) + def finalize_turn_surface( + self, + surface: str, + articulation_surface: str | None = None, + ) -> None: + """Back-stamp the pipeline's final *served* surface onto the turn. + + Weekly-audit T13 (2026-07-22): ``ChatRuntime.chat`` seals a + ``TurnEvent`` with the runtime-owned surface, but + ``CognitiveTurnPipeline`` applies the Shadow-Coherence / + logos-morph surface authority AFTER ``chat`` returns. The + telemetry record therefore captured a surface the user never + saw — ``TurnEvent.surface != pipeline.run().surface`` — breaking + the ``warmed_session_consistency`` telemetry-consistency invariant + and audit/replay trust (Absolute Provenance). + + The pipeline owns the final surface decision, so — exactly like + ``finalize_turn_trace_hash`` back-stamps the pipeline-owned + ``trace_hash`` — it back-stamps the resolved surface here after + ``resolve_surface`` + logos-morph. Mirrors that method's + contract: operates on the most recent ``TurnEvent`` (main or + refusal-stub path), no-ops when unchanged or when no turn exists. + + NOTE: the opt-in external telemetry sink (``attach_telemetry_sink``) + still receives the pre-override event, the same provisional-then- + back-stamped limitation ``finalize_turn_trace_hash`` carries today + (default sink is ``None`` → no-op). Deferring the single sink + emission to the pipeline serve boundary — which would repair both + surface and ``trace_hash`` in the durable stream — is tracked as a + follow-up (audit ledger R7), not bolted onto this red-fix. + """ + if not self.turn_log: + return + from dataclasses import replace + + last_event = self.turn_log[-1] + updates: dict[str, str] = {} + if surface != last_event.surface: + updates["surface"] = surface + if ( + articulation_surface is not None + and articulation_surface != last_event.articulation_surface + ): + updates["articulation_surface"] = articulation_surface + if updates: + self.turn_log[-1] = replace(last_event, **updates) + def first_admitted_recognizer(self): if not self.config.recognition_grounded_graph: return None diff --git a/core/cognition/pipeline.py b/core/cognition/pipeline.py index ee5f8c0e..099cf75d 100644 --- a/core/cognition/pipeline.py +++ b/core/cognition/pipeline.py @@ -808,6 +808,16 @@ class CognitiveTurnPipeline: # ``source_turn_trace``. See runtime.finalize_turn_trace_hash. self.runtime.finalize_turn_trace_hash(trace_hash) + # Weekly-audit T13 (2026-07-22) — back-stamp the pipeline's final + # *served* surface onto the same TurnEvent, sibling to the + # trace_hash back-stamp above. ``resolve_surface`` + the logos-morph + # authority (above) can override the runtime-owned surface AFTER + # ``runtime.chat`` sealed the TurnEvent, so without this the + # telemetry record disagrees with the served bytes + # (warmed_session_consistency telemetry_consistency_rate < 1.0; + # breaks audit/replay trust — Absolute Provenance). + self.runtime.finalize_turn_surface(surface, articulation_surface) + # B4 producer: capture the leeway the response path already decided — # observational only (reads the runtime's introspection-only accrual and # the response's reach level; never alters the surface, never gates). diff --git a/docs/analysis/weekly-audit-2026-07-22-stragglers-todo.md b/docs/analysis/weekly-audit-2026-07-22-stragglers-todo.md index 6f4bd038..18aaf470 100644 --- a/docs/analysis/weekly-audit-2026-07-22-stragglers-todo.md +++ b/docs/analysis/weekly-audit-2026-07-22-stragglers-todo.md @@ -175,7 +175,15 @@ fail-closed determinism). Execution status: first-match pack semantics unchanged outside the morph rule. - [ ] **R6** — one rule type only (`he_morph_v0.plural_abstain`); construct-state / prep+case / aspect deferred. -- [ ] **T13 (main regression, serving-provenance — needs its own fix PR): +- [ ] **R7** (opened by the T13 fix, 2026-07-22) — the opt-in telemetry SINK + stream (`attach_telemetry_sink`) still receives the pre-override `TurnEvent` + (pre-resolution surface + empty `trace_hash`) — the same provisional-then- + back-stamped limitation `finalize_turn_trace_hash` already carries. A single + deferred sink emission at the pipeline serve boundary would repair BOTH + surface and `trace_hash` in the durable stream. Deferred (default sink is + `None`, so no live consumer is affected today); own PR when a sink consumer + lands. +- [x] **T13 (main regression, serving-provenance — telemetry half FIXED): fast lane is red on main** (was 0-red 2026-07-16): `tests/test_warmed_session_lane.py::TestPipelineOverrideGateInvariants::test_telemetry_consistency_rate_is_one` fails at 0.9444 (17/18). Verified pre-existing on unmodified main (fails @@ -197,3 +205,21 @@ fail-closed determinism). Execution status: the pack surface never claimed geometric certification). Note: smoke does not cover this lane, and GitHub Actions are dead signals — nothing gates fast-lane red on main right now. + + **Resolution (2026-07-22, PR `fix/telemetry-serve-boundary`):** + - **(1) FIXED** — `ChatRuntime.finalize_turn_surface` back-stamps the + pipeline's resolved surface onto `turn_log[-1]`, a sibling to + `finalize_turn_trace_hash`, called from `pipeline.py` immediately after + the trace-hash back-stamp. Lane green: `telemetry_consistency_rate` + 0.9444 → 1.0 (10/10 warmed_session tests pass). `trace_hash` byte-identity + preserved — it folds the pre-decoration surface, not the served surface. + - **(2) OPEN — needs Shay's ruling.** Orthogonal to the red (telemetry now + matches whatever is served, refusal or not). Recommend **AGAINST** a + query-type "definitional/epistemic" classifier bypass: that fails a + geometric coherence gate OPEN on a lexical cue — the fail-open / cue-table + pattern ADR-0252 retired and INV-34 / fail-closed forbid. Principled + alternative: route open-geometry-but-**pack-grounded** surfaces to the + existing hedge-injection arm (`authoritative=False`, honestly hedged), + discriminated by grounding *provenance* (structural), not question type. + Own focused PR + real-data (not synthetic) validation. + - Durable-sink residual tracked as **R7** above.