Problems that stay once the UI suites stop flaking

Suppose every module team fixes its flaky tests and the per-pipeline flake rate falls close to zero. This page works through what the pipeline still does to the release, using the same topology as the overview: about 100 build pipelines, a fan-in, a fan-out that runs only when a person triggers it, and about 100 chained UI pipelines that all have to pass for one candidate.

Genuine defects in a large batch

With the flake rate at zero, the formula on the overview stops being the limit, and a second one takes its place. If each commit has a chance q of breaking some UI suite, a candidate built from B commits is clean with probability (1 − q)B. The time between manual fan-outs sets B, because every commit made by any team since the last fan-out goes into the next one, and that time is never shorter than the two-hour run. The figures below are illustrative, since the study has no measured value for q or for the commits per run.

On time fan-out fan-out candidate of 8 commits Late fan-out fan-out candidate of 20 commits 0h 1h 2h 3h 4h 5h 6h
An illustrative steady rate of four commits an hour. A fan-out started two hours after the previous one carries 8 commits, and one started five hours after carries 20. At q = 1%, the chance of a defect in the candidate rises from about 8% to about 18%, and the red dot marks one such defect.
Commits per candidateClean candidate, q = 1%Clean candidate, q = 2%
1090.4%81.7%
2081.8%66.8%
5060.5%36.4%

A red result from a genuine defect is the gate doing its job, so the question becomes how long the defect keeps the candidate red. The answer depends on run length and on how fast someone can find and fix the commit, and both stay as they are when flakiness goes away.

One real defect costs a run, a diagnosis and a wait for the fan-out

Runs Team Run 1: red defect lands W1 waiting fan-out started by hand Wave 2: green diagnose fix at 3h 0h 2h 4h 6h
A defect that lands at the start of run 1 is reported two hours later. The fix committed at three hours passes wave 1 on its own, then waits for someone to start the fan-out, so the first green candidate comes after two runs, a diagnosis and that wait, with no flaky failure involved. The split between wave 1, the wait and wave 2 is schematic.

The timeline is the best case, where the failing suite points straight at the cause, the fix is right first time and the wait for the fan-out is short. Whoever starts the fan-out while the fix is still being written can start it at once, which gives the other teams' commits a run that goes red again on the known defect, or wait for the fix, which leaves those commits untested for the length of the diagnosis. Two defects landing in different modules on the same day can use up most of the five runs a day holds. Each red run also holds back every other team's commits from that run, which grows the batch for the run after the fix and raises the chance that it carries a new defect of its own.

The timeline covers a defect in product code, whose fix has to go through wave 1 and then wait for the next fan-out. When the defect is in a test, the fix is a commit to that module's part of the system test code. Because the suites are modular, the commit reruns that module's UI pipeline and the chain below it straight away against the same product revisions, and the other UI pipelines keep their results, so a test defect costs one chain run after the diagnosis and no wait for a person.

Finding the commit behind a red UI suite

A UI suite reports which screen or journey broke. It does not report which of the 100 units changed the behaviour, and a candidate that bundles commits from many repositories offers several suspects for each failure. When a microservice change breaks the order journey, the orders team sees the red suite first and has to trace it to a service it does not own, then find the owning team and wait for that team's fix. The time spent on this trace sits inside the diagnose bar in the timeline above, and on a cross-team failure it can be longer than a whole run.

svc-billing commit ui-orders commit platform commit svc-users commit ui-search commit Candidate commits from many repositories ui-orders suite: red order journey broke Orders team sees it first trace back to the billing team's change
The red suite names the order journey and the orders team. The commit behind it belongs to the billing team, and the dashed path is the trace someone has to work out by reading every change in the candidate.

Some failures only appear when two changes meet, such as a frontend module and a service that were each fine against the previous version of the other. Neither team's own pipeline in the first wave catches these, and reverting either commit alone may or may not turn the suite green, which makes bisecting by hand slow.

Chains hide what is wrong further down

A genuine failure in a UI pipeline near the top of a chain stops the pipelines below it from running on that revision. Any defect in a downstream module stays hidden until the upstream fix passes, and it then appears one run later as a fresh red result. Two independent defects in one chain therefore cost two sequential fix cycles, where a flat second wave would have reported both in the same run and let both teams fix them in parallel.

upstream downstream Run N ui-onboarding: red ui-orders: not run ui-search: not run Run N+1 ui-onboarding: green ui-orders: green ui-search: red Run N+2 ui-onboarding: green ui-orders: green ui-search: green defect 2 is here, unseen
Two independent defects in one chain, one in ui-onboarding and one in ui-search. Run N reports only the first because the pipelines below never start, run N+1 reports the second, and the chain is green in run N+2. A second wave without the chain would have reported both defects in run N.

