fix(watch): honor declared pause cadence for idle live panes - #1850
Open
thirtysevend wants to merge 1 commit into
Open
fix(watch): honor declared pause cadence for idle live panes#1850thirtysevend wants to merge 1 commit into
thirtysevend wants to merge 1 commit into
Conversation
5 tasks
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.
Intent
Fix the firstmate watcher defect where an idle live pane whose latest status explicitly declares paused can emit repeated bare stale wakes as its rendered hash changes. A declared pause must absorb stale panes and re-surface only after FM_PAUSE_RESURFACE_SECS with the labeled declared-pause long-cadence reason; an authoritative active run must still override the pause as working, and any subsequent resolved or other new non-pause status must clear pause tracking and restore normal stale behavior. Preserve the stricter confirmed-dead rule for durable captain-held transfers and preserve AFK daemon handoff semantics. Add colocated watcher regression coverage for fresh pause absorption, changing-pane absorption, labeled cadence recheck, and unpause behavior, and update the authoritative architecture documentation.
What Changed
pause_state_classinbin/fm-watch.shnow treats the latest explicitpaused:status as authoritative while the endpoint idles: stale panes are absorbed and re-surfaced only everyFM_PAUSE_RESURFACE_SECSwith the labeled declared-pause long-cadence reason, instead of emitting repeated bare stale wakes as the rendered pane hash drifts. An authoritative active run still overrides the pause as working, and any later non-pause status (e.g.resolved:) clears pause tracking and restores normal stale handling. The stricter confirmed-dead requirement remains in place for durablecaptain-heldtransfers, and AFK daemon handoff semantics are unchanged.tests/fm-watch-triage.test.shto exercise fresh pause absorption, changing-pane absorption, the labeled cadence recheck, and unpause behavior (full suite passes 47/47 in the pipeline Test gate).docs/architecture.mdto document the declared-pause authority, the active-run override, and the clear-on-new-status semantics.Risk Assessment
✅ Low: A well-bounded single-function watcher fix that verifiably eliminates the repeated bare-wake path for declared pauses, preserves the adjacent captain-held and AFK semantics unchanged, satisfies every required intent criterion, and ships colocated regression coverage for all four required scenarios plus a matching documentation update.
Testing
Ran the colocated fm-watch-triage suite via the project's focused runner (all 47 tests pass, covering the new declared-pause regression tests plus the preserved captain-held confirmed-dead, active-run override, secondmate, and AFK handoff guarantees), then manually drove real fm-watch.sh subprocesses against the hermetic fixture on both the base and target commits: the base watcher reproduces the repeated bare-stale-wake defect, while the fixed watcher absorbs fresh and changing-pane declared pauses, re-surfaces once after FM_PAUSE_RESURFACE_SECS with the labeled long-cadence reason, and restores normal stale behavior on unpause. No visual artifact applies (headless CLI watcher; wake-queue transcripts are the end-user surface). Environment note: a broad pkill during test cleanup may have briefly killed the user's production watcher; it re-armed and is running.
Evidence: Before/after watcher demonstration transcript (defect on base vs fixed cadence)
== BEFORE (base fb368dc): live idle pane, latest status declares paused watcher re-arm #1: EXITED (surfaced a wake) wake-queue: stale | test:fm-gate | stale: test:fm-gate watcher re-arm #2 (pane hash drifted): EXITED (surfaced again) wake-queue: stale: test:fm-gate (x2) => defect: every re-arm of the declared-paused live pane appends another bare stale wake == AFTER (fix): same fixture, fresh declared pause absorbs watcher: ABSORBING (still armed after 5s, no exit); .paused marker present; wake-queue EMPTY == AFTER: pane content drifts mid-run - still absorbed watcher: ABSORBING; paused stale suppressor advanced; wake-queue EMPTY == AFTER: pause older than FM_PAUSE_RESURFACE_SECS (240s) watcher: EXITED once for the scheduled recheck wake-queue: stale: test:fm-gate (paused 501s, awaiting external - declared pause, rechecked on a long cadence not a wedge; confirm the wait still holds) == AFTER: crew writes 'resolved:' - pause clears watcher: EXITED with a normal stale wake (stale: test:fm-gate); pause tracking marker: clearedEvidence: Colocated fm-watch-triage suite run (47/47 ok via bin/fm-test-run.sh)
Evidence: Manual demonstration script (reproducible before/after steps)
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
bin/fm-watch.sh:380- In pause_state_class's new declared-pause branch (bin/fm-watch.sh:380), while .paused-<key> exists and the recheck marker is fresher than STALE_ESCALATE_SECS, the function returns 'paused' without consulting crew_absorb_class, so an authoritative active run flips the classification to 'working' only after the recheck window (default 240s) expires. This is bounded, the pane is absorbed either way during the window, and it mirrors the pre-existing captain-held throttle design — noting it only as an acknowledged eventual-consistency tradeoff against the intent's 'active run must override' criterion.✅ **Test** - passed
✅ No issues found.
bin/fm-test-run.sh tests/fm-watch-triage.test.sh— full colocated watcher-triage suite, 47/47 ok, exit 0, including the rewrittentest_declared_pause_and_exited_captain_hold_use_bounded_cadence(fresh pause absorption, changing-pane absorption, labeled cadence recheck, unpause) and the preserved-guarantee tests (test_paused_authoritative_working_preserves_wedge_timer,test_nonterminal_paused_rechecks_authoritative_state,test_afk_present_reverts_watcher_to_one_shot,test_afk_paused_changed_pane_hands_off_plain_stale, secondmate pause/unpause tests)Manual end-to-end before/after demonstration (declared-pause-demo.sh): drove the real fm-watch.sh from the base commit fb368dc against a live declared-paused fixture pane — each of two watcher re-arms with a drifted pane hash appended another barestale: test:fm-gatewake (defect reproduced)Same manual fixture against the fixed watcher: fresh declared pause absorbed (watcher stays armed, pause marker recorded, wake queue empty), pane-content drift absorbed with the paused stale suppressor advanced, a 500s-old pause re-surfaced exactly once with the labeleddeclared pause, rechecked on a long cadencereason, and a subsequentresolved:status cleared pause tracking and emitted the normal bare stale wakeVerifieddocs/architecture.mdin the diff documents the new declared-pause authority, active-run override, and unpause semantics✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.