Skip to content

Fix: Success-path stale check still clobbers loading flag on race (loadSymbols/loadAllFiles/loadRepoFiles) - #35

Open
pullapprove5[bot] wants to merge 1 commit into
masterfrom
pullapprove/pa-8-81e999
Open

Fix: Success-path stale check still clobbers loading flag on race (loadSymbols/loadAllFiles/loadRepoFiles)#35
pullapprove5[bot] wants to merge 1 commit into
masterfrom
pullapprove/pa-8-81e999

Conversation

@pullapprove5

@pullapprove5 pullapprove5 Bot commented Aug 6, 2026

Copy link
Copy Markdown

What was wrong

Three async loaders detected a stale response on their success path but still wrote to the store before bailing:

  • desktop/ui/stores/slices/filesSlice.tsloadAllFiles, loadRepoFiles: if (isStale()) { set({ allFilesLoading: false }); return; }
  • desktop/ui/stores/slices/symbolsSlice.tsloadSymbols: same shape with symbolsLoading

If comparison/repo A's request resolves after the user switched to B — and B's own load has already set the loading flag to true — A's handler resets that flag to false. The UI then renders "loading complete" (empty file panel / no symbols) while B's request is genuinely still in flight. This is the same race class fixed on the catch path in PR #18; these success paths were left untouched by that scoped PR.

loadRepoSymbols in the same file already has the clean idiom: a bare if (isStale()) return;.

What changed

Each stale branch now returns without calling set() at all, so a newer in-flight request keeps ownership of its own loading flag. I also applied the identical one-line change to loadSymbols' catch path, which had the same clobber a few lines below (the catch-path fix that PR #18 made in filesSlice never landed here).

Safety check on "could the flag get stuck true?": every mutation of comparison/repoPath goes through setRepoPath / setComparison / setCommitRange / switchReview, and all four spread a reset (comparisonResetState / diffDataResetState / repoResetState) that includes allFilesLoading: false and symbolsLoading: false. The switch itself clears the flags, so dropping the stale writer's set() cannot strand loadSymbols behind its if (symbolsLoading) return guard.

Tests

Added three cases mirroring the existing rejection-race tests:

  • filesSlice.test.ts — "discards a response that resolves after the comparison changed" (loadAllFiles) and "…after the repo changed" (loadRepoFiles): each asserts the stale payload isn't applied to allFiles and that allFilesLoading stays true.
  • symbolsSlice.test.ts — same for loadSymbols' success path; also extended the existing rejection test to assert symbolsLoading stays true, which pins the catch-path half.

All three new assertions on the loading flag fail against the old code.

Not verified

I could not run scripts/test, vitest, or tsc: this sandbox has no node_modules and no network access to install dependencies. The change is TypeScript-only (no Rust touched), so the type check and the frontend test run should be exercised in CI or locally before merge.


Opened by a PullApprove implementation run (implement-finding v1) for the finding PA-8 — Success-path stale check still clobbers loading flag on race (loadSymbols/loadAllFiles/loadRepoFiles).
Merging this is what closes the finding as fixed.

loadAllFiles/loadRepoFiles (filesSlice) and loadSymbols (symbolsSlice)
detected a stale response on the success path but still did
`set({ ...Loading: false })` before returning. If comparison/repo A's
request resolved after a switch to B — whose own load had already
claimed the flag — A's handler reset it to false, so the UI reported
loading complete while B's request was still in flight.

Return without touching state instead, matching loadRepoSymbols. The
switch itself resets the flags (comparisonResetState/repoResetState), so
nothing gets stuck true. Same one-line change on loadSymbols' catch
path, which had the identical clobber.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

0 participants