Conclusion first: a patch gate is only as trustworthy as the working tree it inspects. When two jobs share one directory, the gate can validate a tree that no single job produced, and still report green.
The scenario below is an illustrative drill, not a report of a real incident. It is written for teams that gate AI-generated patches before they touch main. No measurements or test outcomes are claimed here.
The failure shape (illustrative)
Two patch jobs run against the same checkout on one host. Job A edits src/a.py and starts a slow test. Job B edits src/b.py in the same directory one second later. The gate then runs the full suite once, on one tree, and reports green.
No single patch caused that tree. Job A's tests exercised Job B's file. Both patches may be individually correct, but the gate proved nothing about either one.
Contributing factors
- The worker hard-coded one path,
/srv/patch-work, for every job. - The queue allowed two workers, because one host ran them in parallel.
- The gate diffed the tree only after both jobs had written to it.
- Nothing compared changed files against the file list the patch declared.
- Nothing fingerprinted the tree before and after patch application.
Why a green run hides it
- The test command exits 0, because the mixed tree happens to pass.
- The diff looks reasonable, because every changed file belongs to some job.
- A per-job log review is inconclusive, because both logs share one path.
- A retry makes it worse, because the next job inherits leftover edits.
Gate 1: give every job its own directory
Isolation starts with a job-scoped path. Clone fresh, check out the base commit, then apply.
#!/usr/bin/env bash
# illustrative gate runner; not executed in this article
set -euo pipefail
JOB_ID="${1:?job id required}"
PATCH_FILE="${2:?patch file required}"
WORK_ROOT="${WORK_ROOT:-/srv/patch-jobs}"
BASE_SHA="${BASE_SHA:?base sha required}"
WORKDIR="$WORK_ROOT/$JOB_ID"
rm -rf "$WORKDIR"
git clone --quiet --no-hardlinks "$REPO_URL" "$WORKDIR"
cd "$WORKDIR"
git checkout --quiet "$BASE_SHA"
git apply --index "$PATCH_FILE"
git diff --cached --name-only --diff-filter=ACMR | sort > .changed-files
test -s .changed-files # an empty diff is a gate failure, not a pass
The test -s line matters. A no-op patch should stop the pipeline, not sail through it.
Gate 2: compare changed files with declared files
Ask the patch producer for the file list up front. Write it to .declared-files before applying anything. Then assert equality, not overlap.
sort .declared-files > .declared.sorted
sort .changed-files > .changed.sorted
diff -u .declared.sorted .changed.sorted
Strict equality catches two useful failures at once: undeclared edits, and patches that silently lost a hunk. Set comparison beats counts. A patch declaring three files that touches three different files is still a violation.
Gate 3: fingerprint the tree, not the diff
Diffs describe intent. Tree hashes describe state. Record both ends.
fingerprint() {
git add -A
git write-tree
}
BEFORE="$(fingerprint)"
# ... run the test command here ...
AFTER="$(fingerprint)"
if [ "$BEFORE" != "$AFTER" ]; then
echo "tests mutated the tree; result is not attributable" >&2
exit 1
fi
A test run that rewrites fixtures, snapshots, or config invalidates its own verdict. The comparison above forces the suite to be read-only, or the job to declare its side effects.
Prove the gate can fail
Before trusting any of this, run a canary patch on purpose. It should break exactly one assertion and should turn the gate red.
- Apply a canary patch that changes an expected value.
- Run the full gate unchanged.
- Require a red result and the canary file in
.changed-files. - If the canary stays green, stop and fix the gate before shipping patches.
A contamination test plan (illustrative)
This plan is illustrative and was not executed. Run it in a sandbox repository with quick tests.
for i in 1 2 3 4 5; do
./gate.sh "a-$i" patches/a.patch &
sleep 1
./gate.sh "b-$i" patches/b.patch &
wait
done
Expected result with job-scoped directories: zero cross-links in five rounds. Expected result with a shared directory: at least one run where .changed-files contains both a and b paths. Record the count either way, and keep it as a regression baseline.
Choosing an isolation level
| Setup | Isolation | Cost | Where it fits |
|---|---|---|---|
| Shared dir, one worker, fresh reset per run | Time-only | Lowest disk | Low volume, strict serialization |
| Per-job clone | Full | Repo size times jobs | Default for untrusted model patches |
Per-job git worktree
|
Full working tree, shared objects | Medium | Many jobs on one repo |
| Container per job | Full, including toolchain | Highest | Concurrency plus untrusted build steps |
The shared-directory row is honest only when the queue guarantees one job at a time and resets the tree. Concurrency breaks it silently.
Where free-tier capacity changes the calculus
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
The project offers free model access and a free server option, as described by its operator. That combination makes parallel patch jobs tempting on one machine. It also makes path collisions more likely, because one host often means one working directory unless the runner creates more.
A practical split for that setup:
- Use free model access to draft the declared file list and a one-line intent per file.
- Keep the gate independent of the model, so a wrong declaration fails instead of persuading anyone.
- Give every job its own directory on the free server, even when jobs run one at a time.
- Verify the current free-tier terms on the project's official page before a queue depends on them.
Limitations
-
git write-treeignores.gitignored files; model-written caches can hide there. - Fresh clones cost disk and time;
--no-hardlinkstrades space for safety. - Job isolation does not fix flaky tests, wrong base commits, or truncated patches.
- Single-worker local loops gain little beyond a guaranteed fresh tree.
- Submodules and Git LFS need extra steps not shown here.
Who should skip this
Solo developers patching their own branch do not need three gates. Teams without a stable job identifier should add that first. Anyone whose test suite must write artifacts should fix the suite before adding fingerprints.
Checks before trusting a green gate
- Confirm the working path contains the job ID.
- Confirm
.changed-filesequals.declared-files. - Confirm the tree hash is stable across the test run.
- Confirm the canary patch turns the gate red.
- Confirm the base commit matches the patch's target.
If a mixed-tree postmortem sounds familiar, the free model access and free server option are a cheap way to rehearse this drill. Check the current terms first, then keep the canary red until the gate earns its green.
Top comments (0)