Skip to content

Commit 64045e5

Browse files
johanzanderclaude
andauthored
fix: make a resumed PR read its comments, not only its reviews (#631)
Reviews and conversation comments are two different feeds, and `gh pr view --json reviews` returns only the first. Step 0's rehydration list said "the diff itself, and any inline review comments" and never mentioned the conversation, so a session that followed it exactly still missed the thing that mattered most. That is not hypothetical. On #620 the maintainer posted "this PR should shrink" with a four-step plan: branch protection now rejects pushes to `main` server-side, so the protected-ref enumeration should be DELETED rather than extended. A later session read the reviews, did not read the comments, and spent a full rework ADDING protected-ref patterns — the exact opposite of a standing instruction sitting in the PR's own thread. Two further holes the maintainer had found by hand (`git push origin refs/tags/v1.2.3`, `git push origin HEAD`) were in that same comment and stayed open. The asymmetry is structural, not incidental: a review must attach to a diff, so direction — "do this differently", "this whole approach changed" — can only be expressed in a comment. That makes the feed the skill ignored the one carrying the highest-authority input. So: `comments` joins `reviews` in the Step 0 query; the rehydration list names the conversation explicitly and gives both commands; and a maintainer comment is stated to outrank every bot review on the PR, including later ones. Step 11 re-checks comments each round rather than only at Step 0, because a direction posted mid-loop is invisible to the verdict feed — the bot will keep approving a diff the maintainer has already asked you to redo. The CI-mode table gets the same note, where it matters more: Stage 3's re-trigger IS a comment, so the reason is usually in the same thread. Two Rationalizations rows and two Red Flags name the failure directly, since "I read the reviews, so I know what this PR needs" is exactly how it reads from the inside. No CHANGELOG entry: agent tooling, no user-visible effect. Claude-Session: https://claude.ai/code/session_012LExo6fcbup75vtc9NfoAR Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 42d25bf commit 64045e5

1 file changed

Lines changed: 58 additions & 2 deletions

File tree

.claude/skills/implement-issue/SKILL.md

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ runners — only repo-level `.claude/skills/` and `.claude/agents/` exist there.
5858

5959
| Step | CI mode |
6060
|---|---|
61-
| 0. Resume check | Applies, and matters more here: Stage 3 is re-triggered by hand, so a second `@claude-bot fix` on an issue that already has a `has-fix-pr` PR is a resume, not a restart. Detect the existing PR and continue it — never open a second PR for one issue. The CI checkout has no worktrees, so branch existence on `origin` is the only signal available. |
61+
| 0. Resume check | Applies, and matters more here: Stage 3 is re-triggered by hand, so a second `@claude-bot fix` on an issue that already has a `has-fix-pr` PR is a resume, not a restart. Detect the existing PR and continue it — never open a second PR for one issue. The CI checkout has no worktrees, so branch existence on `origin` is the only signal available. Reading the PR's **conversation comments** matters more here too, not less: the re-trigger is itself a comment, so the maintainer has very often said *why* in the same thread. |
6262
| 2. Diagnose | Stage 2 comment absent → STOP. Post "No deep analysis found. Run `@claude-bot analyze` first" and exit — never self-diagnose in CI; the analyze/fix split *is* the human gate. |
6363
| 3. Confirm gate | The owner's `@claude-bot fix` comment is the go-ahead. Still perform the workaround check and scope assessment — put them in a `## Scope assessment` section of the PR body instead of chat. Escalation path (can't confidently pass the workaround check) still applies: dispatch a fresh general-purpose `Agent` to critique the design before implementing. |
6464
| 4. Worktree | Skip — the CI checkout is already isolated. Create the branch directly (naming per Step 1). |
@@ -85,10 +85,14 @@ for `TODO.md` items and for refactors that never had an issue, so a PR with no
8585
linked issue is the normal shape for that work, not a defect.
8686

8787
```bash
88-
gh pr view <n> --json number,headRefName,isDraft,mergeable,reviews 2>/dev/null \
88+
gh pr view <n> --json number,headRefName,isDraft,mergeable,reviews,comments 2>/dev/null \
8989
|| gh issue view <n> --json number,title,labels,body,comments
9090
```
9191

92+
**`comments` is in that list deliberately — do not drop it.** It is a separate
93+
feed from `reviews`, it is where the maintainer sets direction, and omitting it
94+
has already cost one full rework (see Rehydrate, below).
95+
9296
If `<n>` is a **PR**, resume from it directly — it is the stronger handle,
9397
carrying the branch, the diff, the `## Scope assessment` and the review verdict,
9498
which is everything the table below reads. Read its linked issue too if it
@@ -127,8 +131,38 @@ this skill already forces it to be written down:
127131
discriminate. Interactive mode keeps its scope assessment conversational, so
128132
that heading is absent on most PRs this skill opens; the PR's existence is
129133
what proves Step 9 was reached, not any particular heading
134+
- **the PR CONVERSATION comments, not only its reviews** — see below
130135
- the diff itself, and any inline review comments
131136

