Context
PR #14272 shipped the self-heal observability surface and bounded heal-ledger primitives. During final review, one valid follow-up remained: some production append sites still wrote to the shared heal-event ledger without supplying the validated retention pair, so those event classes could grow the ledger indefinitely if they were the only active writers.
This issue was originally filed with an additional dataDir mutation-coherence claim. That claim is retracted. dataDir is reactive, but that fact alone does not prove every closure constructed inside sibling beforeSet* hooks must migrate after later dataDir changes. Runtime dataDir mutation across all data-bound orchestrator closures is a broader contract question and is out of scope here.
The Problem
appendHealEvent() intentionally owns no production retention defaults. It only arms the append-time prune gate when callers supply finite triggerBytes and maxEvents.
The production append classes that still needed explicit retention coverage were:
ai/daemons/orchestrator/Orchestrator.mjs recordCircuitEvent
ai/services/memory-core/helpers/freezeReprobeRunner.mjs contained-reopen
ai/services/memory-core/helpers/freezeReprobeRunner.mjs unfreeze
ai/services/memory-core/helpers/freezeReprobeRunner.mjs contained
The Fix
- Keep
healEventLedgerStore.mjs pure: no helper-owned production defaults and no direct AiConfig reads inside the helper.
- Read and validate
AiConfig.orchestrator.recoveryActuator.healLedger.{maxEvents,pruneTriggerBytes} directly at each Orchestrator append use-site boundary. No wrapper around the provider; ADR-0019 keeps AiConfig as the reactive state provider.
- Pass that explicit retention pair to all production writers that contribute to the shared #14163 heal-event ledger.
- Add focused regression coverage proving systemic-circuit and freeze re-probe event classes retain under the same bounded policy without mutating the shared AiConfig singleton in tests.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Behavior |
Fallback |
Evidence |
| Shared heal-event append retention policy |
AiConfig.orchestrator.recoveryActuator.healLedger + validateHealLedgerRetention() |
Every production writer to the shared heal-event ledger passes validated {maxEvents, triggerBytes} into appendHealEvent() from the Orchestrator use site. |
Invalid config fails at the AiConfig boundary before append; observability write failures remain non-gating where required. |
Focused unit tests prove circuit events and freeze re-probe event classes prune under the supplied policy. |
| Freeze re-probe and systemic-circuit ledger events |
runFreezeReprobe() / recordCircuitEvent |
contained-reopen, unfreeze, contained, and circuit events are retained under the same bounded policy as data-recovery attempts/outcomes. |
Event append remains best-effort and must not gate heal/unfreeze logic. |
Helper and Orchestrator unit regressions. |
Decision Record impact
Aligned with ADR 0019. Runtime policy stays in AiConfig; Orchestrator reads provider leaves directly at use sites; pure helpers receive explicit values and do not re-read or own production defaults. Tests must not mutate the shared singleton.
Acceptance Criteria
Out of Scope
- No new MCP tool.
- No new retention leaf names.
- No rewrite of #14272's self-heal snapshot envelope.
- No runtime
dataDir mutation contract change.
- No split into multiple micro tickets.
Related
Related: #14163, #14272, #14039, #14128, #14179, #14166
Handoff Retrieval Hints: "PR #14272 heal-ledger retention follow-up"; "appendHealEvent retention policy omitted call sites"; "freeze re-probe heal-ledger retention".
Context
PR #14272 shipped the self-heal observability surface and bounded heal-ledger primitives. During final review, one valid follow-up remained: some production append sites still wrote to the shared heal-event ledger without supplying the validated retention pair, so those event classes could grow the ledger indefinitely if they were the only active writers.
This issue was originally filed with an additional
dataDirmutation-coherence claim. That claim is retracted.dataDiris reactive, but that fact alone does not prove every closure constructed inside siblingbeforeSet*hooks must migrate after laterdataDirchanges. RuntimedataDirmutation across all data-bound orchestrator closures is a broader contract question and is out of scope here.The Problem
appendHealEvent()intentionally owns no production retention defaults. It only arms the append-time prune gate when callers supply finitetriggerBytesandmaxEvents.The production append classes that still needed explicit retention coverage were:
ai/daemons/orchestrator/Orchestrator.mjsrecordCircuitEventai/services/memory-core/helpers/freezeReprobeRunner.mjscontained-reopenai/services/memory-core/helpers/freezeReprobeRunner.mjsunfreezeai/services/memory-core/helpers/freezeReprobeRunner.mjscontainedThe Fix
healEventLedgerStore.mjspure: no helper-owned production defaults and no direct AiConfig reads inside the helper.AiConfig.orchestrator.recoveryActuator.healLedger.{maxEvents,pruneTriggerBytes}directly at each Orchestrator append use-site boundary. No wrapper around the provider; ADR-0019 keepsAiConfigas the reactive state provider.Contract Ledger Matrix
AiConfig.orchestrator.recoveryActuator.healLedger+validateHealLedgerRetention(){maxEvents, triggerBytes}intoappendHealEvent()from the Orchestrator use site.runFreezeReprobe()/recordCircuitEventcontained-reopen,unfreeze,contained, and circuit events are retained under the same bounded policy as data-recovery attempts/outcomes.Decision Record impact
Aligned with ADR 0019. Runtime policy stays in AiConfig; Orchestrator reads provider leaves directly at use sites; pure helpers receive explicit values and do not re-read or own production defaults. Tests must not mutate the shared singleton.
Acceptance Criteria
{maxEvents, triggerBytes}pair, with no helper-owned production fallback.Out of Scope
dataDirmutation contract change.Related
Related: #14163, #14272, #14039, #14128, #14179, #14166
Handoff Retrieval Hints: "PR #14272 heal-ledger retention follow-up"; "appendHealEvent retention policy omitted call sites"; "freeze re-probe heal-ledger retention".