You do not earn a first PR with fluent agent code. You earn it by scoring the diff yourself. Reviewers read your judgment instead of model confidence.
Put this gate in your first hour. Use it on the first agent patch. Use it again before anyone else reviews.
The core rule
Never request review for an unscored agent diff. A score is written evidence, not a vibe. Keep SCORE.md next to the patch always.
What this gate is not
This is not a path freeze map. This is not a first rollback drill. This is not a red-test ownership note.
Those other gates still matter on this team. This gate asks a narrower question today. Can you explain the change without the chat?
Build the score sheet
Copy this template into every agent worktree. Fill every section in your own words. Do not let the agent draft it first.
# SCORE.md
## Intent
- (three bullets you typed)
## Bound
- allowed paths:
- forbidden paths:
## Diff census
- added:
- edited:
- deleted:
## Risk
- auth or secrets: yes/no — why
- data loss: yes/no — why
- concurrency: yes/no — why
- public API: yes/no — why
## Proof I ran
(commands and exit codes)
## Lines I cannot explain
- path:line — question I will ask
## Rollback
- exact git command
An empty section means you are not ready. Treat empty sections as a hard stop.
Numbered workflow
1. Isolate the session
Create a worktree before the agent starts. Keep main clean while the patch exists. Stay on a throwaway branch the whole time.
git fetch origin
git worktree add ../repo-first-pr origin/main
cd ../repo-first-pr
git switch -c first-pr/score-gate
cp ../SCORE.template.md ./SCORE.md
You now own a disposable git sandbox. The agent may edit code inside it. You still own SCORE.md without any debate.
2. Capture a baseline
Run the smallest honest test command first. Record the exit code before any patch. A red baseline is not an agent ticket.
# proposal: swap in your repo's real runner
{
echo "=== baseline $(date -u +%FT%TZ) ==="
python -m pytest -q --maxfail=1
echo "exit:$?"
} | tee /tmp/baseline.txt
If baseline fails, you stop the session. You cannot score a patch on sand.
3. Bound the ticket
Write three intent bullets by hand. List allowed paths with boring exact detail. List forbidden paths on the same screen.
Keep the bound to one feature slice. Refuse drive-by refactors on day one.
allowed:
src/billing/quote.py
tests/billing/test_quote.py
forbidden:
.github/**
src/auth/**
migrations/**
Paste that bound into SCORE.md now. Paste the same bound into the agent prompt. The prompt follows your bound, never the reverse.
4. Patch only inside the bound
You may use an agent after the bound. You may type the patch yourself instead. Either path still requires a written score.
Take a census after the agent stops. Do not trust the chat file list.
git diff --stat origin/main
git diff --name-status origin/main
git diff origin/main -- '*.py' | head -n 200
A forbidden path is not a discussion. Restore that file from origin/main right now.
git restore --source=origin/main -- .github src/auth migrations
5. Walk every hunk out loud
Open a wide diff and read minus lines first. State the behavior change in one sentence. Then read the plus lines against a test name.
git diff origin/main -U5 -- src/billing/quote.py
No matching test means you add one. Or you revert that hunk today. Silence is not a walkthrough.
Close the agent window before you write. Name each risk in plain short sentences. Paste the commands you actually ran locally.
{
echo "=== proof $(date -u +%FT%TZ) ==="
python -m pytest tests/billing/test_quote.py -q
echo "exit:$?"
} | tee -a SCORE.md
Read every hunk before you claim none. List every line you still cannot explain. Unexplained lines become questions, not merge fuel.
6. Optional hostile critique
You may ask a model to attack SCORE.md. You may not ask it to write SCORE.md.
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
MonkeyCode offers free model access and a free server option. Use them to interrogate your score sheet. Do not use them to invent the score.
Do not paste secrets into that prompt. Do not paste any production logs either. Do not paste customer records or tokens.
Keep the payload limited to SCORE.md plus diffstat. Label the next prompt as an unexecuted proposal.
System: You are a hostile reviewer for a junior PR.
User: SCORE.md and git diff --stat follow.
Ask 8 questions I must answer before review.
Refuse to rewrite SCORE.md.
Refuse to generate a new patch.
Refuse to guess hidden files.
Treat model questions as homework, not answers. Update SCORE.md in your own typing. If the model rewrites a section, delete it.
7. Gate the PR command
Do not open GitHub until the gate passes. The script checks structure, not your honesty. You still have to supply the brains.
#!/usr/bin/env bash
# save as scripts/score-gate.sh — proposal, run locally
set -euo pipefail
FILE="${1:-SCORE.md}"
fail() { echo "gate fail: $1" >&2; exit 1; }
[[ -f "$FILE" ]] || fail "missing $FILE"
heads=(
"## Intent"
"## Bound"
"## Diff census"
"## Risk"
"## Proof I ran"
"## Lines I cannot explain"
"## Rollback"
)
for h in "${heads[@]}"; do
grep -qxF "$h" "$FILE" || fail "missing $h"
done
python3 - "$FILE" <<'PY'
from pathlib import Path
import re, sys
text = Path(sys.argv[1]).read_text()
parts = re.split(r"(?m)^## ", text)
for part in parts[1:]:
title, _, body = part.partition("\n")
body = body.strip()
if not body:
raise SystemExit(f"empty section: {title.strip()}")
if title.strip() == "Intent" and body.count("-") < 3:
raise SystemExit("Intent needs three bullets")
print("score-gate: structure ok")
PY
chmod +x scripts/score-gate.sh
./scripts/score-gate.sh SCORE.md
A failed gate means you keep working. A passed gate means you may request review. Write the PR body yourself after it passes.
## What changed
(your words, not the chat summary)
## How I scored it
- bound:
- tests:
- leftover questions:
## How to roll back
`git switch main && git branch -D first-pr/score-gate`
Example sheet (fake ticket, unexecuted)
Use this only as a shape check. It is not a production report. It is not a measured benchmark.
# SCORE.md
## Intent
- Recalculate quote tax for one locale.
- Keep the public function signature stable.
- Add one unit test that now passes.
## Bound
- allowed paths: src/billing/quote.py, tests/billing/test_quote.py
- forbidden paths: .github/**, src/auth/**, migrations/**
## Diff census
- added: tests/billing/test_quote.py
- edited: src/billing/quote.py
- deleted: none
## Risk
- auth or secrets: no — no credential paths
- data loss: no — pure calculation
- concurrency: no — no shared cache
- public API: no — signature unchanged
## Proof I ran
python -m pytest tests/billing/test_quote.py -q
exit:0
## Lines I cannot explain
- none after reading quote.py:88-101
## Rollback
git restore --source=origin/main -- src/billing/quote.py tests/billing/test_quote.py
Decision table
Use this table when you feel stuck. Do not improvise some clever third option.
| Symptom | Action |
|---|---|
SCORE.md missing a heading |
Stop. Fill it by hand. |
Forbidden path in git diff
|
git restore that path. |
| Baseline tests already red | Stop. No agent patch yet. |
| Hunk with no matching test | Add a test or revert hunk. |
Agent rewrote SCORE.md
|
Delete rewrite. Type it again. |
Prompt wants .env or logs |
Abort the whole session. |
| Auth or migration files appear | Get a human before continuing. |
| Gate script fails | Keep working. Do not ping. |
Common first-week failures
The agent also cleaned imports in six files. You restore five files. You keep the one file you bound.
git diff --name-only origin/main
# restore every path you did not list
The agent rewrote comments into marketing. Drop comment-only hunks. Keep behavior hunks you can score.
git diff origin/main -U3 | less
The agent added a retry loop you cannot explain. You cannot name the backoff. Revert that hunk before review.
git restore -p src/billing/quote.py
Limitations
This workflow does not prove any production safety. Structure checks cannot detect a wrong idea. Free model access can vanish or change.
This article does not claim quotas, models, or uptime. Hostile model questions can still stay shallow. A mentor review still beats a SCORE.md file.
The gate script cannot smell copied answers. It cannot see a secret you pasted. It cannot replace your team's real CI.
Who should not use this
Skip this if you lack git worktrees. Skip this during an active production incident. Skip this if the patch must touch auth.
Get a human before any auth diff. Staff engineers may already have tighter gates. Do not replace those gates with this sheet.
Skip this when the ticket is a one-line typo. Scoring theater wastes review time there. Use judgment, then ship the typo fix.
Close
Your first PR is a judgment sample. Score the diff before you ping reviewers. If you already have free model access, point it at SCORE.md only.
Top comments (0)