Pre-ADR-0061 every "How do I X?" question fell through to the
universal disclosure even when X was a pack-resident lemma. The
teaching corpus carries CAUSE/VERIFICATION chains only — procedural
knowledge is fundamentally different in kind from propositional
claims and deserves its own ratification path (deliberately out of
scope; a future parallel `procedure_chains_v1.jsonl` schema is
discussed in the ADR's non-goals).
ADR-0061 adds the honest cold-start fallback: ground the topic in
pack semantic_domains and note explicitly that ratified step-by-step
guidance does not exist yet.
Surface format:
"procedure-grounded ({pack_id}): {lemma} ({d1}; {d2}).
Step-by-step guidance for {lemma} is not yet ratified
in this session."
Selector — **last** pack-resident lemma in the verb-phrase subject:
"define a concept" → concept (object beats verb)
"verify a claim" → verify (verb wins when object is OOV)
"correct an error" → correct
"learn this" → learn
"do stuff" → None (falls through to universal disclosure)
Stopwords: only `be` and `have` (dialogue fillers). Procedure verbs
are deliberately NOT stopworded so the verb-as-fallback rule fires
when the object is OOV — keeps surface coverage.
Trust-boundary invariants:
- Every visible non-template token is lemma / pack-domain / template.
- Deterministic: same subject_text → same bytes.
- Returns None for fully-unknown utterances → universal disclosure
fires. Never fabricates surface from nothing (ADR-0053 contract).
- "not yet ratified" trust-label preserved.
Cognition lane lift:
public : intent 100% / surface 100% / term 91.7% / versor 100% (unchanged)
holdout : intent 100% / surface 94.7%→100.0% / term 79.2%→83.3% / versor 100%
Two cases fixed:
- procedure_define_010 ("How do I define a concept?") — surface +
term `concept` now captured.
- procedure_verify_034 ("How do I verify a claim?") — surface only
(case has no expected_terms; the verb fallback grounds it).
Combined effect: holdout `surface_groundedness` closes to 100%; 4 of
5 architectural holdout misses now resolved (this ADR + ADR-0060 +
the supersede from epistemology v1). Remaining 2 are UNKNOWN-intent
cases (unknown_spirit_041, unknown_word_018) — out of scope; deserve
their own ADR with distinct selector semantics.
- chat/pack_grounding.py — `_extract_procedure_topic_lemma` helper +
`pack_grounded_procedure_surface` composer.
- chat/runtime.py — import + dispatch branch for `IntentTag.PROCEDURE`.
- tests/test_procedure_surface.py — 15 tests pin: extraction
(last-wins / verb-by-elimination / be+have skipped / None on empty /
strips punctuation / case-insensitive); surface (contains lemma /
contains domains / pack_id / "not yet ratified" label / None for
no-pack-lemma / deterministic); end-to-end through ChatRuntime.
Lanes (regression): smoke 67 / cognition 121 / teaching 17 /
procedure 15 — all green.
The non-negotiable field invariant (versor_condition < 1e-6) is
unaffected: this ADR changes surface composition only.
166 lines
6.6 KiB
Python
166 lines
6.6 KiB
Python
"""ADR-0061 — PROCEDURE intent routes to pack-grounded surface.
|
|
|
|
Pre-ADR-0061, ``PROCEDURE`` intent had no pack-grounded composer:
|
|
every ``"How do I X?"`` question fell through to the universal
|
|
disclosure even when ``X`` was a pack-resident lemma. This closed
|
|
``procedure_define_010`` ("How do I define a concept?") as a
|
|
surface-and-term holdout miss and ``procedure_verify_034``
|
|
("How do I verify a claim?") as a surface miss.
|
|
|
|
ADR-0061 adds ``pack_grounded_procedure_surface(subject_text)``:
|
|
extracts the **last** pack-resident lemma from the verb-phrase
|
|
subject (deliberately: procedure verb → topic, last is the topic)
|
|
and emits a deterministic acknowledgement surface that grounds
|
|
the topic in pack semantic_domains and notes explicitly that
|
|
step-by-step guidance is not yet ratified.
|
|
|
|
These tests pin:
|
|
|
|
- Extraction picks the last pack-resident lemma (not the first).
|
|
- Stopwords ``be`` / ``have`` are skipped.
|
|
- Verbs (``define``, ``verify``, ``correct``, ``learn``) are NOT
|
|
stopworded — when the verb is the only pack-resident lemma,
|
|
the verb is the topic by elimination.
|
|
- Surface is deterministic.
|
|
- Surface preserves the trust-boundary clause about
|
|
not-yet-ratified guidance.
|
|
- Returns ``None`` when no pack lemma is found (so the universal
|
|
disclosure still fires for fully-unknown procedure utterances).
|
|
- Live ``ChatRuntime`` routes ``procedure_define_010`` through
|
|
this composer and the surface contains ``concept``.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from chat.pack_grounding import (
|
|
PACK_ID,
|
|
_extract_procedure_topic_lemma,
|
|
pack_grounded_procedure_surface,
|
|
)
|
|
from chat.runtime import ChatRuntime
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Topic-lemma extraction (last-wins on procedure subjects)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_extract_picks_last_pack_lemma() -> None:
|
|
"""For verb-phrase subjects the topic is the object — last
|
|
pack-resident lemma wins."""
|
|
assert _extract_procedure_topic_lemma("define a concept") == "concept"
|
|
|
|
|
|
def test_extract_returns_verb_when_only_pack_lemma() -> None:
|
|
"""When the verb is the only pack-resident lemma (object is OOV
|
|
or filler), the verb is the topic by elimination — preserves
|
|
coverage on procedure utterances with non-pack objects."""
|
|
assert _extract_procedure_topic_lemma("verify a claim") == "verify"
|
|
assert _extract_procedure_topic_lemma("correct an error") == "correct"
|
|
assert _extract_procedure_topic_lemma("learn this") == "learn"
|
|
|
|
|
|
def test_extract_skips_dialogue_fillers() -> None:
|
|
"""``be`` and ``have`` are pack-resident but stopworded."""
|
|
assert _extract_procedure_topic_lemma("be a teacher") is None # 'teacher' is OOV
|
|
assert _extract_procedure_topic_lemma("have knowledge") == "knowledge"
|
|
|
|
|
|
def test_extract_none_when_no_pack_lemma() -> None:
|
|
assert _extract_procedure_topic_lemma("") is None
|
|
assert _extract_procedure_topic_lemma(None) is None # type: ignore[arg-type]
|
|
assert _extract_procedure_topic_lemma("do stuff") is None
|
|
|
|
|
|
def test_extract_strips_punctuation() -> None:
|
|
assert _extract_procedure_topic_lemma("define, a concept.") == "concept"
|
|
|
|
|
|
def test_extract_is_case_insensitive() -> None:
|
|
assert _extract_procedure_topic_lemma("DEFINE A CONCEPT") == "concept"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Surface composition
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_surface_contains_topic_lemma() -> None:
|
|
surface = pack_grounded_procedure_surface("define a concept")
|
|
assert surface is not None
|
|
assert "concept" in surface
|
|
|
|
|
|
def test_surface_contains_topic_domains() -> None:
|
|
"""Pack-grounded: the topic lemma's top semantic_domains are
|
|
surfaced verbatim — no rewording."""
|
|
from chat.pack_grounding import _pack_index
|
|
concept_domains = _pack_index().get("concept", ())
|
|
assert concept_domains, "test fixture: 'concept' must be a pack lemma"
|
|
|
|
surface = pack_grounded_procedure_surface("define a concept")
|
|
assert surface is not None
|
|
assert any(d in surface for d in concept_domains[:2])
|
|
|
|
|
|
def test_surface_contains_pack_id() -> None:
|
|
surface = pack_grounded_procedure_surface("define a concept")
|
|
assert surface is not None
|
|
assert PACK_ID in surface
|
|
|
|
|
|
def test_surface_preserves_not_yet_ratified_clause() -> None:
|
|
"""Trust-boundary label: procedure guidance is not yet ratified.
|
|
Must appear in every surface emitted by this composer."""
|
|
surface = pack_grounded_procedure_surface("define a concept")
|
|
assert surface is not None
|
|
assert "not yet ratified" in surface
|
|
|
|
|
|
def test_surface_returns_none_for_no_pack_lemma() -> None:
|
|
"""A procedure subject with no pack-resident lemma falls
|
|
through to the universal disclosure — preserves the honesty
|
|
contract for fully-unknown procedures."""
|
|
assert pack_grounded_procedure_surface("") is None
|
|
assert pack_grounded_procedure_surface("do stuff") is None
|
|
|
|
|
|
def test_surface_is_deterministic() -> None:
|
|
a = pack_grounded_procedure_surface("define a concept")
|
|
b = pack_grounded_procedure_surface("define a concept")
|
|
assert a == b
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# End-to-end through ChatRuntime
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_procedure_define_010_now_emits_concept() -> None:
|
|
"""The exact holdout case this ADR targets:
|
|
`procedure_define_010` ("How do I define a concept?") expected
|
|
``term=['concept']`` and was missing it pre-ADR-0061. Through
|
|
the live runtime, the surface must now contain ``concept``."""
|
|
rt = ChatRuntime()
|
|
response = rt.chat("How do I define a concept?")
|
|
assert response.grounding_source == "pack"
|
|
assert "concept" in response.surface.lower()
|
|
|
|
|
|
def test_procedure_with_no_pack_lemma_falls_through() -> None:
|
|
"""A procedure utterance with no pack-resident lemma still
|
|
receives the universal disclosure (no surface fabrication)."""
|
|
rt = ChatRuntime()
|
|
response = rt.chat("How do I do stuff?")
|
|
assert response.grounding_source == "none"
|
|
assert "insufficient grounding" in response.surface.lower()
|
|
|
|
|
|
def test_procedure_verify_a_claim_grounds() -> None:
|
|
"""When the object is OOV (``claim`` isn't a pack lemma) but
|
|
the verb is pack-resident (``verify``), the composer surfaces
|
|
the verb — keeps surface_groundedness coverage."""
|
|
rt = ChatRuntime()
|
|
response = rt.chat("How do I verify a claim?")
|
|
assert response.grounding_source == "pack"
|
|
assert "verify" in response.surface.lower()
|