System test commits can turn the gate red by themselves

A commit to one module's system tests triggers that module's UI pipeline and the chain below it directly, without waiting for the manual fan-out, so the test code takes part in the gate on the same terms as product code and can break a candidate with no product change at all. These runs use the product revisions from the last fan-out. When a team updates a UI test for a new feature, the test commit runs straight away against a product that does not have the feature yet, and the suite stays red until someone starts a fan-out that carries the feature. Nothing in the pipeline ties a test revision to the product revision it was written against, so the team has to hold back its test commit until the feature has been fanned out, or accept a red suite in the meantime.

Product Tests UI suite Fan-out: P1 Feature commit P2passed wave 1, waiting Next fan-out: P2started by a person Test commit T2written for the feature triggers at once T2 against P1: redfeature not there yet last product uses the T2 against P2: greenafter the fan-out
The test commit for a feature reaches the UI suite before the feature does. The suite runs it against P1, the product revision from the last fan-out, and stays red until someone starts the fan-out that carries P2.

Environment failures without a flaky test

A test can be deterministic and still fail when the environment under it is unhealthy. A deployment that fails partway, a service that is restarting, a database that another UI pipeline has just modified, or a downstream system that is down all produce a red suite. While flaky tests are common, these failures get filed with them, and once the tests are fixed they become the main source of red results that no code change explains. They need their own classification in the failure reports, owned by whoever owns the environment and not by the module team whose suite happened to be running.

deploy failed partway service restarting shared data changed downstream system down test code unchanged UI suite: red today needed Filed as a flaky testmodule team chases it Environment failureenvironment owner fixes it
The suite goes red with its test code unchanged, because something under it failed. Filing the result as a flaky test sends the module team after a test that has nothing wrong with it, while a separate class for environment failures sends it to the people who can fix the cause.

Tests that were commented out stay out

Fixing the flaky tests that are still running does nothing for the ones that were commented out along the way. Their coverage has been missing for as long as they have been out, and no pipeline result shows it. Getting the flake rate down can therefore leave the gate passing more often while checking less than it did before the teams started. Before the flakiness work is called done, each module team needs to find its commented-out tests in the system test code and decide, one test at a time, whether to restore it, rewrite it lower in the pyramid, or delete it with a note on what it covered.

Before: 30 tests run, 5 of them flaky, so the suite is often red After: 25 tests run and pass, 5 commented out with no result and no record passes flaky commented out
An illustrative suite of 30 tests. Once the 5 flaky tests are commented out the suite goes green far more often, and the 5 behaviours they covered have no check and leave no trace in the pipeline results.

Run length and pipeline capacity

The two-hour run is set by the longest chain of UI suites plus the first wave and the deploy, and flakiness has no part in it. Five runs a day stays the ceiling on candidates and on fix attempts, and the manual fan-out keeps the real number below it, because each run waits for a person to start it. The study has no record of why the fan-out is manual. If the reason is agent or environment capacity, affected builds and test tiers reduce the load that an automatic fan-out would add. A change to the shared platform folder still rebuilds and retests every module, and each system test commit starts another run of its own suite and the chain below it, so the queue for agents and test environments is set by commit volume across the whole programme. Run length goes up as teams add tests, because no step in the current setup removes a UI test when a lower-level test starts to cover the same behaviour.

On time By hand run 1 run 2 run 3 run 4 run 5 run 1 run 2 run 3 waiting waiting waiting 0h 2h 4h 6h 8h 10h
A ten-hour working day. When each fan-out starts as soon as the previous run ends the day holds five runs, and in this example the waits for someone to start it leave room for three, with the last gap too short for another run.

Flakiness returning

New UI tests are written every week, and some of them will be flaky. Without a measured flake rate per test and a rule for what happens when a test crosses it, the rate drifts back up, and the module teams are again judging each new flake on its own. The fix work described in this study holds only if the flake rate is tracked as a pipeline measure and published per suite.

Which practice addresses each remaining problem

Remaining problemPractice
Manual fan-outStart the fan-out automatically once wave 1 is green, with affected builds and test tiers keeping the load in bounds
Large batches of commits per candidateMerge queue, affected builds
One defect blocks the whole release for several runsRelease assembly from verified versions, release branch
Slow tracing of a red suite to a commit and an ownerBuild ownership and build cop
Chains hiding downstream defectsRelease assembly, plus flattening chains that encode no real dependency
Test commits out of step with product commitsRecord the system test revision in the release manifest next to the product revisions, as an extension of release assembly
Environment failuresRemoving the causes of UI flakiness, for environment isolation and test data
Commented-out testsQuarantine, test pyramid
Run length and capacityTest tiers, test pyramid, affected builds
Flakiness returningQuarantine, build ownership