Development

Splitting a Smoke Suite by Blast Radius: Read-Only, Writes, Money

Antonio Evans11 min read

A three-lane control panel drawn from above.
Key points

Key points

  1. 1Tag every smoke check as read-only, write, or money, and run the tiers in that order so a cheap failure cannot hide an expensive one.
  2. 2Read-only checks never change state, so they can run on every commit and finish in seconds to a minute.
  3. 3Write checks create or change data or config, so a failure must block the deploy and leave an inspectable artifact behind.
  4. 4Money checks touch billing, payments or quotas, so a failure blocks the deploy and pages a human, because a retry can double-charge.

Why failure cost, not test speed, is the right axis

Most smoke suites are organized by speed. The fastest checks run first, the slower ones after, and everything that fits in a fixed time budget gets called "smoke." That works until a single failure forces a judgment call nobody has pre-agreed on: is a red build worth waking someone at 3 a.m.? Teams answer that question differently at different hours, which is how a broken checkout page ships on a Friday evening.

The better axis is blast radius, meaning what a failure costs if it is real and what it costs if it is a false alarm. A smoke suite exists to answer one question, whether a build is worth testing further, and it stops the pipeline before deeper suites waste time on something fundamentally broken the QA Wolf smoke testing guide. That gate is only useful if everyone agrees in advance what each failure triggers.

Trunk-based development makes this urgent. When developers commit to a shared branch many times a day, every commit triggers the pipeline, and the team is expected to jump on any failure quickly to keep the trunk deployable the JetBrains trunk-based development guide. You cannot ask an entire team to drop everything for a health endpoint blip and also ask them to treat a billing failure casually. Different failures need different responses, so the suite needs to encode the difference.

There is also a cost argument. Detecting a problem in smoke testing takes minutes; finding the same problem after a full regression suite takes hours or days, and the cost of repair rises as more commits stack up behind a break the Momentic smoke testing guide. Ordering by blast radius keeps the cheap, fast checks in front so the expensive checks only run against a build that has already proven it can boot, authenticate and reach its dependencies.

Defining the three tiers precisely

The tiers are defined by what a check touches, not by how important the feature feels. A login test is read-only if it verifies the login page renders and the session cookie is issued against a dedicated account. It becomes a write the moment it stores a new user or mutates a profile record.

TierTouchesTypical examplesOn failureRun where
Read-onlyNo state at all; GET requests, health endpoints, static pagesHealth and readiness endpoints, database connectivity, home page status, auth page render, dependency reachabilityMark the build red; rerun once; keep the deploy paused until greenEvery commit, plus a scheduled probe
WriteCreates or changes data or config; POST, PUT, PATCH, DELETE, migrations, flagsSignup with a throwaway account, CRUD on a test project, feature flag toggle, schema migration smoke, queue publish and consumeBlock the deploy; attach the request log and the record ID for cleanupEvery commit or every merge, depending on runtime
MoneyBilling, payments, quotas, subscriptions, credit consumptionTest-mode checkout with a known test card, invoice line generation, quota increment and reset, refund path, webhook replay from the payment providerBlock the deploy and page the on-call human; freeze further deploys to the billing surfacePre-deploy on the release candidate, plus a scheduled run

The read-only boundary is stricter than most teams assume. A production smoke suite must never create permanent data, modify user accounts, trigger billing events or send real notifications, and every check should be read-only or use dedicated smoke accounts with sandboxed permissions the QASkills production smoke suite skill. A test that accidentally charges a customer is worse than having no smoke tests at all. Write the rule into the tier definition and enforce it in review, because the temptation to "just add a quick order test" never goes away.

The money tier deserves its own boundary too. It is not "anything important." It is specifically anything that moves money, changes a quota that gates usage, or emits an invoice or receipt. A quota check belongs here even if no card is charged, because an off-by-one on a quota limit either denies paying customers or gives away product, and both have a dollar figure attached.

Ordering rules so a cheap failure never masks an expensive one

The core ordering rule is simple: run read-only first, write second, money last, and stop at the first failing tier. But stopping at the first failure is exactly how a read-only failure masks a money failure, so you need two refinements.

First, fail fast on read-only but do not fail silently on the tiers behind it. When the read-only tier fails, do not run write and money checks against the same broken build, because their results will be noise. Instead, mark the skipped tiers as "blocked by tier 1" in the report rather than "passed." A skipped test that reports as green is how a broken billing probe reaches production with a clean dashboard.

Second, make the tier order a pipeline dependency, not a convention. In GitHub Actions, jobs run in parallel unless one job declares that it needs another, in which case it waits for the dependency to finish before it starts the freeCodeCamp GitHub Actions guide. Use needs so the write tier cannot start until read-only is green, and the money tier cannot start until write is green the GitHub Actions workflow syntax reference. That single declaration turns ordering from a habit into an enforced rule.

The third rule: if the read-only tier fails, still run a tiny, separate money probe on a schedule. A read-only outage suggests the app is down, but it does not prove billing is fine, and the money surface has its own dependencies (the payment provider, webhook receivers, ledger jobs) that can break while the web tier is healthy. A scheduled money probe catches that divergence without ever running money checks against a broken build on the commit path.

