Skip to content
fx-blog

When a Test Goes Red: Triage, the Heal Guard and Quarantine

The cheapest fix for a red AI test is to hide it. On checkout a red test is labelled, not fixed: four triage labels, a heal guard that diffs every fix, quarantine that expires in 30 days, and a defect that closes only on a newer passing run.

Harry4 min readIntermediate
  • Judgment
  • Verification
MarkdownSave

Key takeaways

  • A run never fixes anything: each failure gets one of four labels, FUNCTIONAL, SCRIPT, SETUP/ENV or FLAKY, with its evidence.
  • FLAKY needs an observed passing re-run; a hunch does not count.
  • npm run qa:heal-guard blocks a fix that removes, weakens or suppresses an assertion; a changed expected value passes only if the case says so or a named human approves.
  • A quarantined test still runs and still reports its real status, for at most 30 days.
  • A defect closes as fixed only after a newer verification run in which its case passed, and a recurrence re-opens the same file.
Contents

TL;DR When an AI agent's test goes red, the cheapest fix is to hide it, and a green run made by editing the test tells everyone the feature works. AI test failure triage in stlc removes that option. Only here: a fix must pass npm run qa:heal-guard, which diffs it against the base and blocks a removed or weakened assertion, a skip or a retry, and writes its verdict to reports/heal-guard/.

Do this: Before you fix your next red test, label it FUNCTIONAL, SCRIPT, SETUP/ENV or FLAKY, and write down the evidence for that label.

Part 2 ended with ten scripts for orders checkout. The first uat run came back red: TC-INT-ORDERS-001 expected a tax_total of 4.20 and got null. At 2 a.m. the agent has three cheap options: loosen the assertion so null passes, add a retry, or skip the test. Any of them turns the run green and hides what is wrong.

This series, in four parts:

  1. A QA Pipeline Your AI Agent Can't Fake
  2. Your First stlc Run: Checkout From Docs to Scripts
  3. When a Test Goes Red: Triage, the Heal Guard and Quarantine (you are here)
  4. The QA Board and the Release Gate

A red test gets a label, not a fix

/qa-run never edits a test or the product. It writes each failure to failures.md with the evidence and exactly one label:

Label Means
FUNCTIONAL the product is wrong
SCRIPT the test is wrong
SETUP/ENV data, fixture or environment
FLAKY an identical immediate re-run passed

Checkout's failure was SETUP/ENV: the uat seed predates the tax migration. The product was fine, and loosening the assertion would have buried that. The other red test, TC-E2E-ORDERS-001, is FUNCTIONAL. The new order never appears in the list, so it goes to /qa-defect as DEF-orders-001.

FLAKY needs a re-run someone saw pass. I hold that line even for CI: a retry there is recorded as retried-in-ci, never FLAKY, because nobody ran the one immediate, unchanged re-run the label means.

The latest run on the stlc board: a sample orders run at 67 % with one failure classified SETUP-ENV, the expected and actual values, and the command that class leads to

The heal guard: what a fix may not do

For a SCRIPT failure, /qa-heal repairs the test, and npm run qa:heal-guard checks the diff against the base. /qa-heal and /qa-flaky are not done until it exits 0. You can run it yourself on any diff.

The heal guard on a SCRIPT fix: a removed or weakened assertion, or a skip, retry or wait, is blocked; a changed expected value passes only if the case says so

  • removed, weakened and suppressed (skip, only, retries:, toPass()) changes are blocked, always;
  • a changed expected value passes only if every new value is already in the case, or a named person approves it with --human "<quote>".

So changing 4.20 to null, the move an agent reaches for first, is blocked, and the verdict lands in reports/heal-guard/ either way. The guard's own tests try 20 ways to fake a green heal, and each one must be blocked.

Flaky tests are quarantined in the open

TC-E2E-ORDERS-002, the order list filter, fails on CI when the filter chips render late. A re-run passes, so the case is quarantined in the ledger (shortened here: the real one also has Evidence and Released columns):

textregression/quarantine.md
| Case ID           | Since      | Until      | Reason                                  | Ticket   |
| TC-E2E-ORDERS-002 | 2026-10-05 | 2026-10-30 | filter chips render late on CI (timing) | TASK-201 |

The grant lasts at most 30 days, lint fails once it expires unreleased, and the case still runs and reports its true status. Checkout's second quarantine, TC-API-ORDERS-002, ran out on 2026-10-10 without a release. Lint flags it.

A defect closes on evidence

The rounding bug from part 1 has a file now: /qa-escape opened DEF-orders-002 with Origin: ESCAPED. Its escape analysis names the phase that missed it and the type that should have caught it (in this example, DESIGN and unit).

DEF-orders-002, the escaped rounding bug: opened by /qa-escape with backfill cases, closed as fixed only after a newer passing verification run, re-opened on recurrence

  1. Backfill: design adds a unit case for a three-line order.
  2. Verify: /qa-defect orders --verify looks for a run newer than every recurrence in which that case passed.
  3. Close: only then does the file get Resolution: fixed (verified <run-id>).

Nobody gets to call it fixed on their word. A repeat failure re-opens the same file.

Try it

textPaste into your AI
Here is a failing Playwright test and its error. Before changing anything, label the failure FUNCTIONAL, SCRIPT, SETUP/ENV or FLAKY, and show the evidence for the label. If it is SCRIPT, propose a fix that keeps every assertion at least as strict as before, and say which line a heal guard would block if you loosened it.

Checkout now has two red tests with known causes, two quarantines (one expired) and two open defects, all in files and none easy to see at a glance. May checkout ship? Part 4, The QA Board and the Release Gate, opens the board on this exact state.

Read this with your AI

textPaste into your AI
Read the post "When a Test Goes Red: Triage, the Heal Guard and Quarantine".
1. Summarise it in 5 bullets for a QA engineer.
2. Ask me 3 questions to check I understood; wait, then correct me.
3. Look at my last three test fixes and say which ones a heal guard would have blocked.

FAQ

Can the agent just add a retry to make a flaky test pass?

No. Retries, timeouts, waits, skips and toPass() are suppressed changes the heal guard never allows. A flaky case goes to quarantine in the open, with an expiry date of at most 30 days, and keeps running.

What happens when a fixed bug comes back?

The same defect is re-opened with a recurrence line, never duplicated. It can close again only after a newer verification run in which its case passed.

Sources

  1. stlc CONTRACTS.md: triage, quarantine, defects, heal guard

Was this useful?

Only you and the owner see your answer and rating. Send private feedback

Enjoyed it? Support fx-blog with a coffee.

The QA Board and the Release Gate

"May it ship?" should not be answered in a chat. The stlc board on orders checkout, and a QA release gate: a report verdict derived from its gate rows, rejected by lint if it disagrees, which the dev deploy step reads before checkout ships.

4 min readAdvanced

A QA Pipeline Your AI Agent Can't Fake

Forty green AI-written tests shipped a bug and nobody could say what they proved. Five questions to ask any AI test pipeline, and the route stlc takes from docs to a verdict, where a feature's state is computed from the files each step wrote.

4 min readBeginner

Comments

Oldest first

No comments yet. Start the conversation.

You sign in first; what you typed stays here. · 0 / 2,000