fix(ci): derive the diff range from the event so pushes stop failing the gate - #25
Merged
Merged
Conversation
…the gate `github.base_ref` is populated for pull_request events only. On a push it is empty, so both git-range sites interpolated to the literal ref `origin/..HEAD` and the step died with `fatal: ambiguous argument`. Every push to a default branch has failed the gate since this reusable was adopted — aletheia's Gate Attestation has been red on main for days, and the signal went unnoticed because pull requests take a different path through the same workflow. Both sites now derive the range from whichever event fired: the PR base when there is one, otherwise the push's `before` commit, falling back to the head commit alone. `before` is all-zeros on a branch's first push and may be unresolvable in a shallow fetch, so it is verified rather than assumed. The attribution scan in particular must keep working on a push — that is precisely when a marker would reach the default branch without review.
forkwright
added a commit
that referenced
this pull request
Aug 15, 2026
…ot the base tip (#40) `git diff A..B` is not range notation — it is a plain comparison of two endpoints, identical to `git diff A B`. The docs-only step fed it `origin/${BASE_REF}..HEAD`, so against a base that keeps moving it reported every file main changed since the branch forked, not the files the PR proposes. A PR touching only README.md is classified NOT docs-only the moment an unrelated .rs commit lands on main. Measured on forkwright/kanon's `docs/2254-entry-point-truth`, which changes 2 files: the two-dot range yields 39 files, 37 of them non-doc. Three-dot yields 2. The exemption can therefore only ever fire on a branch that is exactly up to date with its base, which is not a property any PR holds for long. The consequence differs by gate shape. Here the PR falls through to full-gate-build, so the cost is a wasted build. In a trailer-only gate with no build fallback the same expression hard-blocks the PR: kanon's standalone gate-attestation.yml carries the identical two-dot expression at line 52 and exits 1 with "No Gate-Passed trailer found" for a docs-only PR that its own exemption was written to let through. Only the pull_request arm changes. The push arms are correct as two-dot: before..after is precisely what that push changed, and all three were re-checked against a fixture (event.before present, all-zeros, and absent) and resolve unchanged. Verified by extracting this workflow's own range-selection block and running it against a fixture PR whose branch touches only README.md while the base moved ahead with a code change: pre-fix (origin/main): range=origin/main..HEAD files=[README.md code.rs] docs_only=false rc=1 post-fix (this branch): range=origin/main...HEAD files=[README.md] docs_only=true rc=0 The permanent assertion belongs in scripts/check_event_shape_guards.py, which scans for pull_request-only values reaching git and would cover this class directly. That script is still unmerged on fix/gate-push-event-trailer-sha, and wiring it from here would collide with that branch in actionlint.yml, so this change is scoped to the defect. Follows up #25, which introduced the event-derived range.
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.
The failure
github.base_refis populated forpull_requestevents only. On a push it is empty, so both git-range sites in this reusable interpolated to the literal reforigin/..HEADand the step aborted with exit 128.Every push to a default branch has failed the gate since this reusable was adopted. aletheia's Gate Attestation has been red on
mainsince at least 2026-07-24 — six consecutive pushes, every one a merge that landed with the gate reporting failure. It went unnoticed because pull requests populatebase_refand take a working path through the same workflow, so PR-side signal looked healthy the whole time.The fix
Both sites now derive the range from whichever event actually fired:
beforecommit,beforeis all-zeros on a branch's first push and may be unresolvable under a shallow fetch, so it is verified withgit rev-parse --verifyrather than assumed. Every branch of that decision resolves to a range git will accept.Why the attribution scan matters here
The docs-only step failing is a nuisance. The attribution scan failing is the part worth fixing carefully: a push to the default branch is exactly when an attribution marker would land without review. Making that step abort on the event it most needs to cover is the worst possible failure mode, so it keeps scanning on a push rather than being skipped.
Blast radius
This reusable is consumed by aletheia and epitelesis. The change only adds fallbacks on a path that previously always aborted, so PR behaviour is byte-identical —
BASE_REFnon-empty takes the same first branch it always did.Verification
YAML parses. Neither
origin/${{ github.base_ref }}site remains. The real proof is the next push to a consumer's default branch going green, which I will confirm rather than assume.