test(NO-TASK): Filter the bash 5 job-control warning, and preflight the CI matrix locally - #76
Open
aaronware wants to merge 3 commits into
Open
test(NO-TASK): Filter the bash 5 job-control warning, and preflight the CI matrix locally#76aaronware wants to merge 3 commits into
aaronware wants to merge 3 commits into
Conversation
…sh 3 wording `bash -i` with no controlling terminal complains about job control on stderr, and the wording depends on the bash version. macOS ships bash 3.2, which prints only "no job control in this shell" — the string this filter matched. Every CI runner has bash 5, which prints "cannot set terminal process group (N): Inappropriate ioctl for device" first, so the filter let a line through and two `assert.equal(stderr, '')` checks failed on Linux and nowhere else. Match the family rather than one member of it, so the test measures the snippet instead of the platform. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A green `npm test` on a workstation is evidence about macOS, not about ubuntu-latest, and this CLI shells out to bash, git and the filesystem — where the two platforms differ in behaviour and in wording. The bash 5 job-control regression in the previous commit passed locally and failed in CI for exactly that reason. `npm run preflight` runs the local gates, and now runs on git push via a husky pre-push hook. `npm run preflight:linux` stages the working tree into a node container per matrix version, removes ignored files so the container sees a clean checkout plus uncommitted edits, and runs install, typecheck, build, test and the agent-readiness floor. The matrix, the linter version and the score floor are read out of ci.yml rather than restated, and the scorer that was inlined in the workflow now lives in scripts/agent-lint-report.mjs so both callers compute the score the same way. A preflight that could disagree with the gate it previews would be worse than no preflight at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CLAUDE.md is new: it says what to run before pushing, which changes make preflight:linux non-optional — spawning a shell, shelling out, filesystem semantics, TTY and process behaviour — and how to write a test that survives the crossing. Never assert on the exact text a system tool emits, prefer a positive match over an empty-string equality, and filter noise by family rather than by the one phrasing this laptop happens to print. The bash 5 failure is cited as the worked example, since a rule with a scar attached is easier to remember. The README Development section gains the same two commands and the reason the local run is not the evidence CI produces. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
mainis red, and #71 is only the messenger — the failure arrived with #70 and reproduces onevery PR opened since.
Why it failed
test/shell-init.test.jssources snippets inbash -i. With no controlling terminal, bashcomplains about job control on stderr, and the helper filtered that noise out:
That is the entire message bash 3.2 prints — the version macOS ships. Bash 5, on every CI
runner, prints a second line first:
The filter dropped the second line and let the first through, so two
assert.equal(stderr, '')checks failed on Node 22.12 and 24.
Agent-readinessnever ran at all — itneeds: test.The fix matches the family rather than one member of it.
Why it got past us, and what now stops it
npm testpassing on a workstation is evidence about macOS, not aboutubuntu-latest, and thisCLI shells out — to bash, to git, to the filesystem — where the two differ in behaviour and in
wording. Nothing we had could have caught this before CI did.
npm run preflight— typecheck, build, test. Also runs ongit pushvia a new huskypre-pushhook.npm run preflight:linux— stages the working tree into anode:<version>container permatrix entry, runs
git clean -Xdfinside so the container sees a clean checkout plus youruncommitted edits, then install → typecheck → build → test → the agent-readiness floor.
The matrix, the linter version and the score floor are read out of
ci.ymlrather than restated,and the scorer that was inlined in the workflow now lives in
scripts/agent-lint-report.mjssothe workflow and the preflight compute the score with the same code. A preflight that could
quietly disagree with the gate it previews would be worse than no preflight.
CLAUDE.mdis new: which changes makepreflight:linuxnon-optional, and how to write a testthat survives the crossing — never assert on the exact text a system tool emits, prefer a
positive match over an empty-string equality, filter noise by family rather than by the phrasing
your laptop happens to print.
Verification
Run locally before pushing, both directions:
Green on macOS and red on Linux in a single command, which is the failure mode this PR exists to
remove.
One thing to decide separately
Agent-readiness measures 86.4% in the container against the recorded 84% floor. Ignored
files are stripped inside it, so that should be a CI-faithful number rather than the inflated
local reading
ci.ymlwarns about — if this PR's CI run agrees, the floor is 2.4 points behindthe score and worth raising deliberately.
🤖 Generated with Claude Code