The claim vs the behavior
scripts/lib/plan-paths.sh:10 states:
# bash 3.2 (macOS stock) compatible: no associative arrays, no `mapfile`.
That claim is currently false. The file has not parsed under bash 3.2 since the
premise-freshness lint (#74) landed.
Repro
On stock macOS (/bin/bash is 3.2.57):
$ /bin/bash -n scripts/lib/plan-paths.sh
scripts/lib/plan-paths.sh: line 171: syntax error near unexpected token `;;'
scripts/lib/plan-paths.sh: line 171: ` case "$token" in *//*) continue ;; esac # drop URL host:port'
$ /bin/bash scripts/lint-plan.sh .agents/plans/any-plan.md
scripts/lib/plan-paths.sh: line 171: syntax error near unexpected token `;;'
$ echo $?
2
Confirmed pre-existing on main (same construct, line 120 there).
Cause
Bash 3.2's parser bug: a ) in a case pattern inside a $( ) command
substitution closes the substitution early. The offending case sits inside
the command substitution that builds plan_cited_anchors' result.
Why it matters
Every script here uses #!/usr/bin/env bash, so on a machine with no newer bash
ahead of /bin/bash on PATH, scripts/lint-plan.sh exits 2 with a syntax
error instead of linting. A gate that fails to run is worse than one that runs
noisily — the same gate-legibility family as #98/#99/#101.
CI does not catch it (the runner has bash 4+), and lint-shell-safety.sh does
not parse-check.
Fix
Write the patterns with a leading paren, which 3.2 parses correctly:
case "$token" in (*//*) continue ;; esac
Apply to every case pattern inside a command substitution in the file, then
either verify the header claim holds or drop the claim.
Suggested guard
A parse check — /bin/bash -n (or any 3.2) over every tracked scripts/**/*.sh
— would keep the claim honest. The natural home is lint-shell-safety.sh, which
already enumerates tracked scripts via git ls-files -s after #101.
Provenance
Found by the Wave 2 agent during delivery of the #98/#99/#101 bundle
(branch rad/gate-legibility-lints). Left unfixed there deliberately:
pre-existing, unrelated to #98, and outside that plan's approved scope.
The claim vs the behavior
scripts/lib/plan-paths.sh:10states:That claim is currently false. The file has not parsed under bash 3.2 since the
premise-freshness lint (#74) landed.
Repro
On stock macOS (
/bin/bashis 3.2.57):Confirmed pre-existing on
main(same construct, line 120 there).Cause
Bash 3.2's parser bug: a
)in acasepattern inside a$( )commandsubstitution closes the substitution early. The offending
casesits insidethe command substitution that builds
plan_cited_anchors' result.Why it matters
Every script here uses
#!/usr/bin/env bash, so on a machine with no newer bashahead of
/bin/bashon PATH,scripts/lint-plan.shexits 2 with a syntaxerror instead of linting. A gate that fails to run is worse than one that runs
noisily — the same gate-legibility family as #98/#99/#101.
CI does not catch it (the runner has bash 4+), and
lint-shell-safety.shdoesnot parse-check.
Fix
Write the patterns with a leading paren, which 3.2 parses correctly:
Apply to every
casepattern inside a command substitution in the file, theneither verify the header claim holds or drop the claim.
Suggested guard
A parse check —
/bin/bash -n(or any 3.2) over every trackedscripts/**/*.sh— would keep the claim honest. The natural home is
lint-shell-safety.sh, whichalready enumerates tracked scripts via
git ls-files -safter #101.Provenance
Found by the Wave 2 agent during delivery of the #98/#99/#101 bundle
(branch
rad/gate-legibility-lints). Left unfixed there deliberately:pre-existing, unrelated to #98, and outside that plan's approved scope.