Skip to content

tri: an absent compiler is exit 2 "could not run", not exit 1 "the check failed" - #3054

Merged
gHashTag merged 1 commit into
masterfrom
w51-gate-could-not-run
Sep 3, 2026
Merged

tri: an absent compiler is exit 2 "could not run", not exit 1 "the check failed"#3054
gHashTag merged 1 commit into
masterfrom
w51-gate-could-not-run

Conversation

@gHashTag

@gHashTag gHashTag commented Sep 3, 2026

Copy link
Copy Markdown
Owner

Closes #3045

What happened

$ git -c core.hooksPath=.githooks commit -q -m x
tri: t27c not found. Run: cd bootstrap && cargo build --release
tri: local commands still work -- see 'tri help'
$ echo $?
1

No commit. Nothing else printed. .githooks/pre-commit runs under set -euo pipefail and its first statement is bash scripts/tri check-now; that script exits 1 when it cannot resolve t27c, and set -e aborts the hook.

The NOW gate did not run. It found nothing wrong. An absent build artefact is reported as a failing pre-commit gate, in a message whose first line names a build step rather than a blocked commit and whose second line reads as reassurance. It fires on every fresh worktree — the normal state at the start of a unit of work.

The change

scripts/tri exits 2 on that path. POSIX 1003.3 calls it UNSUPPORTED"the testing environment lacks basic support for compiling or running the test case" — and the convention is already this repository's, not a new one: tools/check_now_entry_shape.py exits 2 with "Reporting nothing rather than a pass this run did not earn" for the same situation one layer up.

The hook catches 2 and says what happened. The commit is still refused — a gate that could not run must not pass.

Verified, three arms

no compiler scripts/tri 2, hook 2, prints "could NOT RUN … Nothing about your change was checked"
no compiler, local commands tri help 0, tri loop-help 0, tri disk 0
with a compiler, NOW entry present scripts/tri 0, hook 0, ✅ NOW entry gate passed

The bug the fix nearly shipped

The first draft of the hook was

if ! bash "$ROOT/scripts/tri" check-now; then
  rc=$?

$? there is the negation's status, which is 0 — so the hook would have exited 0 and let the commit through with the gate unrun: the exact defect being fixed, reintroduced by the fix. Caught by probing, not by reasoning:

$ bash -c 'set -e; f(){ return 2; }; if ! f; then rc=$?; echo "captured rc=$rc"; fi'
captured rc=0
$ bash -c 'set -e; f(){ return 2; }; rc=0; f || rc=$?; echo "|| form rc=$rc"'
|| form rc=2

The probe is in the comment above the line.

The test

It builds its own compiler-less tree rather than asserting on whatever the ambient checkout contains: scripts/tri derives REPO_ROOT from its own location, so a temp directory holding only scripts/ has none of the four binary paths. Deterministic on a developer machine with a build and in CI without one.

mutant result
exit 1 again an absent compiler exits 2, not 1 FAILED
restore the "local commands still work" line 2 assertions FAILED
make the branch unconditional (if true) only the control catches itcontrol: a resolvable compiler is not reported as could-not-run FAILED
restored 8 ok

That third mutant is why the control is there: it satisfies every positive assertion in the file.

It also verifies the claim the deleted line made instead of repeating it — tri help, tri loop-help and tri disk all exit 0 with no compiler present.

Runs in loop-tools-gate.yml, the one job that has no compiler in it, next to the step that already asserts the loop helpers dispatch without one.

Noticed, not touched

scripts/tri carries the loop-helper dispatch block twice — lines 12–30 and lines 371–383. The first is live; the second is unreachable, because the first exits or execs for every input that reaches it. Its comment says the helpers are "dispatched before anything is forwarded to t27c", which is true of the copy above it and false of itself. Filed separately rather than deleted here.

…eck failed"

Closes #3045

`.githooks/pre-commit` runs `scripts/tri check-now` under `set -e`. With t27c
unbuilt the script exited 1 with "t27c not found" and "local commands still
work", and the commit was refused. The NOW gate had not run. It found nothing
wrong. An absent build artefact was reported as a failing pre-commit gate, in a
message naming a build step rather than a blocked commit, with a second line
that reads as reassurance. It fires on every fresh worktree, which is the normal
state at the start of a unit of work.

scripts/tri now exits 2 on that path. POSIX 1003.3 calls it UNSUPPORTED -- the
environment lacks basic support for running the check -- and
tools/check_now_entry_shape.py already uses 2 for the same thing one layer up,
so the convention is this repository's rather than a new one.

The hook catches 2 and says the gate did not examine the commit. The commit is
still refused: a gate that could not run must not pass.

`if ! cmd; then rc=$?` captures the NEGATION's code, which is 0. The first draft
of the hook had exactly that, and it would have let the commit through with the
gate unrun -- the defect being fixed, reintroduced by the fix. Probed with a
two-line shell experiment rather than reasoned about; the probe is in the
comment.

The regression test builds its own compiler-less tree (scripts/tri derives
REPO_ROOT from its own location, so a temp directory holding only scripts/ has
none of the four binary paths) instead of asserting on whatever the ambient
checkout contains. Three mutants, three kills, and the third is the point:
making the branch unconditional satisfies every positive assertion and is caught
only by the control, TRI_T27C pointing at a binary that exits 0.

It also verifies the claim the deleted line made rather than repeating it:
`tri help`, `tri loop-help` and `tri disk` all exit 0 with no compiler present.

Runs in loop-tools-gate.yml, the one job with no compiler in it.
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-09-03 20:14:38 UTC

Summary

Status Count
Total Open PRs 16
PRs with Failing Checks 10
PRs with All Checks Green 6
READY 0
FAILING 10
PENDING 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=9b8875f1c9d4 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

📓 NotebookLM Notebook linked to this PR

This notebook contains session context, decisions, and artifacts for this work.

@gHashTag
gHashTag merged commit 9433ef3 into master Sep 3, 2026
27 checks passed
@gHashTag
gHashTag deleted the w51-gate-could-not-run branch September 3, 2026 20:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pre-commit refuses the commit when t27c is not built, and says 'local commands still work'

1 participant