PYR0D-356: Run the supervision host by default on a Claude primary and hand away heartbeats to its engine #42

Merged
john merged 3 commits from fm/fm-adopt-away-host into main 2026-10-02 07:21:08 +00:00
Owner

Story: PYR0D-356

What this does

Adopts upstream's away-mode supervision host on this home, so an away posture gets an engine turn that re-reads the captain's away words, instead of the daemon only relaying escalations.

  1. Host default-on for a Claude primary - minimal cherry-pick of upstream 0a2cdf95. A config/supervision-host holding off opts a home out. Upstream 12e90e14 (secondmate opt-out inheritance) was not brought in: it conflicts on live-lab files this fork removed.
  2. Dispatch breaker fixed fork-locally - an ancestor CommonJS package.json (reproduced with /home/john/package.json) made Node refuse the TypeScript import in bin/fm-branch-dispatch.mjs, silently handing every wake to main. .pi/extensions/lib/package.json ("type":"module") types the library directory. It is the narrowest scope: the dispatch import graph is only fm-branch-dispatch.ts and fm-async-exec.ts. Pi discovery only reads a subdirectory package.json for a pi.extensions manifest, so Pi's loader is unaffected.
  3. Scope addition found while proving it - on a host or Pi home in the away posture there is an away record but no state/.afk, so the watcher absorbed every idle heartbeat and the engine never got a turn on a quiet fleet. The heartbeat block in bin/fm-watch.sh now checks the away record too. Quiet mode is unaffected.

The Forgejo green-and-head merge gate in bin/fm-pr-merge.sh is already in the rebuild; nothing changed there. Porting #33/#27/#30 is out of scope (#27 is the parallel watchdog task).

Proof

Scratch-home tests in tests/fm-supervision-host.test.sh: dispatch under a CommonJS ancestor; an away heartbeat reaches the engine with the away words appended and a declined wake is handed back to main. tests/fm-watch-triage.test.sh: heartbeat under an away record. No away mode was entered on the live home, and the live daemon and watcher were not touched.

Trial plan (for firstmate to run)

Run on the live home after this lands and homes fast-forward.

  1. Overnight park. Enter away mode with words that name an idle-fleet action (for example "keep the fleet moving, queue the next backlog item when idle"). Leave at least one worker finishing and one idle gap longer than the heartbeat interval. Next morning confirm: the host's engine log shows a turn on the idle heartbeat with the words in its prompt, an action followed from the words (or a recorded decline handed back to main), and no captain-facing chatter for routine wakes.
  2. Usage-limit hit. While away, let the engine's account reach its limit (or run with a low-quota account). Confirm the host records the failed turn, hands the wake back to main rather than dropping it, and resumes engine turns after the reset without a manual restart.
  3. Opt-out. Write off to config/supervision-host, confirm the host steps aside and the plain watcher arm delivers wakes to main; remove the file to restore.

Check afterwards that the live daemon and this host do not double-handle a wake (the parallel watchdog task owns that reconciliation).

Story: PYR0D-356 ## What this does Adopts upstream's away-mode supervision host on this home, so an away posture gets an engine turn that re-reads the captain's away words, instead of the daemon only relaying escalations. 1. **Host default-on for a Claude primary** - minimal cherry-pick of upstream 0a2cdf95. A `config/supervision-host` holding `off` opts a home out. Upstream 12e90e14 (secondmate opt-out inheritance) was not brought in: it conflicts on live-lab files this fork removed. 2. **Dispatch breaker fixed fork-locally** - an ancestor CommonJS `package.json` (reproduced with `/home/john/package.json`) made Node refuse the TypeScript import in `bin/fm-branch-dispatch.mjs`, silently handing every wake to main. `.pi/extensions/lib/package.json` (`"type":"module"`) types the library directory. It is the narrowest scope: the dispatch import graph is only `fm-branch-dispatch.ts` and `fm-async-exec.ts`. Pi discovery only reads a subdirectory `package.json` for a `pi.extensions` manifest, so Pi's loader is unaffected. 3. **Scope addition found while proving it** - on a host or Pi home in the away posture there is an away record but no `state/.afk`, so the watcher absorbed every idle heartbeat and the engine never got a turn on a quiet fleet. The heartbeat block in `bin/fm-watch.sh` now checks the away record too. Quiet mode is unaffected. The Forgejo green-and-head merge gate in `bin/fm-pr-merge.sh` is already in the rebuild; nothing changed there. Porting #33/#27/#30 is out of scope (#27 is the parallel watchdog task). ## Proof Scratch-home tests in `tests/fm-supervision-host.test.sh`: dispatch under a CommonJS ancestor; an away heartbeat reaches the engine with the away words appended and a declined wake is handed back to main. `tests/fm-watch-triage.test.sh`: heartbeat under an away record. No away mode was entered on the live home, and the live daemon and watcher were not touched. ## Trial plan (for firstmate to run) Run on the live home after this lands and homes fast-forward. 1. **Overnight park.** Enter away mode with words that name an idle-fleet action (for example "keep the fleet moving, queue the next backlog item when idle"). Leave at least one worker finishing and one idle gap longer than the heartbeat interval. Next morning confirm: the host's engine log shows a turn on the idle heartbeat with the words in its prompt, an action followed from the words (or a recorded decline handed back to main), and no captain-facing chatter for routine wakes. 2. **Usage-limit hit.** While away, let the engine's account reach its limit (or run with a low-quota account). Confirm the host records the failed turn, hands the wake back to main rather than dropping it, and resumes engine turns after the reset without a manual restart. 3. **Opt-out.** Write `off` to `config/supervision-host`, confirm the host steps aside and the plain watcher arm delivers wakes to main; remove the file to restore. Check afterwards that the live daemon and this host do not double-handle a wake (the parallel watchdog task owns that reconciliation).
A host or Pi home in the away posture has the record but no .afk flag, so the watcher absorbed every idle heartbeat and the engine never got a turn on a quiet fleet. The heartbeat block now reads the record too.

An ancestor CommonJS package.json made Node refuse the TypeScript import in bin/fm-branch-dispatch.mjs, silently handing every wake to main. A package.json in the library directory types it as ES modules.
no-mistakes(document): Document away-record heartbeat routing to the Pi branch
All checks were successful
CI / Test coverage guard (pull_request) Successful in 31s
CI / Behavior portable parallel 2 (pull_request) Successful in 15m27s
CI / Behavior portable parallel 1 (pull_request) Successful in 17m18s
CI / Lint 1 (pull_request) Successful in 21m50s
CI / Lint 2 (pull_request) Successful in 26m14s
CI / Behavior portable serial 2 (pull_request) Successful in 16m4s
CI / Behavior portable serial 1 (pull_request) Successful in 20m38s
CI / Behavior portable serial 3 (pull_request) Successful in 17m17s
CI / Behavior portable serial 4 (pull_request) Successful in 14m40s
CI / Behavior portable serial 6 (pull_request) Successful in 16m14s
CI / Behavior portable serial 7 (pull_request) Successful in 16m26s
CI / Behavior portable serial 8 (pull_request) Successful in 16m19s
CI / Behavior portable serial 5 (pull_request) Successful in 26m42s
CI / Repo invariants (pull_request) Successful in 8s
CI / Behavior tests (Herdr) (pull_request) Successful in 13m29s
CI / Behavior portable serial 9 (pull_request) Successful in 24m52s
45e297aa3f
john merged commit c8866e92a3 into main 2026-10-02 07:21:08 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
john/firstmate!42
No description provided.