Add /address-review: work every pre-merge review finding to a decision - #21061
Add /address-review: work every pre-merge review finding to a decision#21061CamSoper wants to merge 3 commits into
Conversation
The review pipeline finds things and has no way to make anyone look at them. `scrape-review-outcomes.py` has an `ignored_low_confidence` column precisely because authors clear 🚨 and stop reading. New author-side skill `/address-review`: watches for the pinned review to land after a PR goes ready, enumerates every item that needs a decision (including the inline one-click style suggestions), walks them one at a time with a proposed fix for each, batches the fixes into a single push, writes the `#update-review` mention, and won't call the PR done while anything is undecided. Two references cover watching (event subscription vs. bounded polling) and the closed disposition set (fixed / refuted / deferred / accepted / not-applicable, the last three note-required). `review-worklist.py` is the deterministic half: it parses the pinned body through validate-pinned.py's helpers (one parser for the comment format), merges in the inline suggestions, assigns stable per-finding ids, and answers "is anything still open?" with --require-clean. State lives in a gitignored .review-worklist-<PR>.json so a lost session resumes. Meta changes making this the expectation rather than an option: - AGENTS.md: shipping a PR includes finishing its review. - CONTRIBUTING.md: §Working the review to zero — the five outcomes, and why an unrefreshed fix scrapes as ignored. - /shipit: new mandatory Step 9 hands off to the review loop; PRs now open as drafts per CONTRIBUTING §Draft-first. - /pr-review: disclose what a merge would be merging over. - /docs-review: point at the post-push half. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017e8zEPDdXm3xuDfLWBfbP5
There was a problem hiding this comment.
✅ No issues found
About Unblocked
Unblocked has been set up to automatically review your team's pull requests to identify genuine bugs and issues.
📖 Documentation — Learn more in our docs.
💬 Ask questions — Mention @unblocked to request a review or summary, or ask follow-up questions.
👍 Give feedback — React to comments with 👍 or 👎 to help us improve.
⚙️ Customize — Adjust settings in your preferences.
|
Your site preview for commit 7f15832 is ready! 🎉 http://www-testing-pulumi-docs-origin-pr-21061-7f158321.s3-website.us-west-2.amazonaws.com |
Pre-merge Review — Last updated 2026-08-21T23:15:33ZTip Summary: Agent-tooling PR, not reader-facing content: it adds the Review confidence:
Investigation log
🔍 Verification trail43 claims extracted · 5 verified · 0 unverifiable · 0 contradicted
🚨 Outstanding in this PRNo outstanding findings.
|
… bucket table Round 1 of #21061's own review — 1 blocker, 3 low-confidence, all fixed. 🚨 [L127-144] fetch_inline_suggestions returned [] on both a gh failure and a decode failure, indistinguishable from "this PR has no suggestions", so --require-clean could answer "clean" for a worklist whose ✏️ items were never enumerated — the opposite of the docstring's fail-closed promise. It now returns (suggestions, ok), and `ok` gates `clean` alongside parse_confidence. A failed fetch renders its own warning banner and the header reads "every listed item decided — but the list is incomplete" rather than "0 items still open".⚠️ [L188] `text` carried only the bullet's first line, because the shared parser returns column-0 lines by design — dropping the fix prose and suggested patch, which is the part the author acts on and what the skill's Step 4 "Proposal:" is built from. New _bullet_blocks() groups each bullet with its continuation lines; one block per bullet, so counts are unchanged.⚠️ [L96] The BUCKETS table read as config for all four buckets while only two rows were live: _split_low_confidence hard-coded the⚠️ heading and both loops hard-coded their flags. All four paths now read the table.⚠️ [L326] /shipit's closing line said "ready for review" immediately after this PR made PR creation unconditionally --draft. Now says what's true. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017e8zEPDdXm3xuDfLWBfbP5
|
@claude #update-review All four findings fixed in 7cb09b9 — no disputes. [L127-144] 🚨 — you were right, and the docstring was writing a check the code didn't cash. [L188] [L96] [L326] Self-test extended to cover all three code fixes — multi-line bullet capture, block boundaries, and a failed fetch blocking Generated by Claude Code |
|
🤖 Review updated on @CamSoper's request. |
…let regex Both round-2 findings were⚠️ low-confidence; both are real and cheap.⚠️ [L153-164] The suggestions fetch failed closed on a total decode failure but not a partial one: decoded_any latched True on the first page that parsed, so a JSONDecodeError — or a valid-JSON error object — on page 2 returned (short list, ok=True). A genuinely short suggestion set that reads as complete is the same signal loss as an empty one, just quieter. Adds failed_any; ok is now `decoded_any and not failed_any`.⚠️ [L44-48] The module docstring claimed parsing kept "exactly one parser" via extract_bucket_bullets, which stopped being true when _bullet_blocks replaced that call and duplicated its bullet regex. Took the reviewer's second option — export the rule rather than document the divergence — and it turned out the regex already existed in four places: twice inside validate-pinned.py, once in scrape-review-outcomes.py, once here. Hoisted it to validate-pinned.FINDING_START_RE; all four sites now reference the one object (asserted by identity in the self-test). The docstring now says what _bullet_blocks actually is: same recognition rule, wider capture. Self-test grows four cases for the fetch's completeness signal, stubbing `run` rather than gh. 184 pytest cases and the full pipeline suite green. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017e8zEPDdXm3xuDfLWBfbP5
|
@claude #update-review Both round-2 findings fixed in 7f15832 — no disputes. [L153-164] — right, and the comment I wrote ( [L44-48] — took the second option, and it was more crowded than the finding suggested: that regex existed in four places, not two. The docstring now describes what actually happens instead of claiming a reuse that had stopped being true: same recognition rule, wider capture — Self-test adds four cases for the fetch's completeness signal (all-pages-decode, silent gh failure, error object, partial failure), stubbing Generated by Claude Code |
|
🤖 Review updated on @CamSoper's request. |
Proposed changes
The review pipeline is good at finding things and has no way to make anyone look at them.
scrape-review-outcomes.pycarries anignored_low_confidencecolumn precisely because authors clear 🚨 and stop reading. This adds the author-side counterweight: a skill that works a PR's pinned review to zero, and the meta-file changes that make doing so the expectation rather than an option.New skill —
/address-review(.claude/commands/address-review/)Watches for the pinned review to land after a PR goes ready for review, then walks every item with the author — 🚨 blockers,⚠️ low-confidence, and the ✏️ inline style suggestions — one at a time, with a proposed fix for each. Fixes batch into a single push (keeping the shape
auto-refresh-gate.pyrecognizes), disputes and fix-responses go out in one@claude #update-reviewmention, and the skill won't call a PR done while anything is undecided. It's also explicitly pushy: it offers to watch at ready-for-review without being asked, and says once — with a count — when a merge would leave items open. It never blocks a merge the user has decided on; "just merge it" becomesacceptedwith the user's reason on each open item, so the post-merge scrape reads the truth.Two references:
watching.md(event subscription where available, bounded polling otherwise, plus the short-circuit labels that mean no review is coming at all) anddispositions.md(the closed set —fixed/refuted/deferred/accepted/not-applicable, the last three note-required).New script —
review-worklist.py(.claude/commands/docs-review/scripts/)The deterministic half. Parses the pinned body through⚠️ section so advisory polish isn't miscounted as low-confidence findings, and never reports an unparseable body as an all-clear. State lives in a gitignored
validate-pinned.py's helpers so the comment format keeps exactly one parser, merges in the inline one-click suggestions, assigns stable per-finding ids (outstanding:L40-50,style:content/docs/a.md:L88), and answers "is anything still open?" via--require-clean. Splits the ✏️ style block out of the.review-worklist-<PR>.json, so a lost session resumes instead of restarting.Meta changes
AGENTS.md§PR Lifecycle — shipping a PR includes finishing its review; names the skill and the--require-cleancheck. (Also completes a sentence that had been left truncated mid-clause.)CONTRIBUTING.md— new §Working the review to zero: the five outcomes, and why a fix that never refreshed the review scrapes as ignored./shipit— new mandatory Step 9 hands off to the review loop (8 → 9 steps, counters renumbered). PRs now open as drafts, matching CONTRIBUTING §Draft-first, which is what Step 9's ready-for-review offer assumes./pr-review— Step 6 now discloses what an approval would be merging over; disclosure, not a gate, and the maintainer's own PRs route through/address-reviewfirst./docs-review— one line pointing at the post-push half.Testing
./scripts/test-review-pipeline.shpasses; the runner's--self-testdiscovery picks upreview-worklist.pyautomatically (no change needed there). Also verified against the realpr20079-pinned-review.mdfixture and confirmed/address-reviewis discovered bydocs-tools/scripts/scrape-metadata.py.make lintis unaffected — nothing here is undercontent/, and prettier ignores*.md.Related issues (optional)
None.
Generated by Claude Code