fix(mcp): collapse duplicate results in memwal_recall - #682
Closed
harrymove-ctrl wants to merge 1 commit into
Closed
fix(mcp): collapse duplicate results in memwal_recall#682harrymove-ctrl wants to merge 1 commit into
harrymove-ctrl wants to merge 1 commit into
Conversation
A limit=5 recall on a real account returned the same fact five times, so one preference consumed the entire retrieval budget and crowded out every other memory the query should have surfaced. Storing a fact repeatedly is legitimate: each remember is a distinct event with its own blob and timestamp, and there is no content-level uniqueness constraint by design (the sole unique index is request idempotency on remember_jobs (owner, idempotency_key), which guards retries, not content). Deduping on write would silently discard a genuine re-statement, so the fix belongs on the read side. Collapses results whose text matches after trimming, whitespace collapsing, and case folding, keeping the highest scoring copy since rows arrive ranked. Matching is exact-after-normalization rather than fuzzy: merging facts that merely resemble each other would hide real information. The reply reports how many copies were folded so nothing disappears silently.
Collaborator
Author
|
Folding this into #681 instead, at Harry's request: one PR is less review and merge overhead, and both changes are MCP fixes landing together. The commit is carried over intact as Combined suite on that branch: 205 pass, 0 fail. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A
limit=5recall on a real dev account returned this:One preference consumed the entire retrieval budget. Every other memory the query should have surfaced was crowded out, and the model burned context on five copies of one sentence.
Why the fix is on the read side, not the write side
Storing the same fact repeatedly is legitimate. Each
rememberis a distinct event with its own blob and timestamp, and there is deliberately no content-level uniqueness constraint: the only unique index on the write path iswhich is request idempotency, guarding a retried request from being processed twice. It says nothing about content, and a repo-wide search finds no content dedup anywhere in the MCP tools, the SDK, or the relayer.
So this is not a regression, it is a gap. Deduping on write would silently discard a genuine re-statement of a fact, which is worse than the duplicates. Collapsing on read is safe and fixes the actual symptom.
Approach
collapseDuplicatesfolds results whose text matches after trimming, whitespace collapsing, and case folding, keeping the first occurrence. Rows arrive ranked best-first, so the survivor is the highest scoring copy.Matching is exact-after-normalization, not fuzzy or embedding-based. Merging facts that merely resemble each other would hide real information; near-duplicate merging, if ever wanted, belongs behind an explicit opt-in.
The reply reports what was folded rather than quietly returning fewer rows than requested:
That also surfaces the underlying repetition, which is usually worth knowing.
Tests
mcp/__tests__/recall-dedupe.test.ts, 7 cases, including the two that matter most for safety:"prefers dark roast coffee"and"prefers dark roast coffee in the morning only"must both survive, since losing either is silent data lossPlus rank-order preservation, highest-scoring-survivor, whitespace/case normalization, and the empty set.
npm testin services/server/scripts: 202 pass, 0 fail.Not included
Back-filling the retrieval budget after collapsing (over-fetching so
limit=5still returns 5 distinct facts) would need either an over-sample on every call, which multiplies SEAL decryption cost for the common no-duplicate case, or an adaptive second round trip. Worth doing, but it is a separate performance tradeoff and does not belong in this fix.Found while verifying WALM-324. Unrelated to that fix and deliberately kept out of #681.