Skip to content

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

Part of ci-critical-path — The critical path from a change to its verdict, and from a merge to its verified deploy, runs under a minute warm.

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.

Searches the titles and descriptions of every page this site publishes.