gate pinned its own name and left the other half of the pair unpinned - #806
Merged
Conversation
Branch protection requires two contexts, `gate` and `lint`, and a required context is a check-run NAME. GitHub takes that name from an explicit `name:` when a job has one and from the job id otherwise. `gate` pins its name. `lint` did not, and the asymmetry was mine. A peer reading this reported the hole as renaming the job id, which is caught: renaming `lint` to `linting` fails two tests, one here and one in `action-lint.test.ts`, because both assert `jobs.lint` exists. Checked by making the rename rather than by reading the assertions. The hole is the other direction. ADDING `name: pr-lint` while leaving the job id `lint` breaks the required context exactly as thoroughly -- the check-run becomes `pr-lint`, the context named `lint` never reports, and every pull request blocks with no failing check to explain it -- and the whole suite passed with that edit in place. A job called `lint` still sits in the file, which is what both existing assertions look at. This is the shape that keeps turning up: the name written in the required list and the place that emits it are different places, and only one of them was guarded. Record-Id: r-lintcontextname Provenance: authored Certainty: firm Blast: local Undo: easy Ruled-out: asserting the name equals "lint" | the job has no `name:` today and should not gain one, so the property is its absence; asserting equality would invite someone to add `name: lint`, which is redundant and one edit from wrong Ruled-out: leaving it because renaming the id is already caught | that catches one of the two ways the context can stop reporting, and the uncaught one leaves a file that still reads correctly Limit: this pins where the name comes from, not that the check ever runs. A workflow-level failure before job dispatch produces no check run at all, and neither this nor the trigger assertion sees that Verified: the hole was reproduced before it was closed -- `name: pr-lint` added to the job left all 35 assertions in both files passing. The peer's reported version was tested too and does not reproduce: renaming the job id fails two assertions. One negative control on the fix, restored with the workflow byte-identical CommitLore-Version: 2.0.0
CommitLore — record lintTrailers: clean — 1 commit in Limits (2)
Ruled out (4)
Trailer violations fail this check. Active constraints are informational — they are what the repository already decided, not a verdict on this PR. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follows #805. Closes the other way a required context can stop reporting.
The asymmetry
Protection requires
gateandlint. A required context is a check-run name, which GitHub takes from an explicitname:when a job has one and from the job id otherwise.gatepins its name (ci-gate.test.ts:37).lintdid not. That was mine.The reported hole is already caught; the real one was not
A peer reported the risk as renaming the job id. Tested by making the rename rather than by reading the assertions —
lint→lintingfails two tests, one here and one inaction-lint.test.ts, because both assertjobs.lintexists.The hole is the other direction:
Reproduced before closing it. A job called
lintstill sits in the file, which is exactly what both existing assertions look at.The shape
The name written in the required list and the place that emits it are different places, and only one of them was guarded. Same shape as the matrix-interpolated contexts in #803 and the
branches: [dev]near-miss another session hit today — a name and its enforcement site drifting apart.The assertion
That the job carries no
name:— the property is its absence, not an equality. Assertingname === 'lint'would invite someone to add a redundantname: lint, which is one edit from wrong.Negative control: adding
name: pr-lintfails the assertion; restored byte-identical.Limit, in the commit
This pins where the name comes from, not that the check ever runs. A workflow-level failure before job dispatch produces no check run at all, and neither this nor the trigger assertion sees that.
Full suite green,
tsc --noEmitclean.