Context
#14084 leaf 1 (the graduated converged design — see the #14084 graduation comment). The Memory Core repair reports perpetual exit 1 even when its only residue is genuinely-unembeddable + operator-acknowledged. The heart of the fix is a pure decision: given a repair's unrecoverable residue + a durable acknowledgement, is this accepted-loss (terminal + ack-matched) or must it escalate (transient, or un-acknowledged/stale)?
The Architectural Reality
- The detect-producer pure-fn pattern (
dataIntegrityCoverageDiagnosis.mjs / sqliteIntegrityDiagnosis.mjs / storeBloatDiagnosis.mjs) is the shape to mirror: injected inputs → a verdict, no I/O, unit-testable in isolation.
- The fingerprint inputs are fixed by @neo-gpt's strategy-fingerprint AC: residue
(ids + reasonCodes) + provider/model/context-budget + the active-recovery-strategy version + the sorted terminality-policy set (terminalReasons) (added in PR #14108 review — the ack must go stale on a policy/capability change, not only a residue change). The durable ack RECORD + the operator-ack surface are leaf 2; the defragChromaDB.mjs wiring is leaf 3.
The Fix
A pure classifyRepairResidue({residue, ack, strategyVersion, provider, contextBudget, terminalReasons}):
escalate when ANY residue row's reason is NOT in the terminal whitelist (transient/unknown must always escalate).
- else (all-terminal) compute a stable fingerprint over the residue + strategy/provider/context + the sorted terminality-policy set (
terminalReasons); accepted-loss iff ack is present AND ack.fingerprint === currentFingerprint; else escalate (un-acknowledged or stale ack).
- Returns
{outcome, reasonCode, fingerprint, nonTerminalReasons}; pure + deterministic (the fingerprint is a stable hash, no Date/randomness).
- A frozen
TERMINAL_REASONS default (embedding-context-exceeded, document-absent); transient reasons never qualify.
Acceptance Criteria
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
classifyRepairResidue({residue, ack, strategyVersion, provider, contextBudget, terminalReasons}) |
#14084 graduated design + @neo-gpt strategy-fingerprint AC |
accepted-loss | escalate | no-residue verdict + stable fingerprint over (sorted residue ids+reasons, strategyVersion, provider, contextBudget, sorted terminalReasons policy set) |
non-terminal → escalate; missing/stale ack → escalate; terminality-policy change → escalate; empty residue → no-residue |
module + fn JSDoc |
unit spec per branch |
TERMINAL_REASONS (frozen) |
#14084 reason-taxonomy |
embedding-context-exceeded, document-absent; shared with the diagnosis reasonCode vocabulary |
n/a |
JSDoc |
spec |
Out of Scope
- The durable ack record + operator-ack surface (leaf 2).
- The
defragChromaDB.mjs outcome wiring + the terminal diagnosis (leaf 3).
Related
#14084 (parent — the graduated design), #14026 (the detect signal the ack suppresses), #14066 (the partial-promote contract this refines), #14085 (the residue-shrinking Prevent sibling), #14039.
Live latest-open sweep: checked latest open + the #14084 leaf set at 2026-06-26T14:22Z; no accepted-loss-classifier leaf exists. A2A: #14084 graduation comment posted; design hand-off from @neo-opus-vega.
Origin Session ID: 5ab545e1-f09e-46c5-ae62-8cf5b2b96193
Handoff Retrieval Hints: query_raw_memories("accepted-loss residue classifier terminal-reason fingerprint escalate"); anchors: the data-integrity detect-producer pure-fn pattern, #14084 graduation comment.
Context
#14084 leaf 1 (the graduated converged design — see the #14084 graduation comment). The Memory Core repair reports perpetual
exit 1even when its only residue is genuinely-unembeddable + operator-acknowledged. The heart of the fix is a pure decision: given a repair's unrecoverable residue + a durable acknowledgement, is this accepted-loss (terminal + ack-matched) or must it escalate (transient, or un-acknowledged/stale)?The Architectural Reality
dataIntegrityCoverageDiagnosis.mjs/sqliteIntegrityDiagnosis.mjs/storeBloatDiagnosis.mjs) is the shape to mirror: injected inputs → a verdict, no I/O, unit-testable in isolation.(ids + reasonCodes)+provider/model/context-budget+ the active-recovery-strategy version + the sorted terminality-policy set (terminalReasons) (added in PR #14108 review — the ack must go stale on a policy/capability change, not only a residue change). The durable ack RECORD + the operator-ack surface are leaf 2; thedefragChromaDB.mjswiring is leaf 3.The Fix
A pure
classifyRepairResidue({residue, ack, strategyVersion, provider, contextBudget, terminalReasons}):escalatewhen ANY residue row's reason is NOT in the terminal whitelist (transient/unknown must always escalate).terminalReasons);accepted-lossiffackis present ANDack.fingerprint === currentFingerprint; elseescalate(un-acknowledged or stale ack).{outcome, reasonCode, fingerprint, nonTerminalReasons}; pure + deterministic (the fingerprint is a stable hash, noDate/randomness).TERMINAL_REASONSdefault (embedding-context-exceeded,document-absent); transient reasons never qualify.Acceptance Criteria
ack.fingerprint→accepted-loss.escalate(regardless of ack).escalate.(sorted residue ids+reasons, strategyVersion, provider, contextBudget, sorted terminalReasons policy set)— order-independent, no time/randomness. A terminality-policy-only change (residue terminal under both the old and new policy) invalidates a stale ack →escalate.escalate(no loss to escalate); a distinctno-residueoutcome (the caller treats as clean).Contract Ledger Matrix
classifyRepairResidue({residue, ack, strategyVersion, provider, contextBudget, terminalReasons})accepted-loss | escalate | no-residueverdict + stable fingerprint over(sorted residue ids+reasons, strategyVersion, provider, contextBudget, sorted terminalReasons policy set)TERMINAL_REASONS(frozen)embedding-context-exceeded,document-absent; shared with the diagnosisreasonCodevocabularyOut of Scope
defragChromaDB.mjsoutcome wiring + the terminal diagnosis (leaf 3).Related
#14084 (parent — the graduated design), #14026 (the detect signal the ack suppresses), #14066 (the partial-promote contract this refines), #14085 (the residue-shrinking Prevent sibling), #14039.
Live latest-open sweep: checked latest open + the #14084 leaf set at 2026-06-26T14:22Z; no accepted-loss-classifier leaf exists. A2A: #14084 graduation comment posted; design hand-off from @neo-opus-vega.
Origin Session ID: 5ab545e1-f09e-46c5-ae62-8cf5b2b96193
Handoff Retrieval Hints:
query_raw_memories("accepted-loss residue classifier terminal-reason fingerprint escalate"); anchors: the data-integrity detect-producer pure-fn pattern,#14084graduation comment.