Frazer QA
Frazer QA tests every change on a live preview: what the change affects, what to test at three depths, the runs by agents and runners, and results that Frazer Reviewer and auto-merge read as evidence. Agents call it rather than each writing their own suite: they say what they changed and why (fir pr test, MCP qa_test_runs_create), the tester decides what the suite needs, and a new flow that matches existing coverage by its traced routes and criteria is not added twice. Previews are its environments; frazer qa … is its command word, and frazer previews … its registered shortcut for previews.
A preview is a live environment for one change, at one URL on frazer.run, that people and agents open, test and comment on. Previews exist for every unit of work, a workspace, a pull request, a stack, a level of a plan, a merge-queue test batch, a program, a release candidate or a moment in the past, so a change is tested where it really runs: with its services, its data, its sign-in and its neighbors. On top of the preview, Frazer answers the four questions you ask of a change: what does it affect, what to smoke test, what to fully test, and what to test before release, and it records the answers as evidence that Frazer Reviewer and auto-merge read.
Subjects
Section titled “Subjects”| Subject | What the preview runs | Life |
|---|---|---|
workspace |
An agent’s or a person’s workspace before a pull request exists | The session’s life plus 24 hours |
pull_request |
One layer’s tree, on request | Until it merges or closes |
stack |
The default unit: the top layer’s tree, updated in place on every push to any layer | Until the stack merges or closes |
node |
A level of a plan above stacks (a phase, by default): the tops of its stacks together, for the items that test the interfaces between them | Until its stacks merge or close |
test_batch |
A merge-queue test batch, for tests only | The run; listed only when it fails |
program |
Every open stack of a program together: unreleased work tested as one | The program’s life, rebuilt on every change |
release |
A release candidate at production-like size, before its first stage | The candidate’s life |
moment |
What ran in an environment at a past time, with data from that second, for a reproduction | The issue’s life plus 7 days |
Previews are on by default for people’s and agents’ changes alike; a policy turns them off by path, by label (preview: skip) or by class. A stack whose test plan has items that need a running service or a screen gets one preview, shared by its layers unless someone asks for a layer’s own. A new version rebuilds only the copies whose inputs changed and moves the preview’s revision (v3 → v4); its URL stays. Campaign shards and dependency updates get tests-only previews that exist for their run and are gone after it, because nobody visits a shard. Nobody waits on a preview to read a change: the pull request shows its plan and checks at once, and the preview line fills in as copies become ready.
The recipe
Section titled “The recipe”A recipe (.frazer/preview.yaml) says what a preview runs, shares, branches and fakes; it is checked by schema and never holds a secret. One recipe can compose several repositories, or a monorepo can list its services by path.
apiVersion: frazer.ai/v1kind: PreviewRecipename: payments-platformbaseline: pellwyn-staging/payments # the environment previews share, at main@verifiedrepositories: [pellwyn/ledger, pellwyn/ledger-client, pellwyn/payouts, pellwyn/gateway, pellwyn/web]services: ledger-api: { repo: pellwyn/ledger, path: services/api, artifact: api-image } payouts-worker: { repo: pellwyn/payouts, artifact: worker-image, consumes: [events:ledger.events] } gateway: { repo: pellwyn/gateway, artifact: gateway-image } web: { repo: pellwyn/web, artifact: web-image } # pellwyn/ledger-client is a library: its consumers are rebuilt against the pull requestroutes: { "/": web, "/api/": gateway } # the front doordata: ledger-db: { database: pellwyn-staging/ledger-db, source: masked, isolation: branched, seed: seeds/ledger.yaml } events: { mode: route-by-header } # copies consume only the messages that carry their keyfakes: card-payments: { mode: sandbox } bank-rails: { mode: recorded, from: traces, window: 7d } email: { mode: inbox }personas: merchant-admin: { roles: [admin], seed: seeds/personas/merchant-admin.yaml } support: { roles: [support] }life: { sleep_after: 10m, inactive_ttl: 3d, on_merge: delete }budget: { per_preview_month_usd: 25 }A repository without a recipe gets one inferred from its deployment definitions, its database bindings and its CI artifacts, offered as a pull request (“Inferred recipe: 6 services, 2 databases, 1 queue, 3 fakes suggested”).
Across repositories. A preview takes the pull requests Fir links to its subject: the layers of a stack across repositories, the pull requests of one campaign shard, the layers that implement one plan item, or the open stacks of a program. Every other repository runs its baseline version. A person or agent may pin a repository to a version for one preview (--pin pellwyn/gateway@v41), and the pin shows on the preview. A changed library has no service of its own; its consumers are rebuilt against it and copied. A preview never matches branch names and never depends on a production service.
Baseline and copies
Section titled “Baseline and copies”The baseline is an environment at main@verified with masked data that every preview of a platform shares; it follows main@verified within 15 minutes (a target) and refreshes its data nightly. A preview runs copies only of the services its change touches. Its front door stamps a routing key on every request (in W3C Baggage and tracestate); inside the cluster, requests that carry the key reach the copies, and the rest reach the baseline.
request ──► front door (payout-status-pellwyn.preview.frazer.run) stamps the routing key pv-8b31 ▼ gateway (copy) ──► ledger-api (copy) ──► ledger-db branch ledger-db@pv-8b31 │ └──► fx-rates (baseline, no copy) ──► fx-db (baseline) └──► web (copy) payouts-worker (copy) ◄── events topic (shared; takes only messages with pv-8b31)Services forward the key through OpenTelemetry’s propagators. When an unchanged service between two of a preview’s copies drops the key, the preview copies that service too and wires it to its other copies directly, and says so (“propagation gap: risk-check drops baggage; copied”); the preview’s doctor lists the services that drop the key so teams can fix them. Queue consumers in copies take only messages with their key. The baseline’s own jobs and schedules never run for a preview.
| Isolation | Data | When |
|---|---|---|
shared |
The baseline’s databases; personas’ tenants keep test data apart | Read-mostly and UI changes |
branched (the default) |
A branch of the masked replica for every database a copy writes, made in seconds at any size | Most changes |
isolated |
A full copy of the affected part of the system, with branches of every database in it | Load, faults, migrations at production size, release candidates, past moments |
Data. Branches come from the masked replica, so a branch is instant and never unmasked. Seeds follow the schema and run after migrations, and a seed that no longer applies fails its check on the pull request that broke it. A pull request’s migrations run on its branch. By default production data never enters a preview: production’s traffic shapes (routes, mixes, rates, sizes) feed load profiles and recorded responses, and payloads come from staging or the masked replica. Recorded production payloads come only on an opt-in per service (below).
Fakes and the inbound router. A preview never reaches what it must not: card payments go to a provider’s sandbox shared per project with every object tagged by preview, or to a stateful Frazer fake for load and fault runs; email and text messages land in the preview’s inbox; identity providers are a test provider with the recipe’s personas; third-party APIs answer from responses recorded from traces, or from contract stubs; time is a per-preview clock offset. Because OAuth callbacks and webhooks need a fixed URL, each organization registers one URL per provider (https://in.preview.frazer.run/<org>/<provider>), and the inbound router forwards each request to its live preview by a signed state or a per-preview token; it never sees tokens.
Personas and sign-in. The recipe declares personas, never real accounts. A login handle (frazer previews login) is single use, must be redeemed within 10 minutes and signs a browser in as the persona for at most the run; every mint is an audit row. Apps on Frazer sign-in get their session from the handle; apps with their own login get a persona seeded in their user store and signed in once with a generated password the agent never sees. Testers get the same from the preview’s toolbar (“Sign in as merchant-admin”). There is no shared bypass secret. Browsers for agents shows how an agent’s browser uses them.
URL and access. Every preview has one host under preview.frazer.run: https://<handle>.preview.frazer.run serves the latest revision, and https://v<n>-<handle>.preview.frazer.run serves one revision for good. One wildcard certificate covers them all. Cookies are host-only: the edge refuses a cookie for frazer.run or preview.frazer.run. Previews sit behind Frazer sign-in by default, are shared with people or groups with an expiry, are reached by agents through their own identities, and carry X-Robots-Tag: noindex. The toolbar shows the revision, the persona switcher, the inbox, the preview’s flags, Open in devbox, and comments anchored on the page that become review threads on the pull request.
Life. A preview sleeps in two steps: after 10 idle minutes its copies freeze (waking in about a second), and after an hour frozen they scale to zero (waking in about 20 seconds); both are targets. It is deleted when its subject merges or closes, after 3 days without a push, a visit or a run, or by hand. Every resource a preview creates carries its ID, and a reconciler deletes anything whose preview is gone. A failed preview names its cause from a fixed list (build missing, image pull, crash loop, migration failed, seed failed, health check timed out, propagation gap, quota, no funds) with the evidence and the fix. When the budget or the balance cannot cover a preview, it is not created and says so (“Not run: no funds”), never a smaller copy.
Never a silent fallback. When a copy is not ready (building, crashed, updating), requests for it get 503 with frazer-preview-status: copy_not_ready; they never reach the baseline’s version as if it were the change, and a run that hits it ends no_verdict: preview_failed. Copies run the build Frazer CI made for the change, the same build production runs; dev servers run only in a devbox attached to the preview. After an hour asleep a preview is unapplied: its render and its suspended data branches stay, and waking re-applies it within the 20-second target. When capacity is short a new preview waits as queued with its place and estimate (“Queued · capacity · 12th in line · about 2 min”), agents’ own fixes first; it is never made smaller to fit. When a plan item is approved or a workspace opens on it, Frazer warms the images and data branches the change will need, so the first preview skips both.
Production payloads, only on an opt-in per service
Section titled “Production payloads, only on an opt-in per service”A service can give Frazer QA masked production payloads for recorded mocks, load profiles and replays, only when its organization opts in for that service. The approval is a capture approval (ca-…) of kind payload_capture, the same record that covers production probes and exception snapshots for the fix agent, so every capture on your services is in one list (frazer monitoring capture-approvals list).
| Step | What happens |
|---|---|
| Off (the default) | The service gives shapes only; nothing about a request’s values leaves its node |
| Shadow (first, at least 24 hours) | The capture point classifies what it would record and stores nothing; the report says what the masking rules must cover (“61,400 requests seen · 7 fields to mask · 0 card-like values · 2 free-text fields to redact”) |
| Approve | A person, never an agent, approves a masking rule set for the service (fields and paths, detectors, and per field keyed tokenization that keeps joins, redaction, generalization or synthetic substitution). The approval expires after 30 days by default; renewing it is one card with the period’s counts |
| On | The capture point samples (by default 1 % of requests, at most 10,000 a day) and masks before anything leaves the node; it drops, never masks, any request that carries a card number, card authentication data, a secret or a credential |
| Use | Only recorded mocks, load profiles and replays, only in isolated previews; never exported and never shown raw to a person or an agent; kept 14 days by default in the service’s region |
| Watch | Every change and read is audited. A detector that finds something the rules do not cover suspends capture and asks the rules’ owner to approve an update; an expired, revoked or unreachable approval stops capture within 60 seconds; one switch per organization turns every capture off |
A service tagged as part of a cardholder data environment cannot turn capture on. An organization that must report production data used in tests names the group that is told of every capture and renewal (the approval’s report_to).
What a change affects
Section titled “What a change affects”fir pr affected answers at system level, across repositories: every affected item has a kind (service, endpoint, flow, screen, table, migration, topic, job, consumer, setting, flag), a why (the path that makes it affected), a source (the build graph, contract records, the service graph from traces, flows and screens from test runs and recorded sessions, data from migrations and query fingerprints, the environment’s settings and flags) and a confidence (certain for build and contract edges, observed with its share of traffic for trace edges, inferred for static guesses). It is a record on the pull request version, the stack and the plan level, recomputed when a version moves.
$ fir pr affected 6120 --repo acme/storefront13 affected · 3 services changed · 1 consumer · 3 endpoints · 2 screens · 2 tables · 1 migration · 1 topic · 1 flagservices web (changed) · checkout-api (changed) · payments (changed)consumer notifications ← consumes payment.captured; contract payment-events v4 → v5 (certain)endpoints POST /api/gift-cards/{code}/holds (new) · POST /api/checkout (changed) · POST /api/payments/authorize (changed)screens Checkout (observed in 31 % of sessions) · Order confirmation (observed, 29 %)data gift_card_holds (new, migration 0142) · orders (written)topic payment.captured (schema change)flag split-payment (on in the preview, off in production)The example is Acme’s stack split-payment, top layer acme/storefront#6120 v3 “Split a payment between a gift card and a card”, by the coder agent for amara (demo data).
Test plans: smoke, full, pre-release
Section titled “Test plans: smoke, full, pre-release”A test plan (tp-…) is generated from the impact and the plan item’s acceptance criteria, then kept as a record people and agents edit. Each item names what it tests, why (the affected item it covers), the criterion it proves, its estimate and its depth. The generator is deterministic; the testing agent adds items only for what the rules cannot derive.
| Depth | Asks | Contains | Target time |
|---|---|---|---|
| Smoke | Is the change alive in the composed system? | Copies healthy; each changed endpoint’s main path; each affected screen’s main flow; sign-in; the smoke tests of each changed contract’s consumers | 3 minutes at the median |
| Full | Does it do what its criteria say, everywhere it reaches? | The affected Frazer CI tasks; every affected flow; tests written from the acceptance criteria; consumers’ contract tests; migrations up and down on the branch; visual diffs and accessibility of affected screens; mutation of changed lines | 15 minutes at the median |
| Pre-release | Will production hold? | The release’s full plans, without duplicates; load at the declared peak against the baseline; faults on dependencies; migrations at production size; rollback and upgrade rehearsal; the canary’s expected effects; security scans | With the release candidate |
- Tests from criteria are written by the tester, not the author, and every test says where it came from. A testing agent of another model family writes the tests that prove a plan item’s criteria from the plan alone; the implementing agent never sees them before its run and may not edit them. Each test carries its origin:
criteria,regression(fails before the fix, passes after),person, orcharacterization(generated from the code it checks). Only the first three count as evidence for required items. Oracles come from the criteria and backend state and are never tuned on a passing run. - Wants become items. “A load test at twice the Black Friday peak before item 1.3 merges” becomes a pre-release load item of every layer that implements item 1.3.
- Coverage is checked per criterion, never by asking. Each acceptance criterion and each affected item maps to at least one plan item, checked deterministically; no model is asked whether anything is missing.
The pull request’s Test tab answers the four questions first, then the runs (product UI, demo data):
acme/storefront#6120 v3 · stack split-payment · preview pv-6a1c v3 · split-payment-storefront-acme.preview.frazer.run1 What it affects 13 items · 3 services · 1 consumer · 3 endpoints · 2 screens · 2 tables · 1 topic · 1 flag [Open]2 Smoke 6 items · 6 passed · 2 min 41 s · $0.033 Full 24 items · 23 passed · 1 failed (split payment total off by 1 cent) · 14 min 02 s · $0.614 Pre-release 8 items · run with the release · load at 2× the Black Friday peak · payments slow Also Load test ▸ Test the tests: 14 mutants · 11 killed · 3 survived ▸ Emulate ▸ Open in devbox ▸Agents get the same as one result: fir pr test 6120 --json returns the impact, the items by depth, the verdicts, the evidence and the cost.
Test runs
Section titled “Test runs”| Kind | Runs as |
|---|---|
api, contract |
Frazer CI tasks against the preview’s front door with a persona’s handle; consumers’ contract tests from the contract records |
ui |
Replays of flows in a browser from Frazer Browsers, next to the preview |
exploratory |
A testing agent session with a budget and a goal from the plan; it finds paths and writes flows |
visual, accessibility |
Screenshots per viewport and theme against the base, and accessibility rules, on affected screens only |
migration |
Up and down on the branch; at production size before release, with lock time and duration |
load |
Your own load-test scripts, run unmodified, or a load profile Frazer generates from production’s shapes at the multiple the plan names, on an isolated preview against fakes only, judged against the baseline’s run with margins and intervals, not fixed thresholds |
mutation |
Mutants of changed lines with only their covering tests: testing the tests. A surviving mutant is a finding with the line, the mutant and a suggested test |
simulation |
Deterministic simulation of the subject’s services, their dependencies and the recipe’s fakes, through an integration with a simulation service on your own contract, the cost shown first in core-hours. Each finished run comes back as a test run: every property’s verdict, the findings and the moments behind them, each finding with that moment as its reproduction. Never a required item by default; a plan can make it one for R3 changes |
emulation |
Faults on an isolated preview: latency, errors, resets, bandwidth limits, partitions, a dependency down or slow, recorded dependencies, clock offsets, lower resource limits, production-size data. The fault schedule is a file recorded with the run, so a failing run reruns exactly |
property |
Seeded, property-based exploration of affected screens in the agent browser: random sequences of actions checked against properties over time written from the criteria, plus default ones (no uncaught exceptions, no unhandled rejections, no error logs, no 4xx or 5xx responses, no growing DOM or listener counts). No model runs: the runner explores for a time budget, and a violation reruns from its seed |
performance |
The change’s fail-to-pass tests rerun as a workload: instruction counts and wall time against the base, compared by Welch’s test |
Static before models. A testing agent authors a flow once from the plan’s criteria and verifies it three times green; a deterministic runner replays it on every version; the agent heals a flow only when a replay fails for a reason it can explain; and judging is deterministic first (backend state, API responses, accessibility rules, pixel diffs), with a model only for what those cannot decide. A new flow must pass three times on fresh previews before it can be a required item; a flaky test is quarantined by Frazer CI’s rules, and a quarantined proof test still blocks its item until it is replaced. Every run is a Frazer CI run, inside microVMs whose egress reaches only the preview’s front door, its fakes and the inbound router. Every failed item gets a cause from a fixed list (locator_changed, timing, runtime_error, test_data, environment, product_defect, test_defect); only locator_changed and timing may be healed, product_defect is a finding on the pull request, and environment never counts against the change. State checks cover every effect the criterion names (the row, the event, the fake’s payment, the email), not just the screen. Reruns of a failed item run alone, one after another; a new flow’s burn-in adds one run in a seeded random order; tests that share a fake or a persona take a lock.
Results as evidence
Section titled “Results as evidence”A test run (tr-…) records the items it ran, the preview and its revision, the data branches, the personas, each item’s verdict, the evidence, the cost, the time, the harness and model where a model ran, and its links; Frazer CI signs it.
| Verdict | Meaning |
|---|---|
pass |
The item’s assertions held at this revision |
fail |
They did not; the evidence names where |
flaky (k of n) |
Mixed across reruns on one revision |
no_verdict |
It could not run: no_funds, preview_failed, timed_out, blocked_egress, quarantined. Never a pass |
What auto-merge requires grows with the risk class:
| Risk class | Required items |
|---|---|
| R0 | The affected Frazer CI tasks |
| R1 | Plus the smoke plan on a preview when the change reaches a running service or a screen |
| R2 | Plus the full plan, consumers’ contract tests and a migration rehearsal on a branch |
| R3 | Plus the pre-release items the plan marks, and the person’s sample |
A no_verdict never satisfies a required item, and the pull request says why (“waiting: smoke not run, no funds”). An agent’s claim that it tested a change counts only with the test run record at that version. Frazer Reviewer’s design, accessibility, integration and production-safety lanes read results by item at the exact version.
Outcomes link back. When an incident, revert or hotfix is traced to a change: if a plan item covered the failure, failed, and the change merged anyway, the record says told (“Failed on Nov 12 on #6120 v3: split payment total off by 1 cent · merged by override”); if an item covered it and passed, it is a test miss, remedied by a stronger assertion, a state check or a mutant that would have caught it; if no item covered it, it is a plan miss, remedied by the source that should have made it affected. The overview shows misses per 1,000 merged changes by source.
A preview of a past moment
Section titled “A preview of a past moment”To reproduce an issue, a moment preview runs the digests that were live in an environment at a time, with a branch of the masked replica at that second, and replays the failing requests’ traces through its front door with a persona standing in for the user, isolated so the past never mixes with today’s baseline:
frazer previews create --at release:v2.14.2 --data at:2026-10-18T09:12A reproduction counts only when Frazer CI’s own rerun fails at the issue’s version, passes at the fix, and also fails on known wrong fixes (a seeded mutant of the fix, the fix partly reverted); see Issues. A concurrency bug reproduces under a recorded schedule. Any run can be replayed with no model (qa_test_runs_replay).
A devbox attached to a preview
Section titled “A devbox attached to a preview”A devbox attached to a preview has its workspace at the subject’s version and takes over one of the preview’s services: the preview’s requests for that service reach the process on the box, over Frazer Access, while the copy keeps running behind it. A person edits and reloads while the preview, its data branches, fakes and personas stay; an agent session attaches the same way from its own cell. Per stack the workspace sits at the stack’s top; per program it attaches to the program’s rolling preview. One box or session serves a service at a time, the preview shows which, and a run that counts as evidence for merging never uses a taken-over service.
frazer devboxes attach lena-dev --preview pv-6a1c --service checkout-apifrazer previews attach pv-6a1c --service checkout-api --from ws/s-e7a1frazer devboxes detach lena-devPrices
Section titled “Prices”Previews have no fee of their own: they bill the compute they use, per second while awake on the Frazer fleet and nothing while asleep, with their data branches at the managed-database rates. Recipes, the impact of a change and test plans cost nothing. API tests, load generators, mutation runs and emulation bill as compute-hours at the runner rate ($0.045 per vCPU-hour); UI flows, exploratory testing and reproductions through the UI bill as browser-hours ($0.02 each, an estimate); a testing agent’s session bills as agent runtime plus tokens; recordings and artifacts as Frazer Storage. Each is priced once.
Reference
Section titled “Reference”fir pr preview <n>, fir pr test <n>, fir pr affected <n> and fir stack preview <name> are the forms agents use from a workspace; they are the same calls as the frazer previews commands below, and every one is also an MCP tool with the same JSON.
CLI
| Command | What it does |
|---|---|
frazer previews create | Create a preview for a subject (--for pr:<repo>#<n>, stack:<name>, node:<plan>#<node>, program:<n> or ws:<workspace>), or of a past moment with --at; with --dry-run, print what it would copy, share, branch and fake, its URL and its cost. |
frazer previews url | Print a preview's URL, the latest revision's or one revision's. |
frazer previews login | Mint a single-use login handle that signs a browser in as one of the recipe's personas. |
frazer previews logs | Read the logs of a preview's copies. |
frazer previews exec | Run a command in one of a preview's copies, such as one of its scheduled jobs. |
frazer previews sleep | Put a preview to sleep now; wake brings it back. |
frazer previews why | Explain a failed or slow preview from its fixed list of causes, with the evidence and the fix. |
frazer previews attach | Attach an agent session's workspace to a preview, so it serves one of the preview's services (--service, --from). |
All of them: CLI reference.
Related
Section titled “Related”- Templates and previews: preview policies, templates and preview data
- Frazer Browsers: flows, reruns and logins through the UI
- The merge queue: test batches and what merges with no person
- Devboxes: attach a box to a preview