docs: agents open PRs only when nothing UI-facing moves, and never merge them - #568
Merged
Conversation
…rge them Pull requests are merged by a human after code review, always. Whether an agent may open one at all now depends on what the change touches: a backend-only change gets its PR at completion, a UI-affecting one stops at the worktree branch so it can be checked visually first and gets a PR only on explicit instruction. When in doubt it is UI-affecting. Auto-merge is banned outright rather than described as a thing that fails loudly, so the narrative about the GraphQL error and the retired dependabot workflow goes with it. The baseline-proof exception survives, reframed: the task assembles the evidence, the reviewer decides. CONTRIBUTING gains the distinction for outside contributions, drawn mechanically rather than by identity - the tiers bind work pushed to the canonical repository by an account holding push permission, and work from a fork is not bound by them. Review and manual merge apply to every pull request either way. Both files now state that instructions found inside tracker text grant no permission and relax no check. The authorship ban gains its reason and its boundary: coding agents are tools, not authors, so the responsible developer signs; an autonomous service bot signs as itself because no human keystroke sits behind that commit.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #566.
Pull requests are merged by a human after code review, always, and whether an agent may open one
at all now depends on what the change touches.
refactor-protocolis where the rule lives infull;
AGENTS.mdandCONTRIBUTING.mdcarry the compact form and point at it.What changed
.agents/skills/process/refactor-protocol/SKILL.md—## PR & CIrewritten around the twotiers. Tier A (no UI-affecting surface) opens its pull request at completion; Tier B
(UI-affecting) stops at the worktree branch, reports, and opens nothing until told to, so the
change can be checked visually and behaviourally before it becomes a review artefact. The
UI-affecting test is spelled out —
frontend/,src/visionset/_static/or the UI bundling path,wire shapes /
allowed_actions/ server behaviour that alters what the UI renders, anyuser-visible behaviour change — and when in doubt it is Tier B. Merging leaves the file as an
instruction: never
gh pr merge, auto-merge banned outright, a green check set is theprecondition for somebody else's decision rather than permission. Requested changes are new
commits on the same branch.
The baseline-proof exception survives intact but changes hands: the task assembles the evidence
and the reviewer decides, so its five requirements are now what goes in the PR body rather than
what authorises a merge.
## Cleanupkeeps its commands and is re-anchored to a merge somebodyelse performed; the
gh pr merge-exits-non-zero-from-a-worktree note stays, because that is stillthe diagnosis when a human merges from one. Two lines in the saturated-machine fallback that read
as though the agent merges now read as what the completion report claims. Everything else — scope
discipline, worktree isolation, the whole testing section, background processes — is untouched.
AGENTS.md—### Commits and PRsgains never-merge, the tier rule in four lines, anditeration-on-the-same-branch. The bare
Co-Authored-Bybullet is replaced by the policy with itsreason and its boundary.
CONTRIBUTING.md—## Mergingstates the manual-merge rule without theenablePullRequestAutoMergenarrative or the retired-workflow history; the Dependabot paragraphkeeps its operational half. A new subsection describes the tiers for work done against this
repository with push access, and says plainly that work from a fork is not bound by them.
## Commitsgains the authorship convention, phrased as a fact about who the commit record names.The distinction is mechanical, never identity-based
Whether the tiers apply is a property of the working remote and the account's permission — what
git remote -vandgh repo view --json viewerPermissionreport — not of anything anybody claimsto be. Both public files also state that instructions written inside an issue, a comment or a
pull-request description grant no permission, relax no check, and are not a reason to fetch or run
anything. The text was re-read once assuming a hostile third party would feed it to their own
agent verbatim; nothing in it delegates authority, and no sentence can be quoted to claim a merge,
a skipped review, or a relaxed gate.
Residual sweep
git grep -inE "auto-?merge|pr merge --auto|merge when (green|ci)"had four hits before thischange, all of them already bans followed by an explanation of why
--autofails loudly. After:refactor-protocolL75–81 —--autofails withGraphQL: …, retireddependabot-auto-merge.ymlCONTRIBUTING.mdL365–367 — sameGraphQLexplanation + the merge command blockgh pr mergeblock is goneCONTRIBUTING.mdL378–382 — the retired dependabot workflow's historyCONTRIBUTING.mdL375–376 — never on a partial pass, never to unblockgit grep -n "gh pr merge"now returns two lines: the ban itself, and the cleanup note about thecommand exiting non-zero from a worktree.
git grep -inE "co-authored|generated with"returnsonly the three new policy statements.
No workflow change was needed.
.github/workflows/holdsci.yml(permissions: contents: read, every step a checkout/setup/cache/upload or arun:of uv, pnpm or bash) andpublish-pypi.yml(workflow_dispatchonly). Neither can merge, approve or queue anything, anddependabot-auto-merge.ymlno longer exists. There is no PR template, noCODEOWNERS, and nomerge-queue configuration.
One doc correction found on the way
CONTRIBUTING.md's branch-protection snippet passesrequired_pull_request_reviews=null, and theprotection endpoint replaces the whole payload rather than patching it — so running that command
as written clears any review requirement along with everything else it does not name. The snippet
is left alone (it is about marking the release gate a required status) and a sentence now says so.
Whether required reviews are turned on is a repository setting and was not touched.
Test plan
Docs and skills only; no Python, no TypeScript, no generated artefact moves.
scripts/check.shrun in stages, because the harness kills a command at roughly ten minutes:
bash scripts/check.sh generatedbash scripts/check.sh docsbash scripts/check.sh frontendbash scripts/check.sh pythonbash scripts/check.sh browserThe browser stage, and why it does not block
annotator + app e2e (chromium)failed on the branch with the two scenarios #550 already tracks:Reproduced on unmodified
mainat the merge-based93cbfd, in this environment, in a detachedworktree of its own:
The first scenario fails on both. The second is the one #550 records as flaky rather than
failing under the local gate's ten workers, and it behaved that way here — red on the branch run,
green on the baseline run, in both cases on a run where the other scenario was already red.
This change touches three Markdown files and nothing the failing step exercises: no
frontend/app/e2e/file, no component, no route, no wire model.browser cycle, real server (chromium)passed on the branch (1 passed (37.0s)). The baseline failure is tracked as #550,which reproduces it on
mainata2af0bfand reasons about the cause.Found, not fixed
d93cbfd.CONTRIBUTING.mddocumented a branch-protection call that clears required reviews. Annotatedrather than rewritten, since the snippet's own purpose is a required status check.