Skip to content

feat(iterate-pr): acknowledge top-level feedback with a reaction - #78

Merged
thecodedrift merged 3 commits into
mainfrom
feat/iterate-pr-ack-reaction
Jul 30, 2026
Merged

feat(iterate-pr): acknowledge top-level feedback with a reaction#78
thecodedrift merged 3 commits into
mainfrom
feat/iterate-pr-ack-reaction

Conversation

@thecodedrift

Copy link
Copy Markdown
Member

A top-level review comment has no thread to resolve, so the skill deduped by scanning existing comments for a reference marker citing the same author and snippet. That is fragile, and it failed in practice: on #75 and again on #77 the review summary kept reporting as unaddressed after it had been answered, leaving a permanent needs_attention that had to be reasoned about by hand on every pass — exactly the "I see it but we dealt with it" loop this removes.

A 🎉 reaction on the original comment is a machine-readable acknowledgement. fetch_pr_feedback.py now reads reactions.hooray, marks the item acknowledged, and buckets it as resolved, so a re-run reports zero rather than re-surfacing it. GitHub returns the reactions object on comments by default, so this costs no extra API call.

Verified on #77: needs_attention went 2 → 0 with no other change.

One thing the docs now call out explicitly. The reaction must be posted against the PR-scoped endpoint:

repos/{owner}/{repo}/issues/<pr>/comments      ← correct
repos/{owner}/{repo}/issues/comments           ← every comment in the repository

I used the repo-wide form while doing this and took the last match. It happened to be the right comment, but only by luck — with a busier repo it would have reacted on some other PR's review. Items now carry comment_id so the id comes from the feedback data instead of from matching body text.

The inline-thread path is unchanged: those still reply-then-resolve, which was already reliable.

A top-level review comment has no thread to resolve, so the skill had
to dedupe by scanning existing comments for a reference marker citing
the same author and snippet. That is fragile, and it failed in practice
— on #75 and again on #77 the summary comment kept reporting as
unaddressed after it had been answered, leaving a permanent
needs_attention to reason about by hand every pass.

A hooray reaction on the original is a machine-readable acknowledgement.
fetch_pr_feedback now reads reactions.hooray, marks the item
acknowledged, and buckets it as resolved, so a re-run reports zero
instead of re-surfacing it. Verified on #77: needs_attention went 2 to 0
with no other change.

The reaction step is documented against the PR-scoped comments endpoint
specifically. The repo-wide repos/{owner}/{repo}/issues/comments returns
every comment in the repository, and selecting from it will eventually
react on another PR's comment — I did exactly that here and got the
right answer by luck.

Items now carry comment_id so the id comes from the feedback data rather
than from matching body text.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CDv57zHq7abms3RReSQw6q
@thecodedrift thecodedrift added the skip-changeset PR intentionally ships no release note (bypasses the changeset requirement) label Jul 30, 2026
@thecodedrift
thecodedrift marked this pull request as ready for review July 30, 2026 20:45
@thecodedrift

Copy link
Copy Markdown
Member Author

@claude /review

@claude

claude Bot commented Jul 30, 2026

Copy link
Copy Markdown

Claude finished @thecodedrift's task in 3m 5s —— View job


Review complete

  • Gather context (diff, changed files)
  • Review fetch_pr_feedback.py changes
  • Review SKILL.md changes
  • Post overall assessment

Summary

