Scenario: illustrative. The timings and file counts below are invented to make the argument, not measured. No code here was executed.
An agent opens a patch at 02:14. CI returns green after a single run. The diff touches 14 files, and three of them live under tests/fixtures. Two suites in this repo are known to flake.
The reviewer sees green and approves. That approval carries almost no information, because the suite never had a real chance to say no.
Most teams fix this by adding gates. That is the wrong lever. What a green run means depends on the order you run things in, not on how many boxes you tick. A statistical check placed first will happily absorb the failure a deterministic check would have caught in two seconds.
Three gates, cheapest first
Start with anything that is deterministic and fast. Then move to structure. Then, last, move to anything that depends on repetition.
Gate one asks: did the patch move the ground the tests stand on? Gate two asks: would these properties notice a wrong answer? Gate three asks: was this suite even stable enough to vote? Each gate answers a different question, and a later gate cannot rescue an earlier one.
Gate one: fingerprint the fixtures, not the assertions
Assertions live in the diff, so reviewers read them. Fixtures usually do not get read. Hash them instead, and compare against the base commit.
# Illustrative. Requires git and sha256sum. BASE=$(git merge-base origin/main HEAD) git ls-tree -r "$BASE" -- tests/fixtures | awk '{print $3, $4}' > /tmp/fx.base git ls-tree -r HEAD -- tests/fixtures | awk '{print $3, $4}' > /tmp/fx.head diff /tmp/fx.base /tmp/fx.head && echo "FIXTURES: unchanged" \ || echo "FIXTURES: changed - gate one blocks" A hash mismatch is not proof of cheating. It is proof that the pass condition changed, which is enough to stop the line. Print the blob hashes next to the review link so a human can see exactly what moved.
Gate two: a property that never fails is decoration
A property test is only worth its runtime if it can fail. Prove that by running each property against a deliberately broken variant of the function under test. If the property survives the mutant, the property is worthless.
# Illustrative, unexecuted. pytest + hypothesis. from hypothesis import given, strategies as st from shop.cart import merge_lines MUTANTS = { "drops_last_line": lambda xs: merge_lines(xs)[:-1], "doubles_total": lambda xs: [dict(l, qty=l["qty"] * 2) for l in merge_lines(xs)], } @given(st.lists(st.fixed_dictionaries({"sku": st.text(min_size=1), "qty": st.integers(1, 9)}))) def test_merge_preserves_total_quantity(lines): assert sum(l["qty"] for l in merge_lines(lines)) == sum(l["qty"] for l in lines) # The gate: every mutant must break at least one property. def test_properties_are_not_decorative(): killed = {name: False for name in MUTANTS} for name, broken in MUTANTS.items(): try: test_merge_preserves_total_quantity() # substitute mutant inside except AssertionError: killed[name] = True assert all(killed.values()), f"surviving mutants: {killed}" The mutant wiring above is sketched, not finished. Treat it as a shape to implement, and check it by temporarily deleting the assertion: the gate must then fail loudly.
Gate three: freeze flaky tests with an expiry date
Freezing is standard. Freezing forever is how teams lose a suite. Put each quarantine in a file, owned, dated, and self-expiring.
{ "quarantine": [ {"id": "tests/e2e/test_checkout.py::test_retry", "owner": "payments", "reason": "shared clock in fixture", "frozen": "2026-11-10", "expires": "2026-12-10"} ] } The gate refuses to count frozen tests as evidence. It also fails outright when an entry passes its expires date. Two states, no silent drift.
Composing the verdict
Run the three gates in fixed order and emit a machine-readable reason code. One reviewer, one code, one next action.
| Code | Trigger | Action |
|---|---|---|
BLOCKED_FIXTURE | blob hash mismatch | re-read the pass condition |
BLOCKED_PROPERTY | surviving mutant | fix the property, not the patch |
BLOCKED_UNKNOWN | frozen tests exceed budget or expire | un-freeze or replace |
PASS_WITH_DEBT | all gates clean, quarantine within budget | merge, debt logged |
PASS | all gates clean, no quarantine | merge |
The ordering matters because each code is a cheaper stop than the next. A fixture mismatch costs seconds and kills the run before an hour of flaky reruns can muddy it.
Where a hosted model and server help
Two of these gates want disposable compute. The mutant pass wants a throwaway environment per patch. The failure-classification step wants a second opinion on whether a red run is real or noise.
This is where MonkeyCode is relevant. The project offers free model access and a free server option, so a mutant pass and a fresh reproduction can run somewhere other than a reviewer's laptop. I have not measured that setup, so treat the fit as a proposal rather than a result. Quota and capacity details change; check the project's own page before you plan a pipeline around them.
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
Keep the free tier for exactly this: short-lived, non-sensitive, per-patch jobs. Model access helps classify failures; the server option removes the "works on my machine" objection from the reproduction step.
Who should skip this
If your suites are already non-deterministic, fix that first. These gates assume a test can be trusted when it runs once and passes. If your fixtures are generated at runtime, hashing them is noise; fingerprint the generator input instead.
Also skip the hosted step for code you cannot send off-box. The ordering argument still holds locally, and the first two gates cost nothing but time.
How to check the gate actually works
Do not trust a gate you have never seen fail. Inject three bad patches, one per gate, and confirm each produces its own code. Then break the gate script itself and confirm the pipeline reports an error rather than a pass.
A green build is a claim. Gate order decides whether the claim is worth reading. If you want to try the mutant pass on shared hardware before committing, the free server option is a low-cost place to start.
