forked from heavy-duty/box
decide_state() derived state from three inputs -- draft flag, requested reviewers, submitted reviews -- and read NOTHING about mergeability or checks. Combined with the `if requested "$HUMAN"` short-circuit at the top of its precedence, the label was sticky: once the maintainer was requested, the PR read state:needs-human through conflicts, through red CI, through a force-push that staled every approval. Nothing demoted it. Observed twice in one afternoon, in two different shapes. Three PRs sat at state:needs-human while CONFLICTING for hours -- the board inviting a merge GitHub had already disabled. And #119, after a rebase, read MERGEABLE, four green checks, state:needs-human, with ZERO reviews bound to its head: every visible signal saying "merge me" over a tree no reviewer had seen. That second shape is the dangerous one, because unlike a conflict nothing on the page contradicts it. The rule the label now keeps: state:needs-human means a human could merge this RIGHT NOW, so anything making that false outranks the request that put it there. CONFLICTING or failing checks -> state:needs-rebase (new; the agent's to fix) approvals staled by a push -> state:addressing (nobody reviewed this tree) An UNFINISHED round still yields to an explicit human request -- a maintainer pulling a PR to themselves early is deliberate, and MISSING (nobody has reviewed yet) is a different fact from STALE (everyone reviewed something else). That distinction is why the two are handled in different arms rather than collapsed. UNKNOWN mergeability is deliberately NOT treated as unmergeable: GitHub reports it for about a minute after every merge while it recomputes, and flapping every open PR through needs-rebase on each merge would be worse than the bug being fixed. A failed read of either fact degrades to the same "do not know" value, for the same reason -- an API hiccup must not relabel the board. Also adds merge-next, because a correct needs-human still does not say WHICH PR to merge first, and order matters when they conflict through CHANGELOG.md. Queue order is intent, so the reconciler never sets it; it only CLEARS it the moment the PR stops being mergeable-by-a-human -- precisely the staleness that made needs-human untrustworthy. Both live shapes are pinned in test/labels-reconcile.sh (19 -> 29 fixtures), including that UNKNOWN does not trigger needs-rebase and that a draft outranks a conflict. Proven non-vacuous: dropping the mergeability arm fails 4 assertions, dropping the STALE precedence fails 2, restoring returns 29/0. Closes #136 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| scripts | ||
| workflows | ||
| labeler.yml | ||