Conversation
keenvc
added a commit
to keenvc/firstmate
that referenced
this pull request
Sep 20, 2026
…ot wedge a supervisor
This was referenced Sep 30, 2026
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.
Problem
Herdr
capture/composer_state-style supervisor probes (and every other synchronous herdr CLI read) ran with no bounded read timeout. A wedged herdr server or a hung pane read blocked the calling supervisor indefinitely and leaked one stuck shell per occurrence instead of failing loudly and freeing the caller.Fix
Every synchronous herdr CLI read/write in
bin/backends/herdr.shnow runs under a real process-level bound through the repo-wide bounded runnerbin/fm-timeout-lib.sh(fm_run_timed), which kills the whole child process group and reports the bound as exit 124.FM_BACKEND_HERDR_CLI_TIMEOUT(default 10s, invalid/zero falls back to 10) plus afm_backend_herdr_boundedhelper.fm_backend_herdr_cli(the single owner every capture, composer-state, busy-state, pane/agent read, and write goes through), its protocol-mismatch retry,fm_backend_herdr_client_status,fm_backend_herdr_version_check,fm_backend_herdr_resolve_bare_selector,fm_backend_herdr_socket_path, andfm_backend_herdr_events_capable.herdr serverlaunch stays exempt: its purpose is to outlive the call and a bound would kill the server. A regression test pins that exemption so it cannot be bounded by accident.Audit
bin/backends/herdr.shis the only supervision path that calls herdr:fm_backend_capture,fm_backend_composer_state,fm_backend_busy_state, and the recovery-grade liveness reads all dispatch into it. The remaining direct herdr invocations in the repo are outside ordinary supervision (fm-remote-doctor.sh,fm-herdr-ci-cleanup.sh,fm-install-herdr.sh,fm-remote-herdr-guard.sh,fm-herdr-lab.sh), and the event subscriber (bin/backends/herdr-eventwait.py) keeps its own bounded socket reader.Test
tests/fm-backend-herdr-probe-timeout.test.shfakes a herdr that ignoresTERMand never answers a read, then asserts for capture, composer-state, and the generic CLI owner that the call returns within the bound and the recorded process is gone (the KILL escalation reaps a TERM-ignoring child). It also asserts theserverlaunch is not bounded. Portable, no real herdr required.Verification
bash tests/fm-backend-herdr-probe-timeout.test.sh- 4/4 okbash tests/fm-backend-herdr.test.sh- all okbash tests/fm-herdr-session-cleanup.test.sh,fm-busy-state,fm-task-inbox,fm-send-strict,fm-send-resolve-key,fm-agy-harness,fm-busy-adapter-wiring- all okbin/fm-lint.sh bin/backends/herdr.sh bin/fm-test-run.sh tests/fm-backend-herdr-probe-timeout.test.sh- exit 0bin/fm-test-run.sh --check-coverage- ok total=219bin/fm-doc-audience-check.sh- okDocs
docs/herdr-backend.md"Current transport behavior" anddocs/configuration.mddocument the bound, its default, and the server exemption.