fix(backends): make a missing adapter file a guardable refusal under set -e - #3512
Open
npayette84 wants to merge 1 commit into
Open
Conversation
fm_backend_source attempted . backends/<name>.sh with only an || return 1 guard, but on bash 3.2 a failed source of a nonexistent file is a fatal special-builtin error under set -e even inside ||/if guards: the whole caller shell exited with status 0 and its EXIT trap, so fm-teardown.sh's herdr preflight never reached its 'prerequisites are unavailable; nothing was changed' refusal and teardown silently reported success while doing nothing. This is the reproducible herdr-preflight-missing-adapter fixture failure in tests/fm-teardown.test.sh, failing since the fixture landed in 66b0f77 on stock macOS bash. Precheck adapter existence in fm_backend_source - the single owner of adapter sourcing - so a missing adapter returns 1 guardably for every backend and every caller, letting each consumer's own refusal fire. Every other failure class keeps its existing fail-stop behavior; no errexit suppression is introduced anywhere. Add a library-boundary regression in tests/fm-backend.test.sh: under set -eu, sourcing with the adapter absent must refuse instead of killing the caller. It fails before the fix (caller shell died, rc=1) and passes after; the existing teardown fixture stays the end-to-end regression. Validated on macOS stock bash 3.2.57 from a fresh upstream/main base: tests/fm-teardown.test.sh 58 ok (all four preflight refusal modes), tests/fm-backend.test.sh (new regression red on base, green here), tests/fm-backend-herdr.test.sh 182 ok, tests/fm-afk-launch.test.sh 46 ok, tmux/cmux smoke rc 0, bin/fm-lint.sh and bin/fm-doc-audience-check.sh clean, /bin/bash -n parse coverage over bin/*.sh and bin/backends/*.sh.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Confidence Score: 5/5The PR appears safe to merge, with no actionable correctness or security failures identified. The existence check uses the same adapter path subsequently sourced and converts only the documented missing-file failure into a normal refusal while preserving successful adapter loading. Reviews (1): Last reviewed commit: "fix(backends): make a missing adapter a ..." | Re-trigger Greptile |
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
Ship the independently selected correction for the pre-existing macOS Bash 3.2 herdr-preflight-missing-adapter teardown fixture failure: fm_backend_source on stock bash 3.2 under set -e made a failed source of a missing adapter file fatal to the caller shell even inside ||/if guards, so fm-teardown.sh's herdr preflight exited 0 silently through its EXIT trap instead of printing the 'prerequisites are unavailable; nothing was changed' refusal, which is the herdr-preflight-missing-adapter fixture failure in tests/fm-teardown.test.sh. The fix is exactly the judge-selected candidate B (commit e0b5d224): a seven-line existence precheck ([ -f "$FM_BACKEND_LIB_DIR/backends/$name.sh" ] || return 1) inserted in fm_backend_source right after fm_backend_validate, plus its focused library-boundary regression test in tests/fm-backend.test.sh (under set -eu, sourcing with the adapter absent must refuse instead of killing the caller). Requirements and exclusions: do not import candidate A's errexit bracket helper (fm_backend_source_file) because it can misreport a half-loaded adapter as successfully sourced and let destructive teardown cleanup proceed; do not broaden into corrupt, unreadable, or partial-install adapter handling; preserve the existing fail-stop behavior for every non-missing-file failure class; base must be the fresh current upstream/main and the PR targets upstream/main without merging. Already verified before this run: the patch bytes match candidate B exactly; the new regression test is red on the unmodified upstream base (caller shell died rc=1) and green on the branch; and the full prescribed validation set passed on macOS stock bash 3.2.57 (teardown 58 ok including all four preflight refusal modes, backend suite with the new regression, herdr backend suite, afk-launch suite, tmux/cmux smoke rc 0, fm-lint clean, doc-audience-check ok, bash -n parse coverage over bin/.sh and bin/backends/.sh).
What Changed
fm_backend_sourceinbin/fm-backend.shnow checks that$FM_BACKEND_LIB_DIR/backends/$name.shexists and returns 1 if it does not, right afterfm_backend_validateand before any.of the adapter. On bash 3.2 a failed.on a nonexistent file is a fatal special-builtin error even inside||andifguards, so callers running underset -ewere exiting instead of taking their refusal path. The precheck means the source only ever runs against a file that is present.test_backend_source_missing_adapter_refuses_guardablytotests/fm-backend.test.sh, registered in the suite runner. It sources the library underset -eu, pointsFM_BACKEND_LIB_DIRat an empty backends directory, and asserts two things: the caller shell survives (rc 0) and the guard reportsrefused.Risk Assessment
✅ Low: A single guarded existence precheck whose only behavioral delta is turning a fatal missing-file source into a returnable refusal — every known backend has its adapter present so normal paths are unchanged, fail-stop is preserved for all other failure classes, and the change is accompanied by a behavior-level regression test on an unmodified upstream base.
Testing
Ran the two targeted suites on macOS stock bash 3.2.57 - tests/fm-teardown.test.sh (58 ok, rc 0, all four herdr preflight refusal modes including the previously failing missing-adapter fixture) and tests/fm-backend.test.sh (29 ok, rc 0, including the new library-boundary regression) - then produced the end-user evidence by invoking the real bin/fm-teardown.sh --force against an install with the herdr adapter deleted, once with the pre-fix base fm-backend.sh and once with the branch's: pre-fix exits 0 with only a raw "No such file or directory" line, post-fix exits 1 with the visible "prerequisites are unavailable ... nothing was changed" refusal and every record, the task branch and the isolated copy intact with no treehouse return or pane close attempted. A base-vs-branch failure-class probe confirms the change is confined to the missing-file case, with syntax-error, unreadable and nonzero-return adapters retaining identical fail-stop behavior. No UI surface is involved, so the reviewer-visible artifacts are CLI transcripts; the worktree was left clean.
Evidence: Teardown CLI transcript: missing herdr adapter, pre-fix vs post-fix
Source: Teardown CLI transcript: missing herdr adapter, pre-fix vs post-fix
CASE: before-fix (bin/backends/herdr.sh deleted; fm-backend.sh from 763f597) $ bin/fm-teardown.sh task-x1 --force --- stderr --- .../bin/fm-backend.sh: line 609: .../bin/backends/herdr.sh: No such file or directory --- exit code: 0 exit status : 0 (operator is told teardown succeeded) refusal explained : NO (silent) CASE: after-fix (bin/backends/herdr.sh deleted; fm-backend.sh from the branch) $ bin/fm-teardown.sh task-x1 --force --- stderr --- error: herdr teardown prerequisites are unavailable for task-x1; nothing was changed - restore the adapter and rerun teardown --- exit code: 1 exit status : NON-ZERO (operator sees a failure) refusal explained : yes ('nothing was changed' printed) endpoint metadata : preserved task status record : preserved isolated copy (wt) : preserved on fm/task-x1 treehouse return run : no herdr pane close : noEvidence: Failure-class parity under set -eu on bash 3.2.57 (base vs branch)
Source: Failure-class parity under set -eu on bash 3.2.57 (base vs branch)
bash: 3.2.57(1)-release base ok caller-rc=0 guarded-result=sourced branch ok caller-rc=0 guarded-result=sourced base missing caller-rc=1 guarded-result=<caller shell died before the guard> branch missing caller-rc=0 guarded-result=refused base nonzero caller-rc=0 guarded-result=refused branch nonzero caller-rc=0 guarded-result=refused base syntax caller-rc=2 guarded-result=<caller shell died before the guard> branch syntax caller-rc=2 guarded-result=<caller shell died before the guard> base unreadable caller-rc=1 guarded-result=<caller shell died before the guard> branch unreadable caller-rc=1 guarded-result=<caller shell died before the guard>Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
tests/fm-backend.test.sh:515- The regression test sets FM_BACKEND_LIB_DIR to a directory it created and namedbackends, so the path fm_backend_source actually consults is$TMP_ROOT/missing-adapter-lib/backends/backends/herdr.sh— the mkdir'd directory is the lib dir, not the adapter dir. The case therefore exercises "adapter parent directory absent" rather than the fixture's real shape (populatedbackends/dir with onlyherdr.shremoved). Both fail[ -f ]identically, so the test is valid and still red-before/green-after, buttmpbin="$TMP_ROOT/missing-adapter-lib"; mkdir -p "$tmpbin/backends"would mirror tests/fm-teardown.test.sh:1560 exactly and prove the precheck keys on the file rather than on the missing directory.bin/backends/herdr.sh:79- The same silent-exit-0 class remains reachable one level down: bin/backends/herdr.sh:79 and :87 source fm-composer-lib.sh and fm-transition-lib.sh unguarded, so a partial install where the adapter is present but a sibling lib is missing still kills the caller shell under set -e before teardown's refusal prints. This is explicitly excluded by the intent ("do not broaden into corrupt, unreadable, or partial-install adapter handling") and the change correctly preserves fail-stop for that class, so no action is expected here — noting it only as the known remaining boundary of this fix.✅ **Test** - passed
✅ No issues found.
bash tests/fm-teardown.test.sh(58 ok, rc 0; includes herdr-preflight-missing-adapter, missing-parser, missing-explicit-close-helper, unresolvable-lock)bash tests/fm-backend.test.sh(29 ok, rc 0; includestest_backend_source_missing_adapter_refuses_guardably)Manual CLI reproduction: realbin/fm-teardown.sh task-x1 --forcerun against an install withbin/backends/herdr.shremoved, executed twice - once with base 763f597bin/fm-backend.sh(pre-fix) and once with the branch's - capturing stdout/stderr, exit code, record survival, treehouse-return and herdr pane-close side effectsFailure-class parity probe underset -euon bash 3.2.57 comparing base vs branchfm_backend_source herdrfor present/missing/nonzero-return/syntax-error/unreadable adapter files✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.