Completes the ADR-0206 §5 math-serving deferral in its own careful PR. The GSM8K wrong=0 serving gate, select_self_verified, now takes a ReachPolicy. This changes NO serving behavior today — it is the safe, byte-identical, sanctioned first edit to the most wrong=0-critical line, with a live-wiring test, so a future VERIFIED widening has a precise, proven integration point. Why it can't actually widen yet (the tension scoping surfaced): GSM8K wrong=0 is ABSOLUTE (zero wrong, ever); a reliability license is STATISTICAL (a 0.99 Wilson floor); math answers aren't disclosed like the cognition path (E). So widening the math serve on a statistical license would eventually serve a SILENT wrong. ADR-0206 §4 foresaw this: VERIFIED is "the only state that will license widening past gold," and it is reserved pending a canonical-comparison pass (the soundness≠correctness gap) that is unbuilt. Design (safe by construction): - select_self_verified(..., policy=STRICT_POLICY). STRICT (the default every one of the 5 callers passes) is the prior logic verbatim — unique answer → Resolution; zero-verify or disagreement → refuse. Byte-identical: the pinned serving-lane SHAs (demo_composition 3a3d09f3, fabrication 01e1b6b7, math_teaching_corpus eaf160d1) are unchanged; Resolution is unchanged; no import cycle. - A wider reach resolves a disagreement ONLY via _canonically_verified — the VERIFIED gate — whose body returns None (capability unbuilt). So the widening is STRUCTURALLY inert: a disagreement refuses regardless of policy. wrong=0 holds by construction, not caller discipline. A statistical reliability license is NOT consulted by the math path (the cognition/math asymmetry is deliberate: cognition discloses, math is absolute). - test_seam_is_live_wiring injects the gate to prove the consumer fires under a wider reach — and STRICT still refuses even then. Verified: smoke (90), invariants (56), governance + selfverify + ms2 (354 incl. the new seam tests), GSM8K serving regression byte-identical (the one red, test_serving_unchanged_by_search expecting stale 6/44, fails identically on clean main — a pre-existing stale artifact, not this change). Three-lens adversarial review (byte-identity/seal, structural wrong=0 inertness, no-overclaim): all held. The real unlock — a VERIFIED canonical-comparison producer — is scoped in docs/analysis/VERIFIED-canonical-comparison-scoping-2026-06-06.md (recommended: back-substitution / constraint-satisfaction on a checkable problem class). Still deferred: SITUATE (stakes), the live FEED-BACK loop, reach_level JSONL emission.
192 lines
10 KiB
Markdown
192 lines
10 KiB
Markdown
# ADR-0206 — Response Governance Bridge (scaffold)
|
|
|
|
- **Status:** Accepted (scaffold step) — **cognition-path widening landed 2026-06-06**
|
|
(Step E: the license-gated APPROXIMATE rung). The math-serving seam (§5) remains deferred.
|
|
- **Date:** 2026-06-03 (amended 2026-06-06)
|
|
- **Supersedes / relates to:** ADR-0175 (calibrated-learning reliability
|
|
gate), the Epistemic-State program (Phase 3, `core/epistemic_state.py`)
|
|
- **Scope of THIS PR:** purely additive — design on record + cognition-path
|
|
seam, STRICT-only, no behavior change.
|
|
|
|
> **2026-06-06 amendment (Step E — cognition-path widening landed).** The `LICENSE`
|
|
> node is now **called from serving**: `govern_response` returns `APPROXIMATE_POLICY`
|
|
> for a genuine licensed `Action.SERVE` `LicenseDecision` (STRICT for everything else,
|
|
> so every existing call site is byte-identical). The first consumer is the converse-guess
|
|
> estimator (`generate.determine.estimate`): a refused converse query whose predicate-class
|
|
> earned SERVE on the **ratified** reliability ledger
|
|
> (`generate/determine/data/estimation_ledger.json`) is served as a **disclosed**
|
|
> `[approximate]` estimate via `shape_surface`. wrong=0 is preserved by construction
|
|
> (disclosure) + by the gate (θ_SERVE=0.99, earned by volume). **Still deferred:** the
|
|
> math-serving seam (`select_self_verified`, §5), `SITUATE` (stakes), and the live
|
|
> `FEED BACK` loop — E uses an offline, sealed, hash-verified ledger. Lane:
|
|
> `evals.determination_estimation`.
|
|
|
|
## Context — the consumption gap
|
|
|
|
CORE has two **built** epistemic substrates:
|
|
|
|
1. **A ratified decode-state taxonomy** — `core/epistemic_state.py`, a
|
|
`@unique` 15-member `EpistemicState` enum plus an orthogonal
|
|
`NormativeClearance` axis. Every chat turn is *labeled* with its
|
|
decode-state (derived from the grounding source) and the label is
|
|
stamped onto `TurnEvent` / `ChatResponse` and emitted to telemetry.
|
|
|
|
2. **A deterministic risk-reward gate** — `core/reliability_gate/`
|
|
(ADR-0175). `license_for(class, action, ceilings)` decides whether a
|
|
class has *earned* an action via `measured_reliability / θ_required ≥ 1`.
|
|
|
|
A source audit (2026-06-03) established the load-bearing fact this ADR
|
|
addresses:
|
|
|
|
> **The decode-state taxonomy is LABEL-ONLY.** No consumer reads a
|
|
> decode-state to weigh stakes, modulate response risk, or gate
|
|
> approximation/creativity. Every read is a stamp, serialize, badge, or
|
|
> filter. The reliability gate is likewise *explicitly not serving-wired*
|
|
> (`core/reliability_gate/__init__.py`: "NOT wired into the serving/eval
|
|
> path"). The loop that would let these substrates **govern response
|
|
> behavior** has zero consumers.
|
|
|
|
This is the same shape as the ratify-vs-consume gap: the artifacts exist,
|
|
the runtime does not read them to act.
|
|
|
|
## Decision
|
|
|
|
Introduce the **Response Governance Bridge** — the missing consumer that
|
|
reads the two substrates and produces a per-response `ReachPolicy`
|
|
governing *how far into uncertainty a response may reach*. This ADR ships
|
|
only the **scaffold**: the design on record + a live but inert seam on the
|
|
cognition path. The risk-reward widening logic and the math-serving seam
|
|
are explicitly deferred (§5).
|
|
|
|
### §1 — The governing loop (designed; not all built)
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
T[turn] --> S[SITUATE<br/>stakes/gravity]
|
|
S --> L[LICENSE<br/>reliability_gate.license_for]
|
|
L --> G[GOVERN<br/>govern_response → ReachPolicy]
|
|
G --> H[SHAPE<br/>shape_surface reads policy]
|
|
H --> D[DISCLOSE<br/>decode-state label]
|
|
D --> F[FEED BACK<br/>outcome → ledger]
|
|
F -. next turn .-> L
|
|
```
|
|
|
|
| Step | Status |
|
|
|------|--------|
|
|
| SITUATE (stakes/gravity from intent + domain + decode-state) | **designed** — not built |
|
|
| LICENSE (`reliability_gate.license_for`) | **built + called from serving** (Step E, 2026-06-06) |
|
|
| GOVERN (`govern_response → ReachPolicy`) | **STRICT, + license-gated APPROXIMATE** (Step E) |
|
|
| SHAPE (`shape_surface`, response path reads policy) | **STRICT = identity; APPROXIMATE = disclosed** |
|
|
| DISCLOSE (decode-state label) | **built** |
|
|
| FEED BACK (outcome → reliability ledger) | **designed** — not built |
|
|
|
|
Only **GOVERN + SHAPE** ship here. SITUATE and FEED-BACK are named and
|
|
deferred to follow-ups.
|
|
|
|
### §2 — The reach policy
|
|
|
|
`core/response_governance/policy.py` defines:
|
|
|
|
- `ReachLevel` — `STRICT < APPROXIMATE < EXTRAPOLATE < CREATIVE`. Only
|
|
`STRICT` is emitted today; the rest name the spectrum the bridge will
|
|
earn entry to via the reliability gate.
|
|
- `ReachPolicy(level, admissible_states, rationale, license_ratio)` — the
|
|
inspectable per-response decision (same discipline as
|
|
`reliability_gate.LicenseDecision`).
|
|
- `govern_response(*, epistemic_state, license_decision, stakes)` — the
|
|
decision point. **Scaffold: returns `STRICT_POLICY` for every input.**
|
|
- `shape_surface(policy, *, committed_surface, decode_state,
|
|
disclosed_alternative)` — the consumer. **At `STRICT` it is the IDENTITY
|
|
transform.** Higher levels surface a *disclosed alternative* for
|
|
non-admissible decode-states — real, policy-sensitive code so the seam is
|
|
live, but unreachable in production because `govern_response` never emits
|
|
them.
|
|
|
|
### §3 — Why STRICT-only scaffold
|
|
|
|
The scaffold makes the email's "in active development" claim **true the
|
|
moment it lands** while guaranteeing `wrong == 0` is untouched:
|
|
|
|
- `govern_response → STRICT` is the **single load-bearing return**. The
|
|
cognition response surface now flows through `shape_surface`, but STRICT
|
|
is identity, so the path is **byte-identical** to pre-bridge.
|
|
- The seam is **live wiring, not dead code**: `test_seam_is_live_wiring`
|
|
forces `APPROXIMATE` and proves the *same consumer the production path
|
|
calls* yields a different surface. The cognition path's strictness is
|
|
held by exactly the STRICT return — mutate it and the proofs diverge.
|
|
- The **math-serving chokepoint (`select_self_verified`) is not touched.**
|
|
It is the single most load-bearing line for `wrong == 0`; after the
|
|
ProofNode lesson (a merge silently killed a guard) it does not get its
|
|
first edit in a scaffold PR. The deferred math seam (§5) carries its own
|
|
widening test.
|
|
|
|
### §4 — Taxonomy scoping (honestly scoped, not half-dead)
|
|
|
|
Source-verified split of the 15 `EpistemicState` members (2026-06-03,
|
|
including the mapping functions in `epistemic_state.py`): **9 produced, 6
|
|
never produced.** (The earlier audit's "7 never produced" over-counted —
|
|
its grep excluded `epistemic_state.py`, where the partial→`EVIDENCED_INCOMPLETE`
|
|
mapping lives. `EVIDENCED_INCOMPLETE` *is* produced; corrected count is 6.)
|
|
|
|
| Role | Count | States | Consumed by loop as |
|
|
|------|-------|--------|---------------------|
|
|
| **ACTIVE** (produced + consumed) | 9 | `DECODED`, `EVIDENCED_INCOMPLETE`, `INFERRED`, `UNVERIFIED_POSSIBLE`, `UNVERIFIED_NOVEL`, `CONTRADICTED`, `AMBIGUOUS`, `UNDETERMINED`, `EPISTEMIC_STATE_NEEDED` | strict-admissible / approximate+ / extrapolate+ / creative / force-refuse / sentinel |
|
|
| **RESERVED** (named trigger, not produced) | 5 | `VERIFIED`, `COMPUTATIONALLY_BOUNDED`, `SCOPE_BOUNDARY`, `PERCEIVED`, `DECODED_UNARTICULATED` | each gated on a capability that must land first |
|
|
| **RECONCILE** (drift, own PR) | 1 | `EVIDENCED` | declared but never produced; `recognition/outcome.py` owns its own `"evidenced"` |
|
|
|
|
Reserved triggers:
|
|
- `VERIFIED` — needs a canonical-comparison pass (the soundness ≠
|
|
correctness gap); the **only** state that will license widening past gold.
|
|
- `COMPUTATIONALLY_BOUNDED` — search-budget exhausted; `generate/derivation/search.py`
|
|
is the near-term emitter.
|
|
- `SCOPE_BOUNDARY` — out-of-domain refusal with a reason; needs domain-scope
|
|
detection.
|
|
- `PERCEIVED` — raw ingest pre-comprehension; needs a perception lane.
|
|
- `DECODED_UNARTICULATED` — decoded but no realizer surface; articulation-gap.
|
|
|
|
The partition is enforced by `test_taxonomy_partition_is_total_and_disjoint`
|
|
(total + pairwise-disjoint over the live enum), so adding an enum member
|
|
without scoping it fails the build.
|
|
|
|
### §5 — Deferred (one kind of change per PR)
|
|
|
|
- **Math-serving seam** — **LANDED 2026-06-06 (its own PR, as planned).**
|
|
`select_self_verified` now takes `policy=STRICT_POLICY`; STRICT is
|
|
byte-identical (every caller passes it → the pinned serving-lane SHAs are
|
|
unchanged). A *disagreement* may widen past gold ONLY via
|
|
`_canonically_verified` — the `VERIFIED` (soundness ≠ correctness) gate, which
|
|
is **unbuilt and returns `None`**, so the widening is **structurally inert**:
|
|
even a wider reach refuses, preserving the absolute `wrong == 0` by
|
|
construction (not convention). A statistical reliability license is
|
|
deliberately NOT consulted here — math serving is absolute-wrong=0, not
|
|
disclosed like the cognition path. `test_seam_is_live_wiring` injects the gate
|
|
to prove the consumer fires (STRICT still refuses even then). **The real
|
|
widening remains blocked on a `VERIFIED` producer** (a canonical-comparison
|
|
pass) — scoped in
|
|
`docs/analysis/VERIFIED-canonical-comparison-scoping-2026-06-06.md`.
|
|
- **`EVIDENCED` reconcile** — map recognition's outcome into
|
|
`EpistemicState.EVIDENCED` at the boundary (or document the two axes). A
|
|
real corrective defect; kept out of this purely-additive scaffold.
|
|
- **JSONL emission of `reach_level`** — `reach_level` is carried on
|
|
`TurnEvent` / `ChatResponse` but **not** added to the telemetry audit
|
|
dict here, so every pinned lane SHA stays byte-identical. Emission +
|
|
SHA re-pin is a follow-up (re-pinning a frozen gate is not "additive").
|
|
- **SITUATE / FEED-BACK / widening** — the risk-reward logic itself.
|
|
|
|
## Consequences
|
|
|
|
- **Honest claim unlocked:** decode-state taxonomy + risk-reward gate =
|
|
*built*; the bridge that lets them govern response reach = *in active
|
|
development* (committed seam, STRICT-only, design on record, widening
|
|
gated behind wrong==0 proofs). Never "live."
|
|
- **`wrong == 0` preserved:** STRICT identity + untouched
|
|
`select_self_verified`; serving metric stays `3/47/0`.
|
|
- **No frozen gate touched:** telemetry JSONL byte-identical → all pinned
|
|
lane SHAs green.
|
|
|
|
## Verification
|
|
|
|
- `tests/test_response_governance.py` — STRICT-only contract, STRICT
|
|
identity, **live-wiring proof (cognition path)**, taxonomy partition.
|
|
- Full-surface suite green (doctrine: not smoke).
|
|
- `scripts/verify_lane_shas.py` green; `3/47/0` preserved.
|