The core mechanism is sound: reading reactions.hooray off GET .../issues/{pr}/comments (which the script already fetches) to mark a top-level comment acknowledged/resolved is a clean, no-extra-call fix for the stated problem (fragile marker-text scanning under-reporting resolution on #75/#77). The comment_id plumb-through so agents react by id instead of matching body text is a good simplification, and the PR-scoped vs. repo-wide endpoint distinction called out in the docs is correct and worth having in writing.

I left 3 inline comments with concrete, verifiable issues:

  1. Regression for review_summary items (SKILL.md line 215, and the framing at line 183) — the new reaction-based dedup is only wired up for issue comments (fetch_pr_feedback.py's get_issue_comments loop). Formal PR review bodies (review_summary/changes_requested, sourced from pr_info["reviews"]) never get a comment_id, and the old marker-scan dedup text that used to cover all top-level items (including these) was removed. Net effect: review summaries now have no dedup mechanism at all, which is the same "keeps re-surfacing after being addressed" bug this PR sets out to fix, just for a narrower item type.
  2. Missing --paginate on the example verification command (SKILL.md line 193) — get_issue_comments() in the script paginates, but the doc's one-off select(.id == <comment_id>) check doesn't, so it can silently miss real comments past the first 30 on a busy PR.
  3. Reaction isn't actor-scoped (fetch_pr_feedback.py line 474) — reactions.hooray > 0 counts anyone's 🎉, not just the agent's own. A human celebrating a comment for unrelated reasons would silently mark it resolved. Low-probability but a silent failure mode worth a one-line callout.

Nothing here blocks the core idea — #1 is the one I'd actually want addressed (or explicitly scoped out of this PR's claims) before merge, since the PR description currently implies full coverage of "top-level comments" including review summaries.

Comment thread .agents/skills/iterate-pr/SKILL.md Outdated
Comment thread .agents/skills/iterate-pr/SKILL.md Outdated
Comment thread .agents/skills/iterate-pr/scripts/fetch_pr_feedback.py Outdated
Review found the raw count trusts anyone: a maintainer reacting 🎉 to a
review comment for unrelated reasons would bucket it resolved and drop
real feedback silently — the one direction this must never fail in.

Now confirmed against the authenticated user, and fails closed: if the
viewer cannot be identified or the lookup errors, the item resurfaces.
Answering twice beats dropping something. The per-comment reactions
lookup is skipped when the count is zero, so the common case costs no
extra call.

Two more from the same review. The 🎉 dedupe only ever worked for issue
comments, but the docs implied it covered review_summary items too —
GitHub exposes no reactions endpoint for a review body, so those have no
reaction target and keep the reference-marker scan. And the documented
lookup query lacked --paginate, which defaults to 30 per page and would
silently miss a comment on a later page.

Verifying this caught a bug in the fix itself: the viewer lookup used
`gh api user --jq .login`, but run_gh json.loads() its stdout and --jq
emits a bare unquoted string. It threw, failed closed, and every item
resurfaced — correct behavior from a broken lookup, which is the good
kind of failure but still wrong. Reads the login off the object now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CDv57zHq7abms3RReSQw6q
@thecodedrift

Copy link
Copy Markdown
Member Author

Re: @claude[bot] — "Claude finished @thecodedrift's task in 3m 5s — Review complete… The core mechanism is sound…"
#78 (comment)

All three findings fixed; each has a reply on its thread.

Unscoped reaction count — the important one, and the failure direction was right: anyone's 🎉 would have dropped real feedback silently. Now confirmed against the authenticated user and fails closed, so an unidentifiable viewer resurfaces the item rather than hiding it. Verified three ways: our reaction → true, viewer swapped to another login → false, zero count → false with no API call.

review_summary gap — the docs overclaimed. GitHub has no reactions endpoint for a review body, so those items never had a reaction target. The skill now scopes the mechanism to items carrying a comment_id and keeps the reference-marker scan for the rest.

Missing --paginate — fixed, and worth the callout: the script paginated but the doc example did not, and the doc is the copied one.

Verifying the scoping fix also caught a bug inside it — gh api user --jq .login returns a bare string that run_gh's json.loads() rejects, so the lookup threw and everything resurfaced. Fail-closed did its job, but from a broken lookup.

— AI Coding Agent

@thecodedrift
thecodedrift merged commit 570b34d into main Jul 30, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changeset PR intentionally ships no release note (bypasses the changeset requirement)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant