DEV Community

Alex Zhu
Alex Zhu

Posted on

Name a Diff Signer: A One-Page Wiki SOP for AI-Authored Patches

You open the shared repository on Monday morning and find three pull requests already merged into main. The commit messages mention an agent loop, a free host, and a late Friday experiment that ran too long. Nobody on the team can replay the session, because the shared free server no longer holds that chat. You are now the person who must decide whether those diffs stay, get reverted, or wait for a signer.

Shared free-tier coding loops fail in a boring way that looks like velocity until review is missing. The model will draft a patch, the host will keep the process alive, and git will still record a merge. Git will not record a human who read the blast radius after the chat history vanished. This playbook gives you a signer window, three named seats, and a one-page wiki run you can paste.

The failure you are actually gating

An AI-authored patch is not a complete change until a named human accepts the blast radius in git. Tool traces vanish when a free session ends, so the agent is not an owner and not an audit trail. You need a signer who can still explain the diff after the chat history is gone for good. You also need that name written before tokens start moving, not after main has already gone red.

Waiting until Monday morning trains the team to treat silence as consent on unsigned merges. The SOP below treats a missing signer as a failed gate, the same way missing tests fail a build. Social memory will not survive a long weekend, which is why the wiki page has to be boring and short. If you cannot point to a handle, you do not have a review; you have a hope.

Three seats and one signer window

Fill three seats on one wiki page before anyone launches a shared coding loop. Keep overnight ownership, topology guesses, and staging gates on other pages so this run stays about the diff. The loop starter is a duty, not a fourth throne, and that duty can rotate every spike.

  1. Diff signer — the human who reads the patch and writes SIGNER: @handle on the pull request.
  2. Merge captain — the person allowed to press merge after the signer line exists and the window is still open.
  3. Rollback owner — the person who reverts within an agreed window if CI or production complains.

The person who starts the loop and the diff signer must be different people whenever two humans are available. If you are alone, you still write your name in the signer seat, then you wait one sleep cycle before merging auth, billing, or deletion paths. That pause is the control; skip it and the SOP is only theater. Name the rollback owner before the first tool call, because finding a volunteer after main breaks is not a handoff.

The one-page wiki run you can paste

Copy the block below into your team wiki. Replace the bracketed fields before the loop, not after the revert. Keep the page short enough to read in two minutes on a phone.

# Diff-Signer SOP (AI-authored patches)

Status: ACTIVE
Lab date (UTC): YYYY-MM-DD
Shared host: [workstation or free server label]
Model access: [free-tier label only; no guessed quotas]
Repository: [org/repo]
Branch: [topic branch]
Loop starter (duty): [@handle]
Diff signer: [@handle]
Merge captain: [@handle]
Rollback owner: [@handle]
Signer window: [start UTC] → [end UTC]
Path allowlist: [src/app/ docs/]
Out of scope: [secrets, lockfiles, prod Terraform]
Rollback window: [example: 4 hours after merge]

## Gate
- No merge to main without `SIGNER: @handle` in the PR body.
- No merge if the signer window has expired.
- No merge if the rollback owner is offline and the diff touches infra.

## After the loop
- PR URL:
- Commit SHA:
- Signer read the diff without the chat transcript: [yes/no]
Enter fullscreen mode Exit fullscreen mode

If the page grows past one screen, you are mixing runbooks. Split host health, prompt topology, and overnight coverage away from this signer page. A wiki that tries to govern every AI fear will not get filled on Friday. Empty fields mean the loop does not start.

Steps for the person who starts the loop

Follow these steps in order. Do not start the agent until step four is green on the wiki page.

  1. Create a topic branch from an updated default branch and push it empty, so the pull request exists before the model writes files.
  2. Open the wiki page, fill every seat, and ping the diff signer in chat with the page link and the allowlist.
  3. Write a path allowlist in the pull request body so the loop cannot wander into secrets, lockfiles, or production Terraform.
  4. Wait for the signer to reply window open on the wiki page; if they do not reply, you do not start the loop.
  5. Run the coding loop only against the topic branch, and stop when the signer window ends, even if the agent wants one more file.
  6. Push the diff, paste the pull request URL onto the wiki page, and walk away without merging.

Here is a small command sequence you can paste. Treat it as a proposal until you have run it in your own clone.

# Proposal: create the review branch before the agent writes anything
git fetch origin
git switch -c lab/ai-patch-$(date -u +%Y%m%d) origin/main
git push -u origin HEAD

# Proposal: open a PR with a signer placeholder the local check can read
gh pr create --title "lab: AI patch pending signer" --body "$(cat <<'EOF'
SIGNER: UNASSIGNED
ROLLBACK: @handle
ALLOWLIST: src/app/ docs/
WIKI: https://wiki.example/diff-signer-sop
EOF
)"
Enter fullscreen mode Exit fullscreen mode

If your team does not use gh, create the same pull request in the browser and keep SIGNER: as the first line of the body. The important part is the token in the body, not the CLI flavor. An empty branch with a real pull request beats a local pile of unreviewed files on a laptop.

Steps for the person who signs the diff

You are not reviewing the model's personality. You are reviewing a git diff that must survive after the free session disappears. Read the tree first, then read any chat transcript only if the tree is already defensible.

  1. Open the pull request without opening the chat transcript first, so you judge the files, not the story the agent told.
  2. Reject the patch if it touches paths outside the allowlist, even when the change looks clever or the commit message sounds confident.
  3. Reject the patch if you cannot explain the failure mode in one sentence on the wiki page beside the SHA.
  4. If you accept, replace SIGNER: UNASSIGNED with SIGNER: @yourhandle and a UTC timestamp inside the pull request body.
  5. Tell the merge captain the window is still open, and do not merge if you also started the loop and a second human exists.

