Issue: runMemoryReflection handler uses individual store.store() causing N lock acquisitions
Severity: Medium
Affected: index.ts — runMemoryReflection function
Problem
In the runMemoryReflection handler, mapped reflection memories are written using individual store.store() calls inside a loop:
for (const mapped of mappedReflectionMemories) {
const vector = await embedder.embedPassage(mapped.text);
// ... dedup check (vectorSearch) ...
const storedEntry = await store.store({ // ← N lock acquisitions
text: mapped.text, vector, importance,
category: mapped.category, scope: targetScope, metadata
});
}
Additionally, storeReflectionToLanceDB passes a callback store: (entry) => store.store(entry) which also uses individual writes.
Each store.store() call acquires a file lock. When multiple mapped memories are processed, this creates N lock acquisitions instead of 1.
Impact
- Low frequency trigger: Only on
/new or /reset command hooks — not a high-volume path
- N lock acquisitions: If 3-5 reflection memories are extracted per session, each gets its own lock
- Risk: Under simultaneous reflection generation (multiple agents), lock contention possible but less severe than auto-capture
Suggested Fix
Collect all mapped entries into an array, then call store.bulkStore() once:
const capturedEntries = [];
for (const mapped of mappedReflectionMemories) {
// ... dedup check ...
capturedEntries.push({
text: mapped.text, vector, importance,
category: mapped.category, scope: targetScope, metadata
});
}
if (capturedEntries.length > 0) {
await store.bulkStore(capturedEntries);
}
Similarly update the storeReflectionToLanceDB callback to collect and batch.
Related
Note
Unlike the auto-capture path (#675/#676), this is not a critical hot path since reflection generation only runs on session boundaries (/new, /reset). Recommend fixing separately after PR #678 is merged.
Issue:
runMemoryReflectionhandler uses individualstore.store()causing N lock acquisitionsSeverity: Medium
Affected:
index.ts—runMemoryReflectionfunctionProblem
In the
runMemoryReflectionhandler, mapped reflection memories are written using individualstore.store()calls inside a loop:Additionally,
storeReflectionToLanceDBpasses a callbackstore: (entry) => store.store(entry)which also uses individual writes.Each
store.store()call acquires a file lock. When multiple mapped memories are processed, this creates N lock acquisitions instead of 1.Impact
/newor/resetcommand hooks — not a high-volume pathSuggested Fix
Collect all mapped entries into an array, then call
store.bulkStore()once:Similarly update the
storeReflectionToLanceDBcallback to collect and batch.Related
handleSupersedebatch writes (fixed in PR fix: Issue #675 #676 - regex fallback and handleSupersede batch writes #678)Note
Unlike the auto-capture path (#675/#676), this is not a critical hot path since reflection generation only runs on session boundaries (
/new,/reset). Recommend fixing separately after PR #678 is merged.