core/chat/example_surface.py
Shay d5a6e81b33 feat(adr-0067): cross-pack teaching chains — Plan Phase 4 closed
ADR-0064 bound each teaching corpus 1:1 to a single ratified pack;
chains whose subject + object resolved to different packs were
dropped at load time. Phases 1–3 ratified the per-pack DAGs needed
to lift that constraint safely.

ADR-0067 introduces a deliberately narrow cross-pack chain shape.
Each entry carries explicit subject_pack_id and object_pack_id
fields, and the loader verifies per-chain residency. Same-pack
entries are rejected as corpus-misfilings (anti-leakage). The
cross-pack composer is the fall-through after the in-pack composer,
so the cognition lane stays byte-identical.

Files:
- chat/cross_pack_grounding.py — CrossPackChain + loader +
  single-chain composer + multi-chain enumerators
- teaching/cross_pack_chains/cross_pack_chains_v1.jsonl — 5 seed
  chains (family×identity, parent×understanding, family×memory,
  identity×family, understanding×parent)
- chat/runtime.py — fall-through wiring in CAUSE/VERIFICATION
- chat/narrative_surface.py, chat/example_surface.py — merge
  cross-pack chains, per-chain pack-residency helpers
- tests/test_cross_pack_chains.py — 31 tests covering loader,
  surface, multi-chain access, runtime integration, in-pack
  precedence
- tests/test_narrative_example_intents.py — corpus-tag assertions
  widened to allow cross-pack aggregation

Verification:
- 31 new tests pass
- Curated lanes: smoke 67 / cognition 121 / teaching 17 / packs 6 /
  runtime 19 — all green
- Cognition eval byte-identical (public 100/100/91.7/100, holdout
  100/100/83.3/100)
- Full lane: 2098 passed, 2 skipped, 0 failed in 2:30
2026-05-18 17:22:43 -07:00

129 lines
4.6 KiB
Python

"""chat/example_surface.py — Phase 3.4: EXAMPLE intent composer.
When a prompt classifies as EXAMPLE — "Give me an example of X",
"Show me an instance of X", "Example of X" — the composer surfaces
a reviewed chain where X appears as the **object**, inverting the
typical "X is the subject" chain access pattern.
For "Give me an example of truth":
(light, cause, reveals, truth) exists in the cognition corpus
"Example of truth: light reveals truth."
This is the *converse* of NARRATIVE. Where NARRATIVE walks every
chain rooted on X as subject ("X reveals A; X grounds B"), EXAMPLE
walks chains where X is the object ("A reveals X; B grounds X").
Both consult the same aggregated teaching index — no new corpus
ratification required.
Design constraints (matching ADR-0052..0065 doctrine):
- **No content synthesis.** Every visible non-template token is
pack-sourced or a verbatim chain atom.
- **Deterministic ordering.** Examples sort by (intent, subject,
connective) so identical corpus state yields identical surfaces.
- **Dedup by subject.** Multiple chains can have the same object X
with the same subject Y (e.g. cause/verification both
``Y reveals X``). Emit one example per distinct subject.
- **Bounded count.** Default ``max_examples=3`` keeps the surface
readable.
Returns ``None`` when no chain references X as object — caller
falls through to pack-grounded DEFINITION (if X is pack-resident)
or to OOV invitation (if X is unknown).
"""
from __future__ import annotations
from chat.cross_pack_grounding import cross_pack_chains_for_object
from chat.pack_resolver import _pack_lexicon_for, resolve_lemma
from chat.teaching_grounding import (
_all_chains_index,
_pack_for_corpus,
)
from generate.semantic_templates import humanize_predicate
def _object_domains_for_chain(chain) -> tuple[str, ...]:
"""Resolve object domains for both in-pack and cross-pack chains."""
object_pack_id = getattr(chain, "object_pack_id", None)
if object_pack_id:
return _pack_lexicon_for(object_pack_id).get(chain.object, ())
return _pack_for_corpus(chain.corpus_id).get(chain.object, ())
def example_grounded_surface(
object_lemma: str,
*,
max_examples: int = 3,
) -> str | None:
"""Return a deterministic EXAMPLE-tier surface, or ``None``.
Aggregates every reviewed chain whose **object** equals
*object_lemma* across all registered teaching corpora. Dedups
by subject (the same subject acting under both cause + verification
on the same object produces one example, not two). Sorts
lexicographically for replay stability.
Returns ``None`` when no chain references *object_lemma* as
object — caller routes through pack-grounded DEFINITION (if
the lemma is pack-resident) or to OOV invitation.
"""
if not object_lemma or not isinstance(object_lemma, str):
return None
key = object_lemma.strip().lower()
if not key:
return None
if max_examples < 1:
return None
index = _all_chains_index()
matching: list = [chain for chain in index.values() if chain.object == key]
# ADR-0067 — merge cross-pack chains whose object equals the lemma.
matching.extend(cross_pack_chains_for_object(key))
if not matching:
return None
# Dedup by subject — same subject acting twice (cause +
# verification) on this object is one example. Stable sort
# by (intent, subject, connective).
seen_subjects: set[str] = set()
deduped: list = []
for chain in sorted(
matching, key=lambda c: (c.intent, c.subject, c.connective),
):
if chain.subject in seen_subjects:
continue
seen_subjects.add(chain.subject)
deduped.append(chain)
if len(deduped) >= max_examples:
break
first = deduped[0]
object_domains = _object_domains_for_chain(first)
if not object_domains:
resolved = resolve_lemma(first.object)
if resolved is None:
return None
object_domains = resolved[1]
head_object = "; ".join(
object_domains[: max(1, first.domains_object_k)]
)
corpora = tuple(sorted({c.corpus_id for c in deduped}))
corpora_tag = corpora[0] if len(corpora) == 1 else " + ".join(corpora)
clauses: list[str] = []
for chain in deduped:
connective = humanize_predicate(chain.connective)
clauses.append(f"{chain.subject} {connective} {chain.object}")
examples_text = "; ".join(clauses)
return (
f"{first.object} — example-grounded ({corpora_tag}): "
f"{head_object}. Example: {examples_text}. "
f"No session evidence yet."
)
__all__ = ["example_grounded_surface"]