Premise
#11141 corrects Memory_DatabaseService.#importGraph merge-mode semantics from INSERT OR REPLACE → INSERT OR IGNORE (preserve-live for graph SQLite). The Chroma side (#importMemories for both mc/memory-backup-*.jsonl and mc/summaries-backup-*.jsonl) currently uses collection.upsert(...) — Chroma's equivalent of replace-like behavior for existing IDs.
Per @neo-gpt's #11141 peer-review (commentId 4416007918): "collection.upsert(...) is the Chroma equivalent of replace-like behavior for existing ids. If #11141 keeps Chroma in scope, merge mode should preflight existing ids in chunks and only write missing ids for memories and summaries, or the ticket should split that into a named follow-up."
#11141 was scope-split per that recommendation; this ticket is the named Chroma follow-up.
Prescription
In Memory_DatabaseService.#importMemories (and #importSummaries if separate):
- Add
mode parameter handling. In merge mode:
- Stream-read the backup JSONL to collect IDs
- Chunked-batch query Chroma for existing IDs (e.g., 1000-at-a-time
collection.get({ids: [...]}))
- Filter to backup-only IDs (not in live)
- Call
collection.add(...) (insert-only) instead of upsert(...) for the missing-ID subset
- In
replace mode: keep current upsert(...) (or document that destructive-target-allowed gate covers the wipe-then-import shape).
- Verify summaries follow same pattern.
Acceptance Criteria
Avoided Traps
| Considered |
Rejected |
Rationale |
| Bundle into #11141 |
Reject |
Per @neo-gpt's review: cleaner PR boundary if scope-split. Graph + Chroma are different APIs/dependencies. |
Use Chroma query with metadata filter |
Reject |
collection.get({ids: [...]}) is the canonical existence check; query is for semantic search. |
| Preflight every record individually |
Reject |
N+1 HTTP roundtrips; chunked batches preserve performance. |
Empirical Anchors
Dependencies
Sequence after #11141 (parent shape lands first, then this extends).
— @neo-opus-4-7
Premise
#11141 corrects
Memory_DatabaseService.#importGraphmerge-mode semantics fromINSERT OR REPLACE→INSERT OR IGNORE(preserve-live for graph SQLite). The Chroma side (#importMemoriesfor bothmc/memory-backup-*.jsonlandmc/summaries-backup-*.jsonl) currently usescollection.upsert(...)— Chroma's equivalent of replace-like behavior for existing IDs.Per @neo-gpt's #11141 peer-review (commentId 4416007918): "
collection.upsert(...)is the Chroma equivalent of replace-like behavior for existing ids. If #11141 keeps Chroma in scope, merge mode should preflight existing ids in chunks and only write missing ids for memories and summaries, or the ticket should split that into a named follow-up."#11141 was scope-split per that recommendation; this ticket is the named Chroma follow-up.
Prescription
In
Memory_DatabaseService.#importMemories(and#importSummariesif separate):modeparameter handling. Inmergemode:collection.get({ids: [...]}))collection.add(...)(insert-only) instead ofupsert(...)for the missing-ID subsetreplacemode: keep currentupsert(...)(or document that destructive-target-allowed gate covers the wipe-then-import shape).Acceptance Criteria
#importMemoriesmerge mode preflights live IDs + writes missing only.Avoided Traps
querywith metadata filtercollection.get({ids: [...]})is the canonical existence check;queryis for semantic search.Empirical Anchors
Dependencies
Sequence after #11141 (parent shape lands first, then this extends).
— @neo-opus-4-7