fix: review_requested wakes the labels sweep — blocker:unrequested clears when the ask lands #143

Merged
claude-bot-andresmgsl merged 3 commits from build/137-review-request-wake into main 2026-07-24 13:33:11 +00:00
5 changed files with 70 additions and 5 deletions
Showing only changes of commit c0e796b6c9 - Show all commits

View file

@ -30,10 +30,16 @@ jobs:
scope:
# Not on labeled/unlabeled: those events change no paths, so labeler has
# nothing new to derive — and label churn is precisely what they are.
# review_requested/review_request_removed likewise change no paths — they
# exist to wake reconcile (#137) — and running labeler on them widens
# exactly the window #130 documents, where a label written during a
# scope run is clobbered.
if: >-
github.event_name == 'pull_request_target' &&
github.event.action != 'labeled' &&
github.event.action != 'unlabeled'
github.event.action != 'unlabeled' &&
github.event.action != 'review_requested' &&
github.event.action != 'review_request_removed'
runs-on: ubuntu-latest
concurrency:
group: labels-scope-${{ github.event.pull_request.number }}

View file

@ -10,7 +10,11 @@ on:
issues:
types: [opened, edited, assigned, unassigned, labeled, unlabeled, closed, reopened]
pull_request_target:
types: [opened, reopened, ready_for_review, converted_to_draft, synchronize, labeled, unlabeled]
# review_requested/review_request_removed wake the sweep that clears (or
# restores) blocker:unrequested — without them the one event that makes
# the label false could not clear it, and a quiet repo wore the red flag
# until the advisory cron (#137).
types: [opened, reopened, ready_for_review, converted_to_draft, synchronize, labeled, unlabeled, review_requested, review_request_removed]
permissions:
contents: read
checks: read # mergeability/check-rollup read for PR state

10
changelog.d/137.md Normal file
View file

@ -0,0 +1,10 @@
### Fixed
- `blocker:unrequested` now clears the moment the panel is asked: the labels
caller (and the `docs/CONSUMERS.md` stub) listens on `review_requested` and
`review_request_removed`, so the one event that falsifies the label — or
makes it true again — wakes the reconcile sweep instead of waiting for an
unrelated push or the advisory cron. The `scope` job skips both events:
they change no paths, and running the labeler on them widens the #130
clobber window. Adopting the new triggers is a stub edit riding the pin
bump to the first tag carrying this change (#137).

View file

@ -284,7 +284,10 @@ on:
schedule: [{cron: "*/15 * * * *"}] # advisory; the handoff label is the real wake
workflow_dispatch: # bootstraps missing labels on a fresh repo
pull_request_target:
types: [opened, reopened, ready_for_review, converted_to_draft, synchronize, labeled, unlabeled]
# review_requested/review_request_removed are unreleased — not in 0.2.0;
# add them with the pin bump to the first tag carrying ceremony#137. They
# wake the sweep that clears blocker:unrequested when the panel is asked.
types: [opened, reopened, ready_for_review, converted_to_draft, synchronize, labeled, unlabeled, review_requested, review_request_removed]
# Unreleased — not in 0.1.0; add only with the first tag carrying ceremony#32.
issues:
types: [opened, labeled, unlabeled, assigned, unassigned, closed]
@ -311,8 +314,13 @@ to the first tag carrying ceremony#32; never mix refs to adopt it early.
`pull_request_target` is intentional: fork PRs need the base repository's
token to write labels. The reusable workflow executes no PR code. It checks
out only the consumer's base branch and the pinned ceremony implementation.
The #52 ruling invariants ride exactly these triggers — the caller above is
unchanged since #18, so adopting them is a pin bump, not a stub edit.
The #52 ruling invariants ride exactly these triggers — but the caller above
is no longer the #18 shape, so adopting current triggers is a stub edit, not
a bare pin bump. The pending edit is `review_requested` and
`review_request_removed` (#137): the wake that clears `blocker:unrequested`
the moment the panel is asked, without which a quiet repo wears that flag
until the advisory cron. Make that edit with the pin bump to the first tag
carrying ceremony#137 — never before it and never through mixed refs.
`.github/labels.conf` has one mandatory panel setting, one mandatory
`triage-actors` setting, and then zero or more scope rows:

View file

@ -65,4 +65,41 @@ check "PR author is recused from the required panel" 0 "one three" printf '%s\n'
check "LABELS.md enumerates no repo's scope labels" 1 "0" \
grep -c 'scope:[a-z0-9]' "$ROOT/LABELS.md"
# The caller's pull_request_target list and the CONSUMERS.md stub's must be
# the same list. review_requested/review_request_removed are the wake that
# clears blocker:unrequested — the label sat false for as long as a quiet
# repo stayed quiet because the one event that falsifies it was never
# listed (#137). The stub is prose, so nothing but this row keeps the two
# lists from drifting: a type in one file only is a wake that fires at home
# and nowhere in the fleet, or the reverse.
pr_target_types() { # $1 = file → its pull_request_target types line, unindented
awk '/pull_request_target:/{f=1; next} f && /types: /{sub(/^ */,""); print; exit}' "$1"
}
types_in_sync() { # $1 = caller, $2 = stub → 0 when both lists exist and match
local a b
a="$(pr_target_types "$1")" b="$(pr_target_types "$2")"
[ -n "$a" ] && [ "$a" = "$b" ]
}
CALLER="$ROOT/.github/workflows/self-labels.yml"
STUB="$ROOT/docs/CONSUMERS.md"
check "caller and stub pull_request_target lists are identical" 0 "" \
types_in_sync "$CALLER" "$STUB"
# shellcheck disable=SC2016 # expansion belongs to the nested bash
check "the caller lists both review-request wakes" 0 "" bash -c \
'awk "/pull_request_target:/{f=1; next} f && /types: /{print; exit}" "$1" |
grep -F review_requested | grep -qF review_request_removed' _ "$CALLER"
# the failing cases: drop a type from either file, or reorder one list only,
# and the identity row above goes red — exercised here on mutated copies
mut_caller="$TMP/mut-caller.yml" mut_stub="$TMP/mut-stub.md"
sed 's/, review_request_removed//' "$CALLER" >"$mut_caller"
check "a type dropped from the caller goes red" 1 "" \
types_in_sync "$mut_caller" "$STUB"
sed 's/, review_request_removed//' "$STUB" >"$mut_stub"
check "a type dropped from the stub goes red" 1 "" \
types_in_sync "$CALLER" "$mut_stub"
sed 's/review_requested, review_request_removed/review_request_removed, review_requested/' \
"$STUB" >"$mut_stub"
check "a reorder in one list only goes red" 1 "" \
types_in_sync "$CALLER" "$mut_stub"
summary