From 11d475c097d55b5bd7d9ce8271be8762c4266faa Mon Sep 17 00:00:00 2001 From: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com> Date: Sun, 22 Mar 2026 12:00:22 +0000 Subject: [PATCH 1/2] fix(skills): approve after trivial follow-up to COMMENTED review The review-pr skill assumed the prior bot review was always APPROVED when skipping trivial incremental changes. When the prior review was COMMENTED (requesting changes), the bot said "existing approval stands" but no approval existed, leaving the PR without bot approval. Extract LAST_REVIEW_STATE alongside LAST_REVIEW_SHA in the preflight, and after resolving threads on trivial follow-ups, submit an approval when the prior state was non-APPROVED. Evidence: 2 occurrences (PR #1655 run 23401754507, plus 1 historical). Co-Authored-By: Claude Opus 4.6 --- .claude/skills/review-pr/SKILL.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/.claude/skills/review-pr/SKILL.md b/.claude/skills/review-pr/SKILL.md index 7acf5bcb60..5da6f27f12 100644 --- a/.claude/skills/review-pr/SKILL.md +++ b/.claude/skills/review-pr/SKILL.md @@ -33,8 +33,10 @@ PR_AUTHOR=$(gh pr view --json author --jq '.author.login') # Uses "| length > 0" instead of "!= \"\"" to avoid bash ! history expansion. # IMPORTANT: `gh pr view --json reviews` returns `.commit.oid` (NOT `.commit_id`). # The REST API (`gh api .../reviews`) uses `.commit_id` — don't confuse the two. -LAST_REVIEW_SHA=$(gh pr view --json reviews \ - --jq "[.reviews[] | select(.author.login == \"$BOT_LOGIN\" and (.body | length > 0 or .state == \"APPROVED\"))] | last | .commit.oid // empty") +LAST_REVIEW=$(gh pr view --json reviews \ + --jq "[.reviews[] | select(.author.login == \"$BOT_LOGIN\" and (.body | length > 0 or .state == \"APPROVED\"))] | last | {sha: (.commit.oid // empty), state: (.state // empty)}") +LAST_REVIEW_SHA=$(echo "$LAST_REVIEW" | jq -r '.sha // empty') +LAST_REVIEW_STATE=$(echo "$LAST_REVIEW" | jq -r '.state // empty') ``` If `LAST_REVIEW_SHA == HEAD_SHA`, this commit has already been reviewed — exit @@ -50,13 +52,21 @@ gh api "repos/$REPO/compare/$LAST_REVIEW_SHA...$HEAD_SHA" \ --jq '{total: ([.files[] | .additions + .deletions] | add), files: [.files[] | "\(.filename)\t+\(.additions)/-\(.deletions)"]}' ``` -If the incremental changes are trivial, skip the full review **and do not -submit a new approval** — the existing review stands. Go directly to step 7 to -resolve any bot threads addressed by the new changes, then exit. Do NOT proceed +If the incremental changes are trivial, skip the full review — go directly to +step 7 to resolve any bot threads addressed by the new changes. Do NOT proceed to steps 2, 3, or 4. Rough heuristic: changes under ~20 added+deleted lines that don't introduce new functions, types, or control flow are typically trivial. +After resolving threads, check `LAST_REVIEW_STATE`: +- **`APPROVED`** — the existing approval stands, do not submit a new one. Exit. +- **`COMMENTED`** (or any non-APPROVED state) — the prior review requested + changes that the trivial follow-up now addresses. Submit an approval: + ```bash + gh pr review --approve -b "" + ``` + Then proceed to step 6 (monitor CI). + Then read all previous bot feedback and conversation: ```bash From 4b2bd9c08fed2868fe2a490abdc659b6d0edd267 Mon Sep 17 00:00:00 2001 From: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com> Date: Sun, 22 Mar 2026 17:05:24 +0000 Subject: [PATCH 2/2] fix(skills): scope jq pipe in LAST_REVIEW filter to prevent runtime error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `(.body | length > 0 or .state == "APPROVED")` expression has a jq pipe precedence bug: `|` has the lowest precedence in jq, so `.state` resolves against the body string (pipe output), not the review object. This causes `Cannot index string with string "state"` when the bot's prior review has an empty body (every `--approve -b ""` approval). Fix: `((.body | length) > 0 or .state == "APPROVED")` — parenthesizing the pipe scopes it correctly. Co-Authored-By: Claude Opus 4.6 --- .claude/skills/review-pr/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.claude/skills/review-pr/SKILL.md b/.claude/skills/review-pr/SKILL.md index 5da6f27f12..1b260167ce 100644 --- a/.claude/skills/review-pr/SKILL.md +++ b/.claude/skills/review-pr/SKILL.md @@ -34,7 +34,7 @@ PR_AUTHOR=$(gh pr view --json author --jq '.author.login') # IMPORTANT: `gh pr view --json reviews` returns `.commit.oid` (NOT `.commit_id`). # The REST API (`gh api .../reviews`) uses `.commit_id` — don't confuse the two. LAST_REVIEW=$(gh pr view --json reviews \ - --jq "[.reviews[] | select(.author.login == \"$BOT_LOGIN\" and (.body | length > 0 or .state == \"APPROVED\"))] | last | {sha: (.commit.oid // empty), state: (.state // empty)}") + --jq "[.reviews[] | select(.author.login == \"$BOT_LOGIN\" and ((.body | length) > 0 or .state == \"APPROVED\"))] | last | {sha: (.commit.oid // empty), state: (.state // empty)}") LAST_REVIEW_SHA=$(echo "$LAST_REVIEW" | jq -r '.sha // empty') LAST_REVIEW_STATE=$(echo "$LAST_REVIEW" | jq -r '.state // empty') ```