fix(bin): restore timed worker launches on Bash 3.2 - #32
Merged
Merged
Conversation
added 2 commits
September 29, 2026 22:53
…h 3.2
fm_exec_timed read $BASHPID unguarded to tell whether it was called from
the script itself (the exec replaces the script, so the owner is its
parent) or from a subshell (the script stays the owner). macOS /bin/bash
3.2 has no BASHPID, so under set -u every bounded call died with
"BASHPID: unbound variable", including the tasks-axi call that moves a
backlog item to In flight on every worker launch.
Neither ${BASHPID:-} nor ${BASHPID:-$$} keeps the owner correct under
bash 3.2. The empty default never matches, so a direct caller's owner
becomes the watchdog itself and a parent that dies during watchdog
startup goes undetected. The $$ default always matches, so a subshell
caller's owner becomes the script's parent instead of the script: a
script that dies during startup goes undetected, and the command is
ended when the script's parent exits even though the script lives.
The watchdog now makes the same decision from its own pid instead: after
the exec, perl's $$ is the pid of the shell that called fm_exec_timed,
so an owner equal to it means the caller was the script itself and the
owner resolves to the $PPID bash passes in. This is exact on every bash
version and unchanged under bash 5.
The timeout-lib tests now run both startup-owner cases, subshell and
direct caller, under stock /bin/bash 3.2 where it exists, and pin that a
set -u bash 3.2 caller runs the command and gets its status back.
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
Standing guidance from the user's global instructions: when you see a bug, lint failure, or flaky test, get it fixed along the way; bug fixes start by reproducing the bug as an end user would experience it.
Context needed to read this: the running Firstmate is the fork https://github.com/rega10/firstmate. The fork sync that landed as PR 31 (merge b90709f) brought in upstream change 8a18fe2 (upstream kunchenguid#5917), which added${BASHPID:-$ $}. Reproduction on the mini:
[ "$owner" != "$BASHPID" ] || owner=$PPIDat bin/fm-timeout-lib.sh:224 inside fm_exec_timed. macOS /bin/bash 3.2 has no BASHPID, and Firstmate scripts run underset -u, so fm_exec_timed dies with "BASHPID: unbound variable". On the MacBook, where the only bash is /bin/bash 3.2, every worker launch now fails while moving the backlog item to In flight. That blocks the LocMon central deploy and a dashboard PR. Every other script in bin/ already guards the variable as/bin/bash -c 'set -u; source bin/fm-timeout-lib.sh; fm_exec_timed 5 1 true'prints "bin/fm-timeout-lib.sh: line 224: BASHPID: unbound variable".What Changed
BASHPIDvariable under Bash 3.2 withset -u.Risk Assessment
✅ Low: The change is confined to Bash 3.2 compatible owner resolution in the Perl watchdog and behavioral regression coverage; the reviewed call paths preserve the existing owner and timeout behavior.
Testing
The baseline reproduced the reported Bash 3.2 failure. An initial targeted run exposed a test assertion that also used
BASHPID; after fixing it, the timeout behavior tests passed. A disposable real backlog transition moved a task from Queued to In flight, with persisted state captured as evidence.set -u, a bounded command runs and returns its output and exit statusBASHPID: unbound variable; the fixed command exited 0, andtest_stock_bash32_runs_the_bounded_commandpassed.tasks-axi showreports Queued before dispatch and In flight afterward./bin/bash tests/fm-timeout-lib.test.shexercised timeout, signal, owner-death, and refusal behavior with real processes.Evidence: Bash 3.2 backlog transition
Source: Bash 3.2 backlog transition
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.
set -u, a bounded command runs and returns its output and exit statusBASHPID: unbound variable; the fixed command exited 0, andtest_stock_bash32_runs_the_bounded_commandpassed.tasks-axi showreports Queued before dispatch and In flight afterward./bin/bash tests/fm-timeout-lib.test.shexercised timeout, signal, owner-death, and refusal behavior with real processes./bin/bash -c 'set -u; eval "$(git show b90709f934cf1df09a6a1fb5519f26f639cc3de6:bin/fm-timeout-lib.sh)"; fm_exec_timed 5 1 true'/bin/bash -c 'set -u; source bin/fm-timeout-lib.sh; fm_exec_timed 5 1 true'/bin/bash tests/fm-timeout-lib.test.shDisposable worktree-local backlog: realfm_backlog_atomic_transition dispatchunder/bin/bash3.2, verified withtasks-axi showbefore and after✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.