Why this is worth reading: a free coding model can return a patch that passes your test suite and still create a costly change. It might delete a seed file, flip an executable bit, rewrite a 400-line module to change two lines, or bundle a new dependency lockfile into a one-line fix. You do not need to read every line first. You need to read the shape of the diff.
Most code review tools show you a unified diff and ask you to evaluate it line by line. That is the wrong order for model-generated work. The first pass should be a shape check: which paths changed, what was deleted, whether file modes or binary content changed, and how much churn each file carries. This article gives you a small local script that prints that shape and a decision table for acting on it.
Start from the diff metadata, not the code
git diff can print the raw numbers used to build the visual diff you see on GitHub or GitLab. The --numstat option outputs one line per file with added lines, removed lines, and path. The --summary option reports renames, mode changes, symlink changes, and create/delete events. Those two commands are enough to catch several classes of bad patch before you read code.
git diff --numstat origin/main HEAD
git diff --summary origin/main HEAD
git diff --check origin/main HEAD
Enter fullscreen mode Exit fullscreen mode
git diff --check is especially useful because it flags trailing whitespace and conflict markers, two common artifacts of model-generated multi-line edits. Do not skip it just because a CI linter may run later.
A reproducible autopsy script
Save this as diff_autopsy.sh and run it with two refs. It prints a per-file churn table, flags zero-add and zero-delete files, and reports mode changes and low-similarity renames.
#!/usr/bin/env bash
set -euo pipefail
base=${1:-origin/main}
head=${2:-HEAD}
echo 'PATH|ADDED|REMOVED|CHURN'
git diff --numstat "$base" "$head" | while IFS=$'\t' read -r added removed path; do
if [[ $added == - || $removed == - ]]; then
churn=binary
else
churn=$((added + removed))
fi
printf '%s|%s|%s|%s\n' "$path" "$added" "$removed" "$churn"
done
echo
echo 'only-removals'
git diff --numstat "$base" "$head" | while IFS=$'\t' read -r added removed path; do
[[ $added == 0 ]] && printf '%s\n' "$path"
done
echo
echo 'only-additions'
git diff --numstat "$base" "$head" | while IFS=$'\t' read -r added removed path; do
[[ $removed == 0 ]] && printf '%s\n' "$path"
done
echo
echo 'mode-changes'
git diff --summary "$base" "$head" | grep 'mode change' || true
echo
echo 'renames-at-60-percent'
git diff --find-renames=60% --summary "$base" "$head" | grep -E 'similarity|=>' || true
echo
echo 'whitespace-check'
git diff --check "$base" "$head" || true
Enter fullscreen mode Exit fullscreen mode
The script is deliberately boring: no API keys, no model SDK, no external service. It works on any branch, any model, and any host. The path parser treats tab as the field separator, so filenames containing spaces do not break the churn calculation.
Read the shape through a decision table
Use this table after the script, not before it. The goal is to direct your limited review time to the riskiest files first.
Signal What you see What to do Test deletion A file under atest/ or tests/ path has 0 additions
Block until the model or the author explains the lost coverage
Seed or fixture deletion
db/seeds.rb, *.sql, .env.example, or similar only removed lines
Treat as a broken local setup; do not merge silently
Binary change
ADDED or REMOVED shows -, or --summary reports a new binary
Reject and ask for the source or a reproducible build step
Low-similarity rename
--summary reports a rename below 60% similarity
Treat it as a delete plus an add; review both sides fully
Executable bit shift
--summary reports a mode change
Verify it was intentional; generated patches rarely need to chmod anything
Pure addition
REMOVED is 0 and the file is not new source code
Check whether it is generated output that should be ignored
Pure deletion
ADDED is 0
Count as a deletion, even if the file still exists in the working tree
High churn
CHURN is above 150 in a single file for a small task
Ask the model to split the change or justify the rewrite
Unrelated path
Files outside the issue’s module or service show up
Scope creep; strip those files from the patch
These flags are not proof of a bug. They are invitations to ask a specific question. A large churn value may be a legitimate extraction or rename. A deleted seed file may have been replaced by a generator. The table just makes the question explicit.
Test the sheet on a synthetic repo
You can verify the script behavior without touching a real project. Create a scratch repository, make a normal commit, then make a branch with one dangerous change.
mkdir autopsy-demo && cd autopsy-demo
git init -b main
printf 'hello\n' > a.txt
mkdir -p tests
printf 'assert true\n' > tests/smoke.txt
git add . && git commit -m "base"
git checkout -b change
: > a.txt # zero additions, one removal
git mv tests/smoke.txt tests/smoke-old.txt
printf '#!/bin/sh\n' > run.sh # pure addition
chmod +x run.sh # mode change
git add -A && git commit -m "model-generated change"
./diff_autopsy.sh main change
Enter fullscreen mode Exit fullscreen mode
The output should show a.txt as a file that only removed lines, tests/smoke-old.txt as a low-similarity rename, run.sh as a pure addition, and a mode change. That synthetic repo is also a useful fixture to keep in CI when you change the script.
Where free model access fits
Disclosure: This article was prepared as part of MonkeyCode’s product outreach.
If you generate a candidate patch with MonkeyCode’s free model access through its free server option, run the autopsy script against the resulting branch before opening a pull request. The script consumes no model quota and does not need the model endpoint to expose any special API; it only reads the diff already written to your repository. This makes it a cheap first gate when you are trying several free-model attempts against the same issue and want to reject obviously bad shapes without burning review cycles.
Limitations and when to skip it
The autopsy sheet is a triage step, not a review. It cannot detect a one-line logic error that leaves all shape metrics unchanged. It does not look for secrets, vulnerable dependencies, broken imports, or flaky tests. Path-based rules such as the test-deletion ratio assume your repository follows a naming convention, so adjust the patterns to your tree.
Skip or simplify this workflow if your patches are almost always tiny and your review process already surfaces the same signals. It is most useful when you are reviewing many model-generated branches in a row, or when a free model has produced a suspiciously large diff and you need a fast way to decide which files deserve human attention first.
Try the sheet on the next four model-generated diffs before reading the code. If the shape flags change your review order, keep it. If every diff comes back clean and uneventful, it has served its purpose and you can move on.