Skip to content

fix(review): cache impact-map's per-file vector query results#4544

Merged
JSONbored merged 2 commits into
mainfrom
claude/fix-impact-map-query-cache
Jul 10, 2026
Merged

fix(review): cache impact-map's per-file vector query results#4544
JSONbored merged 2 commits into
mainfrom
claude/fix-impact-map-query-cache

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Closes #4500.

Summary

  • computeImpactMap (src/review/impact-map.ts) issues one retrieveContextWithMetrics call per changed-symbol file (up to MAX_IMPACT_MAP_INPUT_FILES=20), each a real embedding-model inference call plus a live vector-index query with no result cache — only a 60-second cold-index existence check is memoized. Impact-map is a dynamic feature (bypasses the durable ai_review result cache), so only the 30-minute non-cacheable retry cooldown throttled repeat computation; once that lapsed, the full up-to-20x embed+query loop re-fired for an unchanged PR.
  • Adds impact_map_query_cache (migration 0131), keyed by (project, repo, query_fingerprint). The fingerprint hashes every input that affects the result — queryText, excludePaths, topK, minScore, reranker — since excludePaths in particular varies per changed file (each excludes itself); topK/minScore/reranker are constants for this module's own calls but are hashed rather than assumed, so the fingerprint stays correct if a future caller ever varies them.
  • Unlike the grounding file-content cache (fix(review): grounding re-fetches every changed file's full body every 30 min with zero caching #4499, already merged), this needs a TTL: the underlying vector index can change as new commits get embedded, so an identical query issued later could legitimately have a different correct answer. Set to match AI_REVIEW_NON_CACHEABLE_RETRY_COOLDOWN_MS (30 min) — the same cooldown that already throttles how often this computation is re-attempted.
  • The cache lives in impact-map.ts itself (using the already-injected RagInfra.storage adapter), not inside rag.ts's shared retrieveContextWithMetrics — that function has another caller (rag-wire.ts) that issues one call per pass with no amplification problem, so this scopes the fix to the actual amplification site instead of changing shared retrieval behavior for every caller.

Scope

Validation

  • npm run typecheck
  • npm run db:migrations:check / npm run db:schema-drift:check (both clean; migration renumbered 0130→0131 after rebasing past fix(review): grounding re-fetches every changed file's full body every 30 min with zero caching #4499's own 0130, which merged first)
  • New tests added and empirically verified to FAIL without the fix (temporarily reverted impact-map.ts locally): an invariant test (2 embed/query calls → 1) and a regression test reproducing the exact incident shape (5 cooldown-driven passes on an unchanged head → 5 embed/query calls without the fix, 1 with it). Also added: a genuinely different query still fetches fresh (never masked by another file's cache entry), and a cache entry past the TTL is treated as a miss (never serves a possibly-stale answer).
  • npx vitest run test/unit/impact-map.test.ts test/unit/impact-map-grounding.test.ts test/unit/impact-map-processor-wiring.test.ts test/unit/impact-map-wire.test.ts test/unit/impact-map-collapsible.test.ts test/unit/rag.test.ts test/unit/rag-wiring.test.ts (165 passed) — includes rag.ts/rag-wiring.test.ts to confirm the sibling RAG-grounding caller is completely unaffected, since this fix intentionally does not touch shared retrieval code.

If any required check was skipped, explain why:

  • Full npm run test:coverage not re-run unsharded locally; this change is scoped to one module (impact-map.ts) plus a new table, with no shared-interface changes. Relying on CI for the full gate.

Safety

  • No secrets, wallet details, hotkeys, coldkeys, user PATs, private keys, raw trust scores, private rankings, or private maintainer evidence are exposed.
  • Public GitHub text stays sanitized, low-noise, and does not imply compensation guarantees or optimization tactics.
  • N/A — no auth/cookie/CORS/GitHub App/Cloudflare/session changes.
  • N/A — no API/OpenAPI/MCP behavior changed.
  • N/A — no UI changes.

@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.07%. Comparing base (c6a5504) to head (ca8ea7d).
⚠️ Report is 3 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4544   +/-   ##
=======================================
  Coverage   94.06%   94.07%           
=======================================
  Files         425      425           
  Lines       37774    37794   +20     
  Branches    13794    13797    +3     
=======================================
+ Hits        35533    35553   +20     
  Misses       1586     1586           
  Partials      655      655           
Files with missing lines Coverage Δ
src/db/schema.ts 72.72% <100.00%> (+0.29%) ⬆️
src/review/impact-map.ts 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 10, 2026
@loopover-orb

loopover-orb Bot commented Jul 10, 2026

Copy link
Copy Markdown

Tip

🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩

✅ Gittensory review result - approve/merge recommended

Review updated: 2026-07-10 01:22:38 UTC

4 files · 1 AI reviewer · no blockers · readiness 100/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This PR adds a keyed, TTL'd cache (impact_map_query_cache, migration 0131) around computeImpactMap's per-changed-file retrieveContextWithMetrics call, fixing the up-to-20x embed+query amplification described in #4500. The fingerprint correctly hashes queryText, sorted excludePaths, topK, minScore, and reranker; both cache read and write paths fail open (catch → null / no-op) so a storage error degrades to the pre-existing uncached behavior rather than blocking the review. Schema and migration are in parity, the migration is D1-remote-safe (plain CREATE TABLE IF NOT EXISTS, no temp/pragma/attach), and the new tests genuinely exercise cache hit/miss/expiry/disambiguation via a stateful storage stub rather than fabricated payloads.

Nits — 6 non-blocking
  • migrations/0131_impact_map_query_cache.sql:14 uses `DEFAULT CURRENT_TIMESTAMP` while schema.ts's `fetchedAt` uses `$defaultFn(() => nowIso())` — harmless today since `putCachedImpactMapQuery` always supplies `fetchedAt` explicitly, but worth aligning to avoid the drizzle-vs-SQL-default confusion this repo's migration conventions specifically warn about.
  • IMPACT_MAP_QUERY_CACHE_MAX_AGE_MS in impact-map.ts is a separately-defined `30 * 60 * 1000` literal duplicating AI_REVIEW_NON_CACHEABLE_RETRY_COOLDOWN_MS in processors.ts instead of importing it — if the cooldown constant ever changes, this TTL silently drifts out of sync with the invariant the PR description says it's matching.
  • impactMapQueryFingerprint joins fields with a bare `|`/`,` delimiter (impact-map.ts's fingerprint payload) — since queryText is built from unsanitized symbol names/file paths, a symbol or path containing `|` could theoretically collide with a differently-shaped query; low risk given symbols are AST-extracted identifiers, but worth a comment or a safer separator (e.g. JSON.stringify the tuple) for robustness.
  • codecov/patch is failing at 85% vs the 99% target — the fail-safe catch branches in getCachedImpactMapQuery/putCachedImpactMapQuery (storage-error paths) don't appear to be covered by the new tests, and per this repo's coverage bar that gap should be closed before merge.
  • Import AI_REVIEW_NON_CACHEABLE_RETRY_COOLDOWN_MS from processors.ts for IMPACT_MAP_QUERY_CACHE_MAX_AGE_MS instead of redefining it (impact-map.ts).
  • PR author also opened the linked issue — Link an issue that was opened by a different contributor, or provide a rationale for why this self-authored issue represents genuine discovery work.
Signal Result Evidence
Code review ✅ No blockers 1 reviewer
Linked issue ✅ Linked #4500
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 48 registered-repo PR(s), 40 merged, 363 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 48 PR(s), 363 issue(s).
Gate result ✅ Passing No configured blocker found.
Linked issue satisfaction

Addressed
The PR adds a project/repo/query_fingerprint-keyed cache (hashing queryText, excludePaths, topK, minScore, reranker) with a 30-minute TTL matching the cooldown, wired directly into computeImpactMap's per-file loop so repeated calls reuse cached results instead of re-embedding/re-querying, and includes the required invariant, regression, and negative-path tests plus TTL-expiry and fail-safe coverag

Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Python, TypeScript, JavaScript, Ruby, Go, Kotlin, MDX, Shell
  • Official Gittensor activity: 48 PR(s), 363 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Treat this as maintainer-lane context rather than normal contributor-lane activity.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.

  • Re-run Gittensory review

@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 10, 2026
JSONbored added 2 commits July 9, 2026 18:03
computeImpactMap issues one retrieveContextWithMetrics call per changed-
symbol file (up to MAX_IMPACT_MAP_INPUT_FILES=20), each a real embedding
call plus a live vector-index query with no result cache -- only a
60-second cold-index existence check is memoized. Impact-map is a dynamic
feature (bypasses the durable ai_review cache), so only the 30-minute
non-cacheable retry cooldown throttled repeat computation; once that
lapsed, the full up-to-20x embed+query loop re-fired for an unchanged PR.

Adds impact_map_query_cache, keyed by (project, repo, fingerprint) where
the fingerprint hashes every input that affects the result (queryText,
excludePaths, topK, minScore, reranker) -- excludePaths in particular
varies per changed file, since each excludes itself. Unlike the grounding
file-content cache, this needs a TTL: the underlying vector index can
change as new commits get embedded, so an identical query issued later
could legitimately have a different correct answer. Matches the same
30-minute cooldown that already throttles how often this computation is
re-attempted.

Closes #4500.
Restructure the cache-hit branch to a proper if/else (a braceless
single-statement if with no else was mis-instrumented by v8's coverage
collector) and add a fail-safe test for a throwing cache read.
@JSONbored
JSONbored force-pushed the claude/fix-impact-map-query-cache branch from 4071680 to ca8ea7d Compare July 10, 2026 01:09
@JSONbored
JSONbored merged commit dfef438 into main Jul 10, 2026
12 checks passed
@JSONbored
JSONbored deleted the claude/fix-impact-map-query-cache branch July 10, 2026 01:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. manual-review Gittensor contributor context

Development

Successfully merging this pull request may close these issues.

fix(review): impact-map re-embeds + re-queries the vector index up to 20x per pass with no result cache

1 participant