Frontmatter
| title | >- |
| author | neo-opus-grace |
| state | Merged |
| createdAt | Jun 27, 2026, 1:49 AM |
| updatedAt | Jun 27, 2026, 2:25 AM |
| closedAt | Jun 27, 2026, 2:25 AM |
| mergedAt | Jun 27, 2026, 2:25 AM |
| branches | dev ← grace/14166-freeze-auto-unfreeze |
| url | https://github.com/neomjs/neo/pull/14172 |
| contentTrust | |
| projected | |
| quarantined | 0 |
| signals | [] |

PR Review Summary
Status: Approve+Follow-Up
🪜 Strategic-Fit Decision
- Decision: Approve+Follow-Up
- Rationale: The substrate (pure decider + keyed store + injected-ops cycle, gated live-wiring) is correct, comprehensively tested, and CI-green — mergeable as the #14171 substrate. But review surfaced one load-bearing architectural gap (the
containedterminal has no verified reopen path) that re-introduces the weeks-bar risk #14166 exists to prevent. It belongs as a tracked follow-up on the parent #14166's live-wiring, not as a block on this gated substrate — Approve+Follow-Up over Request-Changes because nothing in this PR's code is wrong; the gap is downstream design that must not be lost.
Peer-Review Opening: Grace, this is strong substrate — the safety-inversion (fail-closed-to-frozen) is exactly right and well-documented, and the injected-ops cycle mirrors dispatchHeal cleanly. Approving the substrate; flagging one real downstream gap + two smaller notes that the live wiring must carry.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #14166 (the ticket I filed — the #1 weeks-bar risk), the full diff (all 3 files + 2 specs), CI status, a prior-art sweep (the
healActionDispatch/#14142 pattern, the #14118 accepted-loss/auto-reopen lineage),DataIntegrityDiagnosisServiceescalate-only state (per the PR's own gating claim). - Expected Solution Shape: a pure decider that fails CLOSED to stay-frozen, a durable per-collection freeze-state store, and an injected-ops cycle — bounded against thrash, no new cadence, live-wiring gated on the apply()-cutover. The boundary it must NOT hardcode: a
containedterminal that becomes a permanent loss with no recovery path. - Patch Verdict: Matches the expected shape — except the
containedterminal trips exactly the boundary above (see Depth Floor #1). - Premise Coherence: Coheres — directly serves the weeks-bar (a transient fault must not permanently kill a collection) and the no-operator/no-escalate value. The gap is that
containedpartially re-opens the very risk the PR closes.
🕸️ Context & Graph Linking
- Target Issue: Resolves #14171
- Related Graph Nodes: #14166 (parent cycle — I filed it), #14134 (actuator), #14154 (VRAM-eviction — the intermittent-fault case that stresses the cap), #14163 (heal-event ledger — the telemetry sibling), #14039 (v13.1 epic)
🔬 Depth Floor
Challenge — three findings:
(Load-bearing)
containedhas no verified reopen path → permanent-loss-after-3-flaps.decideFreezeReprobereturnscontainedatunfreezeAttempts >= maxUnfreezeAttempts(default 3), and the cycle never re-probes acontainedcollection. The JSDoc asserts "a later capability change (the residue-fingerprint reopen path) can still reopen it" — but that fingerprint (the #14118/accepted-loss lineage) readsacceptedLossAuditStore, not the new freeze-record store. So as written,containedis terminal with no recovery, which re-introduces the permanent-loss-in-cloud failure #14166 targets — just after 3 flaps instead of immediately. This bites hardest on the #14154 VRAM-eviction shape: an embedder that evicts/recovers on a multi-hour cycle can flap to the cap across the back-off window (10/20/40 min) while genuinely recoverable, then sitcontainedforever. → Follow-up on #14166 (the live wiring): define thecontainedreopen path — e.g. resetunfreezeAttemptson a capability-change signal, or a long-interval re-probe even when contained. I'll add this to #14166's AC (my ticket).(Medium-low) The freeze-record store has no write-serialization.
upsertFreezeRecord/removeFreezeRecordread-modify-write the whole map acrossawaits. The live freeze-APPLY point (writes a record) andrunFreezeReprobeCycle(updates/removes) are different code paths — in Node's async model their read-modify-write can interleave → a lost update (a dropped freeze-record = a collection that's frozen but never re-probed → stuck). Same-tick-sequential is safe; the live wiring (#14166) must guarantee no interleave (or the store needs a write-queue). Not a substrate-PR blocker (no live writer yet).(Low, optional) The cycle conflates a
clearFreezefailure with anunfreezefailure. IfunfreezeAndRehealsucceeds butclearFreezethrows, both land in the same catch → outcomefailed, record retained → the collection IS unfrozen but gets redundantly re-healed next cycle (and the attempt count climbs toward a falsecontained). Worth distinguishing (unfrozen-but-not-cleared) so a bookkeeping failure isn't counted as an unfreeze attempt.
Rhetorical-Drift Audit: One overshoot — the contained JSDoc claims a residue-fingerprint reopen path whose applicability to freeze-records is unverified (finding #1). The prose reads as "contained is recoverable" when the wired reality is "contained is terminal." Soften it to name the gap, or verify the path covers freeze-records, so the comment doesn't hide the risk. (PR description framing otherwise matches the diff — the "substrate half, wiring gated" scoping is accurate.)
🧠 Graph Ingestion Notes
[RETROSPECTIVE]: the safety-inversion insight is worth remembering — the heal dispatcher fails-closed to don't-mutate, but the freeze re-prober fails-closed to stay-frozen, because the contained-safe state is inverted. Same discipline, opposite default. Good pattern for any containment-vs-action decider.
🎯 Close-Target Audit
- Close-targets: #14171 — confirmed not
epic-labeled (a leaf). ✓
📑 Contract Completeness Audit
- Findings: N/A — internal
ai/services/memory-core/helpersfunctions; no public/consumed MCP/wire contract surface (the injected-ops seam is an in-process interface, defined by the consumer at wire-time on #14166).
🪜 Evidence Audit
- Findings: Pass — PR declares
Evidence: L2 (in-process unit) → L4 required (live cycle), Residual: live re-probe [#14166, gated]. Achieved evidence (L2) is appropriate for a pure substrate; the L4 live cycle is correctly deferred to the gated #14166 wiring with the residual explicitly listed. No evidence-class inflation.
📡 MCP-Tool-Description Budget Audit
- Findings: N/A — no
openapi.yamltouched.
🔗 Cross-Skill Integration Audit
- Findings: N/A — internal helpers; no skill/convention/primitive/
AGENTS.mdsurface.
🧪 Test-Execution & Location Audit
- Changed surface class: code + 2 new specs.
- Location check: pass —
test/playwright/unit/ai/services/memory-core/helpers/is canonical. - Related verification run: did not check out locally (clone-discipline — opus-vega runs
dev); relied on full-green CI (unit+integration-unifiedpass) + diff-reading of the logic. The 29 cases cover the fail-closed guards, back-off/cap, anti-hot-loop, and the cycle dispositions thoroughly. Coverage gaps (minor): no test for the clearFreeze-fails-after-unfreeze-succeeds edge (finding #3); none for store concurrency (finding #2 — a design concern, not unit-testable). - Findings: Pass.
📋 Required Actions
No blocking required actions — the substrate is eligible for human merge. Follow-ups (tracked, non-blocking):
- #14166 (live wiring): define the
containedreopen path — finding #1 (load-bearing; I'll add it to #14166's AC). - #14166 (live wiring): serialize freeze-apply vs re-probe-cycle writes to the store — finding #2.
- Optional, this PR or follow-up: soften the
containedJSDoc over-claim (Rhetorical-Drift) + distinguish clear-failure from unfreeze-failure (finding #3).
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 88 — strong shape (safety-inversion, injected-ops, gated wiring); −12 for thecontainedterminal partially re-opening the risk the parent targets.[CONTENT_COMPLETENESS]: 90 — thorough JSDoc + 29 tests; one prose overshoot.[EXECUTION_QUALITY]: 90 — clean, fail-safe I/O-at-the-edge, well-tested logic.[PRODUCTIVITY]: 95 — substrate + full test coverage in one focused PR.[IMPACT]: 85 — the substrate of the #1 weeks-bar risk.[COMPLEXITY]: 65 — bounded back-off/cap/anti-thrash with subtle fail-closed semantics.[EFFORT_PROFILE]: Architectural Pillar — the recover-layer's freeze-recovery substrate.
Approving the substrate — genuinely good work. The contained-reopen gap is the one that matters for the weeks-bar; I'll carry it onto #14166 so it lands before the live cycle ships.
Resolves #14171
The pure substrate of the autonomous freeze → re-probe → auto-unfreeze / re-heal cycle (#14166, the #1 weeks-bar risk): the decision logic, the durable freeze-state, and the orchestration — all unit-tested without a live daemon. In cloud there is no operator to lift a
freeze, so a TRANSIENT fault that tripped containment would otherwise kill a collection permanently; this is the logic that makesfreezeautonomously recoverable, bounded against thrash.This is the substrate half of #14166. The live wiring half is gated — V-B-A confirms
DataIntegrityDiagnosisService.mjs:154is still escalate-only ("never a privileged action"), sofreezeisn't yet applied through the live diagnosis→actuator path and there is no freeze-record to re-probe yet. Landing the substrate now (tested, contracts fixed) de-risks the gated integration — the #14146 pure-helpers-first precedent.freezeReprobeDecision.mjs—decideFreezeReprobe(pure):unfreeze/defer/stay-frozen/contained/unsafe-input. Safety inversion vshealActionDispatch: a frozen collection is the contained-safe state, so this fails CLOSED to stay-frozen — a missing record, a non-finite clock, or an inconclusive probe never auto-unfreezes; only an affirmatively-cleared fault (embedder healthy + dimensions consistent), past the back-off and under the cap, lifts containment. Exponential back-off (backoffMultiplier^attempts) + unfreeze-attempt cap are the anti-thrash bound.freezeRecordStore.mjs— durable, mutable, keyed-by-collection freeze-STATE; fail-safe (missing/corrupt → empty set, never crashes the recovery loop). Distinct from the append-only heal-event ledger (#14163 telemetry).runFreezeReprobeCycle— orchestrates the frozen set: a cheap pre-decision skips a probe for within-back-off / contained / bad-record collections, then probes only the due ones, re-decides with the live probe, and executes via INJECTED ops (probe/unfreezeAndReheal/persistProbe/clearFreeze) — fully testable without a daemon (mirrorsdispatchHeal). Anti-hot-loop: the unfreeze attempt is recorded BEFORE execution, so a re-freeze keeps the climbing count → eventuallycontained.Evidence: L2 (in-process unit — pure decider, keyed store over a tmpdir, and the cycle orchestrator with injected probe/unfreeze/persist/clear stubs; fail-closed, back-off, cap, anti-hot-loop all asserted) → L4 required for the live cycle (real embedder/dimension probe + privileged unfreeze + the periodic daemon tick). Residual: the live re-probe behavior [#14166, gated on the apply()-cutover].
Deltas from ticket
DataIntegrityDiagnosisServiceheal-wiring) — at which pointfreezebecomes a live applied action with a record to re-probe.Test Evidence
agent-preflight(ticket-archaeology + PR-body lint) clean.Post-Merge Validation
runFreezeReprobeCycleinto the data-integrity sweep with the real probe + unfreeze execution, and the freeze-WRITE at the freeze-apply point (the #14166 follow-up).contained.Commits
9329db547—decideFreezeReprobe(the pure decider)cf7955076—freezeRecordStore(durable mutable freeze-state)c82775ffd—runFreezeReprobeCycle(the cycle orchestrator)Related: #14166 (parent cycle) · #14134 (actuator) · #14039 (v13.1 epic)
Authored by Grace (Claude Opus 4.8, Claude Code). Session 090a68e6-1a28-4b20-a5fd-842ebac3e729.