Filed by the domain:devx PM seat (#6023), session session_01CPrUz21stTFhJRUirdc4yw, on behalf of three of its R26 devs. Filed unassigned and ungraded — recording only, ⛔ not routed, ⛔ carrying no domain:* label.
Measured, three times independently, in one session
scripts/check-test-completeness.mjs requires a turbo-test-log argument (ci.yml:666 passes one). Run standalone — which is what happens when a dev works through the family that scripts/pm/dispatch-gates.mjs --repo derives for a card — it exits 1 and prints its usage line.
Exit 1 plus text on a gate script is indistinguishable, at a glance, from a finding. Three devs on unrelated cards each hit it, each had to work out that it was an invocation error rather than a red, and each reported it separately as NOT MEASURED:
| card |
what the dev wrote |
| #12935 (PR #13094) |
"NOT MEASURED, not red: scripts/check-test-completeness.mjs exit 1 is its usage message — it consumes a turbo test log and only runs meaningfully inside CI's Test Core job." |
| #12933 (PR #13107) |
"The one non-green is check-test-completeness.mjs, NOT MEASURED: it requires a turbo-test-log argument (ci.yml:666 passes one) and answered with its usage line — an invocation error, not a red gate." |
| #13032 (PR #13104) |
same classification, same reasoning, reached independently |
⭐ All three got it right. That is the point: the cost is not a wrong verdict, it is that three careful readers each had to spend the same reasoning to avoid one, and a less careful fourth would have reported a red PR or, worse, "fixed" something.
Why this is a defect and not just ergonomics
The repo already has a convention for exactly this situation, and this script does not use it. Other gates answer an unmeasurable invocation with PREREQUISITE NOT MET / exit 3, which the dispatch contract explicitly reads as a refusal to measure, ⛔ not a finding. Devs applied that convention correctly and unprompted several times this session (on check:dev-prereqs, check:doc-formula-expressions, check-half-states.mjs).
⇒ This is one script out of step with a convention the rest of the family already honours — and it is out of step in the direction that manufactures false findings rather than suppressing real ones.
⚠️ Related but distinct: this is the inverse of the vacuous-pass class (#13014). There, a gate that cannot measure reports clean. Here, a gate that cannot measure reports red. Both are the instrument speaking in the vocabulary of a verdict, and both cost a reader the same re-derivation.
Suggested direction, ⛔ not a decision
Answer a missing/unreadable log argument with the repo's refusal convention (PREREQUISITE NOT MET, exit 3) and a line naming what it needs, instead of exit 1 + usage. That preserves CI behaviour exactly — ci.yml:666 always passes the argument, so the CI path never reaches the new branch — while removing the false red from every local family run.
⚠️ Whoever takes this should check whether the exit code is consumed anywhere before changing it; a caller keying on exit 1 would make this a wider change than one branch.
Re-check
node scripts/check-test-completeness.mjs; echo "EXIT=$?" # expect 1 + usage
grep -n 'check-test-completeness' .github/workflows/ci.yml # expect the argument-passing call site
grep -rn 'PREREQUISITE NOT MET' scripts/ | head # the convention this script does not use
⚠️ Capture $? before any pipe — ⛔ ${PIPESTATUS[0]} is not safe either (#12979). And reverse-check the third command's hits against a term known present in the same corpus before trusting any zero.
Filed by the
domain:devxPM seat (#6023), sessionsession_01CPrUz21stTFhJRUirdc4yw, on behalf of three of its R26 devs. Filed unassigned and ungraded — recording only, ⛔ not routed, ⛔ carrying nodomain:*label.Measured, three times independently, in one session
scripts/check-test-completeness.mjsrequires a turbo-test-log argument (ci.yml:666passes one). Run standalone — which is what happens when a dev works through the family thatscripts/pm/dispatch-gates.mjs --repoderives for a card — it exits 1 and prints its usage line.Exit 1 plus text on a gate script is indistinguishable, at a glance, from a finding. Three devs on unrelated cards each hit it, each had to work out that it was an invocation error rather than a red, and each reported it separately as NOT MEASURED:
scripts/check-test-completeness.mjsexit 1 is its usage message — it consumes a turbo test log and only runs meaningfully inside CI's Test Core job."check-test-completeness.mjs, NOT MEASURED: it requires a turbo-test-log argument (ci.yml:666passes one) and answered with its usage line — an invocation error, not a red gate."⭐ All three got it right. That is the point: the cost is not a wrong verdict, it is that three careful readers each had to spend the same reasoning to avoid one, and a less careful fourth would have reported a red PR or, worse, "fixed" something.
Why this is a defect and not just ergonomics
The repo already has a convention for exactly this situation, and this script does not use it. Other gates answer an unmeasurable invocation with
PREREQUISITE NOT MET/ exit 3, which the dispatch contract explicitly reads as a refusal to measure, ⛔ not a finding. Devs applied that convention correctly and unprompted several times this session (oncheck:dev-prereqs,check:doc-formula-expressions,check-half-states.mjs).⇒ This is one script out of step with a convention the rest of the family already honours — and it is out of step in the direction that manufactures false findings rather than suppressing real ones.
Suggested direction, ⛔ not a decision
Answer a missing/unreadable log argument with the repo's refusal convention (
PREREQUISITE NOT MET, exit 3) and a line naming what it needs, instead of exit 1 + usage. That preserves CI behaviour exactly —ci.yml:666always passes the argument, so the CI path never reaches the new branch — while removing the false red from every local family run.Re-check
$?before any pipe — ⛔${PIPESTATUS[0]}is not safe either (#12979). And reverse-check the third command's hits against a term known present in the same corpus before trusting any zero.