A useful local inspection looks like the commands below. Run them against the remote topic branch, not against a working tree the agent still owns.

git fetch origin
git diff origin/main...origin/lab/ai-patch-20260911 --stat
git diff origin/main...origin/lab/ai-patch-20260911
Enter fullscreen mode Exit fullscreen mode

Read the stat output before the full diff so the size of the change is visible. If more than a handful of files moved, you probably do not have a signer window; you have a rewrite. Rewrites need a different playbook, a longer window, and a merge captain who is awake.

A local signer check you can reproduce

The artifact below is a small Python gate. It reads a pull-request body from a file and fails when a real signer line is missing. Save it as tools/check_signer.py and run it on your laptop before anyone presses merge.

#!/usr/bin/env python3
"""Fail if an AI-authored PR body has no human SIGNER line.

Example gate: run it against a saved PR body file.
It does not call a vendor API and does not prove the human read the diff.
"""
from __future__ import annotations

import re
import sys
from pathlib import Path

SIGNER_RE = re.compile(
    r"^SIGNER:\s*@?(?P<name>[A-Za-z0-9][A-Za-z0-9_-]{1,38})\s*$",
    re.MULTILINE,
)
FORBIDDEN = {"unassigned", "none", "n/a", "agent", "bot", "model"}


def load_body(path: Path) -> str:
    if not path.is_file():
        raise SystemExit(f"missing PR body file: {path}")
    return path.read_text(encoding="utf-8")


def find_signer(body: str) -> str | None:
    match = SIGNER_RE.search(body)
    if not match:
        return None
    return match.group("name")


def main(argv: list[str]) -> int:
    target = Path(argv[1]) if len(argv) > 1 else Path("pr_body.txt")
    body = load_body(target)
    signer = find_signer(body)
    if signer is None:
        print("FAIL: no SIGNER: @handle line in pull request body")
        return 2
    if signer.lower() in FORBIDDEN:
        print(f"FAIL: signer {signer!r} is a placeholder, not a human")
        return 2
    print(f"PASS: signer is {signer}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main(sys.argv))
Enter fullscreen mode Exit fullscreen mode

Save a sample body and run the check twice so both paths are visible.

printf 'SIGNER: UNASSIGNED\nALLOWLIST: src/\n' > pr_body.txt
python3 tools/check_signer.py pr_body.txt
# expected: FAIL

printf 'SIGNER: @alex\nALLOWLIST: src/\n' > pr_body.txt
python3 tools/check_signer.py pr_body.txt
# expected: PASS
Enter fullscreen mode Exit fullscreen mode

Treat those commands as unexecuted in your environment until you have run them once on a throwaway file. The script does not prove the human read the diff; it only proves the team refused to merge with a blank owner. That is a weak control, and it is still stronger than a chat that vanished with the free session.

If you later wire a forge workflow, keep it equally small. The following snippet is a proposal, not a production pipeline, and you should run it in a fork before trusting it on shared main.

# Proposal only — unexecuted in this article
name: signer-gate
on:
  pull_request:
    types: [opened, edited, synchronize]
jobs:
  signer:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Write PR body
        env:
          BODY: ${{ github.event.pull_request.body }}
        run: printf '%s\n' "$BODY" > pr_body.txt
      - run: python3 tools/check_signer.py pr_body.txt
Enter fullscreen mode Exit fullscreen mode

How a free model server changes the record

Some shared labs point the coding loop at MonkeyCode's free model access and free server option when a spike is cheap enough to discard. Disclosure: This article was prepared as part of MonkeyCode's product outreach. Keep the signer window anyway, because that host is not a substitute for a named human on the pull request.

Do not treat a free host as a durable log of tool calls or prompt retries. Session state can disappear, so the wiki page and the git history are the records you keep. Do not invent quotas, model names, or uptime promises on the wiki; write only the lab date, the branch, and the three handles. If the free server is busy or unavailable, you park the loop and you do not move an unsigned diff onto a laptop.

After the window: a small decision table

Print this table under the wiki SOP so Friday-you does not invent a fourth outcome. Tables survive a long weekend better than tribal memory, and they give the merge captain something to point at besides mood.

Condition Action Who acts
Signer line present, allowlist clean, tests green Merge Merge captain
Signer line present, tests red Hold; do not expand the loop Loop starter
Signer window expired Close or convert to draft Merge captain
Diff escaped the allowlist Refuse merge; reset the topic branch Diff signer
Merge already happened, rollback window open, CI or prod complains Revert the SHA Rollback owner
Chat transcript gone, no signer line Treat as unsigned; revert if already on main Rollback owner

If two rows seem to apply, take the stricter action and write one sentence on the wiki about why. Do not reopen the agent to "just tidy the tests" after the signer window has closed. A second loop is a new page, a new window, and a new ping, not a continuation hidden inside the same pull request.

Limitations and who should skip this

This playbook does not make the model safer, faster, or more accurate, and it does not recover a deleted session. It only makes ownership visible after the chat dies. The Python gate can be spoofed by typing a teammate's handle, so you still need chat pings and the social cost of putting a name on a bad diff. The extra latency will annoy anyone who wanted the agent to land on main before lunch, which is an intended cost rather than a defect in the steps.

You should not use this SOP if a regulated CODEOWNERS flow already blocks merges and a second theater gate would hide the real owners. You should not use it for incident hotfixes that already have a named commander and a recorded bridge. You should not point unsigned agent loops at production credentials on any host, free or paid. Solo developers can still use the signer line as a note to future-you, but the two-person split will not exist, so keep the sleep-cycle pause for dangerous paths.

If you already have a free server for spikes, paste the wiki block before the next loop rather than after the Monday revert.

Top comments (0)