Skip to content

Retire /resolve, self-accepted and /deploy-staging - #21909

Merged
CamSoper merged 3 commits into
masterfrom
CamSoper/drop-resolve-and-deploy-staging
Sep 25, 2026
Merged

CamSoper merged 3 commits into
masterfrom
CamSoper/drop-resolve-and-deploy-staging

Conversation

@CamSoper

@CamSoper CamSoper commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Blocking findings on the author card are the author's to answer — a push, or @claude <why> #update-review. That leaves the /resolve comment lane with no job, and /pr-review was misusing it to answer findings on the author's behalf, which spammed PRs with /resolve comments.

Changes

  • /resolve is gone. Deletes review-resolve.yml, resolve-handler.py, resolve_command.py and their tests. The update lane is now the only REVIEW_STATE writer; agents answer the same way humans do.
  • /pr-review stops answering for authors. Approving posts the approval and the merge, nothing else. Judgments are board-only notes and never lift a row out of blocked; a row with an open 🚨 goes back to the author (--request-changes, or --ask-fix / --close on a workflow-authored PR), with review:waived as the break-glass.
  • author-accepted and the self-accepted gate are gone. The only producer of author-accepted was /resolve. The gate's real job — keeping an author-accepted finding out of the stamp set — is now covered directly: a v3 brief ⚠️ row holds the stamp whatever disposition it carries. No open PR's card carries author-accepted, so nothing live is invalidated.
  • /deploy-staging is retired. It was never used, refuses forks, and staging-deploy-auto.yml already 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.sh is now dispatch-only (still tolerates the old --pr/--dispatch-only flags for open branches running their own copy of the auto-lane YAML).
  • Update-lane trigger no longer drops a quoted from-scratch hashtag. claude-update.yml's job-level if: excluded any comment containing #new-review as a substring, so an update request that only quoted it never reached mention-gate.py, while claude-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-review to live text only, so the substring screens are gone; test_workflow_sanity.py pins it.
  • Docs: address-review, pr-review, docs-review references, scripts/review-v3/README.md, AGENTS.md.

make test-review-pipeline passes.

🤖 Generated with Claude Code

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>
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Sentinel — merge gate status (preview)

Warning

⚠️ Preview mode — this check is NOT blocking your merge

The Sentinel is in preview (report-only) mode: its check-run concludes neutral whatever the gates below say, so nothing here gates this PR. The rows are informational and safe to ignore for now. It would have concluded failure.

This will be enforced in the near future. Once it is, every row below has to be green before this PR can merge. The rows are the sign-offs a merge needs — some yours, some a reviewer's or a deploy's. Tell us in #docs if one looks wrong.

1 of 5 gates would block this merge once the Sentinel is enforced.

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.

@CamSoper
CamSoper marked this pull request as ready for review September 25, 2026 19:29
@github-actions github-actions Bot added review:triaging Claude Triage is currently classifying the PR domain:infra PR touches workflows, scripts, infra, Makefile, or build config labels Sep 25, 2026
@pulumi-bot
pulumi-bot requested a review from a team September 25, 2026 19:31
@github-actions github-actions Bot added review:in-progress Claude review is currently running and removed review:triaging Claude Triage is currently classifying the PR labels Sep 25, 2026
… updates

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@pulumi-bot

pulumi-bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Reviewer's guide v3 — not for the author

Tip

This is the reviewer's guide. Work through the ⚠️ checklist below, then approve — approving asserts only that the ⚠️ items looked right to you. Machine-verified this run: links, shortcodes, page metadata, and every claim marked verified (receipts on the evidence page). Code samples are read, not compiled.

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:

  • /resolve command: its workflow, handler, and tests are deleted.
  • self-accepted disposition: removed from review_state.py, the renderers, the Sentinel, the worklist, and the skills.
  • /deploy-staging: the manual workflow is deleted, and staging-deploy-auto.yml is now the only staging path.
  • Docs (AGENTS.md, the review-v3 README, and the address-review and pr-review skills) are updated to match.

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, /resolve, self-accepted, and /deploy-staging. The only hits were negative assertions in tests, and the staging_evidence gate in .github/review-routing.yml is still in place.

Review confidence:

Dimension Level Notes
mechanics MEDIUM Reference sweep done; workflows and the test suite were not run
facts HIGH

⚠️ Check these before approving

No findings to check — but the editorial stances below still need a human eye.

Editorial stances introduced by this PR

Superlative, ranking, or comparative language the diff adds. No verdict — a page's own framing isn't fact-checkable — but confirm each is a stance the docs should take, and that no agent-written rewrite introduced it unasked.

  • L222 .claude/commands/address-review/SKILL.md — "1. There is no REVIEW_STATE. Every non-fixed disposition still goes through @claude … #update-review, and the local state file is the only ledger." — positioning (found by regex)
  • L132 .claude/commands/pr-review/SKILL.md — "An unanswered 🚨 finding is blocked, not judge. A judge row's other gates — size, shape:infra, a human author, an open ⚠️ — are an approver's call…" — positioning (found by regex)

