From 90fc490ca89c9b1adcfe01a75e1c8d4842d1da88 Mon Sep 17 00:00:00 2001 From: ghost <49853598+JSONbored@users.noreply.github.com> Date: Thu, 9 Jul 2026 02:23:42 -0700 Subject: [PATCH] fix(review): refresh capped RAG files on full reindex --- src/review/rag-index.ts | 8 ++++---- test/unit/rag-index.test.ts | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/review/rag-index.ts b/src/review/rag-index.ts index 19cfea0af8..d845f2e9c1 100644 --- a/src/review/rag-index.ts +++ b/src/review/rag-index.ts @@ -315,15 +315,15 @@ export async function indexRepo( let skipped = 0; let capped = false; for (const entry of tree) { - if (stored >= MAX_CHUNKS_PER_REPO) { - capped = true; - break; - } const known = knownChunks.get(entry.path); if (entry.sha && known?.blobSha && known.blobSha === entry.sha) { skipped += 1; continue; // unchanged since the last full index — skip the fetch/chunk/embed entirely } + if (stored >= MAX_CHUNKS_PER_REPO && (!known || known.count <= 0)) { + capped = true; + break; + } const text = await fetchFileText(env, repoFullName, entry.path, ref, token, admissionKey); if (text === null) continue; const chunks = chunkFile(entry.path, text, namespace); diff --git a/test/unit/rag-index.test.ts b/test/unit/rag-index.test.ts index 30e388174d..f74421f7a1 100644 --- a/test/unit/rag-index.test.ts +++ b/test/unit/rag-index.test.ts @@ -426,6 +426,44 @@ describe("indexRepo: embedding cache (#4365) — skip unchanged files by git blo expect(result.files).toBe(1); // only one of the two new files fit under the cap expect(await countChunks(env, PROJECT, "gittensory")).toBe(MAX_CHUNKS_PER_REPO); // never exceeds the cap }); + + it("refreshes changed files in a full reindex even when the repository is already capped", async () => { + const { env, ai } = indexEnv(); + const ns = ragNamespace(PROJECT, "gittensory"); + await env.DB.batch( + Array.from({ length: MAX_CHUNKS_PER_REPO }, (_, i) => { + const path = i === 0 ? "src/changed.ts" : `src/existing${i}.ts`; + return env.DB.prepare("INSERT INTO repo_chunks (id, project, repo, path, chunk_index, kind, text, blob_sha) VALUES (?,?,?,?,?,?,?,?)").bind( + `${ns}|${path}::0`, + PROJECT, + "gittensory", + path, + 0, + "code", + i === 0 ? "old changed file" : "old", + i === 0 ? "sha-old" : `sha-existing-${i}`, + ); + }), + ); + stubGithub({ + tree: [ + { path: "src/changed.ts", size: 30, sha: "sha-new" }, + ...Array.from({ length: MAX_CHUNKS_PER_REPO - 1 }, (_, i) => ({ path: `src/existing${i + 1}.ts`, size: 10, sha: `sha-existing-${i + 1}` })), + { path: "src/new.ts", size: 10, sha: "sha-new-file" }, + ], + files: { "src/changed.ts": "export const changed = true;\n", "src/new.ts": "export const n = 1;\n" }, + }); + + const result = await indexRepo(env, PROJECT, REPO); + + expect(result).toMatchObject({ indexed: 1, files: 1, capped: true }); + expect(ai.run).toHaveBeenCalledTimes(1); + expect(await countChunks(env, PROJECT, "gittensory")).toBe(MAX_CHUNKS_PER_REPO); + const row = await env.DB.prepare("SELECT text, blob_sha FROM repo_chunks WHERE project=? AND repo=? AND path=?") + .bind(PROJECT, "gittensory", "src/changed.ts") + .first<{ text: string; blob_sha: string }>(); + expect(row).toEqual({ text: "export const changed = true;\n", blob_sha: "sha-new" }); + }); }); describe("indexRepo: MAX_CHUNKS_PER_REPO cap holds", () => {