137+
**Reviews and conversation comments are two different feeds, and `gh pr view
138+
--json reviews` returns only the first.** Read both, every time:
139+
140+
```bash
141+
gh pr view <n> --json reviews --jq '.reviews[] | "\(.author.login) \(.state) \(.submittedAt)\n\(.body)"'
142+
gh pr view <n> --json comments --jq '.comments[] | "\(.author.login) \(.createdAt)\n\(.body)"'
143+
```
144+
145+
**A maintainer conversation comment OUTRANKS every bot review on the PR**,
146+
including ones submitted after it. The bot reviews the diff; the maintainer
147+
decides the direction, and they change direction in comments — that is the
148+
only place they can, since a review has to attach to a diff.
149+
150+
This is not hypothetical. On #620 the maintainer posted "**this PR should
151+
shrink**" with a four-step plan: branch protection now rejects pushes to `main`
152+
server-side, so the protected-ref *enumeration* should be **deleted** rather
153+
than extended. A later session read the reviews, did not read the comments,
154+
and spent a full rework **adding** protected-ref patterns — the exact opposite
155+
of the standing instruction, on a PR whose own thread already said so. Two
156+
further holes the maintainer had found by hand (`git push origin
157+
refs/tags/v1.2.3`, `git push origin HEAD`) were in that comment too, and stayed
158+
open because nobody read it.
159+
160+
So: **before touching code on a resumed PR, read the human comments first, and
161+
newest-first.** If one sets a direction the diff contradicts, that is a
162+
STOP-and-confirm, not something to reconcile silently — the maintainer may have
163+
changed their mind since, and asking costs one message where guessing costs a
164+
rework.
165+
132166
**If those sources do not reconstruct a coherent diagnosis, STOP and report
133167
it.** Do not re-diagnose from scratch on top of someone else's half-finished
134168
branch: you would be building on a design you cannot see, and the commits
@@ -674,6 +708,20 @@ On the verdict:
674708
silently ignore it either.
675709
- **A review from the maintainer rather than the bot** (the `<author>` field):
676710
treat it as authoritative and stop the loop — a human has taken over.
711+
- **A maintainer CONVERSATION comment, which is not a review at all**, is
712+
equally authoritative and arrives on a feed the verdict never touches. Check
713+
it each round, not only at Step 0 — a direction posted mid-loop is invisible
714+
to `gh pr view --json reviews`, and to the bot, which will keep reviewing the
715+
diff as if nothing had been said:
716+
717+
```bash
718+
gh pr view <n> --json comments \
719+
--jq '.comments[] | select(.createdAt > "<submittedAt from the round before>") | "\(.author.login)\n\(.body)"'
720+
```
721+
722+
If one lands, stop the loop and act on it before the next round. A bot
723+
APPROVED on a diff the maintainer has already asked you to redo is worth
724+
nothing.
677725

678726
Fix the blockers, park genuine nits in `TODO.md`, run
679727
`./scripts/quality-check.sh`, commit, and push. Step 9's frontend rule carries
@@ -756,6 +804,8 @@ net is upstream, not this section.
756804
| "the old branch is a mess, cleaner to redo it" | Its commits are the only copy of a diagnosis you no longer have. If you genuinely cannot reconstruct the approach, that is a STOP-and-report, not a licence to reset. |
757805
| "that worktree's session shows dead, so it's mine to take" | Check unsandboxed. A sandboxed `claude agents --json` returned 1 session where the real answer was 17, because `~/.claude/jobs` is sandbox-denied — every other session read as dead. |
758806
| "the review said CHANGES_REQUESTED but nobody assigned it to me" | Nothing else will pick it up. Once the opening session exits, an orphaned PR has no owner at all — `sweep-prs` refuses the job by design. Resuming is how it gets one. |
807+
| "I read the reviews, so I know what this PR needs" | Reviews and conversation comments are separate feeds and `--json reviews` returns only one. The maintainer sets *direction* in comments, because a review can only attach to a diff. On #620 that cost a full rework in the opposite direction. |
808+
| "the bot approved it, so the direction must be fine" | The bot reviews the diff against a checklist; it has no idea what the maintainer asked for in the thread. An approval on a diff you were told to redo is worth nothing. |
759809
| "I can see the assertion is right, no need to run it red" | Assertions that look right have repeatedly bounded only one side, or compared a quantity a second varying term swamped. Seeing it fail is the cheap part. |
760810
| "quality-check.sh passed, that's enough" | Green tests prove the suite is satisfied, not that the fix behaves correctly against the real scenario. Step 8 requires observed output, every time. |
761811
| "the diagnosis is obviously right, skip the confirm gate" | Wrong diagnoses are exactly when confidence is highest. One message, cheap insurance. |
@@ -787,6 +837,12 @@ net is upstream, not this section.
787837
- About to re-diagnose from scratch on top of someone else's half-finished
788838
branch because the Stage 2 comment and PR body didn't reconstruct the
789839
approach. That is a STOP-and-report.
840+
- **About to change code on a resumed PR without having read its conversation
841+
comments** — not just its reviews. They are separate feeds, and the
842+
maintainer's direction lives in the one `--json reviews` does not return.
843+
- About to implement a diff that contradicts a maintainer comment already on
844+
the thread. Stop and confirm; they may have moved on, but guessing costs a
845+
rework and asking costs one message.
790846
- About to open a second PR for an issue that already has one.
791847
- About to relaunch an issue that has already died twice without saying so.
792848
- About to commit or open the PR without having actually run/observed the

0 commit comments

Comments
 (0)