Repository navigation
Retire /resolve, self-accepted and /deploy-staging - #21909
Conversation
Blocking findings on the author card are the author's to answer, by a push or `@claude <why> #update-review`. That makes the /resolve comment lane redundant, and wrong where /pr-review used it to answer findings on the author's behalf. - Remove the /resolve lane: review-resolve.yml, resolve-handler.py, resolve_command.py and their tests. The update lane is now the only REVIEW_STATE writer. - /pr-review: approving posts the approval and the merge, nothing else. Judgments are board-only notes and never lift a row out of blocked. - Drop the author-accepted disposition and the self-accepted gate. A v3 brief⚠️ row now holds the stamp whatever disposition it carries, which covers the case self-accepted existed for. - Retire /deploy-staging (staging-deploy-pr.yml + test_staging_gate.py). staging-deploy-auto.yml is the only lane; a retry is a re-run or a dispatch of testing-build-and-deploy.yml, which G4 already accepts. - Update address-review, pr-review, docs-review references and AGENTS.md. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sentinel — merge gate status (preview)Warning
|
| Gate | What it needs | |
|---|---|---|
| ✅ | G1 review-ran | Nothing to do: review current at fecf1388a. |
| ✅ | G2 findings-answered | Nothing to do: every finding answered. |
| 🔴 | G3 right-approver | Needs approval from a member of any review team (pulumi/docs-blog-review, pulumi/docs-guild, pulumi/docs-marketing-review, pulumi/docs-tools) or a repository administrator — no qualifying human approval at this head (bot approvals never count). |
| ➖ | G4 infra-evidence | Doesn't apply to this PR: no changed path affects the deploy. |
| ➖ | G5 oversized-ack | Doesn't apply to this PR: not oversized. |
Break glass: a member of a routing team (.github/review-routing.yml teams:) can apply review:waived, which is logged.
Evaluated at head fecf1388a.
… updates Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Your site preview for commit fecf138 is ready! 🎉 http://www-testing-pulumi-docs-origin-pr-21909-fecf1388.s3-website.us-west-2.amazonaws.com |
Reviewer's guide v3 — not for the authorTip This is the reviewer's guide. Work through the PR author: your to-do list is the other review comment, "Author action guide" — nothing on this card is yours. Approval needed from: @pulumi/docs-tools — any member's approval satisfies the merge gate. Note What this PR changes:
The main risk is a dangling reference: a workflow, script, or skill that still calls a deleted file or emits a retired disposition. The review ran a repo-wide sweep for the removed file names, Review confidence:
|
Author action guide v3 — nothing blocks mergeNote Nothing here blocks merge — no open items need an answer from you. A human reviewer still approves the merge. This PR removes the 🚨 Fix or disagreeNothing to fix — this section is empty. ❓ Questions for youNo open questions for you. 📎 Full evidence: verification trail, investigation log, review history. Review v3 · updated 2026-09-25T20:29:31Z · head commit fecf138 How to answerEvery 🚨 and ❓ item above needs one of these before merge:
The Please don't edit, hide, or delete this comment — it is the review's record. Full mechanics: CONTRIBUTING.md §AI-assisted contributions. |
|
@claude #update-review Pushed 5e0c1fa, comments only, no logic change. The first commit's comments said the update lane is the only |
|
@claude #update-review Pushed 5e0c1fa, comments only, no logic change. The first commit's comments said the update lane is the only REVIEW_STATE writer and that nothing else writes the card while the model works. That's false: the full-review lane (a ready-transition, triage's auto-fire, or a from-scratch regeneration) also publishes the author card, and its runs routinely overlap an update (#21785, #21871). This commit rewrites those comments in review_state.py, apply-update.py, update.md, validate-pinned.py, the review-v3 README, claude-update.yml and dispositions.md so they describe the race accurately and name both guards: the re-fetch-and-merge, and the stale-publish guard from #21788. Please re-check those comments for accuracy. |
|
🤖 Review updated on @CamSoper's request. |
The job-level `if:` excluded any comment containing `#new-review` as a substring, so an update request that merely quoted that hashtag never reached mention-gate.py. claude-new.yml's gate declined the same comment as a quote, and neither lane ran (hit on #21909). The gate step already applies `--exclude new-review` to live text only, so drop the substring screens and let it decide. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@claude #update-review Pushed fecf138: the update lane's job-level trigger no longer screens out the from-scratch hashtag by substring (see the new bullet in the PR description). mention-gate.py's existing live-text exclusion now makes that call, and test_workflow_sanity.py pins it. Please review that change. |
|
🤖 Review updated on @CamSoper's request. |
#21909 retired the /resolve lane while this branch was open. Three explanatory passages here justified behavior by citing it: the strict drop rule for empty author sections, its spec line, and fix mode's skip of already-answered findings. The behavior stands (a row can still carry a REVIEW_STATE disposition while it sits in its section until a refresh re-renders the card); only the reasoning is reworded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKHS8qr1o8N7QkAdtHyWPz
* Collapse resolved findings and the How-to-answer footer on the author card The author action guide ran past a full screen even when nothing blocked merge: the resolved table (long verbatim claim cells) and the worked-example footer pushed the open items out of view. Reader feedback from #docs (2026-09-22, 2026-09-25) asked for both to fold. - ✅ Resolved since last review renders its table inside a <details> whose summary counts the rows. One helper (compose-review.render_resolved_block) serves both apply-update paths: first-resolve insertion and re-render, so a refresh rebuilds a single fold rather than nesting. The H3 stays outside the fold since every parser anchors on it. - The How-to-answer footer is collapsed. The one reply shape an author must get right (`@claude F1: … #update-review`, tag required) moves into the IMPORTANT callout, which is the part of the card everyone reads, so folding the examples doesn't hide the instruction. Brief and evidence output are byte-identical; the v3 author fixture is regenerated. New test pins the fold across two resolves and checks both row walkers still see the rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKHS8qr1o8N7QkAdtHyWPz * Acknowledge finished review requests with a reaction, not a comment A successful #update-review / #new-review ended with a fresh "🤖 Review updated on @x's request." comment, and an auto-refresh with "🤖 Review auto-refreshed …". On a busy PR these stacked up (six on #21871) and buried the cards and the re-request button. On success the spinner is still deleted, and the requesting comment now gets a 🚀 reaction (ack-request.sh). Auto-refresh success is silent: the cleared 🔄 banner and the card's new stamp already say it. Failures keep their @-mention comment, since those need action. ack-request.sh falls back to the old comment when there is nothing to react to (a submitted review body, a manual dispatch) or the reaction call fails. The #new-review lane is dispatched, so the triggering comment travels as a new `ack_target` input, passed by claude-new.yml, the update lane's retry path, and the redispatch job. Lanes that run scripts from the PR head guard on the helper existing, so branches cut before this change keep today's behavior. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKHS8qr1o8N7QkAdtHyWPz * Let the update lane refresh the author card's summary sentence The italic one-sentence summary is written once at v1 and carried verbatim through every refresh. When the model put live state in it, it went stale: #21871's card was headed "nothing blocks merge" and still opened by naming four claims "only you can confirm". - Prevent: the compose TODO now says no open-item counts and nothing only the author can answer, since the header and sections carry the live state. - Repair: the update patch takes an optional top-level `summary` (one line, ≤300 chars) that apply-update swaps in for the sentence (or inserts under the callout when a card has none). The prompt and update.md tell the model to send it when the current sentence names open items that its actions change, and to omit it otherwise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKHS8qr1o8N7QkAdtHyWPz * Drop the empty 🚨/❓ sections from a card with nothing for the author A nothing-blocks card opened with a NOTE saying there was nothing to do, then spent eight lines on two headed sections each saying "nothing here". build-evidence.drop_empty_author_sections removes both sections when every line in them is the empty placeholder. It runs at initial publish and after every update-lane render. It is strict: any row, bullet, or other text keeps both, and "nothing blocks" is not the test, because a /resolve'd row stays in its section with a disposition. The composer still emits the sections (the model's anchor for added rows). ensure_author_sections puts the pair back before the update lane places a reopened, added, or promoted row. validate-pinned's section-order rule accepts the pair missing together, never one alone. Both helpers match headings line-anchored: the composer's TODO stubs quote "### 🚨 Fix or disagree" in finding text, which fooled a substring check during testing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKHS8qr1o8N7QkAdtHyWPz * Quote each claim once on the author card A 🚨/❓ row quoted its claim (up to 160 chars) plus the verifier's framing note in the table cell. The Do-this block right under the table then quoted the line verbatim and explained the same problem in its Why bullet. On #21871 that doubled every finding. - An author-card cell for a claim verdict now carries a ≤90-char excerpt plus the verdict: enough to say which claim, since the block has the full line (compose-review.author_cell_bullet). Detector and style-blocker rows keep their full message, which is the finding. - The framing note moves out of the cell into the Why TODO as material to write from, so the author reads the reason once, in prose. - The brief's⚠️ rows are unchanged; they have no block to lean on. - normalize-v3-draft's fallback block prefers the evidence record's claim text over the cell's excerpt for "Line (verbatim)". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKHS8qr1o8N7QkAdtHyWPz * Take advisory style suggestions off the Files view by default Non-binding Vale suggestions posted as inline review comments cluttered the Files-changed view and sat between the human review comments (reader feedback, 2026-09-22). The style block on the card is the complete record; the inline copy was the noisy part. Both lanes now post advisory suggestions only when the repo variable REVIEW_STYLE_INLINE is '1'. When it's off, the poster still runs with an explicit empty sidecar. The script already treats that as authoritative: it deletes buttons an earlier run posted and strips the ✏️ marks and banner, so open PRs clean up on their next review. The caption's "✏️ marks one you can apply …" legend is now written only when a mark is actually on the page. The composer's caption is unchanged (it can't know yet), and the annotator reconciles it either way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKHS8qr1o8N7QkAdtHyWPz * Make the social review read as optional, and fold its drafted copy Guin read the social review's "X" section as a request she couldn't fulfil (no work social account), and a post with no social block got three identical "— missing" sections plus a screenful of drafted copy. - CI reviews open with a one-line NOTE: Pulumi's accounts post the copy after the blog goes live, and only a character-limit FAIL fails a check. - When every platform is missing, one line replaces the three headings. - Suggested copy and advisory notes are collapsed in <details> with a count in the summary. The apply/re-run CTA stays visible. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKHS8qr1o8N7QkAdtHyWPz * Drop the decorative 📎 and 💡 from the card footers Heading emoji mark state (🚨 ❓⚠️ ✅). 📎 on the "Full evidence" line and 💡 on the brief's pre-existing count line marked nothing, so both go: "**Full evidence:** …" and "**Pre-existing issues in touched files:** N — …". Cards published before this change still carry the old prefixes, and the update lane refreshes them in place, so every reader keyed on those lines accepts both forms: the section terminators (build-evidence, normalize-v3-draft, validate-pinned), the evidence-URL rewrite and Resolved-section insertion anchor (apply-update), the pre-existing recount, validate-pinned's v3-evidence-link rule, and review-v3/collect.py's rubber-stamp span. build-evidence's self-test fixtures keep the legacy form as backward-compat coverage, and set_evidence_url is tested on both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKHS8qr1o8N7QkAdtHyWPz * Post one-click fixes for blocking findings, derived from the card Readers asked for inline, applyable suggestions for what they have to fix (Julien, 2026-09-25), and for the optional nags to leave the Files view (previous commit). This adds the first half. post-style-suggestions.py --fixes-from-author-card <card> derives suggestions deterministically from the v3 author card's 🚨 rows, with no model sidecar. A row qualifies when it's anchored to one line and its Do-this block quotes text that occurs literally on exactly one line of the anchor, with exactly one single-line fenced replacement. The fence is spliced into the quoted span, so indentation outside it survives. Findings on the same line merge into one suggestion; a later one whose quote no longer matches is skipped. ❓ rows (proposals awaiting an answer), findings already answered in REVIEW_STATE, multi-line fences, and multi-fence blocks are skipped. A corrupt state block posts nothing. These rules come from 18 live Do-this blocks sampled across 8 PRs: the fence replaced exactly the quote in 8 of 10 🚨 blocks. It reuses the style poster's validation (PR-added line, literal match on the checked-out file) and posting (atomic batch with per-comment fallback) under its own marker, so the two sets never touch. The unchanged-set short-circuit now also covers a subset: when a fix lands, its comment is deleted and the survivors stay live, with no new (undeletable) review event. Wired after the v3 build (initial lane) and after the v3 publish (update lane), best-effort. The Do-this Fix TODO and output-format.md now tell the model the fence shape that qualifies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKHS8qr1o8N7QkAdtHyWPz * Skip fix suggestions whose fence rewrites only part of a long quote Running fix-mode derivation against the live author card of #21645, with files checked out at its merge commit, produced one wrong suggestion. F4 quoted a whole three-sentence bullet but fenced only its rewritten last sentence, so splicing the fence into the quoted span would have deleted the first two sentences. For a quote of 80+ chars, a fence under 60% of the quote's length is now skipped as a partial rewrite. On that card the whole-quote rewrites ran 87-95% of the quote's length; F4 was 36%. Phrase-level quotes are unaffected. Result on that card: F2 and F3 post; F4 (partial), F9 (multi-line), F5 (same line as F2, conflicting fence), and F22-F24 (no Do-this block) are skipped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKHS8qr1o8N7QkAdtHyWPz * Fix five issues an adversarial review of this branch found 1. HIGH: the unprefixed `**Full evidence:**` line matches FINDING_START_RE. Under ✅ Resolved, the paragraph walk read it as a finding and swallowed the REVIEW_STATE block behind it, so a hold reason containing "conceding" tripped outcome-annotation-shape and failed the update lane's publish. extract_bucket_bullets, _finding_paragraphs, and scrape-review-outcomes' paragraph walk now stop at card furniture (validate-pinned.is_card_furniture). 2. Fix mode could post corrupting splices whenever the fence and the quote covered different spans: a whole-line fence against a phrase quote, a one-sentence fence against a short whole-line quote, a list marker on one side only, or a line that is itself a quoted string. _span_mismatch now skips each of those with a reason, and a fence that keeps the quote's wrapper matches it as written. The real #21645 card still posts F2 and F3. 3. An optional `summary` sent as "", null, or the prompt's placeholder failed the refresh. normalize_update now drops all three, and the prompt's envelope no longer shows a copyable placeholder. 4. A kept fix comment could name stale F-ids after a re-review renumbered them. In fix mode the comment's header is now part of its identity. 5. Fix mode matched lines on the checkout but posted against the live head. It now posts nothing when the head has moved; the next refresh posts against the new head. Each has a regression test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKHS8qr1o8N7QkAdtHyWPz * Drop /resolve from this branch's rationale text after #21909 #21909 retired the /resolve lane while this branch was open. Three explanatory passages here justified behavior by citing it: the strict drop rule for empty author sections, its spec line, and fix mode's skip of already-answered findings. The behavior stands (a row can still carry a REVIEW_STATE disposition while it sits in its section until a refresh re-renders the card); only the reasoning is reworded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKHS8qr1o8N7QkAdtHyWPz * Document which .claude/ the update lane runs, and correct a comment The #update-review refresh on this PR failed validation: the new-format card this PR published (dropped empty sections, no 📎) was rejected by the default branch's validate-pinned. claude-code-action treats an issue_comment-triggered PR head as untrusted and restores .claude/ from the default branch before the model step, so everything claude-update runs afterwards is master's copy, not the PR's. A comment on the ack path claimed the opposite ("scripts run from the PR head"); that's corrected. The Finalize step now carries a note on the consequence: a PR that changes the card format can't self-refresh through this lane before merge. Use #new-review there, since the initial lane keeps the PR's scripts. No behavior change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKHS8qr1o8N7QkAdtHyWPz * Signal requested reviews with 👀 → 🚀 instead of a spinner comment A requested refresh still cost the timeline a transient "Working on it" comment, and #new-review two ("regenerating from scratch" plus the initial lane's spinner). Each notified every PR subscriber even though it was deleted minutes later. Requested runs now put a 👀 on the comment that asked for them (ack-request.sh --start) and swap it for 🚀 when the card lands, so a successful refresh or regenerate leaves no bot comment at all. Failures clear the 👀 and comment back to the requester by @-mention. An auto-refresh posts nothing in flight: the card's 🔄 banner already says it. A ready-transition, a review-body mention, or a failed reaction keeps the spinner comment as the fallback. review-label-reconcile.yml counts a github-actions[bot] 👀 on a PR comment as a live run, so a long requested review isn't swept to review:stale for lacking a spinner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKHS8qr1o8N7QkAdtHyWPz --------- Co-authored-by: Claude <noreply@anthropic.com>
Blocking findings on the author card are the author's to answer — a push, or
@claude <why> #update-review. That leaves the/resolvecomment lane with no job, and/pr-reviewwas misusing it to answer findings on the author's behalf, which spammed PRs with/resolvecomments.Changes
/resolveis gone. Deletesreview-resolve.yml,resolve-handler.py,resolve_command.pyand their tests. The update lane is now the onlyREVIEW_STATEwriter; agents answer the same way humans do./pr-reviewstops answering for authors. Approving posts the approval and the merge, nothing else. Judgments are board-only notes and never lift a row out ofblocked; a row with an open 🚨 goes back to the author (--request-changes, or--ask-fix/--closeon a workflow-authored PR), withreview:waivedas the break-glass.author-acceptedand theself-acceptedgate are gone. The only producer ofauthor-acceptedwas/resolve. The gate's real job — keeping an author-accepted finding out of the stamp set — is now covered directly: a v3 briefauthor-accepted, so nothing live is invalidated./deploy-stagingis retired. It was never used, refuses forks, andstaging-deploy-auto.ymlalready deploys every same-repo infra PR. A retry is a re-run of the failed "Build and deploy testing" run,gh workflow run testing-build-and-deploy.yml --ref <branch>, or/pr-review --act --deploy N; the Sentinel's G4 already accepts any successful run at the head.staging-deploy.shis now dispatch-only (still tolerates the old--pr/--dispatch-onlyflags for open branches running their own copy of the auto-lane YAML).claude-update.yml's job-levelif:excluded any comment containing#new-reviewas a substring, so an update request that only quoted it never reachedmention-gate.py, whileclaude-new.yml's gate declined the same comment as a quote, and neither lane ran (it happened on this PR). The gate step already applies--exclude new-reviewto live text only, so the substring screens are gone;test_workflow_sanity.pypins it.address-review,pr-review,docs-reviewreferences,scripts/review-v3/README.md,AGENTS.md.make test-review-pipelinepasses.🤖 Generated with Claude Code