Skip to content

fix(recall): over-fetch vector candidates and exclude artifact types#205

Merged
jack-arturo merged 9 commits into
mainfrom
fix/recall-overfetch-and-artifact-exclusion
Jul 4, 2026
Merged

fix(recall): over-fetch vector candidates and exclude artifact types#205
jack-arturo merged 9 commits into
mainfrom
fix/recall-overfetch-and-artifact-exclusion

Conversation

@jack-arturo

Copy link
Copy Markdown
Member

Problem

A Claude Desktop session opened with a memory recall that was "basically useless" — it returned 22 memories about Lennard/Berlin but none were the context the user needed ("Lennard's situation we resolved"), so the assistant concluded it had no shared history.

Reproduced against the production corpus (not a local config glitch):

  • The relevant memory exists and is high value: ee830782 "Lennard BAföG Mahnung Apr 2026" (919 chars, importance 0.8, tags bafoeg/mahnung/freistellung/stundung/legal/german-bureaucracy).
  • Query "...Jobcenter social welfare resolved problem" → it surfaces at rank Using one server for multiple projects? #4.
  • Query "...Berlin flatmate Bürgergeld Wohngeld" → it is absent from all 22 results, even though it's inside the time window and the result count (22) was under the limit (25). It never entered the candidate pool.
  • The pool filled with noise: System test 9/23/25 #1 was a floor-plan memory matched on "Berlin flat" ≈ "Berlin flatmate"; ranks 10–22 were all match_type:keyword on the bare token "berlin"; and three importance-0.000 MetaPattern artifacts leaked in.

Root cause

  1. The recall miss. The vector candidate pool was fetched at 1× the requested limit, with raw vector similarity as the sole gate (vector_fetch_limit = per_query_limit). The richer final score (importance, exact-match, tags) only re-ranks memories that already survived that cut — so a high-importance, exact-topic memory that's a slightly weaker pure-vector match is discarded before its signal can lift it. A high-frequency token like "Berlin" saturates the pool and evicts the relevant memory.
  2. The misleading padding. MetaPattern consolidation artifacts (importance 0.0, "cluster over 0 days") had no recall exclusion and leaked in via bare-token keyword matches.

0.16.0 didn't create these mechanisms; its ranking release amplified them.

Fix

  • Over-fetch + re-rank (automem/api/recall.py): vector_fetch_limit = min(per_query_limit * RECALL_VECTOR_OVERFETCH, RECALL_VECTOR_FETCH_CAP). The existing re-rank (compute_metadata_score → sort) then surfaces the right memory — no scoring-weight changes. Results are still trimmed to the requested limit (_guarantee_priority_results), so response size is unchanged. RECALL_VECTOR_OVERFETCH=1 restores legacy behavior.
  • Artifact exclusion (automem/search/runtime_recall_helpers.py): exclude RECALL_EXCLUDED_TYPES (default {"MetaPattern"}) at the universal _result_passes_filters chokepoint (covers vector, keyword, metadata, expansion, and state-filter paths) plus the graph/metadata keyword Cypher so artifacts don't consume candidate slots.

New config (automem/config.py): RECALL_VECTOR_OVERFETCH=4, RECALL_VECTOR_FETCH_CAP=200, RECALL_EXCLUDED_TYPES=MetaPattern — all env-overridable.

Tests (RED → GREEN)

  • tests/test_recall_overfetch.py — drives /recall with a fake Qdrant: asserts the widened fetch limit (20 vs 5), that the target ranked past 1× is recalled and re-ranked into the top results, that the response stays ≤ limit, and an off-switch (OVERFETCH=1) that reproduces the miss.
  • tests/test_recall_artifact_exclusion.py_result_passes_filters excludes MetaPattern/keeps normal types; _graph_keyword_search emits the Cypher exclusion predicate + param.
  • Full unit suite green: 662 passed, 12 skipped. black + flake8 clean.

Pre-merge validation (infra/deploy-gated — not run in this PR)

Candidate-pool sizing changes ranking, so gate the merge on the existing harnesses (benchmark ownership stays in automem):

  • Recall Quality Lab: make lab-clonemake lab-queriesmake lab-test CONFIG=baselinemake lab-compare CONFIG=fix_v1 BASELINE=baseline.
  • Sweep the multiplier to confirm the default: make lab-sweep PARAM=RECALL_VECTOR_OVERFETCH VALUES=1,2,4,8 (latency vs recall@k — Qdrant fetch cost scales with the multiplier).
  • LoCoMo non-regressing: make test-locomo / make test-locomo-live.
  • Live smoke (post-deploy): re-run the transcript query and confirm ee830782 appears and MetaPattern rows are gone.

