labels: state:needs-human is sticky and blind to mergeability, and nothing says which PR to merge next
#136
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
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/box#136
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 and blind to mergeability, so the board says "your turn" on PRs that cannot be merged — and there is no label that answers "which one do I merge next?"The bug
decide_state()in.github/scripts/labels-reconcile.shcomputes state from exactly three inputs: the draft flag, requested reviewers, and submitted review verdicts. It reads nothing aboutmergeable,mergeStateStatus, orstatusCheckRollup.And this line short-circuits everything:
Once the maintainer is requested, the PR reads
state:needs-humanpermanently. It stays there after the branch develops a conflict, after CI goes red, after a force-push staled every approval. Nothing demotes it.Live right now in this repo, all four labelled
state:needs-human:CONFLICTING/DIRTYCONFLICTING/DIRTYCONFLICTING/DIRTYMERGEABLE/CLEAN, but only 2 of 3 bots have approved at the current headNot one of them is mergeable. All four are telling the maintainer to come and merge.
Why this matters more than a wrong colour: the label is the only thing that makes the board scannable. A maintainer working from GitHub mobile — which is the realistic case, and the whole reason the label exists — has to open every PR to discover none of them are ready. The label is doing the opposite of its job: it converts "nothing to do" into four false invitations.
It is the same failure shape as a stale approval: the state looks settled because nothing contradicted it.
Fix 1 — mergeability outranks the human request
A review request is an opinion about who should look next.
mergeableis a fact about the tree. Facts should win. Proposed precedence:The human short-circuit stays — it is right that an explicit request outranks the bot rounds — it just must not outrank "this branch does not merge."
Fix 2 — a state for "the agent owes a rebase"
state:addressingcurrently means the coding agent owes a reply and fixes to a review round. A conflicted branch also needs agent work, but it is a different job, triggered by a different event, and needs a different action. Folding them together loses that.Proposal:
state:needs-rebase— the branch does not merge (conflict, or a failing required check) and the agent owes a rebase or a fix. Distinct fromaddressing, which stays "owes a reply to reviewers".If you would rather not add a state, reusing
state:addressingis still strictly better than the status quo, because it at least stops claiming the maintainer is the blocker.Fix 3 —
merge-next, so the board answers the actual questionEven with the above correct,
state:needs-humanon three PRs does not say which one to merge first. Ordering matters here: these PRs conflict with each other throughCHANGELOG.mdandtest/cli.sh, so merging out of order costs a rebase every time.Proposal: a
merge-nextlabel on exactly one PR — the head of the merge queue.Unlike
state:*, this cannot be derived from GitHub's facts: queue order is intent. So it follows theblocked/releaseconvention in LABELS.md — set by a human or by the agent maintaining the queue, and never guessed by the reconciler. The reconciler's only job would be to clear it when the PR merges or stops being mergeable, so it cannot go stale the wayneeds-humandid.With all three, the mobile view becomes answerable at a glance:
merge-next+state:needs-human-> merge this onestate:needs-rebase-> agent is on it, ignorestate:bots-reviewing/state:addressing-> not your turnAcceptance
decide_state()readsmergeable/mergeStateStatusand the check rollupstate:needs-human, even with the human requestedstate:needs-rebase(or a documented decision to reusestate:addressing)merge-nextexists, is agent/human-set, and is cleared automatically when the PR merges or stops being mergeableCONFLICTINGmust NOT resolve tostate:needs-humanNote
rig and cast share this reconciler and this failure. Filing there as thin cross-references so the three do not drift; whichever lands first is the reference implementation.
Siblings, same defect byte for byte, each with its own evidence: heavy-duty/rig#87, heavy-duty/cast#127.
A second live case, and it is a different flavour from the conflicts in the issue body — worth pinning because a fix aimed only at mergeability would miss it.
Right now, #119:
Everything the maintainer can see says merge me: green, mergeable, "waiting on the human". But no bot has reviewed this tree. A force-push (a rebase, in this case) moved head and staled all three approvals; the reconciler kept
state:needs-humanbecauseif requested "$HUMAN"short-circuits atdecide_state()line 90, before the*STALE*arm at line 103 is ever consulted.So the sticky label has two failure modes, not one:
Both end at the same place: the board invites a merge that should not happen. The second is the more dangerous one, because nothing else on the page contradicts it — with conflicts, at least the merge button is disabled.
Implication for the fix: precedence must put the
*STALE*check above the human short-circuit too, not just mergeability. Suggested order:The rule underneath:
state:needs-humanshould mean "a human could merge this right now". Anything that makes that false — unmergeable, red, or unreviewed at head — must outrank the request that put it there.Worth a fixture for this exact shape: human requested +
MERGEABLE/CLEAN+ zero head-current reviews must NOT resolve tostate:needs-human.