The fourth rule covers retries. Retry read-only failures automatically, because transient latency and CDN caching are normal, and the smoke suite should tolerate minor variation with generous timeouts and assertions on ranges rather than exact strings the QASkills production smoke suite skill. Never retry a money check automatically without idempotency keys. A retried charge is a second charge unless the payment API deduplicates on a key you supply, and that is the single most expensive mistake a smoke suite can make.

jobs:
  read-only:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Health, reachability, render checks
        run: npm run smoke:readonly
  writes:
    needs: [read-only]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Create and clean up sandbox records
        run: npm run smoke:writes
  money:
    needs: [writes]
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Test-mode checkout, quota move, invoice lines
        run: npm run smoke:money
        env:
          IDEMPOTENCY_KEY: ${{ github.sha }}-smoke

Notice the if on the money job. Running money checks on every pull request invites rate limits, test-data exhaustion and flaky failures that train the team to ignore pages. Run them on the release candidate and on a schedule.

Which tier blocks the deploy and which pages a human

A deploy gate and a page are different controls, and conflating them is where most of the pain lives. A blocked deploy is a state decision: the artifact does not move forward. A page is a human decision: someone must look now.

Quality gates in CI are typically enforced by exit codes. A test command returns zero when everything passes and a non-zero status when anything fails, and the pipeline turns that status into a required check that must pass before a merge or promotion the Momentic CI/CD pipeline testing guide. That mechanism can block a deploy, but it cannot make a human wake up.

FailureDeploy outcomeWho respondsSLA for first responseEscalation
Read-only failsDeploy paused, commit flaggedAuthor of the commitSame working day, or next business morning if it lands overnightTech lead if trunk stays red past an agreed window
Write failsDeploy blocked, promotion stoppedAuthor plus owning teamWithin the deploy windowRollback if the change already reached a shared environment
Money failsDeploy blocked, further deploys to the billing surface frozenOn-call engineer, plus finance or billing ownerImmediately, any hourIncident commander, provider status page check, customer comms if charges are affected

Two hidden rules make this work in practice. The first is that a money failure freezes the surface even if the failing change is unrelated. If the billing smoke is red, nobody ships anything that touches pricing, plans or quotas until it is green, because the failure might be caused by an earlier unflagged change and a second change removes your ability to bisect. The same logic drives rollback decisions: you cannot roll back one change in isolation, all changes roll back or none do the Octopus rollback strategies guide. A freeze protects that option.

The second is that a rollback path should trigger on pipeline failure, not on someone noticing. Pipeline tooling supports failure strategies that roll back the whole pipeline when a stage or step fails, configured by failure type the Harness pipeline rollback documentation. Wiring your money tier into a rollback strategy is the difference between a gate and a report.

There is a subtlety about what a smoke pass means. A passing smoke run does not mean the build is correct; it means the build is testable the Minitap automated smoke testing guide. Keep the tier definitions honest: a read-only pass says nothing about whether a write works, and a write pass says nothing about whether a charge settles. Each tier's green light carries a narrow claim.

A worked example: scoring a checkout service in numbers

Take a checkout service with a 40-check smoke suite. The team currently runs all 40 on every commit, the suite takes 14 minutes wall clock, and the on-call rota ignores smoke alerts because roughly a third of them are transient failures on the payment provider sandbox.

Tag the checks by tier. Suppose 22 are read-only, 14 are writes, and 4 are money. Move the money checks off the commit path and onto the release candidate and a 15-minute schedule. The commit-path suite drops to 36 checks, and because the read-only tier runs first and fails fast, the median commit spends about 40 seconds in smoke on a healthy build and stops there when the app is down.

Now attach costs. Say a transient money-check failure wakes an engineer for a mean of 20 minutes at an on-call rate that works out to about 60 dollars for the interruption once you include context switching. If the current setup produces about 30 false money alerts a month, that is roughly 600 dollars a month in pure noise, plus the harder-to-count cost of the team learning to ignore the alert. Moving money checks to the release candidate does not just save the money; it restores the signal, because a money alert now arrives rarely enough to be believed.

The blocking side is asymmetric on purpose. Read-only failures cost a rerun; write failures cost a blocked merge; money failures can cost a customer refund and a finance reconciliation. Tiering by blast radius means the routine cost stays routine and the expensive failure keeps its alarm.