✅ What you can rubber-stamp

  • Facts: no factual claims found in the changed lines.
  • Mechanics: no internal links added.
  • Style: 0 advisory suggestions left with the author; never blocking.

💡 Pre-existing issues in touched files: 0 — details on the evidence page.

📎 Full evidence: verification trail, investigation log, review history.

Review v3 · updated 2026-09-25T20:29:31Z · head commit fecf138


For the reviewer: the ⚠️ items above are the minutes that matter — the receipts for everything machine-verified are on the evidence page. The author's open items live on their own card (the comment headed "Author action guide"); while any are open, a Waiting on the author list above tracks them, and merge stays blocked until they're answered. If something here seems off, comment on the PR — @claude <your point> #update-review re-adjudicates with your input.

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Author action guide v3 — nothing blocks merge

Note

Nothing here blocks merge — no open items need an answer from you. A human reviewer still approves the merge.

This PR removes the /resolve command, the self-accepted disposition, and the manual /deploy-staging workflow from the review pipeline; the review checked the whole repo for leftover references to the deleted scripts, workflows, and dispositions and found none.

🚨 Fix or disagree

Nothing to fix — this section is empty.

❓ Questions for you

No 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 answer

Every 🚨 and ❓ item above needs one of these before merge:

  1. Fix it — push the change. If your push lines up with the flagged lines, this card shows a 🔄 banner within a minute and then refreshes itself. No banner? Comment:

    @claude I pushed a fix for F1 #update-review
    
  2. Disagree with it — say which item and why; the review re-checks with your input:

    @claude F2: <your reasoning — e.g. where the figure comes from> #update-review
    

    Either way your answer counts: the review marks the item resolved, or keeps it with a 🛡️ note for your human reviewer to weigh — it stops blocking merge in both cases.

  3. Accept it as-is — you own the PR; a one-line reason is a valid answer, and your reviewer sees it beside the finding:

    @claude F2: accepting as-is — <your reason> #update-review
    

    To accept every open item at once: @claude accepting all open items — <reason> #update-review.

The #update-review hashtag matters — it routes your reply to this review, and (besides pushing a fix) it is the only reply that unblocks merge. A bare @claude gets you ad-hoc help and leaves this card — and the merge block — untouched.

Please don't edit, hide, or delete this comment — it is the review's record. Full mechanics: CONTRIBUTING.md §AI-assisted contributions.

@github-actions github-actions Bot added review:no-blockers Claude review completed cleanly; outstanding is empty and removed review:in-progress Claude review is currently running labels Sep 25, 2026
@CamSoper

Copy link
Copy Markdown
Contributor Author

@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 nothing else writes the card while the model works. That's false: the full-review lane (ready-transition, triage auto-fire, #new-review) publishes the author card too, 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 to 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.

@github-actions github-actions Bot added review:stale New commits since last Claude review; refresh on next ready-transition or @claude mention and removed review:no-blockers Claude review completed cleanly; outstanding is empty labels Sep 25, 2026
@CamSoper

Copy link
Copy Markdown
Contributor Author

@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.

@github-actions github-actions Bot added review:in-progress Claude review is currently running and removed review:stale New commits since last Claude review; refresh on next ready-transition or @claude mention labels Sep 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Review updated on @CamSoper's request.

@github-actions github-actions Bot added review:no-blockers Claude review completed cleanly; outstanding is empty and removed review:in-progress Claude review is currently running labels Sep 25, 2026
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>
@github-actions github-actions Bot added review:stale New commits since last Claude review; refresh on next ready-transition or @claude mention and removed review:no-blockers Claude review completed cleanly; outstanding is empty labels Sep 25, 2026
@CamSoper

Copy link
Copy Markdown
Contributor Author

@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.

@github-actions github-actions Bot added review:in-progress Claude review is currently running and removed review:stale New commits since last Claude review; refresh on next ready-transition or @claude mention labels Sep 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Review updated on @CamSoper's request.

@github-actions github-actions Bot added review:no-blockers Claude review completed cleanly; outstanding is empty and removed review:in-progress Claude review is currently running labels Sep 25, 2026
@CamSoper
CamSoper merged commit a0be6fe into master Sep 25, 2026
19 checks passed
@CamSoper
CamSoper deleted the CamSoper/drop-resolve-and-deploy-staging branch September 25, 2026 20:34
CamSoper added a commit that referenced this pull request Sep 25, 2026
#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
CamSoper added a commit that referenced this pull request Sep 25, 2026
* 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>

This branch was successfully deployed

1 active deployment
testing — fecf1388 Deployed Sep 25, 2026 by CamSoper via Do cleanup #14418
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain:infra PR touches workflows, scripts, infra, Makefile, or build config review:no-blockers Claude review completed cleanly; outstanding is empty

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants