docs: preserve labels workflow safety rationale
This commit is contained in:
parent
9755f634a0
commit
1ff660f539
2 changed files with 23 additions and 3 deletions
18
.github/workflows/labels.yml
vendored
18
.github/workflows/labels.yml
vendored
|
|
@ -1,6 +1,23 @@
|
|||
name: labels
|
||||
# Reusable half of the labels automation. Triggers and permissions live in
|
||||
# the caller; docs/CONSUMERS.md carries the complete caller stub.
|
||||
#
|
||||
# The caller uses pull_request_target, not pull_request: every PR in this
|
||||
# family arrives from a fork, where pull_request runs with a READ-ONLY token
|
||||
# and cannot label anything. _target is safe in this workflow because no PR
|
||||
# code is ever checked out or executed — labeler reads changed paths via the
|
||||
# API, and reconcile checks out the BASE branch only. Keep it that way.
|
||||
#
|
||||
# There is no pull_request_review_target, so a review landing cannot wake this
|
||||
# workflow directly — and the */15 cron is advisory: GitHub deprioritises
|
||||
# short intervals hard enough that a quiet repo goes hours between ticks. The
|
||||
# handoff wakes the sweep itself: the author sets state:needs-human, and the
|
||||
# caller's `labeled` event confirms or corrects that optimistic write within
|
||||
# seconds. The cron stays as the last resort for a forgotten handoff.
|
||||
#
|
||||
# This cannot loop: reconciler writes use GITHUB_TOKEN, and GitHub does not
|
||||
# create workflow runs from GITHUB_TOKEN-triggered events. Agent writes use a
|
||||
# PAT and therefore do trigger — exactly the asymmetry wanted.
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
|
|
@ -24,6 +41,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/labeler@v5
|
||||
with:
|
||||
# labeler reads the consumer's .github/labeler.yml via the API
|
||||
# additive only — a hand-applied scope must survive the machine
|
||||
sync-labels: false
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ fi
|
|||
# by requesting the human's review — an explicit request is a fact, and it is
|
||||
# the one this machine trusts (see decide_state's top precedence). The
|
||||
# machine auto-requests the human only in the no-judgment-needed case: every
|
||||
# required verdict is a formal head-current approval. Any approval that counts must be bound to
|
||||
# required verdict is a formal head-current approval. Any approval that counts
|
||||
# must be bound to
|
||||
# the CURRENT head SHA: GitHub keeps approvals alive across pushes, and a
|
||||
# stale approval must never promote unreviewed code to the human.
|
||||
#
|
||||
|
|
@ -32,7 +33,7 @@ fi
|
|||
# sweep tolerates a missing label rather than recreating it.
|
||||
#
|
||||
# The state machine below is pure (globals in, state out) and covered by
|
||||
# fixture tests in test/labels-reconcile.sh.
|
||||
# fixture tests in test/labels-reconcile.test.sh.
|
||||
|
||||
HUMAN="${HUMAN_REVIEWER:-danmt}"
|
||||
BOTS=()
|
||||
|
|
@ -394,7 +395,8 @@ reconcile_pr() { # $1 = PR number; relies on the globals set from its fetch
|
|||
desired="$(decide_state)"
|
||||
|
||||
# encode the runbook's last step for the no-judgment case: every required
|
||||
# verdict is a head-current approval → the human is asked, once. The guard asks whether
|
||||
# verdict is a head-current approval → the human is asked, once. The guard
|
||||
# asks whether
|
||||
# a FRESH human review is needed for THIS head — never "has the human ever
|
||||
# reviewed", which wedged the handoff after any earlier human comment.
|
||||
# Idempotent (a live request suppresses it); race-free via the shared
|
||||
|
|
|
|||
Loading…
Reference in a new issue