reviewing-prs, ardia, gia: only work PRs the user opened, is assigned to, or asked for, or the Actions app authored - #2913
Conversation
User directive, 2026-09-01, delivered mid-turn on a gia sweep of UCD-SERG/serodynamics: "you should only work on PRs that are opened by me (d-morrison or dem-extra1) or assigned to me", after the sweep pushed commits to #284, #292, #298 and #311 and dispatched a review on #310 -- four other authors' PRs and one bot PR, none assigned to the user. Record the rule in memories/preferences.md with both sides: the Do the user stated, and the Don'ts inferred from the near-miss, chiefly that a sweep skill's "drive every open PR" is not a scope grant. Put the mechanism where the population is decided. ardia's step 1 already lists scope rules for drafts; add the authorship filter as the first rule, so the enumeration never reaches another author's PR. gia's step 0 gets the same statement beside its existing which-repo check, and its anti-pattern list gets the corresponding entry. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
…home Two CI failures on the first push, both mine. validate: memories/preferences.md went to 1277 lines against the 1250 cap. main was already at 1238. reviewing-prs.md's own header says new review-scope lessons land there rather than as appends to preferences.md, for exactly this reason, and I had not read it. Move the whole section, repoint ardia's citation, and extend the MEMORY.md row. lint-markdown: MD018 at the line that began "#284, #292 ...". Semantic line wrapping put a PR number at a line start, which markdownlint reads as a space-less ATX heading. Rewrapped so no line begins with "#". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…; fold the old bullet Round-1 review findings on #2913, all three accepted. The LIST_PRS command never fetched assignees, so the "or assigned to me" half of the new filter could not be evaluated from the data the step tells you to pull. Add the field. The new bullet duplicated an older, softer one thirty lines down ("unless told to ... ask first"). Fold them: the old bullet's one real override survives as "or the user named the PR in the request"; "ask first" goes, since author and assignee are two API fields and there is nothing left to ask. The literal logins sat in tension with preferences.md's "Never hardcode usernames" rule, and the reviewer's underlying point was real: a lab member running ardia from the vendored corpus would have filtered on the owner's identity and dropped their own PRs. The skill now resolves the invoking user first (gh api user, or get_me remotely) and only adds the aliases the memory lists. The memory keeps d-morrison and dem-extra1 as this owner's two aliases and says why they are literal: the rule's own exception for values that must match a real account. gia loses its third hardcode site. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
|
Round-1 findings, all three addressed in 1. 2. Duplicate of the older bullet — Addressed. Folded. The old bullet's one genuine override ("unless told to") survives as "or the user named the PR in the request". Its "if unsure, ask first" is gone on purpose: author and assignee are two API fields, so nothing is left to ask, and that softness is exactly what let the incident through. 3. Hardcoded logins vs. the no-hardcoding rule — Addressed, structurally. The underlying point was stronger than a style tension: a lab member running Verified after committing: size checker clean, Not re-dispatching by mention — this repo auto-reviews on push and a mention would race it. Generated by Claude Code |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
User correction, same day as the authorship rule: a PR opened by one of the repository's own workflows (github-actions[bot], e.g. a submodule bump) may be driven without an assignment. Dependabot and Copilot PRs still need one. Record both gh and API spellings of the workflow login. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
|
Pushed Changes: the memory's opening rule and Do/Don't pairs now carry the carve-out and say which parts the user stated and which are inferred (the narrowing to the The three round-1 findings stay addressed as described in the previous comment. Same local checks re-run after committing: size cap, Generated by Claude Code |
This comment has been minimized.
This comment has been minimized.
- State the workflow bot's login once as the app slug and list all three forms (REST/MCP suffix, GraphQL bare, gh --json prefix); the earlier two-form list would have dropped workflow PRs on the GraphQL path scripts/pr-sweep.py uses. - Point ardi.md's and pr-sweep.py's scope statements at the memory's test; a claim comment no longer reads a PR into scope. - Rename the memory heading to carry the workflow case; blank line before it; fix the MEMORY.md index wording; semantic line breaks on the new prose. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
This comment has been minimized.
This comment has been minimized.
|
The automated review of
A second adversarial pass on Generated by Claude Code |
… arm everywhere Second self-review round: the memory's opening sentence, gia's anti-pattern, the MEMORY.md row, and the section heading stated three arms while every other site stated four. derive-dont-enumerate.md still told the reader to claim an unowned PR before driving it. ardia now points at the memory's login-form table instead of restating it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
|
Second adversarial pass (on
Generated by Claude Code |
This comment has been minimized.
This comment has been minimized.
Point pr-overlap.py's docstring at the memory's scope test; record where the named-in-request arm came from and the WORKFLOW_TOKEN edge case for workflow-opened PRs; make ardia's bold lead name all four arms; rebreak three prose lines; note that #310 got a dispatched review, not commits. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
|
Third adversarial pass (on
Generated by Claude Code |
Attribute the WORKFLOW_TOKEN preference to gha's reusable sync workflows rather than the open-sync-pr composite; state that the issue carve-out is inferred; make the every-open-PR qualifier reach ardia's intro. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
|
Fourth adversarial pass (on
Fifth adversarial pass running on Generated by Claude Code |
This comment has been minimized.
This comment has been minimized.
…ot once at listing time Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
|
ARD for Copilot round thirty-one (on 97cfd16), pushed as 447fae7:
Local checks on 447fae7: new-line-breaks, markdownlint (0 errors), validate-skills, check-ascii-punctuation --diff all pass. Posted by Claude Code (AI agent) --- not written by a human. Generated by Claude Code |
There was a problem hiding this comment.
🟡 Changes recommended
The chores predicate can still select and merge a dependency-bot PR that the user explicitly excluded.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 33/33 changed files
- Comments generated: 1
- Review effort level: Balanced
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…edicate Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
|
ARD for Copilot round thirty-two (on 447fae7), pushed as 28c20e5:
Local checks on 28c20e5: new-line-breaks, markdownlint (0 errors), validate-skills, check-ascii-punctuation --diff all pass. Posted by Claude Code (AI agent) --- not written by a human. Generated by Claude Code |
This comment has been minimized.
This comment has been minimized.
Self-review fallback for
|
There was a problem hiding this comment.
🟡 Changes recommended
The chores workflow omits the live scope recheck before its step 2 PR-closing action.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 33/33 changed files
- Comments generated: 1
- Review effort level: Balanced
Copilot round thirty-three: the live recheck named steps 3-5, but step 2 closes a bump PR when the repo has migrated to a native plugin, which is a write action too. Name steps 2-5 and list the close. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
This comment has been minimized.
This comment has been minimized.
Self-review fallback for
|
There was a problem hiding this comment.
🟡 Changes recommended
Explicitly excluded PRs can still pass another positive scope arm, including in delegated scans.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 33/33 changed files
- Comments generated: 3
- Review effort level: Balanced
Copilot round thirty-four: the veto existed only in chores's PR_SCOPE_EXCLUDED, so "do not touch" plus a number still admitted a PR through the author, assignee, or Actions-app arm in AGENTS.md, the memory, ardia's reference filter, and post-merge's scanner brief. State the veto in all four and carry the exclusion list into rechecks and delegated scans. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
This comment has been minimized.
This comment has been minimized.
Self-review fallback for
|
There was a problem hiding this comment.
🔵 Needs a closer look
Two scope-check gaps can still mutate a PR using an omitted or stale classification.
Review details
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
memories/github.md:75
- Step 3 is also mutating: it closes superseded drafts and posts a note. Limiting the scope check to steps 2 and 4 therefore still permits closing or commenting on an out-of-scope PR. Apply the filter before every mutation in steps 2 through 4.
skills/chores/SKILL.md:135 - The chore predicate also depends on the title and labels, but this live recheck explicitly refreshes only author and assignees. If a human-authored PR loses its
chore(title ordependencieslabel after the initial listing, the stale classification can still lead to a close, comment, or merge. Refresh every predicate input before each write.
- Files reviewed: 33/33 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Copilot round thirty-five, two suppressed findings. The GII cleanup sweep gated only steps 2 and 4, but step 3 closes superseded drafts and posts a note; gate every mutation in steps 2 through 4. The chores recheck refreshed only author and assignees, but the predicate also reads the title and labels; re-fetch every input before each write. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
ARD for Copilot round thirty-five (
|
| # | Finding | Disposition |
|---|---|---|
| 1 | memories/github.md: the GII cleanup sweep gated the scope test on steps 2 and 4, but step 3 closes superseded drafts and posts a note. |
Addressed. The sweep now applies the test immediately before every mutation in steps 2 through 4, naming each one (the close in step 2, the close and the note in step 3, the merge in step 4). |
| 2 | skills/chores/SKILL.md: the live recheck refreshed only author and assignees, while the predicate also reads the title and labels. |
Addressed. The recheck now re-fetches every input the predicate reads (author, assignees, title, labels) before each write action in steps 2-5. ardia's recheck is unchanged on purpose: its predicate reads author, assignees, and the request's static request and exclusion lists, so author and assignees are the only mutable inputs there. |
Local checks pass on the committed content. Copilot re-requested on ab89045.
Posted by Claude Code (AI agent) --- not written by a human.
Generated by Claude Code
This comment has been minimized.
This comment has been minimized.
Self-review fallback for
|
There was a problem hiding this comment.
🔵 Needs a closer look
The existing-PR paths in check-history can still race another session holding a live claim.
Review details
Suppressed comments (2)
skills/check-history/SKILL.md:58
- Passing the scope test establishes authorization, not that the branch is free. This replacement now directs the caller to drive the PR even when another session has a live claim;
shared/workflow/claim-pr.md:78-82says that claim still blocks a second session. Check claim status first and only take over an unclaimed or expired PR.
If an open PR already covers it and passes `memories/reviewing-prs.md`'s
scope test (opened by or assigned to the invoking user, explicitly requested,
or authored by the GitHub Actions app), **drive that PR to clean** instead of
re-implementing.
skills/check-history/SKILL.md:88
- This duplicated path has the same authorization/ownership gap: an in-scope PR may still have a live claim from another session, so immediately reviewing or extending it can race that session. Apply the claim check here too and leave live-claimed work alone until the claim expires or is released.
If an open PR already covers the issue, apply the scope test above to the
author and assignee logins the listing prints:
**review or extend it** when it passes, and leave it untouched (reporting
it to the user) when it fails.
- Files reviewed: 33/33 changed files
- Comments generated: 0 new
- Review effort level: Balanced
…s free Copilot round thirty-six, two suppressed findings. Both existing-PR paths told the caller to drive, review, or extend an in-scope PR without reading its claim state, which races another session holding a live claim (claim-pr.md's second-session rule). Read the claim first, skip a live one, and take over an expired one by posting a claim comment. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F
ARD for Copilot round thirty-six (on
|
2026-09-02 04:04 UTC |
|
Claude finished review — View run Confirmed all three prior findings are fixed:
PR SummarySelf-authored memory/skill correction recorded after a Verification performed this round
One thing I want to flag as not a finding on this PR: my working-tree checkout shows I found no new blocking issues, and all previously-flagged findings are resolved in the current diff. VerdictReady for merge Structured Review Data (JSON){
"schema_version": "1.0",
"reviewer": "claude",
"commit_sha": "7b92cbf77322b82d48d0885fc5ddcd671e390ce1",
"verdict": "CLEAN",
"findings": []
}Reviewed commit: 2ce74f9 |
Directives
Two, both delivered on 2026-09-01 during a
giasweep ofUCD-SERG/serodynamics:and, after the session had stood down from every PR failing that test:
What the sweep had done
Pushed commits to #284, #292, #298 and #311 and dispatched a paid review on #310 — four PRs by other lab members, one (#292) by
github-actions[bot], none assigned to the user (verified from the API). Every individual action was a correct ARDI step. The error was the population: it was decided by readingardia's "drive every open PR" as a grant, rather than by asking whose PRs they were. The session then stood down from all five, which over-corrected on #292; the second directive reversed that one.The rule, in one place
A PR is in scope when the invoking user opened it, is assigned to it, explicitly asked for work on it by name (a mention such as "do not touch #N" is not a request; an explicit
chorescall names the Dependabot/Renovate population), or the GitHub Actions app (github-actions) authored it. An explicit exclusion ("do not touch #N") is a veto checked before every positive arm, the user's own PRs included, and travels with the sweep into every recheck and delegated scan. The last positive arm is an author test, not a provenance test: the directive said "workflow-opened", and the rule narrows that on purpose because provenance is not observable from the API, so a workflow PR opened underWORKFLOW_TOKENposts under that token's identity and needs an assignment or an explicit request. A claim comment never adds an arm, and scope is a live precondition re-read before every write. An out-of-scope PR is reported to the user and left untouched: no push, no comment, no review, no merge. When no identity operation is available, the filter fails closed to the explicitly-requested and Actions-app-authored arms. Scope authorizes a PR; whether it is free to work is the separate claim check inclaim-pr.md.Where it lives
AGENTS.md— a compact universal section, since the directive is unscoped and that file is the unconditional cross-agent contract.memories/reviewing-prs.md— the full rule with both sides perCLAUDE.md's "Record both the pattern and the anti-pattern", stating which parts the user said (author/assignee; workflow PRs are fine), which were carried over (the explicit-request arm, fromardia's former "unless told to" bullet), and which are inferred (the Don'ts, the issue carve-out, the narrowing to the Actions app). It records the three forms of the app's login (github-actions[bot]from REST/MCP, baregithub-actionsfrom GraphQL andscripts/pr-sweep.py,app/github-actionsfromgh --json, measured 2026-09-01), the field names per source (author.loginvsuser.loginvsauthor.username; the MCP tools returnassigneesas bare login strings and omit the key when empty), and theWORKFLOW_TOKENcases against gha at82f3c36. It lands here rather than inpreferences.mdbecause that file is at its size cap and this file's header says review-scope lessons go here.skills/ardia/SKILL.md— the reference implementation, in step 1: resolve the invoking user (gh api user,mcp__github__get_me,glab api user), add that user's aliases, normalise the author/assignee fields, apply the exclusion veto, keep the full listing for stack detection, exclude out-of-scope PRs from the action queue, and name them in the report.LIST_PRSfetchesassignees.skills/chores/SKILL.md— the executable predicate:PR_SCOPE_ALIASES,PR_SCOPE_REQUESTED, andPR_SCOPE_EXCLUDEDinputs, a fail-closed identity block, ajqfilter with the veto checked first, and a pre-write refresh of every predicate input (author, assignees, title, labels) before each close, comment, or merge.skills/ardi,gia,ardiaei,mma,cascade,wrap-up,post-merge,handoff,check-history,gi,mwc,shared/workflow/ardi.md,derive-dont-enumerate.md,sync-with-main.md,batch-merge-and-resolve.md,CLAUDE.md,memories/preferences.md,memories/github.md,memories/MEMORY.md,scripts/pr-sweep.py,scripts/pr-overlap.py— every other place that pushes to, comments on, resolves conflicts on, merges, or describes the population of PRs now applies the same test or defers toardia's filter, fetchingauthorandassigneeswhere it lists PRs. A whole-corpus grep for the retired "owns or has explicitly claimed" wording is empty.tool-mappings.yml— aWHO_AM_Ioperation mappinggh api user --jq .logintomcp__github__get_me(the markdown reference is generated from it).On the literal logins
preferences.mdsays never to hardcode usernames. The skills carry no personal usernames — they resolve whoever is running them. Only the memory namesd-morrisonanddem-extra1, as this owner's two aliases for one person (the splitpreferences.md's## Git author mappingalready records), under the rule's own exception for values that must match a real account.Review history
@claudereview: clean on3342a7fand on every reviewed head since through2ce74f9(fifteen clean verdicts); heads the bot quota-skipped got an inline self-review fallback in the thread, each with no findings.shared/workflow/self-review-fallback.md): seven rounds on86037f1…d86a5bd, each addressed in the thread; one pre-existing gap deferred to monitor-open-prs.py polls only --author @me; assigned and workflow-opened PRs are never reconciled #2919 (hooks/monitor-open-prs.pypolls authored PRs only).2ce74f9recommends approval with zero new comments.Verification
After each commit, gated so a failure aborts the push:
check-memory-file-size.py,new-line-breaks(re-run after the commit, since it reads the commit graph),markdownlint-cli2@0.23.0with the repo config,validate-skills.py,check-links.py,check-ascii-punctuation.py --diff --base origin/main; both scripts compile; thechoresjqfilter was extracted from the file and run on sample data for every arm and veto case.🤖 Generated with Claude Code
https://claude.ai/code/session_017trXKZFoCYC4kP7NKNnN6F