chrismdp / fix-review-findings

A failed review is fixed

Public ·
Version 2 of 3
  1. #3 · chrismdp · · 0.8Latest
  2. #2 · chrismdp · · 0.6Showing
  3. #1 · chrismdp · · 0.6
Fork

workflow.yaml

workflow.yaml is AWML 0.6, as it was pushed. The registry draws, checks and fits it converted to AWML 0.8.

# When a Bug review or Security review check fails on a pull request, because the review found
# something Important, a fresh Claude session fixes its findings, Nits included, and the
# repository's app pushes the fix to the pull request's branch as one more commit. It reacts only to
# the failed check, and its only contract is the check's result and the findings the review posted
# in it: it knows nothing of builds, and nothing calls it or waits for it, so every pull request
# whose review fails is fixed the same way, whoever opened it. The push runs CI and the reviews
# again. It stops after two tries on a pull request, never changes Claude Code's own files, and does
# nothing if anyone has pushed since the review. The app can't push a change to a workflow, so a fix
# that touches one is put in the status comment for a person to apply.
awml: "0.6"
title: A failed review is fixed
scopes:
  - { id: public, label: "public: anyone who reads the repository", processing: any }
parts:
  - { id: failed, kind: trigger, label: "Bug review or Security review fails on a pull request from a branch of this repository, opened by someone with write access or by the app", wait: PT1H }
  - { id: token, kind: connector, label: "The repository, through its own Actions token", in: public, ref: chrismdp/issue-to-pull-request#token }
  - { id: app, kind: connector, label: "The repository, through its own GitHub App", in: public, ref: chrismdp/issue-to-pull-request#app }
  - { id: bring, kind: code, op: bring-in, label: "Bring in the failed check's findings, the pull request's patch against main, and the commit the review read", in: public }
  - { id: asked, kind: context, label: "The findings, the patch and the commit they were found on", in: public }
  - { id: tries, kind: code, op: sort, label: "Sort by rule: has anyone pushed since the review, and has the factory already tried twice on this pull request?", in: public }
  - { id: giveup, kind: code, op: do, label: "Say in the status comment that the findings need a person, and why", in: public }
  - { id: started, kind: code, op: do, label: "Post the fix's status comment on the pull request", in: public }
  - { id: status, kind: outside, label: "Post or edit the fix's status comment: Allow", in: public }
  - { id: repo, kind: context, label: "The spec, guide, code, AGENTS.md and REVIEW.md, from the pull request's branch", in: public }
  - { id: fix, kind: ai, op: draft, label: "Fix the findings, Important ones and Nits, test first, changing none of Claude Code's own files", in: public }
  - { id: change, kind: context, label: "The fix, as a patch, with its message", in: public }
  - { id: gate, kind: code, op: check, label: "Run the tests, vet, the examples and wasm parity on the fix", in: public }
  - { id: guard, kind: code, op: sort, label: "Sort by rule: does the fix touch Claude Code's own files or a workflow, and is the branch still at the commit the review read?", in: public }
  - { id: push, kind: code, op: do, label: "Add the fix to the pull request's branch as one more commit, fast-forward only", in: public }
  - { id: offer, kind: code, op: do, label: "Put the fix in the status comment as a patch for a person to apply, since the app may not change a workflow", in: public }
  - { id: pushed, kind: outside, label: "Push one more commit to the pull request's branch: Allow", in: public }
  - { id: contract, kind: comment, label: "Loosely coupled: it reads only the failed check and the findings the review posted in it. Builds and landing don't call it or wait for it" }
  - { id: rerun, kind: comment, label: "The app's push starts CI and the reviews again on the new commit, so a fix that brings its own Important finding fails its check and comes back here, up to two tries. The fix is always a new commit, never a rewrite of the branch" }
  - { id: same, kind: comment, label: "The session runs as the build's draft does: in a sandbox, keeping the login token from its commands, loading no settings or servers from the tree, with a token that only reads" }
  - { id: theirs, kind: comment, label: "A person's push since the review means the branch has moved on, so the fix would be for old code: it stops, saying so" }
lines:
  - { from: failed, to: bring, kind: start, label: "the failed check" }
  - { from: token, to: bring, kind: data, label: "the check's findings, the patch and the branch's commits" }
  - { from: bring, to: asked, kind: data }
  - { from: bring, to: tries, kind: start }
  - { from: tries, to: giveup, kind: start, label: "[pushed since, or tried twice]" }
  - { from: giveup, to: status, kind: data }
  - { from: tries, to: started, kind: start, label: "[otherwise]" }
  - { from: started, to: status, kind: data }
  - { from: status, to: token, kind: data }
  - { from: started, to: fix, kind: start }
  - { from: asked, to: fix, kind: data, label: "the findings and the patch" }
  - { from: repo, to: fix, kind: data }
  - { from: fix, to: change, kind: data }
  - { from: fix, to: gate, kind: start, label: "the fix" }
  - { from: change, to: gate, kind: data }
  - { from: gate, to: giveup, kind: start, label: "[a check fails]" }
  - { from: gate, to: guard, kind: start, label: "[all pass]" }
  - { from: change, to: guard, kind: data }
  - { from: asked, to: guard, kind: data, label: "the commit the review read" }
  - { from: guard, to: giveup, kind: start, label: "[touches Claude's files, or the branch moved]" }
  - { from: guard, to: offer, kind: start, label: "[touches a workflow]" }
  - { from: change, to: offer, kind: data }
  - { from: offer, to: status, kind: data }
  - { from: guard, to: push, kind: start, label: "[none of these]" }
  - { from: change, to: push, kind: data }
  - { from: push, to: pushed, kind: data }
  - { from: pushed, to: app, kind: data }
  - { from: contract, to: failed, kind: tie }
  - { from: rerun, to: pushed, kind: tie }
  - { from: same, to: fix, kind: tie }
  - { from: theirs, to: tries, kind: tie }
implementations:
  actions:
    label: "GitHub Actions, fix.yml"
    blocks:
      - { id: github, label: "GitHub: pull requests, checks and comments", parts: [failed, token, app, asked, repo, change, status, pushed] }
      - { id: readjob, label: "Actions job: read the findings, fix and check, with a token that only reads", platform: actions-code, parts: [bring, tries, gate] }
      - { id: agent, label: "Claude Code, claude-opus-5-5, on the maintainer's subscription", platform: actions-agent, in: readjob, parts: [fix] }
      - { id: writejob, label: "Actions jobs that write, running nothing from the change: one posts the status before the fix, one pushes or comments after it", platform: actions-code, parts: [started, guard, push, offer, giveup] }