What happens
tests/fm-bearings-snapshot.test.sh aborts at 28 of 42 assertions on macOS, under both Bash 5 and stock Bash 3.2:
not ok - restoring the SSHHIP child did not clear only its narrow warning: { ... }
bin/fm-fleet-snapshot.sh is behaving correctly. The fixture hands it a corrupted backlog.
Cause
Two fixture mutations use sed's a\ append with the appended text as the last thing in the script and no trailing newline — tests/fm-bearings-snapshot.test.sh:1667 and :1706:
sed '/## In flight/a\
- [ ] unreadable-child - Submit App Store build (repo: sshhip) (kind: ship)' \
"$sshhip/data/backlog.md" > "$sshhip/data/backlog.next"
BSD/macOS sed emits that appended text without a trailing newline, relying on the script's own newline that isn't there. GNU sed always terminates it. Replayed byte-exactly on macOS:
$ printf '## In flight\n## Queued\n- [ ] reviewer-decision - x\n' > /tmp/in.txt
$ sed '/## In flight/a\
- [ ] unreadable-child - Submit App Store build (repo: sshhip) (kind: ship)' /tmp/in.txt | od -c | tail -4
0000060 S t o r e b u i l d ( r e
0000100 p o : s s h h i p ) ( k i n
0000120 d : s h i p ) # # Q u e u e
0000140 d \n - [ ] r e v i e w e r
(kind: ship)## Queued — the ## Queued header is glued onto the appended line and stops being a section header.
Downstream, reviewer-decision then parses as an in-flight held item instead of a queued one. bin/fm-fleet-snapshot.sh sets captain_actionable only when .state == "queued", so the record drops out of the captain-holds set, decisions_open comes back empty, and the snapshot falls through captain_decision to active_child_work. Every assertion after that point is testing a corrupted fixture.
This is also why CI is green: .github/workflows/ci.yml runs the Bearings assertions on ubuntu with GNU sed.
Reproduce
At 99533c5 on macOS:
bash tests/fm-bearings-snapshot.test.sh
| Invocation |
Runs |
Result |
| unmodified, Bash 5.3.9 |
2 |
exit=1, 28 ok |
unmodified, stock /bin/bash 3.2.57 |
1 |
exit=1, 28 ok |
Expected: 42 ok, exit 0 (what CI sees on ubuntu).
Actual: aborts at 28 on any BSD-sed host.
Test-only counterfactual
Replacing only those two fixture appends with a portable awk, touching nothing under bin/:
- sed '/## In flight/a\
-- [ ] unreadable-child - Submit App Store build (repo: sshhip) (kind: ship)' \
+ awk '{print} /## In flight/{print "- [ ] unreadable-child - Submit App Store build (repo: sshhip) (kind: ship)"}' \
"$sshhip/data/backlog.md" > "$sshhip/data/backlog.next"
(and the same shape for the /unreadable-child/ append at :1667)
runB-fix1 (bash 5) exit=0 ok=42
runB-fix2 (bash 5) exit=0 ok=42
runB-fix3 (bash 3.2) exit=0 ok=42
Proposed minimal fix
The two-line awk '{print} /pattern/{print "..."}' substitution above. It is portable across BSD and GNU, needs no GNU-sed dependency, and is byte-identical in output to what the test intends. An alternative — adding an explicit trailing newline inside the sed script — also works on BSD but is fragile to reformatting, so awk is the safer shape.
Duplicate search
No existing issue or PR reports this. Searched fm-bearings-snapshot, bearings snapshot test, BSD sed, sed portability, sed macOS, test fails macOS. Checked the file lists of every open Bash-3.2/macOS PR (#1200, #1196, #1125, #1117, #1003, #989) and of #1119 — none of them touches tests/fm-bearings-snapshot.test.sh.
Environment
- firstmate
99533c5d7d3702050e6084429dddff6ea4fe1aa0
- macOS 15.7.7, Darwin 24.6.0, arm64 — BSD
sed
- Bash 5.3.9 (Homebrew) and stock
/bin/bash 3.2.57
What happens
tests/fm-bearings-snapshot.test.shaborts at 28 of 42 assertions on macOS, under both Bash 5 and stock Bash 3.2:bin/fm-fleet-snapshot.shis behaving correctly. The fixture hands it a corrupted backlog.Cause
Two fixture mutations use
sed'sa\append with the appended text as the last thing in the script and no trailing newline —tests/fm-bearings-snapshot.test.sh:1667and:1706:BSD/macOS
sedemits that appended text without a trailing newline, relying on the script's own newline that isn't there. GNU sed always terminates it. Replayed byte-exactly on macOS:(kind: ship)## Queued— the## Queuedheader is glued onto the appended line and stops being a section header.Downstream,
reviewer-decisionthen parses as an in-flight held item instead of a queued one.bin/fm-fleet-snapshot.shsetscaptain_actionableonly when.state == "queued", so the record drops out of the captain-holds set,decisions_opencomes back empty, and the snapshot falls throughcaptain_decisiontoactive_child_work. Every assertion after that point is testing a corrupted fixture.This is also why CI is green:
.github/workflows/ci.ymlruns the Bearings assertions on ubuntu with GNU sed.Reproduce
At
99533c5on macOS:/bin/bash3.2.57Expected: 42 ok, exit 0 (what CI sees on ubuntu).
Actual: aborts at 28 on any BSD-sed host.
Test-only counterfactual
Replacing only those two fixture appends with a portable
awk, touching nothing underbin/:(and the same shape for the
/unreadable-child/append at:1667)Proposed minimal fix
The two-line
awk '{print} /pattern/{print "..."}'substitution above. It is portable across BSD and GNU, needs no GNU-sed dependency, and is byte-identical in output to what the test intends. An alternative — adding an explicit trailing newline inside the sed script — also works on BSD but is fragile to reformatting, soawkis the safer shape.Duplicate search
No existing issue or PR reports this. Searched
fm-bearings-snapshot,bearings snapshot test,BSD sed,sed portability,sed macOS,test fails macOS. Checked the file lists of every open Bash-3.2/macOS PR (#1200, #1196, #1125, #1117, #1003, #989) and of #1119 — none of them touchestests/fm-bearings-snapshot.test.sh.Environment
99533c5d7d3702050e6084429dddff6ea4fe1aa0sed/bin/bash3.2.57