An agent patch is not merge-eligible until three hashes agree: the fixture epoch pin, the property-manifest digest, and the witness digest on any flake freeze. A green local test run is not one of those hashes. If the diff rewrote the generator, the property list, or the freeze note, close the change before a reviewer spends time on the prose.
This is a narrower rule than adding more tests. It keeps the patch under review off the oracle that judges it. The workflow below is a fail-closed procedure for that split, with a proposed Python checker and a decision table. Nothing here is a measured defect rate, and no account-specific production incident is claimed.
Why the three clocks drift
Agent diffs often land in setup helpers, golden files, and the test that just went red. A property check can then pass because the generator moved with the bug. A flake note can cite a test name that no longer denotes the same input.
Two other clocks move even when the diff is honest. The fixture generator on a laptop can differ from the review runner by one uncommitted byte, and a freeze window can outlive the files that produced the flake. When those clocks diverge, a hold looks like evidence. It is only a sentence in a log.
External posts about comments, career breaks, or in-browser demos are topic noise for this decision. They do not hash your fixtures. The oracle has to be a file the review job can recompute.
The identity contract
Keep three artifacts outside the agent's writable surface. A freeze file is optional, and it is never a substitute for a witness.
| Artifact | Author | Diff may edit | Fields that must match |
|---|---|---|---|
fixtures/EPOCH |
human or release job, before the draft | no |
epoch_id, generator_sha256
|
checks/manifest.json |
reviewer sampler, not the drafting model | no |
seed, properties, manifest_sha256
|
observations/<id>.json |
the replay runner | no |
epoch_id, witness_sha256, status
|
Verdict labels in this checker are closed, hold, and eligible. hold is not a merge approval. It means a human may read a witness captured against the pinned epoch. eligible means the identity checks passed and no sampled property failed, which is not the same as correct product behavior.
Step 1: Pin the epoch before any draft
Create the pin in a commit that does not contain the agent diff. Name the generator by content hash, not by wall-clock time. Wall clocks differ across laptops and hosted runners. A hash of the generator bytes does not, provided you hash the file you will actually load.
python3 - <<'PY'
import hashlib, json, pathlib
gen = pathlib.Path("fixtures/generate_orders.py").read_bytes()
pin = {
"epoch_id": "orders-2026-09-25-a",
"generator_sha256": hashlib.sha256(gen).hexdigest(),
"inputs": ["fixtures/orders/base.json"],
}
path = pathlib.Path("fixtures/EPOCH")
path.write_text(json.dumps(pin, indent=2) + "\n")
print(pin["epoch_id"], pin["generator_sha256"])
PY
git add fixtures/EPOCH fixtures/generate_orders.py
git commit -m "Pin order fixture epoch before agent review"
The date inside epoch_id is a label chosen for this example on 2026-09-25. It is not a product release, a quota, or a server lifetime. If the generator changes, mint a new epoch id. Do not rewrite the old pin so a failing patch becomes green.
Step 2: Sample properties the diff cannot touch
The manifest names properties and input bounds. The drafting model does not choose the sample. A fixed seed makes one draw reproducible on the same interpreter. Compute the manifest digest over the canonical property list only, so the digest is not a hash of itself.
# Proposed sampler. Not a recorded production run.
import hashlib, json, random
PROPERTIES = [
{"name": "order_total_non_negative", "bound": "orders"},
{"name": "refund_le_captured", "bound": "payments"},
{"name": "idempotency_key_stable", "bound": "retries"},
{"name": "currency_scale_matches_catalog", "bound": "money"},
]
def sample_manifest(seed: int, k: int = 3) -> dict:
rng = random.Random(seed)
chosen = rng.sample(PROPERTIES, k=k)
body = {"seed": seed, "properties": chosen}
canonical = json.dumps(body, sort_keys=True, separators=(",", ":")).encode()
body["manifest_sha256"] = hashlib.sha256(canonical).hexdigest()
return body
if __name__ == "__main__":
print(json.dumps(sample_manifest(seed=20260925, k=3), indent=2))
The seed 20260925 is a review label, not a coverage score. Record the seed you actually used. Protect checks/manifest.json and the sampler path with a review lock, such as a CODEOWNERS entry, so one change cannot edit both the product logic and the property list.
Python's random.Random sequence is not a stable cross-version contract. Record the interpreter version beside the seed if a later runner must reproduce the same draw.
A property in this manifest is a predicate over a saved input, not a rewritten unit test. For refund_le_captured, the witness is the payment record that violated the bound, not a screenshot of the assertion text. If you cannot save that input, do not list the property.
Step 3: Replay against a clean tree
Run the sampled properties against the pinned epoch. Ignore whatever fixtures/ a laptop already warmed. A detached worktree is enough. A hosted runner is optional, and it is not the source of the pin.
MonkeyCode's free model access is one way to draft the patch this gate will judge. Disclosure: This article was prepared as part of MonkeyCode's product outreach. The free server option fits the replay step when you want a machine without a warm fixture cache. This note states no model name, quota, hardware shape, duration, or benchmark.
If either free option is down or unsuitable, run the same checker wherever the pinned files are present. Copy witnesses back to the review branch before you discard the runner. A remote disk is not the archive.
git worktree add --detach ../epoch-replay "$(git rev-parse HEAD)"
cd ../epoch-replay
git diff --name-only origin/main...HEAD > /tmp/agent-diff.txt
python3 tools/check_agent_patch.py \
--epoch fixtures/EPOCH \
--manifest checks/manifest.json \
--diff-list /tmp/agent-diff.txt
git worktree add --detach is ordinary Git. git diff --name-only A...B lists paths changed since the merge base, which is the review surface this gate cares about. The checker in the next step is proposed code. Execute it on your tree before you treat a verdict as evidence.
Step 4: Map mismatches to closed, hold, or eligible
The checker refuses three forgeries. A protected path inside the diff is closed. An epoch hash mismatch is closed. A freeze file with no observation, or with an observation from another epoch, is closed.
A property failure writes a witness and stays closed. A flake can become hold only after a rerun passes on the same epoch and the witness file is still present.
# Proposed gate. Unexecuted until you point it at a real diff.
import hashlib, json, pathlib
PROTECTED = {
"fixtures/EPOCH",
"fixtures/generate_orders.py",
"checks/manifest.json",
"tools/check_agent_patch.py",
}
def sha256(path: pathlib.Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
def manifest_ok(manifest: dict) -> bool:
listed = {"seed": manifest["seed"], "properties": manifest["properties"]}
raw = json.dumps(listed, sort_keys=True, separators=(",", ":")).encode()
return hashlib.sha256(raw).hexdigest() == manifest["manifest_sha256"]
def decide(epoch_path, manifest_path, diff_files, obs_dir, freeze_dir) -> str:
if PROTECTED & set(diff_files):
return "closed"
epoch = json.loads(pathlib.Path(epoch_path).read_text())
manifest = json.loads(pathlib.Path(manifest_path).read_text())
if not manifest_ok(manifest):
return "closed"
gen = pathlib.Path("fixtures/generate_orders.py")
if sha256(gen) != epoch["generator_sha256"]:
return "closed"
observations = [
json.loads(p.read_text())
for p in pathlib.Path(obs_dir).glob("*.json")
]
if any(item.get("status") == "fail" for item in observations):
return "closed"
if any(item.get("epoch_id") != epoch["epoch_id"] for item in observations):
return "closed"
for freeze_path in pathlib.Path(freeze_dir).glob("*.json"):
rec = json.loads(freeze_path.read_text())
match = [
item for item in observations
if item.get("id") == rec.get("observation_id")
]
if not match or match[0].get("epoch_id") != epoch["epoch_id"]:
return "closed"
if not match[0].get("rerun_passed") or not match[0].get("witness_sha256"):
return "closed"
return "hold"
return "eligible"
Read those strings literally. hold blocks the merge and preserves the witness. eligible only clears this identity contract. Human review can still reject the change.
Save a witness as bytes plus a status file. Do not save a prose explanation as the only artifact.
# Proposed witness writer. Call it from the property runner on failure or flake.
import hashlib, json, pathlib
def write_observation(obs_dir, obs_id, epoch_id, status, payload: bytes, rerun_passed: bool):
folder = pathlib.Path(obs_dir)
folder.mkdir(parents=True, exist_ok=True)
blob = folder / f"{obs_id}.bin"
blob.write_bytes(payload)
rec = {
"id": obs_id,
"epoch_id": epoch_id,
"status": status,
"rerun_passed": rerun_passed,
"witness_sha256": hashlib.sha256(payload).hexdigest(),
}
(folder / f"{obs_id}.json").write_text(json.dumps(rec, indent=2) + "\n")
return rec
Wire write_observation before decide. A missing .bin file with a lonely JSON status is the same class of gap as a freeze note without an id. The hash in the status record has to match the bytes you archived, or the observation is incomplete and the verdict stays closed.
Step 5: Key the freeze to an observation, then let it expire
A flake, in this workflow, is one failed attempt followed by a passing rerun on the same epoch and the same witness bytes. The freeze file may cite the observation id, the epoch id, and an expiry label. It may not cite a bare test name. Names survive refactors. Observation ids should not.
{
"observation_id": "obs-2026-09-25-014",
"epoch_id": "orders-2026-09-25-a",
"expires_on": "2026-10-02",
"reason": "single rerun passed on pinned epoch"
}
The seven-day gap is an example label, not an SLA and not a statement about any hosted runner. Choose an expiry your rotation will actually clear. When it passes, delete the freeze file, keep the witness, and treat the next review as a fresh run rather than a pass.
A short mismatch table
Use the table as the review cheat sheet. It is exhaustive for this contract, not for product correctness.
| Observed mismatch | Verdict | Why |
|---|---|---|
Generator bytes differ from fixtures/EPOCH
|
closed |
The replay is a different epoch |
| Manifest path or sampler appears in the diff | closed |
The oracle moved with the patch |
Property status is fail
|
closed |
A miss is not a freeze ticket |
| Freeze observation id is missing | closed |
A note without a witness is not evidence |
| Observation epoch differs from the pin | closed |
The flake was recorded on another fixture world |
| Rerun passed, witness hash present, epoch matches | hold |
A human may read it; merge stays blocked |
| No failures, no freeze, hashes agree | eligible |
Identity passed; product review remains |
Print the three identities in the job log so a reviewer can compare them without re-running a model. The epoch id, the manifest digest, and each witness digest are the only numbers this gate needs.
python3 - <<'PY'
import hashlib, pathlib
for rel in ("fixtures/EPOCH", "checks/manifest.json"):
data = pathlib.Path(rel).read_bytes()
print(rel, hashlib.sha256(data).hexdigest())
PY
What this does not prove, and who should skip it
The checker does not estimate how many defects the properties can find. It does not rank models. A patch can match every hash and still ship a wrong price rule if the manifest never named that rule. Add properties when you learn a new invariant, and do not weaken an existing predicate to clear a closed verdict.
Skip the workflow when there is no generator to pin, because an epoch file over hand-edited JSON is ceremony. Skip it when the only checks are screenshots with no saved input. Skip it when the people who approve the patch can also edit the manifest unchecked. Skip it when you need a fleet-level flake budget; this is a per-patch identity gate, not a reliability model.
Free draft access and a free replay machine do not change those limits. They can produce a diff and a clean process environment. They cannot author fixtures/EPOCH. If a runner is ephemeral, the witness copy on the review branch is the record that matters.
What to wire into review
Commit the epoch pin and the manifest before the agent branch opens. Fail the job on closed. Leave hold red for merge. Let eligible enter human review only after the log shows the same epoch id that fixtures/EPOCH still contains.
If those pins already live in git, the smallest next change is to reject any freeze whose epoch_id disagrees with fixtures/EPOCH. That comparison is the whole gate in miniature. Run it on a clean tree, keep the witness next to the diff, and do not treat a model draft as the oracle.
Top comments (0)