Remove request-review label at receiver review-start - #333
Conversation
Reverses part of the 2026-05-23 redesign: the decider still never touches the trigger label (routing-only), but the receiver now removes it right when a review actually starts. This lets a still-draft PR's label be freely re-applied after addressing review feedback to request another round, instead of sitting "on" with no clear re-request signal. - New script: .github/scripts/review-receiver/remove-request-review-label.sh - review-receiver.yaml: wire the removal step in after the in_progress check update, before approval dismissal; update header comments - review-dispatch.md: document the reversal, update the implementation map and stage-by-stage receiver flow
Plugin Version PreviewPreview only — plugin versions and
|
|
CI red on Generated by Claude Code |
|
🤖 The "AI Code Review" check failure on this PR (check run 93983045453) is a known systemic/intermittent pipeline bug — the review job completes without writing Generated by Claude Code |
Drop 2>&1 in remove-request-review-label.sh so non-404 failures (auth, rate limit, API shape changes) print to the workflow log instead of being silently absorbed by the stdout redirect. || true still keeps the idempotent no-op behavior for the expected 404 case.
…w-label-mechanism-ynp5g1
…hanism-ynp5g1' into claude/review-workflow-label-mechanism-ynp5g1
Dismissed: new commits since last approval require re-review.
Dismissed: new commits since last approval require re-review.
…w-label-mechanism-ynp5g1 # Conflicts: # plugins/claude-code/review-utils/specs/review-dispatch.md
Dismissed: new commits since last approval require re-review.
Dismissed: new commits since last approval require re-review.
## Bug
`read-metrics-and-compute-conclusion.sh` line 81 (the fail-closed "no
metrics + no matching review" error message) interpolates
`$SOURCE_HEAD_SHA` directly, without the `${VAR:-}` default used
everywhere else it's referenced in this script. Under `set -euo
pipefail`, if `SOURCE_HEAD_SHA` is genuinely unset in the calling
environment, this crashes with `unbound variable` instead of reaching
the intended fail-closed output.
## Impact
Instead of the specific title `"Review agent finished but metrics
missing"` (with a useful `::error::` annotation), the check-run shows
the generic `"The review agent failed to run"` — losing diagnostic
signal and masking what's actually a normal (if unwanted) fail-closed
outcome as an infra-looking crash.
## Root cause
Observed live on #333 and on #334's own self-dispatch
review: both ran against `.ai-agent-henry`'s `repo-dispatch.yaml`, which
pins `review-receiver.yaml` at a commit predating #334's
`SOURCE_HEAD_SHA`/`APP_SLUG` env plumbing — so the env var was never set
at all. Companion fix: nsheaps/.ai-agent-henry#(pin bump PR) bumps that
pin so the fallback actually has the data it needs going forward. This
PR is the defensive half — the script should never crash on missing
optional env, regardless of which caller/pin is in play.
## Verification
- `bash -n` — syntax OK.
- Traced: this is the only unguarded reference to `$SOURCE_HEAD_SHA`;
the other two (line ~43, ~50) are inside the `if [ -n
"${SOURCE_HEAD_SHA:-}" ]`-guarded block where it's guaranteed non-empty.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01C9mitQxvjn4FsU2xod85xB)_
Co-authored-by: Claude <noreply@anthropic.com>
Dismissed: new commits since last approval require re-review.
Dismissed: new commits since last approval require re-review.
| # runs only for non-draft transitions. | ||
| # - Shell scripts >3 lines extracted to .github/scripts/review-receiver/. | ||
| # | ||
| # SUPERSEDED (handler instruction, this session): the "receiver MUST NOT |
There was a problem hiding this comment.
Why are we writing that this is superseeded rather than just removing or am I misreading this... This feels more appropriate for a design doc, spec, decision log...anywhere but here
There was a problem hiding this comment.
🤖 Agreed — you're not misreading it, and the "superseded" note was the wrong call. I checked plugins/claude-code/review-utils/specs/review-dispatch.md: its §Status already carries a dated decision log for exactly this (the 2026-05-23 redesign entry and a new 2026-08-12 partial-reversal entry I just added), so the workflow file didn't need to re-host that history at all.
Fixed in agents@286d248: removed the outdated "2026-05-23 redesign" bullet block and the "SUPERSEDED" patch-note, replaced with one short paragraph describing current behavior plus a pointer to the spec's §Status for the "why."
Generated by Claude Code
There was a problem hiding this comment.
🤖 Correction to my reply above: the 2026-08-12 §Status entry in review-dispatch.md was already there from an earlier session — I read it, I didn't add it just now. Only review-receiver.yaml's header comment changed in 286d248. Doesn't change the fix, just correcting the inaccurate "I just added" claim.
Generated by Claude Code
Per Nate's PR review comment, don't keep a "superseded" annotation inline in the workflow — the spec's §Status already carries the dated decision log (2026-05-23 redesign + 2026-08-12 partial reversal). The workflow header now just states current behavior and points there.
Dismissed: new commits since last approval require re-review.
There was a problem hiding this comment.
Review Summary
Verdict: 🟢 APPROVE — re-verification against new HEAD 286d248. Since my last approval at cc29050, one commit landed (286d248) that addresses nsheaps's inline review on the header's SUPERSEDED annotation. The fix is clean: the "SUPERSEDED" patch-note and the old 2026-05-23 redesign bullet block are gone from review-receiver.yaml, replaced with a short paragraph describing current behavior plus a parenthetical pointer to plugins/claude-code/review-utils/specs/review-dispatch.md's §Status (which already carries the dated decision log). Design-decision history stays in the spec; the workflow file describes only current behavior. No script or spec drift; all prior inline threads remain resolved.
Re-verification
What I checked on the new commit (click to expand)
- New commit.
286d248—Trim SUPERSEDED comment block from review-receiver.yaml header. Only one file attributable to this commit pergh pr files:.github/workflows/review-receiver.yaml. - Header trim. Fetched the file at HEAD and read lines 1–50:
- Gone: the
2026-05-23 redesign (Nate 18:08Z):bullet block and theSUPERSEDED (handler instruction, this session):block that nsheaps flagged. - Added: a
(§Status has the dated design-decision log …)parenthetical under theSpec:line, and a one-paragraph description of current behavior of theskipjob's non-touch of the label. No history, no dated notes, no "why we changed our mind" — all of that lives in the spec now, exactly as nsheaps requested. - Flow list is intact and re-numbered correctly (steps 1–9, with step 4
Remove the request-review label…and subsequent steps shifted down as expected).
- Gone: the
- Script + spec unchanged since prior approval.
.github/scripts/review-receiver/remove-request-review-label.shline 29 still>/dev/null || true(stderr surfaces for auth/rate-limit breakage, exit swallowed for 404 idempotence — the minimal observability fix from7b9dac4).plugins/claude-code/review-utils/specs/review-dispatch.mdstill carries the2026-08-12 partial reversalnote in §Status, the implementation-map row, and the renumbered stage-by-stage list (bullets 4 = label removal, 5a = metrics hook merged in from main, cross-references to bullets 7 & 8 correct). - Inline threads. All three of my prior threads still
isResolved: true(P2 swallowed failures, P2 URL encoding, P3 praise on ordering) with the author's acks. The SUPERSEDED thread is functionally addressed by286d248(the code the comment pointed at is gone, so the thread is naturally outdated) — leaving thread state to the author since it's his own thread. - PR description accuracy. PR body still accurately describes the change: decider untouched, receiver removes label at review-start, three files, script is idempotent. No drift from what's shipped.
- Trigger source. This run was legitimately triggered by the new
286d248commit — not another instance of the auto-dismissal loop I flagged in an earlier observation. Real re-review, not churn.
Strengths ✅ (carried over)
- Symmetric, single-purpose change. Receiver flips one behavior; decider still never touches the label; the spec's
2026-08-12§Status entry narrates which half of the 2026-05-23 invariant still holds. - Docs match code. Renumbered receiver flow (steps 4–9), updated
skip:job comment, and the new implementation-map row all agree with what the workflow does. The286d248trim keeps the header lean without losing the "why" — the spec still has it, and there's a pointer. - Right token, right place.
steps.auth.outputs.token(automation App) — same identity that edits labels in the decider — keeps label edits a routing concern. Approval dismissal continues to use the separate review-App token. - Minimal, correct observability fix.
7b9dac4's>/dev/null || true(dropping2>&1) letsgh api's stderr surface for auth/rate-limit/API-shape failures while preserving 404 idempotence. - Comment discipline (new).
286d248is a good example of the "history in the spec, current behavior in the file" principle — the workflow header no longer accumulates dated redesign notes over time.
Follow-ups
None outstanding on this PR's scope. All prior inline threads remain resolved; the SUPERSEDED-annotation concern is addressed in code by 286d248.
Recommendation
APPROVE. Ship once CI recovers from the checkout-as-app TLS flake (author's note) and the metrics-file emission systemic bug (#337) doesn't bite again. Post-merge validation per the PR body: draft PR → apply request-review → confirm removal on in_progress → re-apply → confirm round 2 fires and clears.
🤖 Automated review by @henry-nsheaps · workflow run
Summary
request-reviewlabel (routing-only, unchanged), but the receiver now removes it right when a review actually starts (after posting thein_progresscheck, before dismissing prior approvals).request-reviewafter addressing feedback (fixing code, or just replying to justify a comment) to request another round..github/scripts/review-receiver/remove-request-review-label.sh(idempotent — no-op if the label is already absent).review-receiver.yaml: wires the removal step into thereviewjob using the automation-App token (same identity that edits labels in the decider), updates header comments.plugins/claude-code/review-utils/specs/review-dispatch.md: documents the reversal with a dated note, updates the implementation map and the receiver stage-by-stage flow.The consumer-side gate logic (
dispatch-review.yaml, requiring the label only to force a review on a still-draft PR) is unchanged — this only affects what the receiver does with the label once a review starts.Test plan
python3 -c "import yaml; yaml.safe_load(open('.github/workflows/review-receiver.yaml'))"— YAML parses (done locally)request-review, confirm the review runs and the label is removed once the check flips toin_progressrequest-reviewafter pushing a fix, confirm a second review round fires and the label is removed againGenerated by Claude Code