Skip to content

fix(consolidation): dedup against live memories within a run (#747)#9

Merged
MarvinFS merged 1 commit into
mainfrom
fix/747-consolidate-stale-dedup
May 31, 2026
Merged

fix(consolidation): dedup against live memories within a run (#747)#9
MarvinFS merged 1 commit into
mainfrom
fix/747-consolidate-stale-dedup

Conversation

@MarvinFS
Copy link
Copy Markdown
Owner

What

Ports the upstream #747 fix (rohitg00/agentmemory PR #749) to this LanceDB-backed fork. The consolidate.ts file here is byte-identical to upstream, so the same defect and the same patch apply.

The mem::consolidate handler snapshots existing memories into existingMemories once before the concept-group loop and never refreshes it; the parallel existingTitles Set is written but never read (dead code). The dedup .find() only sees the stale snapshot, so a second concept group that synthesizes the same title in the same run misses the just-created memory, takes the create branch, and writes a duplicate isLatest memory with no parentId - a duplicate plus an orphaned predecessor and a broken version chain.

The fix

  • Remove the dead existingTitles Set.
  • Push each newly created memory into existingMemories.
  • On evolve, replace the matched predecessor in place (the title match does not filter on isLatest, so a plain append would let a third same-title group re-match the superseded row and recreate a second latest). This keeps exactly one matchable row per title and a linear A -> B -> C chain.

Cross-project guard untouched.

Verify

npm install --legacy-peer-deps
npm run build
npm test -- test/consolidate-project-scope.test.ts

Two regression tests added (two-group and three-group same-title collisions), red on the pristine file and green with the fix. Full local suite: 1281 passed (+2 vs baseline), with the same 9 pre-existing Windows-environmental failures unchanged - consolidation is not among them.

Refs #747, upstream PR rohitg00/agentmemory#749.

The mem::consolidate handler snapshots existing memories into
`existingMemories` once before the concept-group loop and never refreshes
it. A parallel `existingTitles` Set was populated on every create/evolve
but never read - dead code. The dedup check therefore scanned only the
stale snapshot, so when two concept groups in the same run synthesized
the same title, the second group failed to find the memory the first had
just created. It fell into the create branch and produced a second
isLatest memory with no parent: a duplicate plus an orphaned predecessor,
and a broken version chain.

Keep the snapshot live instead of carrying an unused index:

- Remove the dead `existingTitles` Set.
- Push each newly created memory into `existingMemories`.
- On evolve, replace the matched predecessor in place. The title match
  does not filter on isLatest, so appending would leave the superseded
  row matchable and let a third same-title group evolve it, recreating a
  second latest; in-place replacement keeps exactly one matchable row per
  title and a linear A -> B -> C chain.

The cross-project guard in the match predicate is untouched, so scoped
runs still refuse to evolve another project's identically titled memory.

Adds regression tests to test/consolidate-project-scope.test.ts: a
two-group collision (asserts one active memory, intact parent chain, no
orphan) and a three-group collision (asserts one active memory, linear
three-version chain). Both fail on current main and pass with this fix.

Signed-off-by: MarvinFS <MarvinFS@users.noreply.github.com>
@MarvinFS MarvinFS merged commit e851f00 into main May 31, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant