fix(watch): keep no-farmable grace alive across transient active-drop blips#69
Open
rxm96 wants to merge 1 commit into
Open
fix(watch): keep no-farmable grace alive across transient active-drop blips#69rxm96 wants to merge 1 commit into
rxm96 wants to merge 1 commit into
Conversation
… blips When watching a target whose drops are not watchable (claimable/blocked/ upcoming), useStallRecovery cleared the no-farmable grace marker on every pass through the no-progress recovery branch -- i.e. whenever activeDropInfo was momentarily present. An oscillating active-drop signal therefore kept restarting the 30s grace, so decideWatchingNoFarmable's give-up path (cooldown + retarget + stop + stall-stop) never fired and the engine wedged in "watching, but target currently not watchable" indefinitely, with a frozen no-progress tracker. Preserve the grace marker across a transient activeDropInfo while the target stays unwatchable; clear it only once canWatchTarget is true again. Extracted as the pure reconcileNoFarmableOnActiveDrop() and unit-tested, including the flicker regression. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Symptom
The engine status panel could get stuck on "Watching, but target currently not watchable" for a very long time (observed: 1h17m) with
SUPPRESSION none,COOLDOWNS none, still actively "Watching", and a frozen no-progress tracker showing0 recovery attempts. A full app refresh cleared it — i.e. it was a wedged runtime state, not expected parking.Root cause
Watchability is decided by drop state, not channels, so a target with only claimable/blocked/upcoming drops is correctly
canWatchTarget = false. When that happens while watching,decideWatchingNoFarmableis supposed to wait outNO_FARMABLE_DROP_GRACE_MS(30s) and then give up: cooldown + retarget + stop + stall-stop. That pure logic is correct and already tested.The bug is in the executor
useStallRecovery: it cleared the no-farmable grace marker (noFarmableDropRef.current = null) on every pass through the no-progress recovery branch — i.e. wheneveractiveDropInfowas momentarily present. If the active-drop selection oscillates (e.g. an upcoming/unlinked drop surfacing for a tick whilecanWatchTargetstays false), the marker is reset on each blip, the 30s grace never completes, the give-up path never fires, and the stale stall tracker keeps showing0 attempts.This matches all observed symptoms: no give-up, no cooldown, no suppression, frozen tracker.
Fix
Preserve the grace marker across a transient
activeDropInfowhile the target stays unwatchable; clear it only once the target is genuinely watchable again (canWatchTarget === true). Extracted as the purereconcileNoFarmableOnActiveDrop(marker, canWatchTarget)and wired into the executor in place of the unconditional reset.Entry condition of the no-farmable branch is intentionally left on
!activeDropInfo(not!canWatchTarget) so the existing channel-switch recovery — for the case where watchable drops exist but not on the current channel — is preserved.Tests
TDD: added a failing regression first, then the fix.
reconcileNoFarmableOnActiveDropunits: preserve while unwatchable, clear when watchable, null-safe.stop-watching+resetStallTracking) fires.npm test(524 passing),npm run typecheck(both tsconfigs), prettier + eslint on changed files: all clean.Notes
Found via a user-reported screenshot. Workaround until merged: stop/restart watching (or toggle the master switch) re-initializes the refs.
🤖 Generated with Claude Code