Out of scope (follow-ups)

  • Entity unification: "Lennard"/"Leonard" are split across spellings and mis-typed (entity:organizations:lennard). Needs an enrichment-validator fix + backfill migration.
  • Low-confidence signal: recall returns weak results with no "nothing strongly matched" cue (what misled the consumer). Consider enabling/raising RECALL_RELEVANCE_GATE or surfacing the top evidence score.

🤖 Generated with Claude Code

Recall could drop the single most relevant memory while padding results
with internal artifacts. Two compounding causes, both reproduced against
the production corpus (query "Lennard social benefits situation Berlin
flatmate ..." returned 22 results that omitted the one relevant memory
and leaked importance-0.0 MetaPattern rows):

1. The vector candidate pool was fetched at 1x the requested limit, with
   raw vector similarity as the sole gate. The richer final score
   (importance, exact-match, tags) only re-ranks survivors of that cut, so
   a high-importance, exact-topic memory that is a slightly weaker pure-
   vector match was discarded before its signal could lift it; a high-
   frequency query token ("Berlin") saturates the pool and evicts it.
   Fix: over-fetch the vector pool (RECALL_VECTOR_OVERFETCH, default 4,
   capped by RECALL_VECTOR_FETCH_CAP=200) so the existing re-rank sees a
   wide enough candidate set. Response is still trimmed to the limit.

2. MetaPattern consolidation artifacts had no recall exclusion and leaked
   in via bare-token keyword matches. Fix: exclude RECALL_EXCLUDED_TYPES
   (default {"MetaPattern"}) at the universal _result_passes_filters
   chokepoint plus the graph/metadata keyword Cypher.

Adds RED->GREEN coverage in tests/test_recall_overfetch.py and
tests/test_recall_artifact_exclusion.py. Full unit suite green (662 passed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ddc9ecce32

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread automem/search/runtime_recall_helpers.py
## Summary

- Preserve the caller's requested vector fetch limit even when
`RECALL_VECTOR_FETCH_CAP` is configured below `limit`.
- Add a regression test for the cap-under-limit edge case.
- Keeps the cap as an over-fetch ceiling without allowing it to make
recall narrower than legacy behavior.

## Context

Follow-up to PR #205. The original over-fetch implementation used
`min(per_query_limit * RECALL_VECTOR_OVERFETCH,
RECALL_VECTOR_FETCH_CAP)`, which can ask Qdrant for fewer candidates
than the requested response limit when the cap is set low.

## Tests

- `venv/bin/pytest tests/test_recall_overfetch.py
tests/test_recall_artifact_exclusion.py`
- `make test`
- A/B already run locally while evaluating PR #205:
  - `locomo-mini`: main `82.98% (195/235)` -> PR `84.26% (198/235)`
  - `locomo`: main `81.58% (1258/1542)` -> PR `81.84% (1262/1542)`

## Risk Notes

- This is a narrow guardrail around the new config; it should only
affect deployments that lower `RECALL_VECTOR_FETCH_CAP` below requested
`limit`.
- No merge performed.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8abbb2f96d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread automem/search/runtime_recall_helpers.py
Comment thread automem/search/runtime_recall_helpers.py
Comment thread automem/api/recall.py
@jack-arturo

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 860e0e7bd9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread automem/api/recall.py
Comment thread automem/config.py
@jack-arturo

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 31121fa10f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread automem/api/recall.py Outdated
Comment thread automem/search/runtime_recall_helpers.py
Comment thread automem/api/recall.py Outdated
Comment thread automem/api/recall.py
@jack-arturo

Copy link
Copy Markdown
Member Author

@codex review

1 similar comment
@jack-arturo

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d18d5d7f30

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread automem/api/recall.py Outdated
@jack-arturo

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: b9d89c2066

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@jack-arturo jack-arturo merged commit 0720da2 into main Jul 4, 2026
7 checks passed
@jack-arturo jack-arturo deleted the fix/recall-overfetch-and-artifact-exclusion branch July 4, 2026 07:09
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