I3949 — A printf piped into grep -q under pipefail is refused, and a here-string replaces it
scripts/ci/pipefail-check refuses, by file and line, a printf or echo piped into `grep -q` in any script that sets pipefail, and the five scripts that carried that spelling give grep the text as a here-string.
READY wave 0 · p1 · implementation profile · parallel safe
Ready. Every dependency is done, so majordomus plan start I3949 will be accepted.
Objective
scripts/ci/pipefail-check refuses, by file and line, a printf or echo piped into `grep -q` in any script that sets pipefail, and the five scripts that carried that spelling give grep the text as a here-string.
Why
Under `set -o pipefail`, grep -q exits on its first match, the printf still writing gets SIGPIPE, and the pipeline returns 141, so a match reads as no match. It shows only under load: case 547 on the 0.30.1 top. A sweep on train 5 found the same spelling in collision-gate (an accepting label read as absent), pages-check (twice: a published snapshot read as undeclared, release metadata read as not metadata), command-graph and generate-site-data, and no gate looked for it.
Current state
pipefail-check measures only the scripts that pipe under set -e without pipefail; a script that sets pipefail is never read again, and five of them pipe a printf into grep -q.
Desired state
pipefail-check exits 10 with a RACE line per site and the here-string remedy; the tree carries no such site; comments, `||`, here-strings and other readers are not findings.
Scope
- scripts/ci/pipefail-check
- scripts/ci/collision-gate
- scripts/ci/command-graph
- scripts/ci/pages-check
- scripts/generate-site-data
- test/cases/300_a_pipeline_cannot_hide_a_failure.sh
- .ai/repo/project/issues/I3949.yaml
Out of scope
- Pipes into `head`, which pipefail exposes the same way only when the producer outwrites the pipe buffer; 69 sites, each to be judged by its producer
- scripts/ci-plan, which pipes printf into grep -q but sets no pipefail, so its status is grep's own
Dependencies
None. This issue is a root of the graph.
Acceptance criteria
- pipefail-check over the tree before this change exits 10 and names collision-gate:89, command-graph:75, pages-check:284 and :454, and generate-site-data:771
- pipefail-check over the changed tree exits 0
- Case 300 writes the spelling, a comment about it, a here-string, an `||` and a script without pipefail, and only the spelling is refused
Validation
- bash test/run.sh 300_a_pipeline_cannot_hide_a_failure
- scripts/ci/pipefail-check
Evidence required
- suite
Evidence
None recorded. Every token above needs a command or an artifact behind it before this issue can be completed; narrative is refused.
Risk
A here-string appends one newline, which grep -q, -x and -E read the same as printf '%s\\n'; the two printf '%s' sites only gain a trailing newline that no anchored pattern can see.
Timeline
- started
- —
- verified
- —
- completed
- —
Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.
Canonical record: .ai/repo/project/issues/I3949.yaml. Read it back with majordomus plan show I3949.