Skip to content

fix: preserve actionable wake delivery during watcher recovery - #2134

Closed
coreldh wants to merge 6 commits into
kunchenguid:mainfrom
coreldh:fm/c0810n-fm-monitor-pub
Closed

coreldh wants to merge 6 commits into
kunchenguid:mainfrom
coreldh:fm/c0810n-fm-monitor-pub

Conversation

@coreldh

@coreldh coreldh commented Aug 11, 2026 •

Copy link
Copy Markdown
Contributor

Intent

Repair PR 2134’s real Pi continuity failure: after an actionable watcher close, an unready successor can be retired leaving only an unrefed retry timer, so Pi may exit before delivering the original typed wake and bounded restoration failure. Retain only the actionable-close retry timer until the next bounded attempt or typed failure; keep background scheduleRetry unrefed. Add a deterministic no-extra-handle control that proves delivery after two retries. This repair was independently red-before-green verified in the owning checkout: the new control failed with the existing unrefed timer, passed 31/31 after the repair, and failed again when unref was restored. The report’s full suite was started as requested but remains nonterminal in known Herdr/bootstrap shards, so its aggregate is NOT_VERIFIABLE; do not infer full-suite green. Update existing PR #2134 only; do not force-push, open a second PR, or merge. PR changes must state that the repair preserves Pi’s owned actionable wake-delivery contract.

What Changed

  • Start the watcher’s singleton heartbeat before its PR-check migration preflight, with a guarded lock-held migration path.
  • Preserve Pi and OpenCode actionable recovery timers until the next bounded attempt or typed fallback delivers the original wake; background retries remain unreferenced.
  • Add regression coverage for no-extra-handle Pi recovery and watcher startup ordering, and document the continuity contract.

Risk Assessment

✅ Low: The bounded Pi actionable-close restoration path now retains the sole required retry timer through its next attempt or typed failure, while ordinary background retries remain unrefed; surrounding startup/migration changes preserve their singleton and preflight boundaries.

Testing

Targeted validation confirmed the actionable-close retry timer is retained through bounded restoration while background scheduleRetry remains unrefed. The focused Pi extension test passed, and a no-extra-handle runtime control produced four arm cycles plus the reviewer-visible original typed wake and bounded failure; full-suite/remote CI status is NOT_VERIFIABLE because it was intentionally not run in this phase.

Evidence: Pi actionable-close runtime delivery transcript
Pi actionable-close runtime delivery control
arm_cycles=4 (initial + successor + 2 retries)
typed_follow_up_delivered=yes
⁣FIRSTMATE_OP: v1 watcher: FIRSTMATE WATCHER WAKE: signal: synthetic wake

watcher: FAILED - Pi extension could not verify a ready successor watcher
watcher: FAILED - Pi extension could not restore watcher continuity after 2 retries

Run bin/fm-wake-drain.sh first and handle the queued wake. Watcher continuity is extension-owned.
Evidence: Focused Pi extension test transcript
ok - Pi extension reports external healthy watcher output
ok - Pi custom tool exposes repair-only metadata and returns automatic-continuation guidance
ok - Pi redundant tool call returns ownership guidance and spawns no second child
ok - Pi scheduled retry remains extension-owned after another tool call
ok - Pi actionable close starts one successor before wake delivery settles
ok - Pi hung successor falls back to one typed actionable wake
ok - Pi hung-successor restoration keeps the runtime alive through wake delivery
ok - Pi unretired successor falls back without an overlapping retry
ok - Pi late unretired closes resume classified supervision
ok - Pi clean empty close triggers a bounded continuity retry
ok - Pi established clean closes stop at the configured retry limit
ok - Pi close handler verifies session-lock ownership before successor launch
ok - Pi watcher arm distinguishes all session lock ownership states
ok - Pi session transitions use a generation owner across /new /resume /fork, stale callbacks, and quit
ok - Pi process-exit cleanup listener remains singular across session replacement
ok - Pi process-exit cleanup stops the attached arm child
ok - OpenCode plugins have an explicit ESM boundary even under a typeless parent package
ok - OpenCode watcher plugin uses the effective FM_HOME state
ok - OpenCode watcher plugin sources the effective config
ok - OpenCode watcher plugin requires session lock ownership
ok - OpenCode watcher coordinator respects primary scope
ok - OpenCode watcher plugin starts one successor before wake prompt delivery settles
ok - OpenCode pre-ready actionable close preserves its successor
ok - OpenCode hung successor falls back to one typed actionable wake
ok - OpenCode unretired successor falls back without an overlapping retry
ok - OpenCode late unretired closes resume classified supervision
ok - OpenCode clean empty close triggers a bounded continuity retry
ok - OpenCode established clean closes stop at the configured retry limit
ok - OpenCode close handler verifies session-lock ownership before successor launch
ok - OpenCode watcher plugin coordinates with the turn-end guard
ok - OpenCode healthy arm output does not suppress the turn-end guard

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • git diff --no-ext-diff --unified=20 b5d430d6fdcd961ce9b681bf196f365c1825c284 294986b638d8875d7960fb40bf6e7d754984dc17 -- .pi/extensions/fm-primary-pi-watch.ts tests/fm-pi-watch-extension.test.sh
  • bash tests/fm-pi-watch-extension.test.sh
  • /var/folders/cq/xf4qcb9j0qzc2dbh173mflbm0000gn/T/no-mistakes-evidence/01KZT3SEM1ZTPYKMXH9Y6BDGXE/pi-runtime-delivery-control.sh
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

coreldh commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

Hi Kun — could you please enable or trigger the repository workflows for both #2134 and #2137? Both PRs are still open and currently show zero CI checks, while the workflows did run successfully on #2141. We’re only asking for the same upstream validation surface for these two fixes—not a merge. Thanks.

@coreldh
coreldh force-pushed the fm/c0810n-fm-monitor-pub branch from 5355a67 to 025843f Compare August 12, 2026 04:38
@coreldh coreldh changed the title fix: establish watcher heartbeat before migration fix: preserve actionable wake delivery during watcher recovery Aug 12, 2026
@coreldh

coreldh commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

Status refresh, verified live on 2026-08-12 at 17:07 UTC. This supersedes the earlier note asking about missing workflow runs — the runs have since executed on this head.

  • Head: 025843f91a6503f0f701c7d26ce9c93ed89e16ff
  • Checks on that head: 14 check runs, all with conclusion success (Repo invariants, Lint shell scripts, Test coverage guard, Stock macOS Bash snapshot compatibility, Behavior timing aggregate, Behavior tests (Herdr), Behavior portable serial 1-4, Behavior portable parallel 1-2, PR must be raised via no-mistakes).
  • Mergeability as reported by the API at that moment: mergeable: true, mergeable_state: clean.

Bounded purpose of this PR: preserve actionable wake delivery during watcher recovery. After an actionable watcher close, an unready successor could be retired leaving only an unrefed retry timer, so the process could exit before delivering the original typed wake. The change retains the actionable-close retry timer until the next bounded attempt or a typed failure, keeps background retry scheduling unrefed, and adds a deterministic control proving delivery after two retries.

One accuracy note carried over from the change's own report: the focused control was verified red-before-green, but the full suite run was nonterminal in known Herdr/bootstrap shards, so no full-suite aggregate should be inferred from it. The 14 green checks above are the upstream CI result on this head.

No action is requested here; this is a state record only.

@coreldh

coreldh commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

Closing this one. The PR-check migration half no longer applies after #3299 removed that machinery, and the retry-timer half only fails in a headless harness with no other handles; Pi and OpenCode primaries run as persistent TUIs, where that condition does not arise. Thanks!

@coreldh coreldh closed this Sep 25, 2026
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.

1 participant