fix(bin): sync upstream main into house (hold reasons, orphan arms, hand-back downtime, polling churn) - #177
Merged
Merged
Conversation
) * test(calm): pin Pi's regular TUI mode where pane assertions read scrollback Pi 1.0.0 defaults its TUI to a fullscreen alternate-screen mode whose scrollable transcript is application-owned, so rows that leave the viewport never enter terminal scrollback and tmux capture-pane -S can no longer see them. The Pi Calm e2e launches now pass --tui-mode regular wherever the flag exists so the transcript assertions keep reading real scrollback on both the Pi 1.0.0 line and earlier Pi lines, which have no such flag and render regular-only anyway. * no-mistakes(document): Correct Pi TUI documentation and scrollback rationale
…ries (kunchenguid#6331) * fix(bin): encode captain-hold reasons and reject self-inventory in complete hold now stores a reason with parentheses, line breaks, or percent signs through a reversible percent encoding that every reader decodes, instead of refusing it. hold --origin records the origin on the held task, and complete refuses the origin as its own inventory entry and an entry held for a different origin; holds with no recorded origin are accepted and flagged. * fix(review): Decode marked hold reasons consistently across readers * fix(review): Remove unnecessary lifecycle test dispatch * fix(review): Correct hold origin identity and inventory recovery * fix(review): Record origins before placing backend holds * fix(document): Clarify captain-hold validation and reason reader documentation * fix(ci): Fixed both findings: failed backend holds restore the previous origin, and invalid base64/UTF-8 reasons remain verbatim. Added regressions and documented valid-literal ambiguity. Both failures were reproduced before fixes. Verification: 54 lifecycle tests and 9 wrapper tests passed; 7 Beads-specific cases skipped because tasks-axi is markdown-only. Focused lint and diff checks passed. No pipeline or publication actions performed
* fix(bin): take over the watcher cycle a main-only pass-through leaves An attended main-only pass-through leaves a successor watcher cycle running through main's handling turn. The session's next park attached to that cycle instead of owning it, so the successor's arm, orphaned by its host's exit, kept owning the watcher while the new park's arm polled it twice a second until the next close or the park boundary, hours later in a quiet second mate. A second-mate restart hit this every time, since its persist request is a main-only close. The host now records the successor it leaves for main, and the next host's first cycle runs bin/fm-watch-arm.sh --take-over on it: when that arm still owns the healthy watcher, the new arm stops it, reports a reason the cycle delivered first, and otherwise owns a fresh cycle. The stop's own downtime publication is undone over an acknowledged episode when no wake was appended in between, so the handover wakes nobody. * no-mistakes(review): Keep left-arm record until the orphaned arm is gone * no-mistakes(review): Relinquish successor arm only after durably recording it * no-mistakes(review): Relinquish successor only after its record reads back * no-mistakes(document): Clarify successor takeover guarantees and authoritative documentation * no-mistakes(ci): Fixed ci-1: acknowledgement restore now requires the exact taken-over arm/watcher ledger row with signal=TERM, awaited within a short bound. Otherwise takeover proceeds without erasing downtime. Added a self-exit regression confirmed failing before the fix and passing afterward; ordinary takeover tests and the full watcher-arm suite pass. Updated Generation reuse documentation. Syntax, diff checks, and ShellCheck pass with existing SC1091/SC2034 warnings excluded. ci-2 remains unchanged * no-mistakes(document): Clarify watcher take-over recovery and restart limits
…cessor already closed (kunchenguid#6355) * fix(bin): restore supervision host hand-back continuity * no-mistakes(review): Scope host hand-back failure fallback to lost pending:handling * no-mistakes(review): Remove stray scratch test copy tests/.tmp-rest.test.sh * no-mistakes(test): Initialise successor globals so early hand-back survives set -u * no-mistakes(document): Document host hand-back downtime failure and Claude lost-handback notice * no-mistakes(ci): I fixed the Greptile finding. The rule that must hold: when the supervision host hands back an actionable wake, its rewake is refused, and no watcher is healthy, the hand-back still has to reach main as a delivered notice. That must be true whether the recovery marker is `pending:handling` or `announced:handling`. Only one place applies this check: the lost hand-back fallback in `bin/fm-claude-stop-autoarm.sh`. **Fix:** that check now accepts both `pending:handling:*` and `announced:handling:*` tokens (a one-line change). Nothing else in the fallback changed: - Refusals on any other marker, such as an already acknowledged one, still exit 0 silently and open no failure episode. - The notice is still sent once per episode, and repeats are recorded as `failed-suppressed`. **Tests:** - `tests/fm-claude-stop-autoarm.test.sh`: the lost hand-back test now runs as a shared helper with two variants, one writing a `pending:handling` marker and a new one writing `announced:handling` (`test_host_lost_announced_handback_notifies_once_per_episode`). - `tests/fm-supervision-host.test.sh`: the end-to-end test where downtime restoration fails is now a shared helper too, with a new `announced` variant (`test_claude_stop_hook_notifies_when_closed_announced_successor_downtime_restore_fails`). It moves the handling episode to `announced` before the host hands back. Without the fix the hook would exit 0 here; the test requires exit 2, `outcome=failed` and a delivered failure notice. **Verification (all under nice -n 10):** - The full `tests/fm-claude-stop-autoarm.test.sh` suite passed (rc=0), including both lost hand-back variants and the benign-refusal test. - In `tests/fm-supervision-host.test.sh` I ran only the four hand-back test functions, all passing (rc=0). The suite can't run single functions, so I used a temporary copy with a trimmed test list and deleted it afterwards; `git status` shows only the 3 intended files changed. - shellcheck is clean on all three changed files. I did not run `bin/fm-lint.sh`. - I did not run the new tests against the unfixed code; the claim that they fail without the fix comes from reading the old check
* perf: cut remote-job idle process creation in the three hot loops Post-update host measurement still attributes most idle churn to three per-sample loops: result-consumer state reads and date calls, the delta reader's capture/hash pass on every poll, and the lane preemption scan's per-field pipelines. This drops each to its minimum without touching the contracts around them. * fm_remote_job_read_state gains an optional result-variable form backed by fm_remote_job_read_line, a builtin-only bounded record read (regular non-symlink file, byte bound, one newline-terminated line, tolerated unterminated tail, no carriage returns). fm_remote_job_wait samples state and the SECONDS clock with no per-sample children; one date call converts the epoch deadline once. * fm-remote-delta-read stats the log each poll and re-runs the bounded capture and hashing only when size, mtime, ctime, inode, or device change. The snapshot's own stat writes the comparison key, so a log that moves between the gate and the capture is never read as stable. * worker_preempting_waiter_exists reads state, home, and the staged argv head with builtins only. The now-unused worker_job_command goes away. The bounded reads use -d '' -n, which behaves identically on the macOS stock bash 3.2 and current bash; -N does not exist on 3.2. Tests cover the malformed-record corpus, delta identity gating, fork-free lane scanning through counting PATH shims, and same-home versus cross-home preemption. No signal traps or sleep contracts change. * no-mistakes(review): Restore subsecond delta keys and byte-bounded builtin record reads * no-mistakes(document): Clarify delta snapshot caching and coarse-timestamp fallback * no-mistakes(lint): Scope UTF-8 regression locales to individual function calls * no-mistakes(ci): Fixed both lint failures by applying the documented production-library analysis boundary at the two affected test imports. Runtime behavior is unchanged; the library remains independently linted. Canonical full-analysis lint passed for the library and both suites, as did bash syntax checks and git diff --check
Integrate upstream through 65e2aa4 with house provisioning bounds, ready timeout reporting, and per-row supervision receipts preserved. Retain the command helper used by house timeout validation and diagnostics alongside upstream polling optimizations.
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
you better have a look and bring in upstream main for firstmate and no mistakes
Context for reading that ask. The fork jazz127/firstmate runs
house(default branch, merge commits only) as the line the fleet runs from; itsmainmirrors upstream kunchenguid/firstmatemain. Forkhouseis at 79066a8. Upstreammainis at 65e2aa4, five commits past the last sync: 349e189 (Pi 1.0 calm transcript test captures, kunchenguid#6338), 6af8331 (preserve hold reasons and reject invalid completion inventories, kunchenguid#6331), 8690c41 (reclaim orphaned watcher arms on the next park, kunchenguid#6335), 241d461 (restore downtime on supervision-host hand-back when the successor already closed, kunchenguid#6355), 65e2aa4 (reduce remote-job polling process churn, kunchenguid#6363). A read-only trial merge conflicts in bin/fm-remote-job-lib.sh, bin/fm-session-start.sh and tests/fm-supervision-host.test.sh.Integration
Merge pinned upstream main
65e2aa443a42108689eee260a0d792608ec3540binto forkhousefrom79066a8692bcf5762abcc532697d36e28574b4eawith a true merge commit.The fork main mirror step was skipped per steering; no fork main branch was created or pushed.
Preserve house provisioning bounds, ready-session timeout reporting, remote worker lifecycle guards, and per-row supervision receipts while integrating upstream hold-reason decoding, watcher takeover, hand-back downtime restoration, Pi transcript fixtures, and remote polling optimizations.
Restore
worker_job_commandfor the house callers retained after upstream removed it from the polling path.Dropped house behavior: none.
This PR must land with a merge commit.
All 16 affected test scripts passed, plus the separate provisioning regression.
Synthetic/offline validation is recorded in the task evidence artifact.
The before fixture models the auto-merged worker without its removed helper: the first long provisioning request exits 126 before cloning.
Restoring the helper makes the provisioning suite pass, including command-named timeout diagnostics and recovery after interruption.
No remote host or multi-GiB clone was exercised.
Linux-only remote worker lifecycle and session-start /proc ancestry cases are not exercised on this macOS host.
No-mistakes Test exception: its targeted batch stopped at its time limit after remote-job, delta-read, and 50 passing supervision-host cases; the remaining pipeline suites were not exercised.
Firstmate expressly accepted the inconclusive Test result for this sync.
The separate worker run completed all 16 affected suites successfully.
House CI must be green before merge; its configured scope is house delivery/workflow regressions, lint, and inventory coverage.
Known baseline lint findings: the two SC2031 warnings in house's PIDFD test PATH reads also reproduce on the unmodified house test file; upstream's test file is clean.
These baseline findings were left unchanged.
evidence-artifact: /Users/jarad/.treehouse/firstmate-570371/1/firstmate/data/hf-upstream-main-sync-5/integration-notes.txt
evidence-command: git ls-remote upstream refs/heads/main
evidence-captured: 2026-10-02T10:49:22Z
Evidence classification
The pipeline attestation below is preserved verbatim.
Its
live_validationclassification of three scenarios refers to Bash CLI probes in disposable fixture homes: worker refusal, full startup digest, and hold-reason readback.The artifacts show synthetic/offline checks of our code, with no real-account, remote-host, or independent harness validation.
All three probes passed; the pipeline's other four scenarios were not driven through that scenario-validation path.
Git ancestry is confirmed separately by the merge's two parents, and the complete local affected-suite run provides the broader synthetic regression evidence.