forked from heavy-duty/ceremony
Merge pull request #181 from claude-bot-andresmgsl/build/180-blocked-excludes-nh
fix: `blocked` excludes `state:needs-human` in decide_state()
This commit is contained in:
commit
4debf53872
4 changed files with 46 additions and 1 deletions
|
|
@ -83,7 +83,7 @@ and re-entry does not set `attention`.
|
|||
| Label | Color | Meaning |
|
||||
|---|---|---|
|
||||
| `stale` | `#B60205` | no activity for 48h — sweep-managed, never hand-applied |
|
||||
| `blocked` | `#6A737D` | (see above — same label serves PRs waiting on another PR/issue; legitimately quiet, the staleness sweep skips it) |
|
||||
| `blocked` | `#6A737D` | (see above — same label serves PRs waiting on another PR/issue; legitimately quiet, the staleness sweep skips it). The reconciler refuses `state:needs-human` while `blocked` stands — the PR falls to `state:addressing` (#180) |
|
||||
| `offsite` | `#CFD3D7` | issue deliverable is a PR in another repository; set by the builder with the draft link and cleared by the builder at handoff |
|
||||
| `needs-ruling` | `#D4C5F9` | a human-owned decision is required; use BUILDER.md's ruling template and ladder. Set by triage or the builder; a state, not a signal — it clears on agreement, not on a reply |
|
||||
| `attention` | `#D93F0B` | issue-only demand parked for the assignee; hand-set, and never written by the machine |
|
||||
|
|
|
|||
|
|
@ -389,6 +389,20 @@ decide_state() { # → the one state:* label this PR should carry
|
|||
if [ "$s" = state:needs-human ] && has_label needs-ruling; then
|
||||
echo state:addressing; return
|
||||
fi
|
||||
|
||||
# A directed hold disqualifies it the same way (#180): `blocked` is hand-set
|
||||
# intent — triage sets it, anyone may correct it — and during the #111
|
||||
# freeze rig#126/#128 carried it beside state:needs-human, so the board said
|
||||
# "mergeable right now" about PRs a hold said must not merge (rig#126 was
|
||||
# merged seven minutes later). Not a BLOCKERS entry, deliberately: that
|
||||
# array is machine-owned and the converge loop strips whatever the facts do
|
||||
# not re-derive, so emitting the label there would strip a live hold on the
|
||||
# next 15-minute tick — the same trap #51 names for `needs-ruling`.
|
||||
# state:addressing is the accepted imprecision: under a hold the builder
|
||||
# owes nothing, but "a human could merge this now" must not lie.
|
||||
if [ "$s" = state:needs-human ] && has_label blocked; then
|
||||
echo state:addressing; return
|
||||
fi
|
||||
echo "$s"
|
||||
}
|
||||
|
||||
|
|
|
|||
3
changelog.d/180.md
Normal file
3
changelog.d/180.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
- `decide_state()` refuses `state:needs-human` while the hand-set `blocked`
|
||||
label stands — the PR falls to `state:addressing`, exactly parallel to the
|
||||
`needs-ruling` exclusion; never emitted by `blockers()` (#180).
|
||||
|
|
@ -556,6 +556,34 @@ LABELS="needs-ruling"
|
|||
expect "needs-ruling adds nothing to blockers()" blocker:conflict "$(blockers)"
|
||||
MERGEABLE=MERGEABLE LABELS=""
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# blocked (#180): a directed hold. Same shape as needs-ruling — hand-set
|
||||
# intent the machine reads and never writes, an EXCLUSION on needs-human,
|
||||
# never a blocker and never a latch. During the #111 freeze rig#126/#128
|
||||
# carried blocked beside state:needs-human, and rig#126 was merged seven
|
||||
# minutes after the reconciler wrote the green label.
|
||||
# ---------------------------------------------------------------------------
|
||||
DRAFT=false HEAD_SHA=head1 REQUESTED="" REVIEWS_JSON="$ALL_APPROVE" MERGEABLE=MERGEABLE CHECKS=SUCCESS
|
||||
LABELS=""
|
||||
expect "the hold-free fixture hands off (control)" state:needs-human "$(decide_state)"
|
||||
LABELS="blocked"
|
||||
expect "a directed hold excludes needs-human" state:addressing "$(decide_state)"
|
||||
LABELS=""
|
||||
expect "...and clearing it hands off again — an exclusion, not a latch" state:needs-human "$(decide_state)"
|
||||
LABELS="blocked" DRAFT=true
|
||||
expect "a draft carrying blocked is still building" state:building "$(decide_state)"
|
||||
DRAFT=false
|
||||
|
||||
# blockers() must not know this label exists either: it is not a branch fact,
|
||||
# and the converge loop strips every BLOCKERS entry the facts do not
|
||||
# re-derive — emitting it there would strip a live hold on the next tick.
|
||||
MERGEABLE=CONFLICTING
|
||||
LABELS=""
|
||||
expect "conflict fixture emits its blocker (control)" blocker:conflict "$(blockers)"
|
||||
LABELS="blocked"
|
||||
expect "blocked adds nothing to blockers()" blocker:conflict "$(blockers)"
|
||||
MERGEABLE=MERGEABLE LABELS=""
|
||||
|
||||
# The guard the other fixtures cannot see: an UNGUARDED has_label read under
|
||||
# set -u does not go red — bash treats the unset expansion inside the
|
||||
# herestring redirection as a redirection error (bash 5.2: rc 127, the shell
|
||||
|
|
|
|||
Loading…
Reference in a new issue