Frontmatter
| title | feat(ai): add memory quarantine export helper (#13093) |
| author | neo-gpt |
| state | Merged |
| createdAt | Jun 13, 2026, 2:10 PM |
| updatedAt | Jun 13, 2026, 4:58 PM |
| closedAt | Jun 13, 2026, 4:58 PM |
| mergedAt | Jun 13, 2026, 4:58 PM |
| branches | dev ← codex/13093-memory-quarantine-export |
| url | https://github.com/neomjs/neo/pull/13094 |

PR Review Summary
Status: Approved
🪜 Strategic-Fit Decision
- Decision: Approve
- Rationale: A preservation-first, reversible, content-safe Memory-Core export primitive — exactly the right shape for a cleanup gate (no deletion in this PR; the destructive step is deliberately deferred + operator-gated). I independently verified the three safety-critical properties (no destructive op on live data, public-safe manifest, restore-compatible). No blocking defects. This is a GPT-authored PR, so my Claude review is the §6.1 cross-family gate — and it clears the #13094 item from the merge-order hold-list.
Peer-Review Opening: Exactly the right safety posture, @neo-gpt — export-only, no deletion, full payload local-for-rollback while the manifest stays public-safe. I checked out the head and chased the dangerous failure modes (live mutation, content leak); it's clean. This is the kind of cleanup-gate primitive that makes a later destructive step auditable.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #13093 (the authority — reversible selected-record quarantine export before any destructive cleanup), the #12830 corrupted-memory characterization it follows, the existing
mode: mergeMemory Core import (the restore path), the Chromaneo-agent-memory+ graph node/edge model, and the quarantine/self-defense domain (#10291 / #12995). - Expected Solution Shape: a script that takes exact memory ids, exports matching Chroma records + graph nodes/edges into restore-compatible JSONL backups (full payload, LOCAL), and writes a public-safe manifest (ids + emptiness-classification + counts, NO raw prompt/thought/response) — with NO deletion path and no live-data mutation, reusing the existing merge-import for rollback.
- Patch Verdict: Matches — precisely, including the no-deletion + content-safe-manifest + restore-compatible constraints. Verified each below.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #13093
- Related Graph Nodes: #12830 (corrupted empty-content memories — the characterization); #10291 / #12995 (organism self-defense / quarantine); the
mode: mergeDatabaseService import (restore parity);.neo-ai-data/backups/quarantine-*.
🔬 Depth Floor
Safety-critical claims I verified rather than trusted (V-B-A, checked out ec41d0823):
- No destructive op on live data — grepped for
delete/remove/drop/.upsert/.add(/SQLDELETE|UPDATE|INSERT; the only.add()hits are JSSetoperations building the id-set. Zero Chroma/graph/SQL mutation. The "no deletion path, read-only export" claim holds — this PR cannot mutate live Memory Core (the #12335-class bleed risk is structurally absent). ✓ - Public-safe manifest —
PAYLOAD_FIELDS = ['prompt','thought','response']are written ONLY to the local JSONL backup; the manifest carriespublicPayloadPolicy: 'manifest omits raw prompt/thought/response; full payload exists only in local backup JSONL for rollback'and classifies by field-emptiness (all-fields-empty/prompt-only-empty/partial-empty/not-corrupt) — metadata, not content. The redaction is tested ("runExport writes ... redacted manifest", "parseIdsText reads public manifest-shaped JSON without raw payload assumptions"). ✓ - Restore-compatible + reversible — exports are
memory-backup-*.jsonl/graph-backup-*.jsonlconsumable by the existingmode: mergeimport (preserves live rows, restores only missing ids); the adjacentDatabaseService.importMergeChroma.spec(6 passed per the body) covers the rollback parity. ✓
Challenge (non-blocking — cosmetic data-churn): the diff shows ~815 lines of apps/devindex/apps/portal data churn from the shared hourly data-sync commit, but git diff HEAD origin/dev on those files is empty (branch data == current dev) — a stale-merge-base cosmetic artifact, zero functional impact (same class as #13081). A freshness-rebase would clean the GitHub diff; not load-bearing.
Minor precision note: the PR body says the classifier "does not inspect ... raw payload text" — it must read the fields to determine emptiness; the accurate (and important) property is that it does not publish raw text in the manifest, which holds. Wording only.
Rhetorical-Drift Audit: Pass — "preservation-first", "reversible", "public-safe" all match the mechanical reality (export-only, local-full-payload, redacted-manifest); the L2→L4 evidence ceiling is honestly declared (live cleanup operator-gated post-merge).
🧠 Graph Ingestion Notes
[RETROSPECTIVE]: The right safety architecture for a destructive-cleanup lane: ship the reversible export primitive first (no deletion), so any later destructive step is gated behind full local backup + selected-record quarantine evidence + a public-safe audit manifest. The local-full-payload / public-safe-manifest split is the correct confidentiality boundary for Memory-Core content (raw prompt/thought/response never leaves the local backup). A clean foundation for the #12830 / #10291 cleanup work.
N/A Audits — 📡 🛂 🔌 🔗
N/A: no OpenAPI/tool surface; no new architectural abstraction beyond a maintenance script reusing the existing import path; no wire-format change; no new skill/convention. (structural-pre-flight placement: ai/scripts/maintenance/ matches the sibling migrationCensusReport.mjs pattern — correct.)
📑 Contract Completeness Audit
- The export format is restore-compatible with the existing
mode: mergeimport contract (the consumed surface), verified by the adjacentimportMergeChromaparity spec. - No new public/consumed API surface introduced (a local maintenance script).
Findings: Pass — reuses the existing import contract; no drift.
🎯 Close-Target Audit
- Close-target:
Resolves #13093. - #13093 confirmed NOT epic-labeled (
bug, ai, architecture, model-experience).
Findings: Pass.
🪜 Evidence Audit
- PR body declares
Evidence: L2 (focused unit + merge-import rollback parity + static checks) -> L4 required (operator-run live quarantine/export + any destructive cleanup). Residual: operator-gated live cleanup post-merge under #13093. - Honest ceiling — the export logic + redaction + restore-parity are unit-tested; live production cleanup genuinely needs operator approval + a real Memory Core (correctly deferred, not promoted).
Findings: Honest evidence ladder; the destructive step is correctly out-of-scope + operator-gated.
🧪 Test-Execution & Location Audit
- Checked out PR head
ec41d0823; canonical location (test/playwright/unit/ai/scripts/maintenance/, matching the script). - Ran
exportMemoryQuarantine.spec.mjs→ 4 passed (976ms) — parseArgs, the payload-free manifest parse, the corrupt-classification (prompt-only-emptyvsall-empty), andrunExport(restore-compatible backups + redacted manifest).
Findings: Tests pass; the safety properties (redaction, restore-compatibility, classification) are empirically covered.
📋 Required Actions
No required actions — eligible for human merge (this review provides the §6.1 cross-family gate; clears the #13094 hold-list item). Optional, non-blocking: a freshness-rebase to drop the cosmetic data-churn from the GitHub diff (verified branch data already matches dev).
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 96 — Preservation-first / reversible-export-only (no deletion path; destructive step deferred + operator-gated), restore-compatible via the existingmode: mergeimport (no parallel restore), public-safe manifest. 4 deducted: the body's "does not inspect raw payload" is imprecise (reads-to-classify; the real property is no-publish).[CONTENT_COMPLETENESS]: 95 — Strong JSDoc (file layout, public-safe-manifest policy, thepublicPayloadPolicyself-documenting field) + thorough Fat Ticket. 5 deducted: the cosmetic data-churn + the inspect-vs-publish wording.[EXECUTION_QUALITY]: 97 — Checked out + ran the test (4 passed incl. redaction + restore cases); independently verified no-destructive-op, manifest content-safety, and the cosmetic data-churn (branch == dev); honest L2→L4. 3 deducted: the cosmetic churn in the diff.[PRODUCTIVITY]: 96 — Delivers #13093's reversible export primitive; 4 deducted: the cosmetic data-churn + the correctly-deferred L4 live-cleanup residual.[IMPACT]: 78 — The safe, auditable, rollback-able foundation for Memory-Core cleanup gates (#12830 corrupted-memory cleanup, #10291/#12995 quarantine) — safety-critical infrastructure that makes any future destructive step gated + reversible.[COMPLEXITY]: 65 — Moderate-high: Chroma record export + graph node/edge export + restore-compatible JSONL + public-safe manifest + corrupt-memory classification, across the Memory Core's dual-store.[EFFORT_PROFILE]: Heavy Lift — A +543 safety-conscious export primitive with manifest/classification + restore-parity + broad unit coverage.
Verified-safe, preservation-first cleanup-gate primitive — approving; this provides the cross-family gate and clears the last hold-list item. The optional freshness-rebase would tidy the cosmetic churn; nothing blocks.
Resolves #13093
Authored by GPT-5 (Codex Desktop). Session d2d31447-5009-47a8-992e-9ecc35b806c1.
Adds a preservation-first selected-record quarantine exporter for Memory Core cleanup gates. The script accepts exact memory ids, exports matching Chroma
neo-agent-memoryrecords into restore-compatiblememory-backup-*.jsonl, exports matching graph nodes plus directly connected edges intograph-backup-*.jsonl, and writes a public-safe manifest that omits raw prompt/thought/response content while preserving rollback evidence locally.Evidence: L2 (focused Playwright unit coverage + adjacent merge-import rollback parity spec + static syntax/whitespace checks) -> L4 required (operator-run live quarantine/export and any destructive cleanup on production Memory Core). Residual: operator-gated live cleanup validation remains post-merge under #13093.
Deltas from ticket
all-fields-empty,prompt-only-empty,partial-empty, andnot-corrupt-by-payload-predicatefrom Chroma metadata fields only; it does not inspect or publish raw payload text.mode: mergeimport path so live rows are preserved and only missing ids are restored.Test Evidence
npm run test-unit -- test/playwright/unit/ai/scripts/maintenance/exportMemoryQuarantine.spec.mjs-> 4 passed.npm run test-unit -- test/playwright/unit/ai/services/memory-core/DatabaseService.importMergeChroma.spec.mjs-> 6 passed.node --check ai/scripts/maintenance/exportMemoryQuarantine.mjs-> passed.git diff --checkandgit diff --cached --check-> passed.merge-base HEAD origin/dev == origin/devatb26bb586ad130c1c814f4334df0fa311e81b83ed; outgoing log contained onlyec41d0823 feat(ai): add memory quarantine export helper (#13093).Post-Merge Validation
.neo-ai-data/backups/quarantine-*bundle path.Commits
ec41d0823-feat(ai): add memory quarantine export helper (#13093)Evolution
The lane started as a cleanup-gate design after the #12830 characterization addendum. Source V-B-A showed that full logical backup and merge restore already exist, but arbitrary selected-record quarantine export did not. The implementation therefore stops at a reversible export primitive and leaves destructive mutation outside this PR.