Skip to content

feat: surface Claude PR review progress as a check run - #95

Draft
andychoquette wants to merge 1 commit into
aws-deadline:mainlinefrom
andychoquette:claude-review-progress-check
Draft

andychoquette wants to merge 1 commit into
aws-deadline:mainlinefrom
andychoquette:claude-review-progress-check

Conversation

@andychoquette

@andychoquette andychoquette commented Sep 15, 2026

Copy link
Copy Markdown

Why

Stage 2 runs on workflow_run, and workflow_run runs never attach to a pull request. So on the PR side all a maintainer sees is Stage 1's collect check going green in seconds, after which the review runs invisibly and its comments trickle in — with no way to tell whether Claude is still working, was superseded, or died.

Stage 1 can't be made to wait for the review: its completion is what fires the workflow_run event, so blocking on the review deadlocks. track_progress on the action isn't an option either — it only engages for pull_request/issue events.

A check run created against the PR head SHA does attach to the PR, so that's the signal used here: opened in_progress once the PR resolves, closed in an always() step.

Decisions worth flagging

  • Both API calls are best-effort. The check run needs checks: write, which only a caller can grant (a caller's permissions block is the ceiling for a reusable workflow). A caller that bumps this workflow without adding the scope would otherwise 403 on a hard-failing step and get no review at all — a progress indicator must never be the reason a review doesn't run. A failed create warns and leaves the step output empty, which gates the closing step off; a failed close warns rather than reddening a job whose review succeeded.
  • Cancellation reports neutral, not failure. A superseded push (caller concurrency group) and the job timeout-minutes are indistinguishable from the step outcome, and neither says anything about the change — findings posted before the cut still stand. Only a genuine agent-step failure is red.
  • Do not mark this required in branch protection. The check is only created when a unique open PR resolves, so the existing clean-skip path (0 or >1 open PRs) would leave a required check pending forever and block the merge.
  • The create call requires a GitHub App token — the Checks API rejects user tokens outright (You must authenticate via a GitHub App). Actions' GITHUB_TOKEN is an installation token so it qualifies, but this step can't be reproduced by hand with a PAT, which is why there's no local repro below.
  • There is still a ~30–60s gap between collect going green and the check appearing. Unavoidable: Stage 1 has permissions: {} and a fork PR gives it a read-only token, so it can't open the check itself.

Test plan

Static only so far: YAML parses, both new shell blocks pass bash -n, the jq payloads produce the documented shapes, and the create-failure branch was exercised against a stub. The Checks API's App-token requirement means the real path can only run inside Actions.

End-to-end verification is a scratch PR on a caller repo after that caller grants checks: write — note Stage 2 always executes the caller's default-branch copy, so a PR that only edits the caller in its own branch tests nothing. Until a caller is updated, its review runs behave exactly as today plus one warning annotation in the (unwatched) workflow_run job log.

Possible follow-up

The agent already has Bash(gh api:*). Passing the check run id into the prompt and having it PATCH output.summary after each posted finding would turn this from a spinner into real progress ("4 of ~9 changed files reviewed, 2 findings posted"). Left out here to keep the change mechanical and to avoid spending agent wall-clock before the basic version is proven.

@andychoquette
andychoquette requested a review from a team as a code owner September 15, 2026 17:13
The review stage runs on workflow_run, and workflow_run runs never attach
to a pull request -- so the PR only ever shows Stage 1's collect check
going green in seconds, while the review itself runs invisibly and its
comments trickle in with no signal for whether it is still working or
already dead. Stage 1 cannot wait for the review: its completion is what
fires the workflow_run event, so blocking on it would deadlock.

A check run created against the PR head SHA does attach to the PR, so the
review stage now opens one as in_progress once it resolves the PR and
closes it in an always() step.

Both calls are best-effort. The check run needs checks: write, which only
a caller can grant, so a caller that bumps this workflow without adding
the scope would otherwise 403 here and get no review at all -- a progress
indicator must never be the reason a review does not run. A failed create
warns and leaves the step output empty, which gates the closing step off.

Cancellation reports neutral, not failure: a superseded push and the job
timeout are indistinguishable from the step outcome, and neither says
anything about the change -- findings posted before the cut still stand.

Not safe to mark required in branch protection: the check is only created
when a unique open PR resolves, so the existing clean-skip path would
leave it pending forever.

Signed-off-by: andychoquette <78888816+andychoquette@users.noreply.github.com>
@andychoquette
andychoquette force-pushed the claude-review-progress-check branch from d8b50da to 86435c2 Compare September 15, 2026 17:14
@andychoquette
andychoquette marked this pull request as draft September 15, 2026 17:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant