4.2 KiB
Quarantine Process
Poka-yoke principle: a flaky or broken test must never silently rot in place. Quarantine is the correction step in the Prevention → Detection → Correction triad described in issue #1094.
When to quarantine
Quarantine a test when any of the following are true:
| Signal | Source |
|---|---|
flake_detector.py flags the test at < 95 % consistency |
Automated |
| The test fails intermittently in CI over two consecutive runs | Manual observation |
| The test depends on infrastructure that is temporarily unavailable | Manual observation |
| You are fixing a bug and need to defer a related test | Developer judgement |
Do not use quarantine as a way to ignore tests indefinitely. The quarantine directory is a 30-day time-box — see the escalation rule below.
Step-by-step workflow
1 File an issue
Open a Gitea issue with the title prefix [FLAKY] or [BROKEN]:
[FLAKY] test_foo_bar non-deterministically fails with assertion error
Note the issue number — you will need it in the next step.
2 Move the test file
Move (or copy) the test from tests/ into tests/quarantine/.
git mv tests/test_my_thing.py tests/quarantine/test_my_thing.py
If only individual test functions are flaky, extract them into a new file in
tests/quarantine/ rather than moving the whole module.
3 Annotate the test
Add the @pytest.mark.quarantine marker with the issue reference:
import pytest
@pytest.mark.quarantine(reason="Flaky until #NNN is resolved")
def test_my_thing():
...
This satisfies the poka-yoke skip-enforcement rule: the test is allowed to skip/be excluded because it is explicitly linked to a tracking issue.
4 Verify CI still passes
pytest # default run — quarantine tests are excluded
pytest --run-quarantine # optional: run quarantined tests explicitly
The main CI run must be green before merging.
5 Add to .test-history.json exclusions (optional)
If the flake detector is tracking the test, add it to the quarantine_list in
.test-history.json so it is excluded from the consistency report:
{
"quarantine_list": [
"tests/quarantine/test_my_thing.py::test_my_thing"
]
}
Escalation rule
If a quarantined test's tracking issue has had no activity for 30 days, the next developer to touch that file must:
- Attempt to fix and un-quarantine the test, or
- Delete the test and close the issue with a comment explaining why, or
- Leave a comment on the issue explaining the blocker and reset the 30-day clock explicitly.
A test may not stay in quarantine indefinitely without active attention.
Un-quarantining a test
When the underlying issue is resolved:
- Remove
@pytest.mark.quarantinefrom the test. - Move the file back from
tests/quarantine/totests/. - Run the full suite to confirm it passes consistently (at least 3 local runs).
- Close the tracking issue.
- Remove any entries from
.test-history.json'squarantine_list.
Flake detector integration
The flake detector (scripts/flake_detector.py) is run after every CI test
execution. It reads .test-report.json (produced by pytest --json-report)
and updates .test-history.json.
CI integration example (shell script or CI step):
pytest --json-report --json-report-file=.test-report.json
python scripts/flake_detector.py
If the flake detector exits non-zero, the CI step fails and the output lists the offending tests with their consistency percentages.
Local usage:
# After running tests with JSON report:
python scripts/flake_detector.py
# Just view current statistics without ingesting a new report:
python scripts/flake_detector.py --no-update
# Lower threshold for local dev:
python scripts/flake_detector.py --threshold 0.90
Summary
Test fails intermittently
│
▼
File [FLAKY] issue
│
▼
git mv test → tests/quarantine/
│
▼
Add @pytest.mark.quarantine(reason="#NNN")
│
▼
Main CI green ✓
│
▼
Fix the root cause (within 30 days)
│
▼
git mv back → tests/
Remove quarantine marker
Close issue ✓