fix(miner-ui): stop a stale governor poll from reverting a just-applied pause/resume - #7871
Conversation
…ed pause/resume LedgersPage syncs the governor pause-state from two independent sources with no ordering guard: a usePolledFetch GET synced during render, and the operator's pause/resume POST written directly on resolve. The POST doesn't share the poll's single-flight guard, so a poll GET already in flight when the operator clicks can resolve after the action's POST and clobber the fresh result with a stale pre-action value -- the UI reverts to "Not paused" (or "paused") until the next tick self-corrects. Mark the next poll-sync after an action lands as to-skip (that poll may predate the action, so its result is not newer); later ticks sync normally, mirroring the generation/cancellation discipline usePolledFetch and useStreamingText already use. The flag is state, not a ref, so the render-phase sync reads it without accessing a ref during render.
|
🚨 Contributor flagged. Click here for more info: Superagent Dashboard |
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
1 similar comment
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
|
Warning ⏸️ LoopOver review result - manual review recommendedReview updated: 2026-07-21 15:48:37 UTC
Review summary Nits — 4 non-blocking
Flagged checks (non-blocking)
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. Visual preview
Click any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy. Scroll preview
A short scroll-through clip (desktop) — click either thumbnail to open the full animation. Evidence for scroll-linked behavior a single screenshot can't show. 🟩 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 LoopOver, a quiet PR intelligence layer for OSS maintainers.
|


What & why
Closes #7791.
LedgersPage(apps/loopover-miner-ui/src/routes/ledgers.tsx) syncs the governor pause-state from two independent sources with no ordering guard between them:usePolledFetch(loadGovernorPauseState, …)GET, synced intopauseStateduring render, andpauseStatedirectly on resolve so it reflects immediately.The POST doesn't share the poll's single-flight guard. If a poll GET is already in flight when the operator clicks Pause and the POST resolves first (plausible — a small local write vs. a read competing for the same SQLite file), the poll's stale pre-pause response lands after the action's fresh result and clobbers it. The UI visibly reverts to "Not paused" even though the governor is paused server-side, until the next poll tick self-corrects (up to 10s). Same in reverse for Resume. This is a display-only bug — it doesn't change what pause/resume do server-side.
The fix
Add an ordering guard mirroring the generation/cancellation discipline
usePolledFetch/useStreamingTextalready use internally: when an action's result is applied, mark the next poll-sync as to-skip — that poll may have started before the action, so its result is not newer. It's still consumed (solastPolledPauseStateadvances and we don't keep skipping), just not allowed to overwrite the action's result. Later ticks — which started after the action — sync normally. The flag is state, not a ref, so the render-phase sync reads it without accessing a ref during render (thereact-hooks/refslint rule). No change to howpauseGovernor/resumeGovernorwork server-side.Tests (
ledgers.test.tsx)Validation
apps/loopover-miner-ui:vitest run32 pass;tsc --noEmitexit 0; eslint 0 errors (the onereact-refresh/only-export-componentswarning is pre-existing onmain); Prettier clean.apps/loopover-miner-uiis not under thesrc/**99% patch gate; the regression test is the coverage deliverable. Branched off currentmain, mergeable-clean.