From 6cb6e8dfbde74beeb749448441765fd5844f0666 Mon Sep 17 00:00:00 2001 From: Alex Southwell <4596216+saphid@users.noreply.github.com> Date: Tue, 3 Nov 2026 08:24:26 +1100 Subject: [PATCH] fix(server): review keeps tracked changes when untracked files overflow the listing Co-Authored-By: Claude Opus 5.5 --- apps/server/src/vcs/GitVcsDriverCore.test.ts | 57 +++++++++++--------- apps/server/src/vcs/GitVcsDriverCore.ts | 7 +-- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/apps/server/src/vcs/GitVcsDriverCore.test.ts b/apps/server/src/vcs/GitVcsDriverCore.test.ts index 9f9d23a8e409b..23a3b7a78525f 100644 --- a/apps/server/src/vcs/GitVcsDriverCore.test.ts +++ b/apps/server/src/vcs/GitVcsDriverCore.test.ts @@ -2308,33 +2308,40 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => { }), ); - it.effect("keeps tracked changes visible when untracked discovery fails", () => - Effect.gen(function* () { - const delegate = yield* ChildProcessSpawner.ChildProcessSpawner; - const failingLsFilesSpawner = ChildProcessSpawner.make((command) => { - if (!ChildProcess.isStandardCommand(command)) { - return Effect.die("expected a standard Git command"); - } - return command.args[0] === "ls-files" && command.args[1] === "--others" - ? Effect.succeed(makeNonRepositoryHandle()) - : delegate.spawn(command); - }); - const driver = yield* makeGitVcsDriverCore().pipe( - Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, failingLsFilesSpawner), - Effect.provide(layerServerConfig), - ); - const cwd = yield* makeTmpDir(); - yield* initRepoWithCommit(cwd).pipe( - Effect.provideService(GitVcsDriver.GitVcsDriver, driver), - ); - yield* writeTextFile(cwd, "README.md", "# tracked change\n"); + it.effect.each(["fails", "exceeds the output limit"] as const)( + "keeps tracked changes visible when untracked discovery %s", + (scenario) => + Effect.gen(function* () { + const delegate = yield* ChildProcessSpawner.ChildProcessSpawner; + const failingLsFilesSpawner = ChildProcessSpawner.make((command) => { + if (!ChildProcess.isStandardCommand(command)) { + return Effect.die("expected a standard Git command"); + } + if (command.args[0] !== "ls-files" || command.args[1] !== "--others") { + return delegate.spawn(command); + } + return Effect.succeed( + scenario === "fails" + ? makeNonRepositoryHandle() + : makeSuccessfulHandle("a".repeat(16 * 1024 * 1024 + 1)), + ); + }); + const driver = yield* makeGitVcsDriverCore().pipe( + Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, failingLsFilesSpawner), + Effect.provide(layerServerConfig), + ); + const cwd = yield* makeTmpDir(); + yield* initRepoWithCommit(cwd).pipe( + Effect.provideService(GitVcsDriver.GitVcsDriver, driver), + ); + yield* writeTextFile(cwd, "README.md", "# tracked change\n"); - const preview = yield* driver.getReviewDiffPreview({ cwd, ignoreWhitespace: false }); - const diff = preview.sources.find((source) => source.kind === "working-tree")?.diff ?? ""; + const preview = yield* driver.getReviewDiffPreview({ cwd, ignoreWhitespace: false }); + const diff = preview.sources.find((source) => source.kind === "working-tree")?.diff ?? ""; - assert.include(diff, "-# test"); - assert.include(diff, "+# tracked change"); - }), + assert.include(diff, "-# test"); + assert.include(diff, "+# tracked change"); + }), ); it.effect("preserves a staged deletion when the removed path still exists", () => diff --git a/apps/server/src/vcs/GitVcsDriverCore.ts b/apps/server/src/vcs/GitVcsDriverCore.ts index a084664bc447c..bbabc2a0b81ff 100644 --- a/apps/server/src/vcs/GitVcsDriverCore.ts +++ b/apps/server/src/vcs/GitVcsDriverCore.ts @@ -3060,12 +3060,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* cwd, ["ls-files", "--others", "--exclude-standard", "-z", "--", ...pathArgs], { maxOutputBytes: REVIEW_METADATA_MAX_OUTPUT_BYTES }, - ).pipe( - Effect.catchIf( - (error) => error.outputLength === undefined, - () => Effect.succeed(null), - ), - ); + ).pipe(Effect.orElseSucceed(() => null)); if (untracked === null) return null; const paths = splitNullSeparatedGitStdoutPaths(untracked).filter( (candidate) => onlyPath === undefined || candidate === onlyPath,