Skip to content

hermetic-check: the gate DECLARES suites hermetic by the absence of a marker and never verified it — 44 of 44 - #538

Merged
jobordu merged 1 commit into
mainfrom
dev1/hermetic-check
Aug 21, 2026
Merged

hermetic-check: the gate DECLARES suites hermetic by the absence of a marker and never verified it — 44 of 44#538
jobordu merged 1 commit into
mainfrom
dev1/hermetic-check

Conversation

@jobordu

@jobordu jobordu commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

hermetic suites (gating) decides membership by the absence of a marker: a suite is hermetic iff nobody wrote # SUITE-DEPENDS in it. Nothing verified the claim. A suite that shells out to gh is declared hermetic by default, passes on every authenticated machine, and fails only on the runner — where it blocks a merge with an assertion naming neither gh nor the dependency.

The instance that prompted it — #499. close-condition-scan.py handles --states at line 264, thirty lines after the network fetch at 234. --states is a pure DECLARE that needs no repository. Locally gh answers and the misordering is invisible; the runner gets AssertionError: 2 != 0.

44 of 44 declared-hermetic suites are hermetic w.r.t. gh   (55 suites, 11 declare SUITE-DEPENDS)
known-positive from refs/pr/499:  gh:0 -> shadowed:1   DETECTED

Design points that are the actual work

⛔ No real gh is exit 2, never 0. With nothing to shadow, every suite scores hermetic and the clean board is an artefact of the machine. "There was no gh" and "no suite needs gh" are two states the verdict depends on telling apart. Mutation-checked: break that precondition and the tool reports a clean board with no gh — the self-test fails.

⚠ Shadowing gh, not truncating PATH. My first reproduction on #499 used PATH=/usr/bin:/bin, which also drops homebrew. Fine for one confirmed case; for a 44-suite survey it manufactures false positives — a suite failing because git moved is not a network leak. git and python3 are asserted unmoved before anything is measured.

Known-positive asserted as a PAIR. The leak is detected alone passes if everything were flagged; the clean suite is not flagged alone passes if nothing were.

⛔ Two defects this tool had, found by running it rather than reasoning about it

  1. Its own --self-test required a real gh — so it would have failed on the runner. The exact defect it detects, in the tool that detects it. Caught by running it with gh absent. It now supplies its own gh fixture and passes with and without.
  2. tree_provenance() reported a clean SHA for a dirty working tree — letting a reading over uncommitted edits be attributed to a commit that never contained them. Now says so explicitly.

⚠ What this does NOT establish

  • Hermetic with respect to gh ONLY. A suite reaching the network by curl, urllib, or a git remote is not covered and is not thereby clean.
  • It does not verify the runner's condition — absent gh vs unauthenticated vs rate-limited all produce the same refusal here; I reproduced one.
  • Not wired into any gate. That is DEVOPS's call, not mine. This lands as an instrument.

Measured at 41daed3; tool at 2fd1182. — DEV1

…f 44

The `hermetic suites (gating)` job decides membership by the ABSENCE of a
marker: a suite is hermetic iff nobody wrote `# SUITE-DEPENDS` in it.
Nothing verified that. A suite shelling out to `gh` is declared hermetic
by default, passes on every authenticated machine, and fails only on the
runner — where it blocks a merge with an assertion naming neither `gh`
nor the dependency.

Instance that prompted it: #499. `close-condition-scan.py` handles
`--states` at line 264, thirty lines after the network fetch at 234.
`--states` is a pure DECLARE needing no repository. Locally `gh` answers
and the misordering is invisible; the runner sees `AssertionError: 2 != 0`.

Each declared-hermetic suite runs twice, varying exactly ONE binary.
A suite whose exit code moves is not hermetic.

  44 of 44 hermetic at 41daed3 (55 suites; 11 declare SUITE-DEPENDS)

Shadowing `gh`, not truncating PATH: replacing PATH wholesale also drops
homebrew, so a suite failing because `git` moved would score as a network
leak. `git` and `python3` are asserted unmoved before anything is measured.

No real `gh` is exit 2, never 0. With nothing to shadow every suite scores
hermetic and the clean board is an artefact of the machine. "There was no
gh" and "no suite needs gh" are two states the verdict depends on telling
apart, so they must not share a code. Mutation-checked: breaking that
precondition makes the tool report a clean board with no gh, and the
self-test fails.

The known-positive is drawn from refs/pr/499, outside the measured
population, and asserted as a PAIR with a clean fixture — "the leak is
detected" alone passes if everything were flagged, "the clean suite is not
flagged" alone passes if nothing were.

Two defects found in this tool by testing it rather than reasoning:
its own --self-test required a real `gh` and so would have failed on the
runner — the exact defect it detects — and `tree_provenance()` reported a
clean SHA for a dirty working tree.

DEV1
@coderabbitai

coderabbitai Bot commented Aug 21, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@jobordu, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 32 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d716a5e4-e757-484e-a606-a3f26eea99e0

📥 Commits

Reviewing files that changed from the base of the PR and between 1385eda and 2fd1182.

📒 Files selected for processing (2)
  • tools/README.md
  • tools/hermetic-check.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jobordu
jobordu merged commit bf80044 into main Aug 21, 2026
5 checks passed
@jobordu

jobordu commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

⇒ Rebased onto 1385eda, and the number moved by itself: 44 → 45 of 45

DEV1.The body says 44 of 44 at 41daed3. It is now 45 of 45 at bf80044#537 landed test_disposition_scan.py and this tool measured it on the next run without being told.

Leaving the body's number as written rather than editing it.A count in a PR body is a claim about a moment; silently updating it would erase that it was ever true of a smaller population. The tool derives the number, so the tool is the authority and the body is a dated reading.

★ Which is the property, not an accident

A stored baseline would have decayed inside the hour. ⚠ This one had a stored-count predecessor in the same file — SUBJ_BASELINE: "23" in the workflow — and that is exactly the shape that goes stale without anyone noticing, because a wrong constant and a right one look identical.

⇒ Rebase was clean; tools/README.md overlapped with #537 and three-way merged. Re-verified after the rebase, not before:

scripts/check-tools-index.py       rc=0
hermetic-check.py --self-test      rc=0
hermetic-check.py                  45 of 45  ---- tree bf80044

⇒ Force-with-lease pinned to the SHA I pushed. — DEV1

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.

1 participant