From 954bfeb8c36a57d1a2ddda4ac75d0d623a7e2194 Mon Sep 17 00:00:00 2001 From: Roberto Cano <3525807+robercano@users.noreply.github.com> Date: Wed, 15 Jul 2026 19:21:41 +0200 Subject: [PATCH] fix(harness): PR auto-assign silently no-oped on gh 2.4.0; add owner review-request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The owner never got assigned to (or asked to review) any bot PR: the follow-up used gh's `-f "assignees[]=..."` bracket-array syntax, which older gh releases (e.g. Ubuntu 22.04's packaged 2.4.0) encode as a literal "assignees[]" STRING field. GitHub ignores the unknown field and still returns 200, so the soft-fail warning never fired — zero assigned events on every PR since the feature landed (#33). - Send both payloads as explicit JSON via `gh api --input -` (version-proof back to early gh 2.x). - Verify the RESPONSE names the owner instead of trusting the exit code (the exit code is exactly what lied here); warn loudly otherwise. - Add the missing second follow-up: request a formal review from the owner, so bot PRs land in their GitHub review queue and fire the review-requested notification. Author is always the bot, so the no-self-review-request rule cannot trip. Verified live against PR #117: the bracket-syntax call returned 200 with assignees untouched; the JSON-body call assigned the owner. Co-Authored-By: Claude Fable 5 --- .claude/scripts/bot-gh.sh | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/.claude/scripts/bot-gh.sh b/.claude/scripts/bot-gh.sh index cb071a2..8c080ed 100755 --- a/.claude/scripts/bot-gh.sh +++ b/.claude/scripts/bot-gh.sh @@ -139,9 +139,30 @@ if [ "$has_assignee" -eq 0 ] && [ -n "$owner" ]; then if [ "$status" -ne 0 ]; then exit "$status"; fi pr_number="${pr_url##*/}" if [ -n "$repo_full" ] && [ -n "$pr_number" ]; then - if ! GH_TOKEN="$GH_BOT_TOKEN" gh api -X POST "repos/$repo_full/issues/$pr_number/assignees" -f "assignees[]=$owner" >/dev/null 2>&1; then + # Send the payload as an explicit JSON --input body, NEVER as + # `-f "assignees[]=..."`: gh only grew the bracket array syntax in later + # 2.x releases — on older gh (e.g. Ubuntu 22.04's packaged 2.4.0) it + # sends a literal "assignees[]" STRING field, which the API silently + # ignores while still returning 200. Exit code 0, nobody assigned, no + # warning — this exact silent no-op shipped for weeks. Same lesson for + # verification: don't trust the exit code, check the response actually + # names the owner (the closing quote in the grep keeps '-bot' + # style logins from matching as a prefix). + resp="$(printf '{"assignees":["%s"]}' "$owner" \ + | GH_TOKEN="$GH_BOT_TOKEN" gh api -X POST "repos/$repo_full/issues/$pr_number/assignees" --input - 2>/dev/null)" || resp="" + if ! printf '%s' "$resp" | grep -q "\"login\":\"$owner\""; then echo "bot-gh.sh: warning — created $pr_url but could not assign it to '$owner' (bot token may lack read:org); PR left unassigned." >&2 fi + # Also request a formal review from the owner: assignment alone does not + # put the PR in the owner's GitHub review queue or fire the + # review-requested notification. The author is always the bot here (the + # whole point of bot-gh.sh), so GitHub's no-self-review-request rule + # cannot trip on the owner. Soft-fail like the assignment. + resp="$(printf '{"reviewers":["%s"]}' "$owner" \ + | GH_TOKEN="$GH_BOT_TOKEN" gh api -X POST "repos/$repo_full/pulls/$pr_number/requested_reviewers" --input - 2>/dev/null)" || resp="" + if ! printf '%s' "$resp" | grep -q "\"login\":\"$owner\""; then + echo "bot-gh.sh: warning — created $pr_url but could not request a review from '$owner'; request it by hand so the owner is notified." >&2 + fi fi exit 0 fi