Sample: Investigator checkbox lost its checked state
- Expected
- A tester stays selected after it is clicked.
- Actual
- The box cleared on the next render.
- Evidence
- trace · screenshot · ledger
Here is how your tests did this week. Every figure is sample data until you connect a pipeline.
3 of 4 steps
POST */refunds*block-destructive-refunds9POST /admin/settingsblock-admin-mutations5POST webhook.sitehost on the blocked list3| Run | Status | Branch | Triggered by | Steps passed | Duration |
|---|
Ready.
No run yet
Pick a scenario and run it to walk through the steps, the requests the door allowed or stopped, and the checkpoints it left.
No requests yet
The request log appears after you run a sample scenario.
| Request | Host | Action | Verdict |
|---|
No checkpoints yet
Checkpoints let a run branch from a saved step. Run the sample to see them.
Every run — local, CI and cloud. Each finished run leaves a signed receipt; this history is a sample fixture until you connect a pipeline.
#1043 Checkout payment
| Run | Status | Branch | Commit | Triggered by | Steps passed | Duration |
|---|
No runs match those filters
Clear the search or widen the status filter.
16 of 18 steps passed · 52s · preview
POST /api/checkout returned 500 at step 17
traceparent 00-4bf92f35…-00f067aa…-01 · server returned no backend detail · the payment form never re-enabled.
A clean browser session starts with a phantom payment token.
Form actions and assertions run inside the isolated browser context.
A permitted payment-method lookup crosses the policy boundary.
The sample policy blocks the destructive request before it leaves the host.
Server error. The Pay now button stayed disabled.
Steps 17 and 18 failed. Checkpoint “Checkout ready” is available to fork.
| Request | Host | Action | Verdict |
|---|---|---|---|
| GET /v1/payment_methods | api.stripe.test | Phantom value only | Allowed |
| POST /api/checkout | staging.shop.test | Passed through · 500 | Allowed |
| POST /v1/refunds | api.stripe.test | Stopped at policy boundary | Blocked |
Suite groups, selector health and flaky warnings for the sample fixture. Connect a pipeline or record a test to replace these numbers with your own.
Sample coverage
110 of 115 tests passing
Across four sample suite groups. Flat fixture data, not your workspace.
Checkout
40 / 42 passing · 42 tests
Authentication
30 / 31 passing · 31 tests
Account settings
23 / 24 passing · 24 tests
Cart and pricing
17 / 18 passing · 18 tests
96.4%
Stable selectors
Heals below the 80% confidence threshold are never applied. They fail the step and appear for review instead.
Review healed locatorsCheckout › applies saved payment method
Account › refreshes session after login
Cart › restores warm checkpoint
| Test | Made by | Last result | Stability | Healed | Time |
|---|---|---|---|---|---|
| Applies the SAVE20 couponcheckout.spec.ts | Recorded | Passed | Steady | 1 | 6.1s |
| Applies a saved payment methodcheckout.spec.ts | Recorded | Flaky | 2 of 52 failed | 0 | 7.4s |
| Guest checkoutcheckout-guest.spec.ts | Hand-written | Failed | Broke on e612af4 | 1 | 8.2s |
| Rejects an expired couponcheckout.spec.ts | Recorded | Passed | Steady | 0 | 4.8s |
| Totals survive a reloadcheckout.spec.ts | Recorded | Passed | Steady | 0 | 5.5s |
Runs, pass rate, flaky tests and suite timing from the sample analytics fixture. Every figure is illustrative until a pipeline posts real runs.
97.0%+3.0 pts since Oct 31
The axis runs 94–98% so the change is visible; a zero-based chart would look flat. Daily series 94 · 96 · 95 · 98 · 97 · 96 · 97%.
| Test | Runs | Flaky rate |
|---|---|---|
| Checkout › applies saved payment method | 52 | 3.8% |
| Account › refreshes session after login | 47 | 2.1% |
| Cart › restores warm checkpoint | 61 | 1.6% |
| Suite | Passing | Median | Slowest 5% |
|---|---|---|---|
| Checkout168 sample runs | 40 / 42 | 60s | 1m 34s |
| Authentication124 sample runs | 30 / 31 | 36s | 1m 2s |
| Account settings96 sample runs | 23 / 24 | 31s | 52s |
| Cart and pricing58 sample runs | 17 / 18 | 24s | 39s |
Synthetic testers propose journeys; the deterministic engine executes every action through the safety door, and each finding comes with signed evidence it can be replayed from. One free investigation per workspace per day.
| Investigation | Target | Testers | Findings | Status |
|---|---|---|---|---|
| inv_4b8869e4Nov 8, 20:36 | demo.playwright.dev/todomvc | 2 | 8 3 stuck · 5 bugs | Success |
| inv_9c02e71aNov 8, 20:12 | staging.acme.test | 3 | running… | Running |
| inv_51f0d7c3Nov 7, 18:44 | checkout.example.com | 1 | budget hit | Failed |
Editing an empty todo deletes it with no undo
Impatient mobile user · step 4 · replay-verified
“Clear completed” count lags one item after reload
Skeptical reloader · step 6 · replay-verified
No visible way to edit on touch — double-tap only
Impatient mobile user · step 2
Filter state is lost when the hash is removed
Skeptical reloader · step 8
Showing 4 of 8 ranked findings · each replays from its signed evidence.
Every QA failure with its steps, expected and actual behaviour, investigation notes, root cause and evidence. Records are created by the Playwright MCP harness when a case fails.
Every pull request the App sees: deterministic QA checks, a grounded LLM pass, verification, then inline comments, a summary and the QAFind review status. Records here are samples until your installation is connected.
Reviews today
6 / 50
Blocking findings open
1
acme/shop#412
Median time to review
1m 48s
webhook → status · sample
Tokens today
41.2k
deepseek-chat · cost estimate off
| Pull request | Status | Verdict | Findings | Model | Updated |
|---|---|---|---|---|---|
| Retry checkout on 500 | Completed | Blocked | 3 1 high · 2 medium | deepseek-chat | 10:42 |
| Show tax line on review page | Completed | Approved | 0 auto-approved · 38 lines | deepseek-chat | 09:58 |
| Admin: bulk role editor | Running | — | — verifying 4 findings | deepseek-chat | 09:51 |
| Refactor cart totals to centsInvalid .qafind-review.yml: fail_on must be one of critical, high, medium, low, none | Failed | — | — | — | 09:12 |
| Update footer linksSuperseded by a new head SHA | Cancelled | — | — | — | 08:47 |
| Docs: onboarding copy | Queued | — | — all files in ignore_paths | — | 08:40 |
of 6 reviews · sample records. Sign in to load reviews queued by your installation.
Contents write is only needed for Apply safe fix. Open App settings ↗
Reply to the bot in a PR thread to teach it a convention.
Each repository can add .qafind-review.yml; the worker reads it at the PR head. Invalid policy fails the review with a clear error.
# acme/shop/.qafind-review.yml
review:
fail_on: high
max_findings: 25
ignore_paths: ['docs/**', '**/*.lock']
approve_when_passed: true
approve_max_changed_lines: 400
approve_protected_paths: ['**/payment/**']
path_instructions:
- path: 'tests/**'
instructions: 'Never add fixed sleeps.'
Retry checkout on 500
Completed Blocked4 files · +86 / −12. The idempotency issue was fixed and verified on 9f2c4a1; a focused test still blocks the status check.
Focused test committed (.only)
CI would run only this test and report the suite green. Remove .only before merging.
Fixed sleep in a test
A 3-second wait races the payment webhook on slow runners. Wait for the confirmation instead.
Retry resubmits the payment without an idempotency key
If the first POST succeeded but the response was lost, the retry charges twice. Verified fixed on 9f2c4a1 by re-running checkout-flow with a forced 500.
Turn a click-through into a Playwright spec. This page is a sample simulator: no browser is attached and no session is captured.
For a real recording run qafind explore <url>, then qafind compile .qafind/traces/<name>-trace.json.
Open http://127.0.0.1:3900
goto · domcontentloaded
Click “Log In to Sandbox”
testId: login-btn · text fallback
Save point post_auth
cookies · local + session storage · DOM hash
Click “Add to cart”
css: [data-testid="add-to-cart"]
Save point cart_filled
cookies · local + session storage · DOM hash
Type “SAVE20” into the coupon box
testId: coupon-input
Click “Apply Coupon”
testId: apply-coupon-btn · text fallback
Check the total shows $50.00
testId: cart-total · text: $50.00
import { test, expect } from '@playwright/test';
import { QAFindRunner, qafindLocator } from 'qafind';
test('checkout-flow', async ({ page, context }) => {
const qafind = new QAFindRunner();
await qafind.initialize(context, page);
await page.goto('http://127.0.0.1:3900'); // 1 · open the shop
const login = await qafindLocator(page, { // 2 · log in
testId: 'login-btn',
text: 'Log In to Sandbox', // falls back to text
});
await login.click();
await qafind.checkpoint('post_auth', page); // 3 · save point
await page.getByTestId('add-to-cart').click(); // 4
await qafind.checkpoint('cart_filled', page); // 5 · save point
await page.getByTestId('coupon-input').fill('SAVE20'); // 6
await page.getByTestId('apply-coupon-btn').click(); // 7
await expect(page.getByTestId('cart-total')) // 8
.toHaveText('$50.00');
});
When a selector breaks, QAFind proposes a replacement. Accept and Reject here change this page only — no spec file is edited in the sample.
Heals applied this week
23
live local log · .qafind/dataset/mutations.jsonl
Average match across the queue
88%
sample fixture
Confidence threshold
80%
below it, the step fails for review
Was looking for
#coupon
Found instead
getByTestId('coupon-input')
Match
94%
threshold 80%
Was looking for
button.btn-save
Found instead
getByRole('button', { name: 'Save changes' })
Match
88%
threshold 80%
Was looking for
text=Continue as guest
Found instead
getByText('Checkout as guest')
Match
81%
threshold 80%
1 · exact_testid
Same test id
data-testid survives a rename of class or id.
2 · aria_fuzzy
Accessible name
Role plus a fuzzy match on the name.
3 · semantic_text
Visible text
The words a customer would read.
4 · structural_xpath
Position in the page
Last resort; usually lands below threshold.
Save points for a browser context: cookies, storage, the page URL and a DOM snapshot. Like a tardigrade’s tun, the state is sealed and revived later — branch new tests from it instead of repeating setup.
post_auth
step 2 · /account
fp 7f3a91c2…
cart_ready
step 5 · /cart
fp c41e08bd…
coupon_save20
guest_checkout
saved_card
Saved: cookies, local + session storage, URL and a DOM snapshot. Process memory and server data are not saved. fingerprint = SHA-256 of the DOM snapshot.
npx qafind fork cart_ready --workers 4
Apply coupon SAVE20
Expired coupon
Guest checkout
Pay with saved card
This preview cannot start branches. Forking runs the CLI against saved checkpoint files on your machine; hosted run capacity is separate.
Decide what the test browser may reach, and give it stand-in keys so real secrets never enter the page. The cloud worker enforces every rule at the door; this console configures and previews them.
| # | Action | Rule | Scope | Match | Why | This week |
|---|---|---|---|---|---|---|
| 1 | Block | block-destructive-refunds | any host | POST */refunds* | Refunds and wipes must never leave a test run. | 9 |
| 2 | Block | block-admin-mutations | staging.shop.test | POST /admin/* | Role tests read admin pages but never change them. | 5 |
| 3 | Block | block-webhook-exfiltration | blocked hosts | any method | Hosts on the blocked list never receive test data. | 3 |
| 4 | Allow | allow-stripe-reads | api.stripe.test | GET /v1/* | Payment lookups are safe with the stand-in key. | 412 |
| — | Block | Default when no rule matches · evaluated by the cloud worker, not this console | ||||
BlockedAllowed
Matched block-destructive-refunds — POST */refunds* covers this path.
Matched allow-stripe-reads — GET /v1/* with the stand-in key.
No rule matched — the default action blocks unknown requests.
Nothing is submitted. The worker evaluates the real rule and writes the decision to the run’s ledger.
Unknown hosts follow the default action: Block.
Browser sees
ph_sec_stripe_test_placeholder
Real value is added at the door · it never enters the page
Browser sees
ph_sec_test_dummy_token
Never swapped onto /delete* or /refund*
Every run writes a hash-linked ledger and signs its Merkle root. This page shows a sample chain and its verification state; a real receipt is written by the cloud worker when a run finishes.
preview-run-1042
Checkout payment · signed Nov 6, 2026 · 10:42 UTC · local sample
5
ledger blocks
2
stand-in keys
1
request stopped
verify: valid · root matches the sample signatureverify: tampered · block #3 prev ≠ hash of #2
| # | Block | What happened | Prev | Hash |
|---|---|---|---|---|
| 0 | EXEC_START | Run began · checkout-flow | 00000000 | 4f1c2a9e |
| 1 | SECRET_SWAP | STRIPE_KEY stand-in replaced | 4f1c2a9e | 9b02d7c1 |
| 2 | EGRESS_BLOCKED | POST /v1/refunds stoppedPOST /v1/refunds allowed (edited) | 9b02d7c1 | c7e95b305a7e0f13 |
| 3 | ASSERTION_EVAL | Total shows $50.00 · passed | c7e95b30 | 21ad8f64 |
| 4 | EXEC_COMPLETE | Run finished in 393 ms | 21ad8f64 | e8c6c259 |
5 blocks · each hash commits to the one before it · sample
| Run | Chain | Merkle root | Blocks | Signed |
|---|---|---|---|---|
| Valid | e2114ac9…a8f6aece | 5 | Nov 6 · 10:42 | |
| Valid | 7a90b2e4…c311fb | 4 | Nov 6 · 08:18 | |
| Valid | d4417c08…92ab0e | 6 | Nov 6 · 07:54 | |
| Valid | 0be3a6d1…71fe4c | 5 | Nov 6 · 07:31 |
See what a page shows days from now — trials ending, coupons expiring, renewal reminders — without waiting for the calendar. The warp shifts the clock the test page reads, not the network around it.
Page time now
Nov 6
+14 days
After the warp
Nov 20
Jump ahead by
Account · billing
Upgrade planServer-side expiry still needs its own test: the warp never changes what the API returns.
Save an outside service’s answer once, then replay it inside the test browser so a test does not fail because that service had a bad day. Unmatched requests go to the real network unless a policy rule stops them.
| Method | Request | Host | Status | Hits this week |
|---|---|---|---|---|
| GET | /v1/payment_methods | api.stripe.test | 200 | 312 |
| GET | /v1/rates?base=USD | api.exchangerate.test | 200 | 488 |
| POST | /v1/payment_intents | api.stripe.test | 200 · synthetic | 205 |
| GET | /flags | cdn.featureflags.test | 200 | 96 |
| GET | /v1/shipping/quote | api.shipping.test | 200 | 41 |
1,140 requests answered locally · 2 misses went to the real network · sample counts
Recorded Nov 3 · pinned so prices in tests never drift with real rates. Static preview: edits are not saved.
GET api.analytics.test/v1/track
run #1042 · step 9
GET maps.test/v2/geocode
run #1039 · step 12
Every miss is listed so nothing slips by unnoticed. Block the host or record it next time.
A sample run that injected latency, a 500 and a timeout to see whether checkout survives a bad day. Faults execute inside the worker’s browser context; this console shows the report it wrote.
The page recovered from latency and the 500, but two Pay now clicks reached the server 180 ms apart with no idempotency key.
Duplicate submission possible
Three faults were injected and the run recovered from two. The retry path duplicated the payment attempt — the failure this check looks for.
Sample run · not a finding about your app
| Fault | Target | Injected | Observed | Outcome |
|---|---|---|---|---|
| Latency | GET /v1/payment_methods | +800 ms on the first attempt | 812 ms · page still reached checkout | Passed |
| Server error 500 | POST /api/checkout | 500 on the first attempt | Retry succeeded after 340 ms | Recovered |
| Timeout | POST /api/checkout | No response for 3 s | Request timed out · retry allowed | Recovered |
| Duplicate click | Pay now button | Two clicks 180 ms apart | Two requests sent · no idempotency key | Warning |
Example report: identifiers, timings and outcomes are illustrative. A real chaos run writes its own signed receipt.
A capsule saves the last moments before a test fails — the trace, the network log and a DOM snapshot — so the bug can be replayed and turned into a Playwright spec.
Prototype — keep real customer data out.
Emails, card numbers, tokens and obvious secrets are scrubbed on a best-effort basis, but capsules are not encrypted. Use staging or preview data only.
TypeError: Cannot read properties of undefined (reading 'total')
Unhandled promise rejection: 409 Conflict
ReferenceError: couponState is not defined
Replay keeps 3 storage keys and 2 cookies. Scrubbing is best effort, not a guarantee.
Teleport replays the recorded steps and writes a Playwright spec that reproduces the bug.
npx qafind teleport cap_7f2a91.json -o tests/repro-bug.spec.tsnpx playwright test tests/repro-bug.spec.ts
npx qafind teleport cap_19bd04.json -o tests/repro-bug.spec.tsnpx playwright test tests/repro-bug.spec.ts
npx qafind teleport cap_c03e77.json -o tests/repro-bug.spec.tsnpx playwright test tests/repro-bug.spec.ts
Run QAFind from any pipeline with one HTTPS request. The endpoint, keys and receipts on this page are sample values; nothing is submitted from this preview.
Three.js CI to attestation flow · loading…
Animated version of the schematic. A recorded clip stays in your browser.
curl -X POST https://api.qafind.si/v1/runs \
-H "Authorization: Bearer air_live_••••" \
-H "Content-Type: application/json" \
-d '{
"suiteName": "checkout",
"targetUrl": "https://staging.example.com",
"phantomConfig": {
"STRIPE_SECRET_KEY": {
"phantom": "ph_sec_example_01",
"allowedHosts": ["staging.example.com"],
"blockedPaths": ["*/refund*"]
}
},
"workflow": { "name": "checkout", "steps": [
{ "action": "goto", "url": "/" },
{ "action": "expectVisible", "selector": "#cart" }
] }
}'
runId and status: QUEUED.resetAt.bun add --dev qafindbunx qafind test --cloud
npm install --save-dev qafindnpx qafind test --cloud
The CLI sends QAFIND_API_KEY only as an HTTPS Bearer token. Real app secrets stay in your runner; only placeholders travel to the cloud.
# .github/workflows/qafind.yml
- run: bunx qafind test --cloud
env:
QAFIND_API_KEY: ${{ secrets.QAFIND_API_KEY }}
QAFIND_API_KEY.Workspace details, people, plan usage and how evidence is signed. Everything here maps to qafind.config.json; this preview is read-only and saves nothing.
Projects
64 / 100 cloud runs today
Resets at midnight UTC · sample value
Running locally is free and does not count toward cloud usage. See plans
| Person | Role | Last active |
|---|---|---|
| Maya Chenmaya@acme.test | Admin | Now |
| Jordan Leejordan@acme.test | Editor | Today, 09:54 |
| Priya Nairpriya@acme.test | Viewer | Nov 5 |
| CI pipelineservice · uses key air_live_7Hk2… | Runner | 2 min ago |
Invites are disabled in this preview; no email is sent.
Pin the service key with QAFIND_TRUSTED_PUBLIC_KEY. Verification shows the ledger was not changed after signing — it is not a compliance assessment.
API keys
Shown once, stored as a SHA-256 hash. Up to 10 active keys on the free plan.
Signed evidence
Every finished cloud run writes a hash-linked ledger signed with Ed25519.
Hosted runs
Receive policy only — allowed hosts, methods, blocked paths — never your application secrets.