labels: state:needs-human is sticky again — the reconciler cannot tell its own human-request from a maintainer's #145
Labels
No labels
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-triage
ready
release
scope:cli
scope:drill
scope:host
scope:installer
scope:templates
scope:tiers
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/box#145
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
state:needs-humanis sticky again — not through a blocker or a staledapproval this time, but through the human request the reconciler makes
itself.
Observable right now
heavy-duty/cast#134, at head
601f616:One of three bots has approved this head, two are mid-round — and the board
says a human could merge it right now.
The loop
The PR reaches three head-current approvals.
decide_statereturnsstate:needs-human, solabels-reconcile.sh#L329-L332
requests the human, once:
The author pushes — a review round, a rebase, anything. Every approval
stales. The round is unfinished again.
Nothing withdraws the request. The reconciler asks the human once and
never retracts.
decide_statereachesL271 (and
L266 on the
MISSINGpath):…and the label comes back, on a round that is not passing.
Once a PR has passed a round even once, it reads
state:needs-humanfor therest of its life, through every subsequent push.
Why the rule itself is right, and the bug is elsewhere
The precedence is not wrong. LABELS.md is explicit and correct that "an
unfinished round still yields to an explicit human request — a maintainer
pulling a PR to themselves early is a deliberate act." A human claiming a PR
should outrank the bots.
The defect is that the reconciler cannot tell its own request from a
maintainer's.
requested "$HUMAN"is true either way. So a machine-derivedfact — "this round passed, at the time we looked" — gets re-read on every later
sweep as if it were a deliberate human act, long after the derivation stopped
holding.
That is the same shape as the bug this label already had twice. box#136 and
cast#127 made
needs-humannon-sticky with respect to blockers and staledapprovals. This is the third route to the same place, and the one LABELS.md
calls out as the worst kind:
Fix directions
Not prescribing one — the crux is the distinguishability problem, and each
option trades differently:
round-pass, it un-asks on round-regress (
DELETE .../requested_reviewers).Restores the invariant without needing to distinguish — but it would also
clear a maintainer's deliberate early request on the next push, which is
the case the precedence exists to protect.
marker the reconciler owns (which the label-taxonomy issue rejected for
other purposes, and would need re-arguing), or inferring from the request's
timing versus the head commit.
round (
MISSING) but not one whose approvals were staled by a push —which is already how LABELS.md justifies treating
MISSINGandSTALEasdifferent facts. This looks closest to the documented intent, and is the
smallest change to the precedence.
Option 3 is the one I would explore first, but the choice is a design call
about whose signal wins, so it wants a maintainer's view rather than mine.
Scope
labels-reconcile.shis byte-identical across box, rig and cast, so thisaffects all three and should land in all three together — same as the label
taxonomy work.
Found while handing off heavy-duty/box#144 and heavy-duty/rig#99, when
cast#134 flipped to
state:needs-humanwith a round still running.Triage: closing — the code this issue patches no longer lives in this repo. Box's labels workflow is now a thin caller of the shared machinery (
.github/workflows/labels.yml→uses: heavy-duty/ceremony/.github/workflows/labels.yml@0.1.0; see also "keep labels caller within pinned feature set",e4d9005). There is no.github/scripts/labels-reconcile.shhere to fix, so no box PR can close this.The substance is not stale, and it should not be lost — re-checked today (2026-08-17) against ceremony's current reconciler (
actions/labels-reconcile/labels-reconcile.sh):outstanding_requestsdrops a requested reviewer only once they hold a head-current verdict, so after a push stales the round the human re-enters the outstanding set — anddecide_state'sif requested "$HUMAN"precedence still cannot tell the reconciler's own request from a maintainer's deliberate claim. The loop described here (round passes once → human requested → push → stickystate:needs-humanforever) appears alive at HEAD.Where it belongs: heavy-duty/ceremony, through its own triage door. This report — with the cast#134 observable and the "distinguish own-request from maintainer-request" framing, which correctly preserves the precedence rule while fixing its input — is ready to be re-raised there. Box's only follow-up, once a fix ships, is the routine pin bump.