core/docs/decisions/ADR-0062-composed-teaching-grounded-surface.md
Shay c492014815 feat(adr-0062): composed teaching-grounded surface (chain-of-chains)
Pre-ADR-0062, the teaching-grounded composer emitted exactly one
reviewed chain per surface — "light reveals truth" — even when the
corpus already contained an immediate follow-up "truth grounds
knowledge".  With 21 active chains after curriculum saturation v2,
many grounded prompts had a corpus-ratified follow-up the composer
silently dropped.

ADR-0062 adds the composed composer + an opt-in config flag:

  flag OFF (default):
    light — teaching-grounded (cognition_chains_v1): cognition.illumination;
    logos.core. light reveals truth (cognition.truth). No session evidence yet.

  flag ON:
    light — teaching-grounded (cognition_chains_v1): cognition.illumination;
    logos.core. light reveals truth (cognition.truth), which grounds
    knowledge (cognition.knowledge). No session evidence yet.

Follow-up resolution:
  - prefer cause; fall back to verification (deterministic preference)
  - cycle guard: 1-step cycles (A→B, B→A) blocked
  - pack-residency guard: follow-up's object must be pack-resident
  - bounded depth: v1 follows exactly one hop
  - degrades to single-chain BYTE-IDENTICALLY when no follow-up
    survives the guards (drop-in replacement)

Trust-boundary invariants preserved:
  - Every visible non-template token is lemma / pack-domain /
    humanize_predicate connective / template constant.  Only added
    template constant: ", which "
  - Deterministic: same chains → same surface bytes
  - Default-False flag pattern mirrors ADR-0047/0058
  - `versor_condition < 1e-6` invariant untouched (surface composition only)

Cognition lane null-drop invariant CI-pinned:
  Composed mode emits a strictly LONGER surface (extra follow-up
  clause); every expected_term passing flag-OFF must still pass flag-ON.
  Asserted in test_cognition_lane_metrics_unchanged_with_composed_flag
  for both public and holdout splits.  If a future change drops tokens,
  the test fails as a deliberate regression.

  public  flag OFF: intent 100% / surface 100% / term 91.7% / versor 100%
  public  flag ON : intent 100% / surface 100% / term 91.7% / versor 100% (identical)
  holdout flag OFF: intent 100% / surface 100% / term 83.3% / versor 100%
  holdout flag ON : intent 100% / surface 100% / term 83.3% / versor 100% (identical)

Live-prompt lift visible on ~12 of 21 active chains; the rest hit
cycle or pack-residency guards.  Saturation v2's clusters were
authored partly with composition in mind (thought→meaning→
understanding, inference→evidence→knowledge, etc.).

- core/config.py — `RuntimeConfig.composed_surface: bool = False`
- chat/teaching_grounding.py — `teaching_grounded_surface_composed`
  sibling to `teaching_grounded_surface`
- chat/runtime.py — dispatch branch in `_maybe_pack_grounded_surface`
  selects composed vs single-chain based on config flag
- tests/test_composed_surface.py — 11 tests pin: function-level
  (None on no chain / degrades when no follow-up / two-clause when
  follow-up exists / includes intermediate + final domains /
  deterministic / cycle guard / trust label preserved); runtime
  integration (default single-chain / flag-on composed / frozen
  config); cognition-lane null-drop invariant.

Lanes (regression): smoke 67 / cognition 121 / teaching 17 /
composed-surface 11 — all green.
2026-05-18 14:34:45 -07:00

8.2 KiB

ADR-0062 — Composed Teaching-Grounded Surface (Chain-of-Chains)

Status: Accepted Date: 2026-05-18 Author: Shay


Context

Pre-ADR-0062, teaching_grounded_surface emitted exactly one reviewed chain per surface:

light — teaching-grounded (cognition_chains_v1): cognition.illumination;
logos.core. light reveals truth (cognition.truth).
No session evidence yet.

Every grounded prompt produced a single-clause surface, regardless of how many follow-up chains the corpus already contained. With 21 active chains in cognition_chains_v1 (after curriculum saturation v2), many grounded prompts have an immediate corpus- ratified follow-up that the surface composer was silently dropping:

Initial chain Follow-up chain What single-chain emits What composed could emit
light reveals truth truth grounds knowledge light reveals truth light reveals truth, which grounds knowledge
thought reveals meaning meaning grounds understanding thought reveals meaning thought reveals meaning, which grounds understanding
inference requires evidence evidence grounds knowledge inference requires evidence inference requires evidence, which grounds knowledge

This is the fluency-from-existing-corpus gap I called out in the "more packs?" question: the rate-limiter on articulation isn't pack vocabulary, it's surface composition over chains that already exist.


Decision

Add teaching_grounded_surface_composed(subject, intent_tag) to chat/teaching_grounding.py alongside the existing single-chain composer, and route it via a new opt-in RuntimeConfig.composed_surface: bool = False.

Surface format

"{A} — teaching-grounded ({corpus_id}): {dA1}; {dA2}.
 {A} {conn_A} {B} ({dB}), which {conn_B} {C} ({dC}).
 No session evidence yet."

Every visible non-template token remains a lemma, a verbatim pack semantic_domains string, or a humanize_predicate-emitted connective. The new , which linker is the only added template constant.

