fix: base the human auto-request on this handoff, not review history #87
2 changed files with 44 additions and 6 deletions
23
.github/scripts/labels-reconcile.sh
vendored
23
.github/scripts/labels-reconcile.sh
vendored
|
|
@ -73,6 +73,16 @@ bot_verdict() { # $1 = login → MISSING | BLOCK | APPROVE | STALE | FEEDBACK
|
|||
esac
|
||||
}
|
||||
|
||||
human_request_needed() { # 0 when needs-human requires a FRESH human request
|
||||
# already requested → the handoff is live; head-current human approval →
|
||||
# nothing left to ask. Anything else (never reviewed, an old comment, an
|
||||
# approval of an older head) stalls the handoff unless we request —
|
||||
# guarding on "has the human ever reviewed" wedged exactly that way.
|
||||
if requested "$HUMAN"; then return 1; fi
|
||||
if [ "$(bot_verdict "$HUMAN")" = APPROVE ]; then return 1; fi
|
||||
return 0
|
||||
}
|
||||
|
||||
decide_state() { # → the one state:* label this PR should carry
|
||||
if [ "$DRAFT" = true ]; then echo state:building; return; fi
|
||||
# an explicit human request outranks the bot rounds — it is the final
|
||||
|
|
@ -136,12 +146,13 @@ 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: three formal
|
||||
# head-current approvals → the human is asked, once. The guard (never
|
||||
# requested, never reviewed) makes it idempotent — and the shared
|
||||
# concurrency group in labels.yml makes it race-free. With a comment-only
|
||||
# bot on the panel this path stays cold and the AUTHOR requests the human.
|
||||
if [ "$desired" = state:needs-human ] && ! requested "$HUMAN" \
|
||||
&& [ -z "$(jq -r --arg u "$HUMAN" '[.[] | select(.user.login == $u)] | last | .state // empty' <<<"$REVIEWS_JSON")" ]; then
|
||||
# head-current approvals → 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
|
||||
# concurrency group in labels.yml. With a comment-only bot on the panel
|
||||
# this path stays cold and the AUTHOR requests the human.
|
||||
if [ "$desired" = state:needs-human ] && human_request_needed; then
|
||||
run gh api "repos/$REPO/pulls/$n/requested_reviewers" -f "reviewers[]=$HUMAN" --silent
|
||||
log "#$n: requested $HUMAN (round passed)"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -119,5 +119,32 @@ REQUESTED="$HUMAN"
|
|||
expect "re-requested human is needs-human again" state:needs-human "$(decide_state)"
|
||||
REQUESTED=""
|
||||
|
||||
# -- an old human comment must not wedge the handoff (codex, #85 round 3) -----
|
||||
REVIEWS_JSON="$(reviews \
|
||||
"$(rev "$HUMAN" COMMENTED old1 "early thoughts" t0)" \
|
||||
"$(rev "$BOT1" APPROVED head1 "" t1)" \
|
||||
"$(rev "$BOT2" APPROVED head1 "" t2)" \
|
||||
"$(rev "$BOT3" APPROVED head1 "" t3)")"
|
||||
expect "old human comment + three approvals is needs-human" state:needs-human "$(decide_state)"
|
||||
expect "old human comment still needs a fresh request" needed "$(human_request_needed && echo needed || echo not-needed)"
|
||||
# ...a stale human APPROVAL likewise needs a re-request for the new head
|
||||
REVIEWS_JSON="$(reviews \
|
||||
"$(rev "$HUMAN" APPROVED old1 "" t0)" \
|
||||
"$(rev "$BOT1" APPROVED head1 "" t1)" \
|
||||
"$(rev "$BOT2" APPROVED head1 "" t2)" \
|
||||
"$(rev "$BOT3" APPROVED head1 "" t3)")"
|
||||
expect "stale human approval needs a fresh request" needed "$(human_request_needed && echo needed || echo not-needed)"
|
||||
# ...a HEAD-CURRENT human approval needs nothing more
|
||||
REVIEWS_JSON="$(reviews \
|
||||
"$(rev "$HUMAN" APPROVED head1 "" t0)" \
|
||||
"$(rev "$BOT1" APPROVED head1 "" t1)" \
|
||||
"$(rev "$BOT2" APPROVED head1 "" t2)" \
|
||||
"$(rev "$BOT3" APPROVED head1 "" t3)")"
|
||||
expect "head-current human approval needs no request" not-needed "$(human_request_needed && echo needed || echo not-needed)"
|
||||
# ...and a live request suppresses re-requesting
|
||||
REQUESTED="$HUMAN"
|
||||
expect "live human request suppresses re-request" not-needed "$(human_request_needed && echo needed || echo not-needed)"
|
||||
REQUESTED=""
|
||||
|
||||
printf 'labels-reconcile tests: %d passed, %d failed\n' "$pass" "$fail"
|
||||
[ "$fail" -eq 0 ]
|
||||
|
|
|
|||
Loading…
Reference in a new issue