A board-task QA pipeline built into Claude Code.
You run /optimus-qa-tester:test with a task ID — OPT-237708 — and step away.
It reads the ticket, derives every variant from the campaign-meta endpoint, loads the knowledge for that campaign
type, and puts a plan up for approval. Then it drives the campaigns on the partner's own site, reviews its own run
against the QA standard, and writes the Jira comment from the evidence it captured.
Hit Play. Control moves along the line, the run halts at every human gate — and when the review rejects the report, control goes back. That loop is the part a development pipeline does not have.
Machine stations stay quiet, human gates glow orange, a rejected review deep red. At a gate the run stops until someone approves.
Illustrative walkthrough — the stations, agents and gates map one-to-one onto the phases in
skills/qa-board-task. On the reference run the review rejected the report
six times before it agreed.
Commands
One does the work. The other four exist so the first never runs on a broken machine, and so what it gets wrong finds its way back to us.
The QA loop. Resolves the issue type, refuses anything that is not a board task, and runs Plan → Execute → Validate → Report.
Picks the data root, writes .env, walks the Google org-client login for Drive and Sheets.
Read-only environment check: playwright-cli, ADC and its scopes, Jira token, data root, Slack webhook. Names the fix, never applies it.
Runs the real QA flow as a dry-run against a task that already passed UAT, then judges its own findings against that task's comment history.
One click. The plugin infers what just happened, offers concrete options, and sends the friction to the team channel with the run's context attached.
What it knows
A router resolves the issue type, the orchestrator owns the four phases, five knowledge skills are always in play, and exactly one sharp skill is loaded for the campaign type under test. The value is not the count — it is that each one carries the goal chain, the storage flags and the traps for its campaign type.
Agents
One drives the browser. The other is not allowed to — its only job is to disagree with the run before anything reaches Jira.
One case — a single variant on a single device — in its own isolated browser session. Dispatched two at a time, so twenty cases are ten batches, not twenty waits.
An independent pass over the finished run against the Mandatory Checks and the sixteen Board QR items. It has no browser and cannot fix anything — it can only approve, or send the report back.
Where humans hold the line
Four decisions stay with a person. The rest is the machine's — bounded by rules it is not allowed to talk itself out of.
Not just the case matrix. It states what it believes the campaign does and the exact step order it will run — the two things a matrix cannot show, and where a wrong run actually begins.
A missing credential, an unreachable partner, an SDK that never loads → it stops and names the blocker instead of quietly working around it.
The independent review. On the reference run it sent the report back six times — dead evidence links, a wrong console count, an over-broad claim — before approving.
The comment is rendered, hashed and shown in full. A person approves; only then is anything written. The workflow never moves a ticket status.
The evidence
This is the change under test: the slider's arrows pulled into the dot row, so prev → dots → next sit on one line. Below is what the run actually captured — not a diagram of it.
Every link in the Jira comment is the URL the upload returned. A link that did not come back verified never reaches the report.
What it produces
Phase D is a pipeline of its own: aggregate the case results, upload the evidence, verify every link came back, render the report, and only then draft the comment.
Per-case results, captured goals, console counts and evidence paths are collected into a single run summary.
Recordings and traces go to the task's Drive root — reused across runs, never recreated. The returned link is the only source of truth.
A self-contained HTML report with the screenshots embedded, published to an internal link — and a Jira comment where every row points at the artifact behind it.
Proof · one real task
A Smart Recommender widget across ten locale builders, each with a control group, verified on local Chrome, a real iPhone and a real Android handset, in both orientations.
| Campaign | Localcontrol group | Localvariant A | iOSreal device | Androidreal device |
|---|
| Phase | Cases | Window | Minutes |
|---|---|---|---|
| Local — Chrome, iPhone UA, portrait + landscape | 20 | 15:34 → 15:59 | 25 |
| iOS — real device via BrowserStack | 10 | 18:54 → 19:27 | 33 |
| Android — physical handset | 10 | 22:46 → 23:07 | 20 |
| Total execution | 40 | — | 78 |
6×–11× on execution. Read it as attention returned, not speed — the person spends their time on the plan, the review and the verdict, instead of driving ten campaigns through three devices by hand.
Published reports · one per campaign
What it nearly said
A QA tool earns trust by what it catches in itself, not by claiming it makes no mistakes. Each of these was produced by the run and stopped before — or shortly after — it reached the ticket. They are the reason the gates exist.
Shortening the goal names for readability broke the renderer's set-match: the headline row stopped comparing captured goals and printed a tick for everything in the plan.
The tick is now derived from the union of what the cases actually captured; anything unmatched is named MISSING rather than dropped.
Check values were written from a per-case template instead of being derived from each case's diagnostics. Twenty-five of twenty-six happened to be right — which is worse, not better.
One case never recorded the check. The verdict was recovered from the screenshots instead, and the report now says which evidence it rests on.
Attachments were picked by filename without being opened. Nine of eighteen showed the QA toolbar strip rather than the slider controls they claimed to.
A file's name is not evidence of its contents — the same mistake in a different costume as the one above.
The check searched the command output for a success string — and the browser CLI echoes back the JavaScript it was given, which contained that very string. The click had actually timed out.
The cart is read from the partner's own page. An SDK signal that says something happened is not evidence that it did.
What we are still fixing
All four are open work. The 78 minutes above is the settled flow — reaching it took the better part of three days, because the tooling was being built while the task was being tested.
The Jira comment and the HTML report are fed from one source, so a short comment and a deep report cannot both exist yet. Half the dual-orientation evidence went unlinked for the same reason.
The iPhone and Android legs work, but the tunnel, the device session and the quota are still managed by hand. That path is not repeatable yet.
The QR gate confirms an artifact exists where the report says it does. It does not yet look at what is inside it — which is why three of the four cases above were caught by a person.
Each case-executor writes its diagnostics in its own shape, so the orchestrator has to guess at names. One canonical schema removes a whole class of reporting mistakes.