A flaky test is annoying when a person runs into it. It becomes a different kind of problem when an AI coding agent does.
A person recognises the shape of it: this test is probably flaky, I need to work out why. An agent working toward a task completion condition sees something else: the test is failing, make the suite green. Those two goals are not equivalent, and only one of them improves the codebase.
What is a flaky test?
A flaky test passes and fails intermittently without any relevant code change. The usual causes are well known and none of them are mysterious:
- Timing issues
- Race conditions
- Test ordering dependencies
- Shared mutable state between tests
- External dependencies that aren't mocked
- Poor synchronization
Every one of those is a real engineering problem with a real fix. The question is whether whatever encounters the failing test goes looking for that fix.
What an agent can do with a flaky test
Retry until green
The test still fails intermittently. The difference is that the failure may not happen on the run that determines the final status. The flakiness is hidden rather than resolved, and the hiding is now committed to the repository.
Weaken the assertion
The test is changed so that it checks less. The CI result turns green, and the test may no longer verify the behavior it was originally written to verify. Nothing in the build output records that trade.
Delete or skip the test
The suite goes green because the check no longer runs. It's also the kind of change that's easy to miss when reviewers are working through a large volume of generated diffs.
Green doesn't always mean verified
A passing test tells you the check passed. It doesn't tell you the behavior you care about was actually verified. Those are the same statement only when the check hasn't been quietly edited.
Why AI changes the risk
Flaky tests existed long before AI coding agents. The difference is the optimization target.
An agent is often given a task with an explicit success condition: make the tests pass. If it doesn't have enough context about why a test is unstable, it will optimize for the visible condition rather than the underlying engineering problem. That's not malice or even a bug — it's the condition being satisfied exactly as stated.
The result is subtle in a specific and unhelpful way: the check becomes easier to satisfy while the thing being checked becomes less reliable. Both movements are invisible in the build status, which is the one place anyone looks.
An agent optimizing to complete a task treats a flaky test as an obstacle to clear, not a signal to investigate.
What handling a flaky test correctly looks like
- Controlling time rather than waiting on it
- Mocking network calls
- Fixing the race condition
- Isolating shared state between tests
- Adding proper synchronization
- Fixing test ordering dependencies
- Fixing the unstable external dependency
And if an assertion genuinely does need to change — which happens, legitimately, whenever behavior changes — the reason should be visible in the diff. That's the whole distinction: not whether assertions ever change, but whether the change was a decision someone made or a side effect of getting to green.
The production risk connection
A test suite is one signal about a change. It isn't the entire risk picture, and treating it as one is how teams end up surprised by changes that passed everything.
A PR can pass its tests while changing a shared dependency, removing an important test, weakening verification, or crossing a high-impact system boundary. Each of those is invisible to a green checkmark.
Not “did CI turn green?” but “what did this change actually alter, and what does that put at risk?” The first is a status. The second is a decision.
This is the same accounting problem as verification debt: capacity to check doesn't scale at the same rate as capacity to generate, and the shortfall gets paid later with interest. It also shows up on the cost side, where a weakened test is cheap today and expensive in a quarter.
Frequently asked questions
What causes flaky tests?
Most commonly: timing and race conditions, test order dependency, shared mutable state between tests, and calls to external services that aren't properly mocked.
Is retrying a failed test in CI a real fix?
No. It hides the flakiness from your build status without addressing why the test is unstable in the first place. The test still fails intermittently — just not on the run that decides the final status.
Should you just delete a flaky test?
Not silently. If a test genuinely no longer covers something meaningful, that's a decision worth making explicitly and visibly, not a side effect of getting CI green again.
Is this specific to AI-generated code?
Flaky tests predate AI by decades. What's different is the incentive. An agent optimizing to complete a task treats a flaky test as an obstacle to clear, not a signal to investigate, the way a person usually would.
How do you tell a legitimate assertion change from a weakened one?
By whether the reason is visible in the diff. Assertions do legitimately need to change when behavior changes. The difference is whether the change is explained and reviewed, or whether it arrived as a side effect of making the suite go green.
A retry wrapper or a quietly loosened assertion is exactly the kind of small, easy-to-miss change Tomosu checks for at the merge gate, before it becomes debt nobody remembers taking on. Book a call →