If the team wants one place to route model-backed probes, for example an LLM-judged check that a generated invoice description is sane before it reaches a customer, a single OpenAI-compatible endpoint for text models removes the need to wire several SDKs into CI (Quanta Inference, https://quantaintelligence.ai/inference). Keep that kind of probe in the money tier, since it inspects billing output.

Tagging and maintaining the suite without rot

The suite stays honest only if tags are enforced mechanically. Pick one convention and check it in CI:

  1. Put the tier in the test name or a metadata annotation, for example smoke:money:invoice-lines-generate.
  2. Add a lint step that fails the build if any smoke test lacks a tier tag, so new tests cannot land untiered.
  3. Add a second lint step that fails if a read-only check issues a non-GET request to the target service (mock servers excepted).
  4. Require every write check to register its cleanup, and fail the run if cleanup did not complete.

That last rule matters more than it sounds. Write checks that leave records behind slowly poison the sandbox until a "passing" test fails on a duplicate constraint, and the team blames the code. Teach maintenance as part of development: when a feature changes, update its smoke test rather than deleting it, because neglected suites produce flaky tests that fail for the wrong reasons the QA Wolf smoke testing guide.

Keep the suite small. A typical smoke suite holds 20 to 50 test cases and finishes in 5 to 15 minutes, and a failure rejects the build before regression begins the TestMu AI smoke testing guide. Tiering helps keep it there: when a check takes too long, first ask whether it belongs in smoke at all, then ask which tier it really is. Many "money" checks are actually read-only assertions about pricing pages that never needed a charge.

If a coding agent is generating or updating these checks, a ready-made skill can install the production smoke pattern directly into the agent rather than re-prompting it every session (Quanta Skills, https://quantaintelligence.ai/skills). Give the agent the tier rules as context, and it will tag and order new checks consistently.

Talking to the billing team before you gate on money

The money tier is the one that crosses an organizational boundary, and it fails politically more often than technically. Before you gate deploys on a billing check, agree four things with the people who own the money surface.

First, which environment. Money checks should run against the payment provider's test mode or a sandboxed ledger, never against live cards, and never against live quota counters that affect customer accounts. Second, the idempotency story. Every money mutation needs a key derived from something stable, usually the commit or the run ID, so a retry cannot double-charge. Third, who gets paged. Put the billing owner on the escalation path, because the on-call engineer may not know whether a failed invoice line is a code bug, a provider outage or a config change.

Fourth, what the failure actually means to finance. A money smoke failure does not necessarily mean customers were charged incorrectly, but it does mean you cannot prove they were not. Say that plainly in the runbook, and include the exact query or dashboard that shows today's charge volume, so the first responder can answer "is money moving incorrectly right now" within minutes.

Do not roll back a database to fix a money failure. Database rollback scripts and restore-from-backup both risk data loss, and the guidance is blunt: do not roll back the database unless a catastrophic event justifies it the Octopus rollback strategies guide. Forward-fix the money surface, and use compensating writes for records that were created incorrectly.

Finally, revisit the tier assignments on a schedule. A check promoted to money because it once charged a real card should stay there. A check demoted to read-only after the query was made safe can move forward in the order. The point of the tiers is that the response is agreed before the failure, and that agreement only holds if it is written down and reviewed.

FAQ

FAQ

What exactly makes a smoke test "read-only"?

It makes no change to application state: no record created, no config edited, no message published, no charge attempted. Health endpoints, page renders, session issuance against a dedicated account and dependency reachability checks all qualify. If the check needs to write anything, even a temporary row, it belongs in the write tier.

Should money checks run on every pull request?

No, in most teams. Running test-mode charges and quota moves on every commit invites provider rate limits, test-data exhaustion and flaky failures, which train people to ignore the alert. Run money checks on the release candidate and on a schedule, plus a narrow probe after any change that touches pricing, plans or quotas.

How do I stop skipped tiers from reporting as passing?

Report skipped tiers explicitly as "blocked by tier 1" and make the pipeline treat an unexecuted money check as a failure of verification, not a pass. Many gate tools support a require-complete option that fails when cases are still unexecuted, which closes this gap the TestCollab quality gates documentation.

A read-only check failed. Do I still need to worry about billing?

Yes, but not by running the money suite against a broken build. Run the scheduled money probe on its own cadence and check the provider status page, because billing depends on the payment provider and webhook receivers, which can fail while the web tier is healthy. Treat that divergence as its own incident type with its own owner.

How long should each tier take?

Read-only should finish in seconds to about a minute; longer means it is doing too much. Write checks can take a few minutes because they create and clean up data. Money checks are the slowest and should not sit on the commit path at all; their runtime matters less than their correctness and their idempotency.

Sources

Sources

  1. Smoke Testing: What It Is, Examples & Checklist
  2. What is Trunk Based Development? | TeamCity CI/CD Guide - JetBrains
  3. Smoke Testing: What It Is, When to Run It, Best Practices - Momentic AI
  4. Production Smoke Suite - QASkills.sh
  5. Learn to Use GitHub Actions: a Step-by-Step Guide - freeCodeCamp
  6. Workflow syntax for GitHub Actions
  7. CI/CD Pipeline Testing: Run, Gate and Alert on E2E Tests
  8. Modern Rollback Strategies | Octopus blog
  9. Rollback pipelines | Harness Platform
  10. Automated Smoke Testing Guide for Engineers (July 2026)
  11. Smoke Testing: Definition, Examples & Checklist 2026
  12. Quality Gates in CI/CD: Fail a Pipeline on Test Results with ...
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles