# ADR-0055 — Inter-Session Memory: Reviewed Discovery Promotion

**Status:** Phase A + Phase B Accepted; Phase C Implemented (split into [ADR-0056](./ADR-0056-contemplation-loop-c1.md) C1 + [ADR-0057](./ADR-0057-teaching-chain-proposal-review.md) C2, both Accepted); Phases D–E substantially landed (`teaching/epistemic.py`, corpus-flywheel / learning-arc)
**Date:** 2026-05-18
**Author:** Shay

---

## Context

CORE already has a multi-tier memory story, but it is undocumented as
a single design and uneven in maturity.  This ADR proposes the shape
of inter-session memory **as a coherent surface**, sketches the
proposal-only path that lets the system contribute its own
reviewed-memory candidates, and names the doctrine guardrails so
later implementation ADRs have a contract to land against.

The north-star direction is explicit:

> CORE should eventually learn by self-thought-through and
> successful discoveries — knowledge-vs-truth confirmations
> stumbled on through reasoning, thinking, and responding to users —
> and these should become part of inter-session memory **in the way
> we do memory**, not in a database/embedding store.

"The way we do memory" means: pack-grounded atoms, reviewed
promotion, deterministic replay, append-only audit trail, no
parallel learning path.  This ADR defines what that looks like end
to end.

---

## Today — the four-tier inventory

```text
turn  ─►  session vault      (ephemeral, exact CGA recall)
                  │
                  └─►  TurnEvent / trace_hash / verdicts   (audit-only)
                                       │
                                       ▼
                          DiscoveryCandidate  (proposed; not built)
                                       │
                                       ▼
                          TeachingChainProposal  (reviewed → applied)
                                       │
                                       ▼
                          reviewed teaching corpus
                (teaching/cognition_chains/cognition_chains_v1.jsonl)
                                       │
                                       ▼
                          ratified packs
        (packs/identity/, packs/safety/, packs/ethics/, language_packs/)
```

### Tier 1 — Session vault (`vault/store.py`)

- Exact, deterministic CGA inner-product recall over a deque of
  stored versors.  Ephemeral, per `ChatRuntime` instance.
- ADR-0054 added matrix-cache indexing + batched recall.
- Holds **everything the session has seen** at the algebraic layer.
- Not promoted to inter-session memory automatically.

### Tier 2 — Turn-event audit trail

- Every turn emits a `TurnEvent` (`core/physics/identity.py`) with
  `trace_hash`, `grounding_source`, `safety_verdict`,
  `ethics_verdict`, `refusal_emitted`, `hedge_injected`.
- ADR-0040 added the JSONL telemetry sink; ADR-0041 the fan-out
  + operator readout; ADR-0042 the four-scene audit-tour demo.
- This is **evidence**, not memory — the record of what the system
  did, with enough state to replay it deterministically.
- It is the raw material from which discovery candidates can be
  mined.

### Tier 3 — Reviewed teaching corpus

- `teaching/cognition_chains/cognition_chains_v1.jsonl` (3 chains
  from ADR-0052, 10 after ADR-0053).
- Append-only JSONL.  Every entry carries a provenance tag
  (`adr-0052:reviewed:2026-05-17`,
  `adr-0053:reviewed:2026-05-18`).
- Pack-consistency check at load (ADR-0052): a chain whose subject
  or object is missing from the pack is silently dropped — the
  "every atom is pack-sourced" invariant is enforced at boundary,
  not at write time.
- `teaching/correction.py` is the canonical repair flow for
  per-session corrections; it does not write to the corpus
  automatically.

### Tier 4 — Ratified packs

- `packs/identity/`, `packs/safety/`, `packs/ethics/`,
  `language_packs/data/*`.
- Self-sealed via companion `.mastery_report.json`; verified at
  startup in production mode.
- `PackMutationProposal` (ADR-0051 lineage) is the only path that
  ever changes a pack; mutation is proposal-only until reviewed.
- These are the long-term substrate — what survives across all
  sessions and reboots.

---

## What is missing

1. **No automated promotion from Tier 1/2 to Tier 3.**  Today, a
   chain enters the reviewed corpus only when a human authors it in
   an ADR PR.  The system itself never proposes one, even when its
   own audit trail makes the candidate obvious (e.g., a turn that
   *would have grounded* if a specific chain existed).
2. **No supersession / forgetting semantics in Tier 3.**
   Append-only is correct for audit; it is not sufficient for an
   "active set" view.  A later chain that contradicts an earlier
   one has no way to mark the earlier one inactive.
3. **No audit lane for silent corpus drops.**  ADR-0052's
   pack-consistency check drops chains that reference missing
   lemmas without logging.  A pack swap can therefore silently
   shrink the active corpus.
4. **No discovery-candidate object at all.**  When a turn produces
   evidence that would extend the corpus (a successful comparison
   that grounded via the pack path; a hedge that fired and then
   was acknowledged in a follow-up turn; an OOV that resolved
   cleanly via decomposition), the evidence dies with the
   `TurnEvent`.

This ADR specifies the proposal-only objects and the doctrine
guardrails that close those gaps **without** introducing a
parallel learning path or an opaque LLM step.

---

## Decision — phased scope

### Phase A — make the current story load-bearing

**A1. Audit CLI lane.**  `core teaching audit` (sibling to
`core pack verify`) — diffs the on-disk corpus JSONL against the
loaded-and-pack-consistency-checked corpus and emits:

```json
{
  "corpus_path": "teaching/cognition_chains/cognition_chains_v1.jsonl",
  "lines_on_disk": 10,
  "lines_loaded": 10,
  "lines_dropped": [],
  "drop_reasons": {}
}
```

Lines dropped by the pack-consistency check are surfaced with the
exact reason (`"subject 'X' missing from en_core_cognition_v1"`).
Run as a non-mutating check; safe to wire into CI.

**A2. Active-set view.**  Add a `superseded_by: chain_id | null`
field to corpus entries (with default `null`).  The loader filters
out any chain whose `chain_id` appears as another's
`superseded_by`.  Append-only history is preserved on disk; the
active corpus is a derived view.  Existing 10 chains carry
`superseded_by: null` — no behaviour change.

**A3. Explicit provenance enum.**  Today `provenance` is a free
string (`adr-0052:reviewed:2026-05-17`).  Constrain it to a typed
shape: `{adr_id, source, review_date}` where `source ∈
{"hand_authored", "discovery_promoted", "imported"}`.  Existing
chains rewrite to `source="hand_authored"`.

Phase A introduces **no learning** and **no automation**.  It
makes the existing corpus inspectable, supersedable, and
provenance-typed so the later phases have something safe to write
into.

### Phase B — `DiscoveryCandidate` from the turn loop

A passive emitter on the `TurnEvent` pipeline that produces a
typed candidate object **whenever** a deterministic rule fires:

```python
@dataclass(frozen=True, slots=True)
class DiscoveryCandidate:
    candidate_id: str                # deterministic hash of contents
    proposed_chain: dict             # subject / intent / connective / object
    trigger: Literal[
        "would_have_grounded",       # turn fell through to universal disclosure
                                     # but a single missing chain would have grounded it
        "successful_comparison",     # COMPARISON path produced a coherent surface
                                     # that the user did not correct
        "hedge_acknowledged",        # hedge_injected then a follow-up turn left it
                                     # unchallenged
        "oov_resolved_via_decomp",   # decomposition produced a deterministic surface
    ]
    source_turn_trace: str           # the originating TurnEvent.trace_hash
    pack_consistent: bool            # subject + object are pack lemmas
    boundary_clean: bool             # no safety/ethics verdict violation in the turn
    review_state: Literal["unreviewed"]  # ALWAYS unreviewed on emit
```

Emission rules are **deterministic and pack-derived** — no LLM
judgement, no stochastic sampling.  A candidate is just structured
evidence: "the audit trail says this turn meets condition X."

Candidates are written to a separate file
(`teaching/discovery_candidates/<YYYY>/<YYYY-MM>.jsonl`,
append-only, per-month rollover for inspection ergonomics).  They
**never** load into the active corpus.

### Phase C — `TeachingChainProposal` (the review surface)

Sibling to `PackMutationProposal`.  Reading a `DiscoveryCandidate`
and turning it into a proposed corpus addition is **proposal-only**:

```python
@dataclass(frozen=True, slots=True)
class TeachingChainProposal:
    proposal_id: str                 # deterministic
    candidate_id: str                # the DiscoveryCandidate it came from
    proposed_entry: dict             # the JSONL line that would be appended
    replay_equivalence_hash: str     # eval-lane trace hashes BEFORE the proposal
    rationale: str                   # template-formatted, not free text
    requires: tuple[str, ...]        # invariants the reviewer must confirm
```

`core teaching propose` CLI generates proposals from recent
candidates.  `core teaching review` lists proposals and accepts /
rejects them.  Acceptance:

1. Runs the cognition eval lane on dev + public splits **before**
   appending — captures `replay_equivalence_hash`.
2. Appends the entry to the corpus JSONL with
   `source="discovery_promoted"` and the originating
   `candidate_id` recorded in `provenance`.
3. Re-runs the eval lane.  If any metric regresses on either
   split, the append is rolled back (`git checkout --` the corpus
   file) and the proposal is marked `rejected_by_replay`.

This is the **only** path by which the system contributes to its
own inter-session memory.  Identity / safety / ethics packs are
**out of scope** for discovery promotion — they remain
hand-authored, hand-ratified.

### Phase D — knowledge-vs-truth: epistemic-tier-aware discovery

Tie discovery into ADR-0021's `EpistemicStatus`.  A candidate is
upgraded to a proposal only when the **source turn's vault entries
are admissible as evidence** (`EpistemicStatus.COHERENT`).
SPECULATIVE / CONTESTED / FALSIFIED turns produce candidates but
**not** proposals — they are kept as evidence-of-reasoning,
inspectable but inert.

This is the doctrine-aligned shape of "knowledge-vs-truth
confirmation":

- **Knowledge** = a chain present in the active corpus.
- **Coherence judgement** = the `EpistemicStatus` stamp on the
  evidence behind the candidate.
- **Truth** = survives review + replay-equivalence on the eval
  lanes.

The system does not assert truth.  It surfaces candidates whose
*own evidence* meets the coherence bar, and review decides.

### Phase E — curriculum integration

Once Phases A–D are deterministic and replay-stable, the
`evals.identity_divergence` and `formation/templates/`
curriculum-teaching path (see [[curriculum-platform]],
[[identity-doctrine]] memories) can consume discovery-promoted
chains as **curriculum candidates** — the same review gate, but
the artifact lives in formation rather than the teaching corpus.

This phase is explicitly **not** the place to ratify identity
shifts.  Identity packs stay hand-ratified per ADR-0027.

---

## Why this is doctrine-aligned

1. **No parallel learning path.**  Every promotion routes through
   `teaching/` review.  Identity / safety / ethics packs are
   off-limits to discovery promotion.
2. **No opaque LLM step.**  Candidate emission is deterministic
   rule-firing on the audit trail.  Replay-equivalence is a
   trace-hash comparison.
3. **Proposal-only by construction.**  `DiscoveryCandidate` and
   `TeachingChainProposal` are typed objects with explicit
   `review_state`.  Nothing applies without review + replay.
4. **Append-only with supersession, not mutation.**  History is
   preserved on disk; the loader derives the active view.
5. **Pack-consistency check stays the gate.**  A chain that
   refers to non-pack atoms is dropped at load — the same gate
   that protects today's 10 chains protects every future
   discovery-promoted entry.
6. **Deterministic replay is the safety net.**  An accepted
   proposal that regresses any eval-lane metric is rolled back.
7. **Identity informs doing.**  This ADR adds capability, not
   identity.  The system learns *how it grounds*, not *what it
   is*.

---

## Non-goals

- **Vector / embedding memory.**  CGA inner product remains the
  algebraic recall metric.  No HNSW, no ANN, no cosine.
- **Database storage.**  Inter-session memory is reviewed JSONL +
  ratified packs.  No SQL, no embedded KV store, no graph DB.
- **Automatic identity / safety / ethics pack mutation.**  Those
  remain hand-ratified.
- **Free-text reasoning logs as memory.**  Only typed,
  pack-grounded chains promote.
- **Removing the human reviewer.**  Review is part of the
  doctrine, not a placeholder for automation.

---

## Open questions

1. **Granularity of `DiscoveryCandidate` triggers.**  The four
   listed are the tightest; a fifth ("refusal averted by hedge")
   is tempting but needs a clean predicate before it can be
   deterministic.
2. **Storage of unreviewed candidates.**  Monthly JSONL rollover
   is one option; per-session is another.  Per-month was chosen
   for inspection ergonomics — revisit once volume is known.
3. **Replay-equivalence on holdouts.**  ADR-0054 wired
   `--split holdout`.  Acceptance currently runs dev + public; the
   call is whether the holdout split is also a regression gate.
   Probably yes once holdout numbers stabilise.
4. **Multilingual packs.**  Discovery promotion is currently
   English-only (`en_core_cognition_v1`).  The proposal mechanism
   generalises; the trigger rules may need per-pack tuning.
5. **What "successful comparison" means.**  Today the pack-grounded
   COMPARISON surface is emitted regardless of user follow-up.
   A trigger that conditions on *user did not correct in the next
   turn* is a stronger but session-spanning signal — needs care
   to stay deterministic.

---

## Cross-References

- [ADR-0021](./ADR-0021-epistemic-status.md) — `EpistemicStatus`
  tiers that Phase D depends on; realized in `teaching/epistemic.py`.
- [ADR-0056](./ADR-0056-contemplation-loop-c1.md) — Phase **C1**:
  contemplation loop (question decomposition + polarity + domain
  typing). Accepted, implemented.
- [ADR-0057](./ADR-0057-teaching-chain-proposal-review.md) — Phase
  **C2**: `TeachingChainProposal` + review + replay-equivalence
  gate, the review surface this ADR proposed. Accepted.
- [ADR-0027](./ADR-0027-identity-packs.md) — ratified-pack
  authority; out of scope for discovery promotion.
- [ADR-0040](./ADR-0040-structured-logging-sink.md) /
  [ADR-0041](./ADR-0041-fanout-sink-cli-verdicts.md) — turn-event
  telemetry that Phase B reads from.
- [ADR-0051](./ADR-0051-trust-boundary-hardening.md) — the
  `PackMutationProposal` lineage `TeachingChainProposal` mirrors.
- [ADR-0052](./ADR-0052-teaching-grounded-surface.md) —
  pack-consistency gate at load that Phase A makes inspectable
  and Phase C relies on.
- [ADR-0053](./ADR-0053-cognition-lane-closure.md) — the existing
  hand-authored corpus this ADR proposes to extend in a
  reviewed-machine-contributed way.

---

## Verification (phase-by-phase)

Each phase landed as its own ADR (C as ADR-0056/0057). Acceptance
criteria, expressed up front so later ADRs had a contract:

- **Phase A**: `core teaching audit` is deterministic; corpus
  drops surface with reason; supersession field defaults `null`
  and changes nothing.  Eval lanes unchanged.
- **Phase B**: `DiscoveryCandidate` emission is replay-equivalent
  — same session, same prompts ⇒ same candidate file.  No
  candidate ever writes to the corpus.
- **Phase C**: A proposal that regresses any eval-lane metric on
  dev or public is rolled back automatically.  No proposal
  applies without review.
- **Phase D**: SPECULATIVE / CONTESTED / FALSIFIED candidates
  never become proposals.  Proven by case-level tests on each
  status.
- **Phase E**: Identity-divergence eval baseline unchanged after
  curriculum candidates are introduced (no identity drift).

The non-negotiable field invariant (`versor_condition(F) < 1e-6`)
is preserved by construction at every phase — none of this work
touches the algebra path.
