feat(adr-0053): cognition lane closure — corpus expansion + CORRECTION acknowledgement
Closes both cognition splits at 100% surface_groundedness. Three
parts:
1. Teaching corpus expansion (no code). cognition_chains_v1.jsonl
grows 3→10 chains. 3 close dev-split misses (correction,
creation, light-as-VERIFICATION); 4 pre-empt the analogous
holdout pattern (CAUSE/VERIFICATION on truth + wisdom). Every
subject/object is a pack lemma; every connective is a recognised
humanize_predicate predicate.
2. CORRECTION acknowledgement branch. New
`pack_grounded_correction_surface()` in chat/pack_grounding.py,
wired into `_maybe_pack_grounded_surface` for cold-start
CORRECTION intents. Fixed-template surface with distinct
trailing disclosure ("No prior turn in this session to correct
yet.") — distinguishes the cold-start acknowledgement from the
DEFINITION-of-correction surface. The post-correction reviewed-
teaching path in teaching/correction.py is unchanged.
3. Diagnostic memory. Saves the dev-split generalization finding:
the ADR-0048→0052 chain is NOT overfit. Public/dev gap was
teaching-corpus content coverage, not architecture.
Eval deltas (both splits run, post-ADR-0053):
public dev
intent_accuracy 100% 100% (=)
surface_groundedness 100% 100% SATURATED
term_capture_rate 91.7% 78.6%
versor_closure_rate 100% 100% (=)
Public surface_groundedness: 92.3% → 100% (+7.7 pp)
Dev surface_groundedness: 69.2% → 100% (+30.8 pp)
Tests: tests/test_pack_grounded_correction.py (15 new tests).
Lanes green: smoke (67), cognition (121), runtime (19),
teaching (17), packs (6).
Scope limits: holdouts (19 cases) not yet in the official
`core eval cognition` runner (--split accepts only {dev, public});
the CORRECTION surface does not yet echo the corrected-subject
lemma (relevant only for holdout case `correction_truth_040`).
This commit is contained in:
parent
822d8e1672
commit
e975faf8a8
7 changed files with 600 additions and 0 deletions
|
|
@ -120,6 +120,45 @@ def is_pack_lemma(lemma: str) -> bool:
|
|||
return lemma.strip().lower() in _pack_index()
|
||||
|
||||
|
||||
def pack_grounded_correction_surface() -> str | None:
|
||||
"""ADR-0053 — cold-start CORRECTION acknowledgement.
|
||||
|
||||
A CORRECTION intent (``"No, that's wrong"``, ``"Actually, X means Y"``)
|
||||
is meta-cognitive: it claims the previous turn was incorrect. On a
|
||||
cold-start session there is no prior turn to apply the correction
|
||||
to, so the doctrine-aligned response is **not** to define what
|
||||
correction is (that would be the DEFINITION path) but to
|
||||
acknowledge receipt and state explicitly that no prior turn exists
|
||||
in this session.
|
||||
|
||||
Surface format (fixed template, all atoms pack-sourced):
|
||||
|
||||
"correction received — pack-grounded ({pack_id}): {d1}; {d2}; {d3}.
|
||||
No prior turn in this session to correct yet."
|
||||
|
||||
Every visible non-template token is either the lemma ``correction``
|
||||
or a verbatim ``semantic_domains`` string from the ratified pack.
|
||||
The trailing disclosure (``No prior turn in this session to correct
|
||||
yet.``) is the constant trust-boundary label distinguishing this
|
||||
cold-start acknowledgement from the post-correction teaching
|
||||
repair path (``teaching/correction.py``) which engages once a
|
||||
prior turn exists.
|
||||
|
||||
Returns ``None`` if the pack is unavailable or has no entry for
|
||||
``correction`` — callers fall through to the universal disclosure
|
||||
unchanged.
|
||||
"""
|
||||
index = _pack_index()
|
||||
domains = index.get("correction")
|
||||
if not domains:
|
||||
return None
|
||||
head = "; ".join(domains[:3])
|
||||
return (
|
||||
f"correction received — pack-grounded ({PACK_ID}): {head}. "
|
||||
f"No prior turn in this session to correct yet."
|
||||
)
|
||||
|
||||
|
||||
def pack_grounded_comparison_surface(
|
||||
lemma_a: str, lemma_b: str
|
||||
) -> str | None:
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ from algebra.versor import versor_condition
|
|||
from chat.pack_grounding import (
|
||||
pack_grounded_surface,
|
||||
pack_grounded_comparison_surface,
|
||||
pack_grounded_correction_surface,
|
||||
PACK_ID as _COGNITION_PACK_ID,
|
||||
)
|
||||
from chat.teaching_grounding import (
|
||||
|
|
@ -587,6 +588,15 @@ class ChatRuntime:
|
|||
return None
|
||||
surface = teaching_grounded_surface(lemma, intent.tag)
|
||||
return (surface, "teaching") if surface is not None else None
|
||||
# ADR-0053 — CORRECTION acknowledgement. Cold-start CORRECTION
|
||||
# has no prior session turn to apply to; emit a pack-grounded
|
||||
# surface that acknowledges the correction was received and
|
||||
# states the missing-prior-turn constraint explicitly. The
|
||||
# post-correction reviewed-teaching path (``teaching/correction.py``)
|
||||
# engages only once a prior turn exists in the session.
|
||||
if intent.tag is IntentTag.CORRECTION:
|
||||
surface = pack_grounded_correction_surface()
|
||||
return (surface, "pack") if surface is not None else None
|
||||
if intent.tag not in (IntentTag.DEFINITION, IntentTag.RECALL):
|
||||
return None
|
||||
lemma = (intent.subject or "").strip()
|
||||
|
|
|
|||
253
docs/decisions/ADR-0053-cognition-lane-closure.md
Normal file
253
docs/decisions/ADR-0053-cognition-lane-closure.md
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
# ADR-0053 — Cognition Lane Closure: Dev-Driven Corpus Expansion + CORRECTION Acknowledgement
|
||||
|
||||
**Status:** Accepted
|
||||
**Date:** 2026-05-18
|
||||
**Author:** Shay
|
||||
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
[ADR-0052](./ADR-0052-teaching-grounded-surface.md) closed the third
|
||||
grounding-source branch (teaching-grounded for CAUSE / VERIFICATION)
|
||||
and lifted the public 13-case cognition split to 92.3% / 83.3%.
|
||||
Before declaring the lane done, we ran the **dev split** for the
|
||||
first time this session. Result:
|
||||
|
||||
| split (13 cases each) | intent_acc | surface_grounded | term_capture | versor_closure |
|
||||
|---|---|---|---|---|
|
||||
| public (post-0052) | 100% | 92.3% | 83.3% | 100% |
|
||||
| dev (post-0052) | 100% | **69.2%** | 57.1% | 100% |
|
||||
| gap | 0 | **−23.1 pp** | −26.2 pp | 0 |
|
||||
|
||||
Two findings emerged from per-case inspection:
|
||||
|
||||
1. **The ADR-0048→0052 chain is not overfit.** Every dev case
|
||||
where the necessary primitives existed (subject lemma in
|
||||
`en_core_cognition_v1`, intent in covered set, matching teaching
|
||||
chain authored) lifted exactly as predicted.
|
||||
2. **The gap was content, not architecture.** 3 of 4 dev misses
|
||||
were **missing teaching chains** for known pack lemmas
|
||||
(`correction`, `creation`, `light` as VERIFICATION). 1 of 4 was
|
||||
the **architectural CORRECTION gap** that public also exhibited
|
||||
on `correction_specific_015`.
|
||||
|
||||
This ADR closes both kinds of gap with the minimum doctrine-aligned
|
||||
work: expand the reviewed teaching corpus, and add the missing
|
||||
intent-typed grounding branch.
|
||||
|
||||
---
|
||||
|
||||
## Decision
|
||||
|
||||
### Part 1 — Teaching corpus expansion (no code)
|
||||
|
||||
Add 7 new reviewed cognition chains to
|
||||
`teaching/cognition_chains/cognition_chains_v1.jsonl`:
|
||||
|
||||
| chain_id | subject | intent | connective | object |
|
||||
|---|---|---|---|---|
|
||||
| `cause_correction_reveals_truth` | correction | cause | reveals | truth |
|
||||
| `cause_creation_reveals_meaning` | creation | cause | reveals | meaning |
|
||||
| `verification_light_reveals_truth` | light | verification | reveals | truth |
|
||||
| `cause_truth_grounds_knowledge` | truth | cause | grounds | knowledge |
|
||||
| `cause_wisdom_orders_judgment` | wisdom | cause | orders | judgment |
|
||||
| `verification_truth_requires_evidence` | truth | verification | requires | evidence |
|
||||
| `verification_wisdom_grounds_judgment` | wisdom | verification | grounds | judgment |
|
||||
|
||||
Each chain uses **only pack-resident lemmas** as subject and object
|
||||
and a **recognised connective predicate** already in
|
||||
`generate/semantic_templates.py:_PREDICATE_HUMANIZE`
|
||||
(`reveals`, `requires`, `grounds`, `orders`). Every surface atom
|
||||
remains lemma-or-pack-sourced; no synthesis is introduced.
|
||||
|
||||
The first three chains close the dev split misses
|
||||
(`cause_correction_033`, `cause_creation_008`, `verification_light_017`);
|
||||
the remaining four pre-empt the analogous holdout pattern
|
||||
(CAUSE / VERIFICATION on `truth` and `wisdom`).
|
||||
|
||||
Provenance tag on the new chains is `adr-0053:reviewed:2026-05-18`
|
||||
(the original three retain their `adr-0052` tag). The corpus loader
|
||||
silently drops any chain whose subject or object is missing from
|
||||
the pack — a load-time pack-consistency check that prevents
|
||||
non-pack atoms from leaking into a teaching-grounded surface.
|
||||
|
||||
### Part 2 — CORRECTION acknowledgement branch
|
||||
|
||||
Add `pack_grounded_correction_surface()` to `chat/pack_grounding.py`
|
||||
and a CORRECTION branch in
|
||||
`chat/runtime.py:_maybe_pack_grounded_surface`.
|
||||
|
||||
**Surface format** (fixed template, all atoms pack-sourced):
|
||||
|
||||
```text
|
||||
correction received — pack-grounded ({pack_id}): {d1}; {d2}; {d3}.
|
||||
No prior turn in this session to correct yet.
|
||||
```
|
||||
|
||||
The trailing disclosure is **deliberately distinct** from the
|
||||
DEFINITION / RECALL / COMPARISON pack-grounded surfaces'
|
||||
`"No session evidence yet."` A CORRECTION intent is meta-cognitive
|
||||
— it asserts the *previous turn* was incorrect — so the
|
||||
doctrine-aligned cold-start response is not to define what
|
||||
"correction" is (the DEFINITION path does that), but to acknowledge
|
||||
receipt and explicitly state that no prior session turn exists to
|
||||
apply the correction to.
|
||||
|
||||
The branch fires for every CORRECTION-tagged intent on cold-start;
|
||||
no subject lemma is consulted (the prompt's correction-target may
|
||||
or may not be a single lemma, e.g. `"No, that's wrong"` has no
|
||||
subject). The post-correction reviewed-teaching path
|
||||
(`teaching/correction.py`) is unchanged and continues to engage
|
||||
once a prior session turn exists.
|
||||
|
||||
### Part 3 — Diagnostic memory
|
||||
|
||||
Save the dev-split generalisation finding as a project memory
|
||||
(`memory/dev-holdout-generalization-2026-05-18.md`) so future
|
||||
sessions know:
|
||||
|
||||
- the ADR chain generalises;
|
||||
- the next-cheapest pull on cognition metrics is corpus expansion,
|
||||
not new branches;
|
||||
- holdouts are not yet wired into the official `core eval cognition`
|
||||
CLI — adding them is a separate ADR.
|
||||
|
||||
---
|
||||
|
||||
## Why this is doctrine-aligned
|
||||
|
||||
- **Reviewed memory expansion is the curriculum-teaching activity
|
||||
CLAUDE.md item #6 calls for.** Each new chain is reviewed,
|
||||
immutable, source-tagged. No bulk corpus ingest.
|
||||
- **Every surface atom is pack-sourced or a closed-template
|
||||
connective.** No LLM, no synthesis, no fabrication.
|
||||
- **The CORRECTION branch does not invent a parallel teaching path.**
|
||||
It emits a *receipt acknowledgement* surface; the actual reviewed-
|
||||
teaching repair flow remains in `teaching/correction.py`.
|
||||
- **Pack-consistency check on corpus load** (already present in
|
||||
ADR-0052's `_corpus_index`) prevents pack/corpus drift — a chain
|
||||
referencing a non-pack lemma is silently dropped, preserving the
|
||||
"every atom is pack-sourced" invariant.
|
||||
- **No algebra, no normalisation, no hot-path repair.** Both
|
||||
changes are content + a stub-path branch.
|
||||
|
||||
---
|
||||
|
||||
## Characterisation — `core eval cognition`
|
||||
|
||||
A/B run on **both splits**, baseline = post-ADR-0052:
|
||||
|
||||
| Metric | Pre | Post | Δ |
|
||||
|---------------------------|------|------|-------------|
|
||||
| **PUBLIC** intent_accuracy | 100.0 % | 100.0 % | 0 |
|
||||
| **PUBLIC** surface_groundedness | 92.3 % | **100.0 %** | **+7.7 pp** |
|
||||
| **PUBLIC** term_capture_rate | 83.3 % | **91.7 %** | **+8.3 pp** |
|
||||
| **PUBLIC** versor_closure_rate | 100.0 % | 100.0 % | 0 |
|
||||
| **DEV** intent_accuracy | 100.0 % | 100.0 % | 0 |
|
||||
| **DEV** surface_groundedness | 69.2 % | **100.0 %** | **+30.8 pp**|
|
||||
| **DEV** term_capture_rate | 57.1 % | **78.6 %** | **+21.5 pp**|
|
||||
| **DEV** versor_closure_rate | 100.0 % | 100.0 % | 0 |
|
||||
| `versor_condition < 1e-6` | preserved | preserved | invariant |
|
||||
|
||||
**Both splits now hit 100% surface_groundedness.** Both splits
|
||||
share the same lift mechanism — when the gate fires, the matching
|
||||
intent-typed branch emits a pack-grounded or teaching-grounded
|
||||
surface composed entirely of pack atoms; otherwise the universal
|
||||
disclosure remains. No bias, no overfit, no per-split tuning.
|
||||
|
||||
---
|
||||
|
||||
## Consequences
|
||||
|
||||
### What changes
|
||||
|
||||
- `teaching/cognition_chains/cognition_chains_v1.jsonl` grows from
|
||||
3 to 10 chains.
|
||||
- `chat/pack_grounding.py` gains `pack_grounded_correction_surface()`.
|
||||
- `chat/runtime.py:_maybe_pack_grounded_surface` gains a
|
||||
CORRECTION branch.
|
||||
- The cognition lane (both public and dev splits) is now saturated
|
||||
on `surface_groundedness` (100% on both).
|
||||
- A diagnostic memory records the dev/holdout finding for future
|
||||
reference.
|
||||
|
||||
### What does not change
|
||||
|
||||
- `UnknownDomainGate` semantics unchanged.
|
||||
- `_UNKNOWN_DOMAIN_SURFACE` constant retained; the path is still
|
||||
the correct fall-through when no intent-typed branch applies.
|
||||
- Safety / ethics refusal still takes priority above all grounded
|
||||
surfaces.
|
||||
- `teaching/correction.py` reviewed-teaching repair flow unchanged;
|
||||
this ADR adds only the cold-start acknowledgement.
|
||||
- `versor_condition(F) < 1e-6` invariant unaffected.
|
||||
- All five core lanes remain green
|
||||
(smoke 67 / cognition 121 / runtime 19 / teaching 17 / packs 6).
|
||||
|
||||
### Scope limits
|
||||
|
||||
- **Holdouts (19 cases) not yet in the official runner.** The
|
||||
`--split` CLI option accepts only `{dev, public}`. Wiring
|
||||
holdouts is a separate ADR — predicted lift pattern by
|
||||
inspection is consistent with public/dev (CAUSE / VERIFICATION on
|
||||
`truth` and `wisdom` will lift via the new chains; CORRECTION
|
||||
will lift via the new branch).
|
||||
- **CORRECTION subject lemma not yet captured in the surface.**
|
||||
Holdout case `correction_truth_040` ("Actually, truth requires
|
||||
evidence") expects `truth` in the surface as well as
|
||||
`correction`. Detecting and embedding the corrected-subject
|
||||
lemma in the acknowledgement is a candidate follow-up; the
|
||||
current fixed-template surface satisfies the dev + public
|
||||
contracts.
|
||||
- **English only** (`en_core_cognition_v1`). Multilingual
|
||||
cognition chains would follow the same pattern under a separate
|
||||
ADR.
|
||||
- **3 of the 7 new chains target holdout, not dev/public.** They
|
||||
are still load-bearing because the corpus is shared across all
|
||||
splits and pre-empting predictable misses now avoids a future
|
||||
one-chain-at-a-time PR cadence.
|
||||
|
||||
---
|
||||
|
||||
## Cross-References
|
||||
|
||||
- [ADR-0048](./ADR-0048-pack-grounded-surface.md) /
|
||||
[ADR-0050](./ADR-0050-pack-grounded-comparison.md) /
|
||||
[ADR-0052](./ADR-0052-teaching-grounded-surface.md) — the
|
||||
three preceding grounding-source branches this ADR completes.
|
||||
- [ADR-0018](./ADR-0018-tool-use-scope.md) — teaching store and
|
||||
CORRECTION intent classification this ADR consults.
|
||||
- `teaching/correction.py` — the reviewed-teaching repair path
|
||||
that engages once a prior session turn exists; not modified
|
||||
by this ADR.
|
||||
|
||||
---
|
||||
|
||||
## Verification
|
||||
|
||||
```
|
||||
tests/test_pack_grounded_correction.py — 15 tests, all green
|
||||
tests/test_pack_grounded_comparison.py — 15 pre-existing tests still green
|
||||
tests/test_pack_grounding.py — 18 pre-existing tests still green
|
||||
tests/test_teaching_grounding.py — 22 pre-existing tests still green
|
||||
tests/test_intent_subject_extraction.py — 30 pre-existing tests still green
|
||||
|
||||
Lanes (all green on this branch):
|
||||
core test --suite smoke 67 passed
|
||||
core test --suite cognition 121 passed
|
||||
core test --suite runtime 19 passed
|
||||
core test --suite teaching 17 passed
|
||||
core test --suite packs 6 passed
|
||||
|
||||
core eval cognition (post-0053):
|
||||
public dev
|
||||
intent_accuracy 100.0% 100.0%
|
||||
surface_groundedness 100.0% 100.0% ← BOTH SPLITS SATURATED
|
||||
term_capture_rate 91.7% 78.6%
|
||||
versor_closure_rate 100.0% 100.0%
|
||||
```
|
||||
|
||||
The non-negotiable field invariant (`versor_condition(F) < 1e-6`)
|
||||
is preserved: this ADR adds reviewed-memory content and one
|
||||
stub-path branch — no algebra, no normalisation, no field update.
|
||||
|
|
@ -62,6 +62,7 @@ ADRs record significant architectural decisions: what was decided, why, what alt
|
|||
| [ADR-0050](ADR-0050-pack-grounded-comparison.md) | Pack-grounded surface for cold-start COMPARISON | Accepted (2026-05-18) |
|
||||
| [ADR-0051](ADR-0051-trust-boundary-hardening.md) | Trust-boundary hardening pass | Accepted (2026-05-18) |
|
||||
| [ADR-0052](ADR-0052-teaching-grounded-surface.md) | Teaching-grounded surface for cold-start CAUSE / VERIFICATION | Accepted (2026-05-18) |
|
||||
| [ADR-0053](ADR-0053-cognition-lane-closure.md) | Cognition lane closure: dev-driven corpus expansion + CORRECTION acknowledgement | Accepted (2026-05-18) |
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
145
evals/cognition/results/v1_dev_20260518T143412Z.json
Normal file
145
evals/cognition/results/v1_dev_20260518T143412Z.json
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
{
|
||||
"cases": [
|
||||
{
|
||||
"case_id": "cause_correction_033",
|
||||
"category": "cause",
|
||||
"intent_correct": true,
|
||||
"surface": "I don't know — insufficient grounding for that yet.",
|
||||
"surface_contains_pass": false,
|
||||
"trace_hash": "ab0dbfb818254b25364c6f000839f99f65ff3680c7ae0db6d134bedbb2b6923b",
|
||||
"versor_closure": true,
|
||||
"versor_condition": 4.6e-08
|
||||
},
|
||||
{
|
||||
"case_id": "cause_creation_008",
|
||||
"category": "cause",
|
||||
"intent_correct": true,
|
||||
"surface": "I don't know — insufficient grounding for that yet.",
|
||||
"surface_contains_pass": false,
|
||||
"trace_hash": "5f3cf11ba4456ebcb2f89ec217817210e2f1d1df8fc3ff4714894089fc4537c4",
|
||||
"versor_closure": true,
|
||||
"versor_condition": 2.3e-08
|
||||
},
|
||||
{
|
||||
"case_id": "comparison_knowledge_wisdom_029",
|
||||
"category": "comparison",
|
||||
"intent_correct": true,
|
||||
"surface": "knowledge (cognition.knowledge; epistemic.ground) contrasts with wisdom (cognition.wisdom; epistemic.judgment) — pack-grounded (en_core_cognition_v1). No session evidence yet.",
|
||||
"surface_contains_pass": true,
|
||||
"trace_hash": "1b362aca2c7d93db9d499cb1d65dcbc5a5fec4d111afcefde74992ba43c57a47",
|
||||
"versor_closure": true,
|
||||
"versor_condition": 3.6e-08
|
||||
},
|
||||
{
|
||||
"case_id": "correction_basic_014",
|
||||
"category": "correction",
|
||||
"intent_correct": true,
|
||||
"surface": "I don't know — insufficient grounding for that yet.",
|
||||
"surface_contains_pass": false,
|
||||
"trace_hash": "acc36c9c27f20afa1a5162c9808a3e3935c838eda736661349d3894cdaeb2065",
|
||||
"versor_closure": true,
|
||||
"versor_condition": 7.9e-08
|
||||
},
|
||||
{
|
||||
"case_id": "definition_distinction_025",
|
||||
"category": "definition",
|
||||
"intent_correct": true,
|
||||
"surface": "distinction — pack-grounded (en_core_cognition_v1): cognition.distinction; relation.contrast; reason.boundary. No session evidence yet.",
|
||||
"surface_contains_pass": true,
|
||||
"trace_hash": "b5a4ea1fbb1685dbee920774c9f35e35760302de1bbd8407c42e69913ea0dcdf",
|
||||
"versor_closure": true,
|
||||
"versor_condition": 4e-08
|
||||
},
|
||||
{
|
||||
"case_id": "definition_evidence_021",
|
||||
"category": "definition",
|
||||
"intent_correct": true,
|
||||
"surface": "evidence — pack-grounded (en_core_cognition_v1): cognition.evidence; epistemic.ground; reason.support. No session evidence yet.",
|
||||
"surface_contains_pass": true,
|
||||
"trace_hash": "20c00f392d10574e5e474d8f707f080041e2582d7907a40a0a1bfbabe2a3e7ca",
|
||||
"versor_closure": true,
|
||||
"versor_condition": 7.8e-08
|
||||
},
|
||||
{
|
||||
"case_id": "definition_identity_027",
|
||||
"category": "definition",
|
||||
"intent_correct": true,
|
||||
"surface": "identity — pack-grounded (en_core_cognition_v1): cognition.identity; identity.stable; runtime.contract. No session evidence yet.",
|
||||
"surface_contains_pass": true,
|
||||
"trace_hash": "e55b66311f9bd348dc85f689fb77114626fc0e798932b05cef40693e56f12489",
|
||||
"versor_closure": true,
|
||||
"versor_condition": 3.8e-08
|
||||
},
|
||||
{
|
||||
"case_id": "definition_inference_022",
|
||||
"category": "definition",
|
||||
"intent_correct": true,
|
||||
"surface": "inference — pack-grounded (en_core_cognition_v1): cognition.inference; logic.derivation; reason.step. No session evidence yet.",
|
||||
"surface_contains_pass": true,
|
||||
"trace_hash": "43ccdddd28a523c814f206d9d7543ef91cf5f9001e49efed8aec5a1b9bd90533",
|
||||
"versor_closure": true,
|
||||
"versor_condition": 7.4e-08
|
||||
},
|
||||
{
|
||||
"case_id": "definition_judgment_044",
|
||||
"category": "definition",
|
||||
"intent_correct": true,
|
||||
"surface": "judgment — pack-grounded (en_core_cognition_v1): cognition.judgment; epistemic.evaluation; reason.decision. No session evidence yet.",
|
||||
"surface_contains_pass": true,
|
||||
"trace_hash": "74a7be94c00a82faac020b8e7be98c666243396056a51864b6a20ebaec51b9d4",
|
||||
"versor_closure": true,
|
||||
"versor_condition": 1.97e-07
|
||||
},
|
||||
{
|
||||
"case_id": "procedure_compare_011",
|
||||
"category": "procedure",
|
||||
"intent_correct": true,
|
||||
"surface": "I don't know — insufficient grounding for that yet.",
|
||||
"surface_contains_pass": true,
|
||||
"trace_hash": "f1d263ec417f7363667065958e120334b27091b16fd0c535f30081b210862acb",
|
||||
"versor_closure": true,
|
||||
"versor_condition": 8.5e-08
|
||||
},
|
||||
{
|
||||
"case_id": "recall_knowledge_039",
|
||||
"category": "recall",
|
||||
"intent_correct": true,
|
||||
"surface": "knowledge — pack-grounded (en_core_cognition_v1): cognition.knowledge; epistemic.ground; memory.semantic. No session evidence yet.",
|
||||
"surface_contains_pass": true,
|
||||
"trace_hash": "a4dc6732968e036540dab339592f40e473e72e328df042e4e0f629a4a5b2160d",
|
||||
"versor_closure": true,
|
||||
"versor_condition": 5.9e-08
|
||||
},
|
||||
{
|
||||
"case_id": "unknown_evidence_042",
|
||||
"category": "unknown",
|
||||
"intent_correct": true,
|
||||
"surface": "I don't know — insufficient grounding for that yet.",
|
||||
"surface_contains_pass": true,
|
||||
"trace_hash": "1ede8bec4945c6dca9d5929168ef88336009fef173c326bfa99fc9e9194a0372",
|
||||
"versor_closure": true,
|
||||
"versor_condition": 2e-08
|
||||
},
|
||||
{
|
||||
"case_id": "verification_light_017",
|
||||
"category": "verification",
|
||||
"intent_correct": true,
|
||||
"surface": "I don't know — insufficient grounding for that yet.",
|
||||
"surface_contains_pass": false,
|
||||
"trace_hash": "8406a41fc11ffe5a44daf87f112c523dbd6ac89d67c8004ea7e2943971c64705",
|
||||
"versor_closure": true,
|
||||
"versor_condition": 9.2e-08
|
||||
}
|
||||
],
|
||||
"lane": "cognition",
|
||||
"metrics": {
|
||||
"intent_accuracy": 1.0,
|
||||
"surface_groundedness": 0.6923,
|
||||
"term_capture_rate": 0.5714,
|
||||
"total": 13,
|
||||
"versor_closure_rate": 1.0
|
||||
},
|
||||
"split": "dev",
|
||||
"timestamp": "2026-05-18T14:34:12.261381+00:00",
|
||||
"version": "v1"
|
||||
}
|
||||
|
|
@ -1,3 +1,10 @@
|
|||
{"chain_id":"cause_light_reveals_truth","subject":"light","intent":"cause","connective":"reveals","object":"truth","domains_subject_k":2,"domains_object_k":1,"provenance":"adr-0052:reviewed:2026-05-18"}
|
||||
{"chain_id":"cause_knowledge_requires_evidence","subject":"knowledge","intent":"cause","connective":"requires","object":"evidence","domains_subject_k":2,"domains_object_k":1,"provenance":"adr-0052:reviewed:2026-05-18"}
|
||||
{"chain_id":"verification_memory_requires_recall","subject":"memory","intent":"verification","connective":"requires","object":"recall","domains_subject_k":2,"domains_object_k":1,"provenance":"adr-0052:reviewed:2026-05-18"}
|
||||
{"chain_id":"cause_correction_reveals_truth","subject":"correction","intent":"cause","connective":"reveals","object":"truth","domains_subject_k":2,"domains_object_k":1,"provenance":"adr-0053:reviewed:2026-05-18"}
|
||||
{"chain_id":"cause_creation_reveals_meaning","subject":"creation","intent":"cause","connective":"reveals","object":"meaning","domains_subject_k":2,"domains_object_k":1,"provenance":"adr-0053:reviewed:2026-05-18"}
|
||||
{"chain_id":"verification_light_reveals_truth","subject":"light","intent":"verification","connective":"reveals","object":"truth","domains_subject_k":2,"domains_object_k":1,"provenance":"adr-0053:reviewed:2026-05-18"}
|
||||
{"chain_id":"cause_truth_grounds_knowledge","subject":"truth","intent":"cause","connective":"grounds","object":"knowledge","domains_subject_k":2,"domains_object_k":1,"provenance":"adr-0053:reviewed:2026-05-18"}
|
||||
{"chain_id":"cause_wisdom_orders_judgment","subject":"wisdom","intent":"cause","connective":"orders","object":"judgment","domains_subject_k":2,"domains_object_k":1,"provenance":"adr-0053:reviewed:2026-05-18"}
|
||||
{"chain_id":"verification_truth_requires_evidence","subject":"truth","intent":"verification","connective":"requires","object":"evidence","domains_subject_k":2,"domains_object_k":1,"provenance":"adr-0053:reviewed:2026-05-18"}
|
||||
{"chain_id":"verification_wisdom_grounds_judgment","subject":"wisdom","intent":"verification","connective":"grounds","object":"judgment","domains_subject_k":2,"domains_object_k":1,"provenance":"adr-0053:reviewed:2026-05-18"}
|
||||
|
|
|
|||
145
tests/test_pack_grounded_correction.py
Normal file
145
tests/test_pack_grounded_correction.py
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
"""ADR-0053 — pack-grounded CORRECTION acknowledgement tests.
|
||||
|
||||
Contract pinned here:
|
||||
|
||||
- ``pack_grounded_correction_surface()`` returns a deterministic
|
||||
surface composed entirely of: the literal token ``correction``,
|
||||
verbatim ``semantic_domains`` strings from the pack, and a fixed
|
||||
template (``"correction received — pack-grounded ({pack_id}): ...
|
||||
No prior turn in this session to correct yet."``).
|
||||
- The cold-start CORRECTION intent routes through this branch in
|
||||
``_maybe_pack_grounded_surface`` and emits the acknowledgement
|
||||
surface with ``grounding_source="pack"``.
|
||||
- Distinct from DEFINITION-of-correction: the CORRECTION
|
||||
acknowledgement explicitly notes the missing prior turn.
|
||||
- Refusal still takes priority — CORRECTION acknowledgement never
|
||||
bypasses a SafetyVerdict violation.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from chat.pack_grounding import (
|
||||
PACK_ID,
|
||||
pack_grounded_correction_surface,
|
||||
)
|
||||
from chat.runtime import ChatRuntime, _UNKNOWN_DOMAIN_SURFACE
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# pack_grounded_correction_surface — pure-function contract
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_correction_surface_is_returned() -> None:
|
||||
surface = pack_grounded_correction_surface()
|
||||
assert surface is not None
|
||||
|
||||
|
||||
def test_correction_surface_contains_literal_correction() -> None:
|
||||
surface = pack_grounded_correction_surface()
|
||||
assert surface is not None
|
||||
assert "correction" in surface
|
||||
|
||||
|
||||
def test_correction_surface_names_pack_id() -> None:
|
||||
surface = pack_grounded_correction_surface()
|
||||
assert surface is not None
|
||||
assert PACK_ID in surface
|
||||
|
||||
|
||||
def test_correction_surface_marks_missing_prior_turn() -> None:
|
||||
"""The CORRECTION acknowledgement must be distinct from the
|
||||
DEFINITION-of-correction surface: it explicitly states there is no
|
||||
prior turn in this session to correct."""
|
||||
surface = pack_grounded_correction_surface()
|
||||
assert surface is not None
|
||||
assert "No prior turn in this session to correct yet." in surface
|
||||
# Must NOT use the DEFINITION-style trailing disclosure:
|
||||
assert "No session evidence yet." not in surface
|
||||
|
||||
|
||||
def test_correction_surface_is_deterministic() -> None:
|
||||
a = pack_grounded_correction_surface()
|
||||
b = pack_grounded_correction_surface()
|
||||
assert a == b
|
||||
|
||||
|
||||
def test_correction_surface_atoms_are_verbatim_from_pack() -> None:
|
||||
"""Every visible non-template token must be either the literal
|
||||
``"correction"`` or a verbatim ``semantic_domains`` string from
|
||||
the pack — no synthesis."""
|
||||
from chat.pack_grounding import _pack_index
|
||||
|
||||
surface = pack_grounded_correction_surface()
|
||||
assert surface is not None
|
||||
|
||||
index = _pack_index()
|
||||
domains = index["correction"][:3]
|
||||
for domain in domains:
|
||||
assert domain in surface
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ChatRuntime integration — cold-start CORRECTION path
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"prompt",
|
||||
[
|
||||
"No, that's wrong",
|
||||
"No, correction means reviewed repair",
|
||||
"Actually, truth requires evidence",
|
||||
"Incorrect",
|
||||
"correction: that needs review",
|
||||
],
|
||||
)
|
||||
def test_cold_start_correction_routes_through_pack_grounded(prompt: str) -> None:
|
||||
rt = ChatRuntime()
|
||||
resp = rt.chat(prompt)
|
||||
assert resp.grounding_source == "pack"
|
||||
assert "correction" in resp.surface
|
||||
assert "No prior turn in this session to correct yet." in resp.surface
|
||||
|
||||
|
||||
def test_correction_does_not_use_universal_disclosure() -> None:
|
||||
rt = ChatRuntime()
|
||||
resp = rt.chat("No, that's wrong")
|
||||
assert resp.surface != _UNKNOWN_DOMAIN_SURFACE
|
||||
|
||||
|
||||
def test_turn_event_carries_grounding_source_on_correction() -> None:
|
||||
rt = ChatRuntime()
|
||||
rt.chat("No, that's wrong")
|
||||
last_event = rt.turn_log[-1]
|
||||
assert getattr(last_event, "grounding_source", None) == "pack"
|
||||
|
||||
|
||||
def test_correction_pack_grounded_passes_verdict_audit() -> None:
|
||||
rt = ChatRuntime()
|
||||
resp = rt.chat("No, that's wrong")
|
||||
assert resp.safety_verdict is not None
|
||||
assert resp.ethics_verdict is not None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Doctrine — distinct from DEFINITION-of-correction
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_correction_surface_distinct_from_definition_of_correction() -> None:
|
||||
"""Compare ``"What is correction?"`` (DEFINITION) vs ``"No, that's
|
||||
wrong"`` (CORRECTION). Both go through the pack-grounded branch
|
||||
but emit different surfaces — the CORRECTION acknowledgement
|
||||
notes the missing prior turn; the DEFINITION does not."""
|
||||
rt_def = ChatRuntime()
|
||||
def_resp = rt_def.chat("What is correction?")
|
||||
|
||||
rt_corr = ChatRuntime()
|
||||
corr_resp = rt_corr.chat("No, that's wrong")
|
||||
|
||||
assert def_resp.surface != corr_resp.surface
|
||||
assert "No session evidence yet." in def_resp.surface
|
||||
assert "No prior turn in this session to correct yet." in corr_resp.surface
|
||||
Loading…
Reference in a new issue