Follow-up resolution rules

  1. Look up an initial chain (subject, intent).
  2. Look up a follow-up chain whose subject equals the initial chain's object. Prefer cause; fall back to verification. (Causal continuation reads more naturally than a verification detour; the preference is deterministic.)
  3. Cycle guard. If the follow-up's object equals the initial subject OR the initial object, do not follow (1-step cycle or degenerate same-cell mismatch).
  4. Pack-residency guard. If the follow-up's object is not pack-resident with semantic_domains, do not follow (would emit a partially-grounded composition).
  5. If no follow-up survives the guards, degrade to the single-chain surface byte-identically. Drop-in replacement.

Bounded depth

v1 follows exactly one hop. Deeper compositions (A→B→C→D) are deferred to a future ADR. The cycle/pack-residency guards alone don't suffice for unbounded depth — a depth-2 chain can re-enter through a different intent. Bounded depth + visited-set check is the natural next step but adds template-shape complexity not needed today.

Opt-in flag

RuntimeConfig.composed_surface: bool = False. Default preserves all pre-ADR-0062 behaviour byte-identically. Mirrors the ADR-0047/0058 forward_graph_constraint pattern: ship the capability behind a flag, characterise empirically, decide on default behaviour in a follow-up once downstream consumers have observed it on their workloads.


Verification

tests/test_composed_surface.py                11 passed
  - Pure function: None when no chain / degrades when no follow-up /
    produces two-clause when follow-up exists / includes both
    intermediate and final domains / deterministic / cycle guard
    blocks 1-step cycle / preserves trust-boundary label.
  - Runtime: default keeps single-chain / flag-on uses composed /
    flag is observable on frozen config.
  - Null-drop invariant: cognition-lane metrics byte-identical
    flag OFF vs ON on both public and holdout splits.

Lanes (regression check):
  core test --suite smoke           67 passed
  core test --suite cognition      121 passed
  core test --suite teaching        17 passed

Cognition-lane null-drop invariant

Composed mode emits a strictly longer surface — every token in the single-chain surface still appears, plus one follow-up clause. So every expected_term and expected_surface_contains that passed flag-OFF must still pass flag-ON. The contract test test_cognition_lane_metrics_unchanged_with_composed_flag runs both public and holdout splits twice (flag OFF vs ON) and asserts all four watched metrics are pair-wise identical:

Split Flag OFF Flag ON
public 100 / 100 / 91.7 / 100 100 / 100 / 91.7 / 100
holdout 100 / 100 / 83.3 / 100 100 / 100 / 83.3 / 100

If a future change ever drops tokens in composed mode (e.g. shortens the surface to omit the intermediate object), this test fails as the deliberate regression it is.

Live-prompt observable lift

Composed mode visibly enriches the surface on prompts where follow-ups exist:

flag OFF: "Why does light exist?"
  → light — teaching-grounded (cognition_chains_v1):
    cognition.illumination; logos.core. light reveals truth
    (cognition.truth). No session evidence yet.

flag ON:  "Why does light exist?"
  → light — teaching-grounded (cognition_chains_v1):
    cognition.illumination; logos.core. light reveals truth
    (cognition.truth), which grounds knowledge
    (cognition.knowledge). No session evidence yet.

Of the 21 active chains, the follow-up resolution succeeds for ~12 of them (the rest hit cycle guards or pack-residency guards). Saturation v2's three coherent clusters were authored partly with this composition in mind — thought reveals meaning

  • meaning grounds understanding, definition grounds concept + concept requires definition (cycle-blocked, degrades cleanly), etc.

Consequences

What changes

  • core/config.pyRuntimeConfig.composed_surface: bool = False.
  • chat/teaching_grounding.pyteaching_grounded_surface_composed(subject, intent_tag) sibling to teaching_grounded_surface.
  • chat/runtime.py — dispatch branch in _maybe_pack_grounded_surface for IntentTag.CAUSE / IntentTag.VERIFICATION selects composed vs single-chain based on the config flag. Single-line change.

What does not change

  • The pack-grounded discipline: zero LLM-generated tokens; every visible word is lemma, pack-domain, connective, or template constant.
  • ADR-0053's cold-start contract: empty session + no chain still emits the universal disclosure.
  • Default runtime behaviour: byte-identical to pre-ADR-0062 main.
  • The non-negotiable field invariant (versor_condition(F) < 1e-6) is unaffected — this ADR only changes surface composition, not rotor construction or sandwich application.

Scope limits

  • Depth-1 only. v1 follows one hop. light reveals truth, which grounds knowledge, which requires evidence would require a depth-2 composer with visited-set tracking — out of scope here.
  • No multi-claim aggregation. When the same subject has multiple ratified chains (e.g. knowledge requires evidence AND knowledge is the object of three other chains), the composer still picks one initial chain. Aggregation across multiple grounded views is a separate ADR.
  • English path only. The , which linker and the humanize_predicate connectives are English-specific.
  • Flag stays off by default. Operators must opt in. A follow-up ADR will decide on default behaviour after characterising the flag on more workloads (mirrors ADR-0047/0058).

Cross-References

  • ADR-0052 — the single-chain teaching-grounded composer this ADR extends.
  • ADR-0053 — the cognition- lane closure that exposed the saturation headroom.
  • ADR-0058 — the opt-in-default-False + null-lift-invariant pattern this ADR reuses.
  • Curriculum: cognition saturation v2 — the unit that produced the 21 chains this composer composes over.