Context
4 components bind a free-text <input value={repoFullName} onChange={...setRepoFullName}> directly to a useCallback(async () => { ...await apiFetch...; setState(...) }, [repoFullName]) + useEffect(() => { void load(); }, [load]):
apps/loopover-ui/src/components/site/app-panels/ams-miner-cohort-card.tsx:101-126
apps/loopover-ui/src/components/site/app-panels/ai-review-settings.tsx:64-93
apps/loopover-ui/src/components/site/app-panels/activation-preview.tsx:68-92
apps/loopover-ui/src/components/site/app-panels/maintainer-settings.tsx:148-174 and :523-538 (FocusManifestEditor)
Since splitRepoFullName (see the companion issue on that function) accepts any non-empty owner/repo pair, every keystroke past the first / produces a new valid repoFullName and fires a new fetch, with no cancellation/ticket/generation guard. If an earlier (shorter, partially-typed) request resolves after a later one, its response silently overwrites comparison/preview/settings/keyStatus state - e.g. ai-review-settings.tsx would show the wrong repo's BYOK key status and AI-review mode after the user finishes typing a different repo name. This is the same bug class as the already-fixed AuditFeed "Load more" out-of-order-response issue, just triggered by keystrokes instead of pagination.
maintainer-panel.tsx's runPreview (line 528) uses the same shape but is button-triggered rather than auto-fetch-on-keystroke, so it's lower risk and is not included as a required fix site here.
Requirements
⚠️ Required pattern - reuse one of the two already-proven guards in this codebase, do not invent a third: either the cancelled-flag idiom from apps/loopover-miner-ui/src/lib/use-polled-fetch.ts:44,53,64 (set in the effect cleanup, checked before every setResult), or the explicit stale-response-generation guard already shipped in apps/loopover-ui/src/components/site/audit-feed.tsx:134. Apply the same guard shape to all 4 components/5 load functions listed above.
Deliverables
Test Coverage Requirements
apps/loopover-ui is not covered by the src/** 99% patch gate - the new regression test(s) are this issue's own coverage deliverable.
Expected Outcome
Typing a new repo name into any of these 4 panels never has an earlier, now-stale request's response silently overwrite the state for the repo the user actually finished typing.
Links & Resources
apps/loopover-ui/src/lib/use-polled-fetch.ts:44,53,64 and apps/loopover-ui/src/components/site/audit-feed.tsx:134 (the two existing guard patterns to reuse); the 4 affected components listed above
Context
4 components bind a free-text
<input value={repoFullName} onChange={...setRepoFullName}>directly to auseCallback(async () => { ...await apiFetch...; setState(...) }, [repoFullName])+useEffect(() => { void load(); }, [load]):apps/loopover-ui/src/components/site/app-panels/ams-miner-cohort-card.tsx:101-126apps/loopover-ui/src/components/site/app-panels/ai-review-settings.tsx:64-93apps/loopover-ui/src/components/site/app-panels/activation-preview.tsx:68-92apps/loopover-ui/src/components/site/app-panels/maintainer-settings.tsx:148-174and:523-538(FocusManifestEditor)Since
splitRepoFullName(see the companion issue on that function) accepts any non-emptyowner/repopair, every keystroke past the first/produces a new validrepoFullNameand fires a new fetch, with no cancellation/ticket/generation guard. If an earlier (shorter, partially-typed) request resolves after a later one, its response silently overwritescomparison/preview/settings/keyStatusstate - e.g.ai-review-settings.tsxwould show the wrong repo's BYOK key status and AI-review mode after the user finishes typing a different repo name. This is the same bug class as the already-fixed AuditFeed "Load more" out-of-order-response issue, just triggered by keystrokes instead of pagination.maintainer-panel.tsx'srunPreview(line 528) uses the same shape but is button-triggered rather than auto-fetch-on-keystroke, so it's lower risk and is not included as a required fix site here.Requirements
Deliverables
ams-miner-cohort-card.tsx's load function ignores a response that resolves after a newer request was issued for a differentrepoFullName.ai-review-settings.tsx's load function has the same guard.activation-preview.tsx's load function has the same guard.maintainer-settings.tsx's load function ANDFocusManifestEditor's load function both have the same guard.Test Coverage Requirements
apps/loopover-ui is not covered by the src/** 99% patch gate - the new regression test(s) are this issue's own coverage deliverable.
Expected Outcome
Typing a new repo name into any of these 4 panels never has an earlier, now-stale request's response silently overwrite the state for the repo the user actually finished typing.
Links & Resources
apps/loopover-ui/src/lib/use-polled-fetch.ts:44,53,64andapps/loopover-ui/src/components/site/audit-feed.tsx:134(the two existing guard patterns to reuse); the 4 affected components listed above