forked from heavy-duty/ceremony
Merge pull request #210 from dan-claude-bot/build/208-checks-state-self-filter
fix: checks_state never grades the label machine's own runs (#208)
This commit is contained in:
commit
b6d7e26d82
3 changed files with 85 additions and 1 deletions
|
|
@ -49,6 +49,15 @@ LABELS=""
|
|||
# retirement heals the board instead of stranding a label nothing recomputes.
|
||||
RETIRED=(state:needs-rebase)
|
||||
STALE_AFTER=$((48 * 3600))
|
||||
# The workflow whose runs checks_state must never grade — its own (#208).
|
||||
# GITHUB_WORKFLOW is ambient in every Actions step and names the CALLER (the
|
||||
# consumer's PR-facing workflow, since consumers name the caller), so this
|
||||
# self-serves with no workflow-file change. The explicit override exists for
|
||||
# two readers: the fixtures, and #209's detached sweep caller, which will
|
||||
# need to point this at the PR-facing caller's name once reconcile no longer
|
||||
# runs inside it. Empty means "filter nothing" — a caller outside Actions
|
||||
# (a local rehearsal, an older pin) must not silently start dropping entries.
|
||||
SELF_WORKFLOW="${SELF_WORKFLOW:-${GITHUB_WORKFLOW:-}}"
|
||||
|
||||
# The needs-ruling invariants (#52) — one implementation for both surfaces.
|
||||
# shellcheck source=lib/ruling.sh
|
||||
|
|
@ -221,7 +230,27 @@ checks_state() { # rollup JSON on stdin → SUCCESS | FAILURE | PENDING | NONE |
|
|||
# a context whose entries are ALL cancelled never reported at all (a killed
|
||||
# or timed-out required job), so it keeps CANCELLED and still blocks —
|
||||
# discard needs a surviving verdict, never an empty context.
|
||||
jq -r '
|
||||
#
|
||||
# And one exclusion that comes before every rule above: the label machine
|
||||
# never grades its own runs (#208). Every reconcile sweep serializes
|
||||
# through one shared concurrency group, and GitHub records a displaced
|
||||
# queued run as CANCELLED — there is no "superseded" conclusion for queue
|
||||
# displacement. When the displaced run was born from a pull_request_target
|
||||
# event, that cancelled entry attaches to the victim PR while its
|
||||
# SUCCESSOR — triggered by a different PR or an issues event — attaches
|
||||
# elsewhere, so the #139 carve-out's premise (a surviving sibling on the
|
||||
# same PR) fails structurally: on the victim the newest self entry stays
|
||||
# CANCELLED, the deny-list scores it FAILURE, and the sweep sets
|
||||
# blocker:ci-red off its own corpse — then re-affirms it every cadence.
|
||||
# Proven on crew#227: every real check green, the only red rollup entry
|
||||
# the sweep's own displaced run. So drop every entry belonging to
|
||||
# $SELF_WORKFLOW before the newest-per-context collapse. Accepted
|
||||
# consequences: a rollup of ONLY self entries scores NONE (honestly: no
|
||||
# checks — never SUCCESS), and a genuine reconcile failure surfaces on the
|
||||
# Actions tab instead of as blocker:ci-red, which is right because no PR
|
||||
# edit can fix the label machinery. An empty $self filters nothing — the
|
||||
# exclusion must never widen into dropping entries on a guess.
|
||||
jq -r --arg self "$SELF_WORKFLOW" '
|
||||
if (has("statusCheckRollup") | not) then "UNREADABLE" else
|
||||
|
||||
# NEUTRAL and SKIPPED satisfy branch protection — a skipped required check
|
||||
|
|
@ -262,7 +291,11 @@ checks_state() { # rollup JSON on stdin → SUCCESS | FAILURE | PENDING | NONE |
|
|||
# and treating it as newest keeps an undateable in-flight run from being
|
||||
# discarded in favour of a stale success. Every ambiguity resolves toward
|
||||
# "not settled".
|
||||
# The #208 exclusion (header above): self entries leave the rollup here,
|
||||
# BEFORE the group_by — a self-only context must vanish entirely, never
|
||||
# survive as an all-cancelled context that still classifies FAILURE.
|
||||
| [ (.statusCheckRollup // [])[]
|
||||
| select($self == "" or (.workflowName // "") != $self)
|
||||
| { ctx: [.workflowName // "", .name // .context // ""],
|
||||
at: ([.startedAt, .createdAt, .completedAt]
|
||||
| map(select(type == "string" and . != ""
|
||||
|
|
|
|||
11
changelog.d/208.md
Normal file
11
changelog.d/208.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
### Fixed
|
||||
|
||||
- `checks_state` drops rollup entries belonging to the workflow it runs
|
||||
inside — `SELF_WORKFLOW`, defaulting to the ambient `GITHUB_WORKFLOW` —
|
||||
before the newest-per-context collapse: the label machine never grades
|
||||
its own runs, and an empty name filters nothing (#208).
|
||||
- A sweep displaced from the shared concurrency queue attaches CANCELLED to
|
||||
its PR while its successor attaches elsewhere, so the sweep set
|
||||
`blocker:ci-red` off its own displaced run and re-affirmed it every
|
||||
cadence (crew#227). A rollup of only self entries now honestly scores
|
||||
NONE (#208).
|
||||
|
|
@ -351,6 +351,13 @@ run_() { jq -n --arg n "$1" --arg o "$2" --arg t "${3:-2026-07-20T15:00:00Z}" \
|
|||
ctx_() { jq -n --arg n "$1" --arg s "$2" --arg t "${3:-2026-07-20T15:00:00Z}" \
|
||||
'{__typename:"StatusContext", context:$n, state:$s, createdAt:$t}'; }
|
||||
|
||||
# Pinned empty for every fixture below except the #208 block, which sets its
|
||||
# own. The script defaults SELF_WORKFLOW from the ambient GITHUB_WORKFLOW —
|
||||
# present in any CI run of this suite — and an inherited name that happened
|
||||
# to match a fixture's workflowName ("ci", "labels") would silently drop
|
||||
# entries these fixtures rely on. The verdicts must not flip with the runner.
|
||||
SELF_WORKFLOW=""
|
||||
|
||||
expect "no checks at all is NONE" NONE "$(rollup '[]' | checks_state)"
|
||||
# A failed fetch leaves no rollup KEY; a PR with no checks leaves an empty
|
||||
# ARRAY. Collapsing the two let an API hiccup read as "nothing is failing" —
|
||||
|
|
@ -429,6 +436,39 @@ expect "a cancelled newest over an earlier FAILURE is still that failure" FAILUR
|
|||
"$(rollup "[$(rec_ FAILURE 2026-07-24T12:16:17Z 2026-07-24T12:17:06Z),\
|
||||
$(rec_ CANCELLED 2026-07-24T12:16:41Z 2026-07-24T12:16:41Z)]" | checks_state)"
|
||||
|
||||
# -- the #208 exclusion: the label machine never grades its own runs. The
|
||||
# shared concurrency group displaces queued sweeps as CANCELLED, and the
|
||||
# displaced run's successor was triggered by a DIFFERENT PR or an issues
|
||||
# event — so on the victim PR the #139 carve-out's premise (a surviving
|
||||
# sibling on the same head) fails structurally: the newest self entry
|
||||
# stays CANCELLED, and the sweep set blocker:ci-red off its own corpse,
|
||||
# re-affirming it every cadence. Proven on crew#227: every real check
|
||||
# green, the only red rollup entry the sweep's own displaced run. rec_
|
||||
# already builds entries under workflowName "labels"; naming that as
|
||||
# self must drop them whole, before the newest-per-context collapse.
|
||||
SELF_WORKFLOW="labels"
|
||||
expect "a displaced self CANCELLED beside green others is no verdict (crew#227)" SUCCESS \
|
||||
"$(rollup "[$(run_ a SUCCESS),$(run_ b SUCCESS),\
|
||||
$(rec_ CANCELLED 2026-08-01T15:17:56Z 2026-08-01T15:17:59Z)]" | checks_state)"
|
||||
expect "a FAILED self run surfaces on the Actions tab, not as the PR's red" SUCCESS \
|
||||
"$(rollup "[$(run_ a SUCCESS),$(run_ b SUCCESS),\
|
||||
$(rec_ FAILURE 2026-08-01T15:00:00Z 2026-08-01T15:01:00Z)]" | checks_state)"
|
||||
expect "a rollup of ONLY self entries is honestly NONE, never SUCCESS" NONE \
|
||||
"$(rollup "[$(rec_ CANCELLED 2026-08-01T15:17:56Z 2026-08-01T15:17:59Z)]" | checks_state)"
|
||||
# must-fail: the filter keys on the self workflow ALONE. Widening it — any
|
||||
# cancelled entry, any labels-shaped name — certifies a genuine foreign
|
||||
# failure green, which is #136's unknown-as-green shape all over again.
|
||||
expect "a genuine foreign FAILURE still blocks beside a cancelled self entry" FAILURE \
|
||||
"$(rollup "[$(run_ a FAILURE),\
|
||||
$(rec_ CANCELLED 2026-08-01T15:17:56Z 2026-08-01T15:17:59Z)]" | checks_state)"
|
||||
# ...and an empty self filters NOTHING: outside Actions no workflow name is
|
||||
# ambient, and the exclusion must never drop entries on a guess — the same
|
||||
# displaced-self rollup keeps blocking there, all-cancelled context intact.
|
||||
SELF_WORKFLOW=""
|
||||
expect "an empty SELF_WORKFLOW filters nothing — the same rollup still blocks" FAILURE \
|
||||
"$(rollup "[$(run_ a SUCCESS),$(run_ b SUCCESS),\
|
||||
$(rec_ CANCELLED 2026-08-01T15:17:56Z 2026-08-01T15:17:59Z)]" | checks_state)"
|
||||
|
||||
# -- a run still IN FLIGHT. `run_()` cannot express this: it always carries a
|
||||
# real completedAt, which is exactly why the supersede rule shipped dating
|
||||
# runs by completion and nothing caught it. Both spellings of "no
|
||||
|
|
|
|||
Loading…
Reference in a new issue