LearnNewsExamplesServices
Frontmatter
id14110
titleAccepted-loss ack record constructor (#14084 leaf 2)
stateClosed
labels
enhancementaiarchitecture
assigneesneo-opus-grace
createdAtJun 26, 2026, 4:35 PM
updatedAtJun 26, 2026, 5:44 PM
githubUrlhttps://github.com/neomjs/neo/issues/14110
authorneo-opus-grace
commentsCount0
parentIssue14084
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJun 26, 2026, 5:44 PM

Accepted-loss ack record constructor (#14084 leaf 2)

Closed v13.1.0/archive-v13-1-0-chunk-6 enhancementaiarchitecture
neo-opus-grace
neo-opus-grace commented on Jun 26, 2026, 4:35 PM

Context

#14084 leaf 2 (after leaf 1 #14106 — the classifyRepairResidue decider). The classifier consumes a durable ack and returns accepted-loss only when ack.fingerprint matches the live terminal residue. This leaf builds the producer of that ack — the durable operator-acknowledgement record — so the ack the operator stores is exactly the one the classifier accepts (the loop closes), and a later residue/strategy/provider change makes the stored ack stop matching by construction (the emergent-invalidation contract).

The Architectural Reality

  • ai/services/memory-core/helpers/classifyRepairResidue.mjs (#14106) exports computeResidueFingerprint — the stable hash the classifier uses. The ack MUST reuse it (so the fingerprints are identical).
  • ai/services/memory-core/helpers/recoveryRunStateStore.mjs is the typed-record-constructor pattern to mirror (createRecoveryDiagnosisEvent / createRecoveryRunStateEntry: pure constructor + schemaVersion + a typed type).
  • The durable PERSISTENCE (store/retrieve-by-fingerprint) + the operator-invocation surface + the defrag wiring are leaf 3 — this leaf is the pure record SSOT.

The Fix

A pure createAcceptedLossAckEntry({residue, operatorId, acknowledgedAt, strategyVersion, provider, contextBudget, terminalReasons, recoveryRunId}) in a ai/services/memory-core/helpers/acceptedLossAck.mjs sibling:

  • Computes fingerprint via the shared computeResidueFingerprint (identical to the classifier's), packaging it + acknowledgedIds (sorted) + residueCount + the strategy/provider/context + the sorted terminality-policy set (terminalReasons) + operatorId + acknowledgedAt into a typed accepted-loss-ack record (schemaVersion: 1). The fingerprint binds terminalReasons (PR #14108 review), so a policy change staleness-invalidates the ack.
  • Pure — no I/O, no time/randomness (the caller supplies acknowledgedAt).
  • Throws on missing operatorId / non-finite acknowledgedAt (mirrors the store's validation).

Acceptance Criteria

  • createAcceptedLossAckEntry returns a typed accepted-loss-ack record whose fingerprint equals computeResidueFingerprint over the same residue + context + sorted terminality-policy set; the record carries the sorted terminalReasons for provenance.
  • Round-trip: classifyRepairResidue({residue, ack: createAcceptedLossAckEntry({residue, …})})accepted-loss (the ack the constructor builds is accepted by the classifier).
  • A changed residue / strategy / provider / context / terminality-policy produces a different fingerprint (the stale ack no longer matches → the classifier escalates).
  • Pure; throws on missing operatorId / non-finite acknowledgedAt.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
createAcceptedLossAckEntry({residue, operatorId, acknowledgedAt, strategyVersion, provider, contextBudget, terminalReasons, recoveryRunId}) #14084 graduated design + computeResidueFingerprint (#14106) typed accepted-loss-ack record with the shared fingerprint binding the sorted terminalReasons policy set bad operatorId/acknowledgedAtTypeError module + fn JSDoc unit spec (round-trip with the classifier)

Out of Scope

  • The durable persistence + retrieve-by-fingerprint + the operator-invocation surface (leaf 3).
  • The defragChromaDB.mjs outcome wiring (leaf 3).

Related

#14084 (parent — graduated design), #14106 (leaf 1 — the classifier this pairs with), #14026 (the detect signal the ack suppresses), #14039.

Live latest-open sweep: checked latest open + the #14084 leaf set at 2026-06-26T14:34Z; no ack-constructor leaf exists. A2A: #14084 graduation comment posted.

Origin Session ID: 5ab545e1-f09e-46c5-ae62-8cf5b2b96193