The per-feature QA pipeline. Where /daily-qa is the unattended, repo-wide,
time-windowed background sweep that only reports, /qa-full is the
present-human, branch-scoped, audit → fix → verify pipeline you run the
moment a feature is done — before /finish-branch and /ship.
implement → /qa-full → /finish-branch → /ship
(audit → fix → verify)
It reuses /daily-qa's trigger matrix (which checks to run based on what
changed) with three deliberate differences:
- Scope is the branch diff (
base..HEAD+ working tree), not a time window. - It fixes, not just reports. Every check runs in three phases — audit
(report-only discovery is fine here), fix (apply the smallest correct fix,
one atomic commit per fix — except
/review's bundled output, see Hard rules), verify (re-run the same check plus the test suite and prove the fix holds). The final verdict is on the repaired branch. - Interactive checks actually run. Because a human is present, the checks
/daily-qaonly recommends —/qa,/web-perf,/design-review, the dynamic/a11ypass — run here when their triggers fire.
This is not an audit skill. It is a full security pipeline, a full performance pipeline, a full correctness/test pipeline, and a full browser/design pipeline, selected per-diff and driven to green.
Hard rules
- The bar is the superskills quality standard — TDD/DRY/SOLID/YAGNI
(applied in every step's fix phase: test first, no duplicated logic, small
single-purpose units, nothing speculative) plus the hard-gate list, which is
spelled out in full in Step 10's Blocker set. The canonical written copy is
ENGINEERING_STANDARDS.mdin the superskills install (a plugin install exposes it at${CLAUDE_PLUGIN_ROOT}/ENGINEERING_STANDARDS.md); it is not expected to exist in the project you're reviewing, so don't flag it as missing. Every fix you land must meet that bar too — a fix that adds untested public surface or duplicates logic is not a fix. - Audit → fix → verify, per check. For every check whose trigger fires:
- Audit — run the sub-skill (its normal report-only output is the discovery pass).
- Fix — for each CRITICAL/HIGH finding (and MEDIUM where the fix is
small and safe), root-cause it (
/debugdiscipline: no symptom patches), write the failing test first when it's a logic bug (/tdd), apply the smallest correct fix, and commit it atomically with a message naming the check and finding. - Verify — re-run the same sub-skill on the diff and re-run the test
suite. A fix is only "fixed" when the re-audit no longer reports it and
tests are green. Never claim a fix without this fresh evidence (
/verifydiscipline). A finding you could not fix (needs a product decision, external service, credentials, or an architectural change beyond the diff) is an UNFIXED blocker: record what you tried and why it's out of reach. Do not quietly downgrade it to a warning.
- Fix only what the diff and the findings justify. Do not refactor untouched code, upgrade dependencies, or "improve" unrelated modules while you're in there. Scope stays on the branch diff plus the exact lines a finding points at.
- Commit, but never push or open a PR. Each fix lands as its own commit on
the current branch so the user can review/revert individually. Exception:
/reviewexposes no per-finding boundary, so its output lands as one commit per invocation (Step 3). Integration and shipping belong to/finish-branchand/ship. - Ground every finding and every fix in concrete evidence: file:line, failing test name, log snippet, severity as the underlying tool produced it, and the commit SHA of the fix. No speculation.
- Separate blockers from warnings. Only test/build failures and CRITICAL/HIGH findings block. Everything else is a warning — fix it when the fix is cheap and safe, otherwise ship it with a follow-up note.
- Bounded loops. At most two fix rounds per check, then one final verification pass (Step 10). If something is still red after that, it's an UNFIXED blocker with the attempts documented — not a third round.
- Never claim SHIP-READY without receipts. The verdict must cite the exact checks that ran, what they found, what was fixed (with commits), what was re-verified, and what was skipped (and why).
- No silent skips — mandatory accounting. Every check must resolve to
exactly one of: RAN-CLEAN (ran, nothing to fix), FIXED(n) (ran, n
findings fixed and re-verified — list commits), UNFIXED (ran, at least one
blocker could not be fixed — reason), SKIPPED (stated reason — e.g. "no
reachable dev server and none could be started", "scanner not authorized in
this env"), NOT-TRIGGERED (its diff trigger didn't fire), or
MANDATORY-FAIL (a
CLAUDE.md-mandatory check that was skipped). A check whose trigger fired but that neither ran nor was explicitly skipped-with-reason is an unaccounted check ⇒ NOT READY. "Recommend-only" is not an allowed resting state for a triggered check. Projects may mark specific checks MANDATORY inCLAUDE.md(e.g./penteston a payments service), and for those, SKIPPED is itself a blocker. - Money and authorization still need a human yes.
/code-review ultrais a billed cloud run, and/review's Codex passes spend OpenAI tokens — ask before launching either, never assume./pentestrequires the user to confirm authorization before it scans — ask, then run. "Ask, then run" is still running; it is not report-only.
Project configuration (CLAUDE.md)
This pipeline reads the project's root CLAUDE.md for a few optional settings.
They are plain prose (CLAUDE.md is agent instructions, not a config file) — look
for a ## qa-full section and honor whatever it states. Example:
## qa-full
- Mandatory checks (must RUN with evidence — a skip is a blocker): `/pentest`, `/defense`
- Hard perf gate: LCP ≤ 2.5s and INP ≤ 200ms on `/` and `/checkout` (breach blocks)
- Design: skip `/design-review` (design is owned by the design team, do not auto-fix visuals)
- Dev URL: http://localhost:3000 (for `/web-perf`, `/qa`, `/a11y`, `/fuzz`)
- Test/build: `pnpm test` and `pnpm build`
- QA tier: exhaustive
Recognized settings (all optional; absence = the defaults in the steps below):
- Mandatory checks — listed commands must read RAN-CLEAN or FIXED in the ledger; SKIPPED is a blocker (any step; Step 10 enforces it). MANDATORY overrides the check's own diff trigger: run it on the diff even when the trigger didn't fire, so NOT-TRIGGERED is not an acceptable state either. Use for compliance-critical surfaces (payments, auth, PII).
- Hard perf gate — turns a
/web-perfbudget breach that survives the fix round from a warning into a blocker (Step 6). - Design: skip
/design-review— opt out of the visual-fix pass (Step 8) entirely; by default it runs on any UI change. This skips the check (ledger: SKIPPED("project opt-out")) — it does not turn it into a report-only run. - Test/build commands — feed Steps 2 and 10. Dev URL — feeds Steps 4
(
/fuzz), 6, 7 and 8. QA tier — feeds Step 7; defaults tostandard.
If there is no ## qa-full section, run with the built-in defaults — nothing here
is required.
Step 1: Establish the diff scope and a clean tree
- Detect the base branch:
gh repo view --json defaultBranchRef -q .defaultBranchRef.name, elsegit symbolic-ref refs/remotes/origin/HEAD, else fall back tomain/master. - If
$ARGUMENTSnames a base branch or--scope <paths>, use it. - Resolve the diff ref:
git fetch origin <base>and useorigin/<base>when that ref exists, else local<base>. This is what/reviewand/qadiff against too, and it stays correct after Step 1.5 creates a working branch (local<base>would then equal HEAD and the set would be empty). Compute the changed-file set:git diff --name-only <diff-ref>...HEAD -- <scope paths>(drop the--part when no--scopewas given) plus uncommitted changes (git status --porcelain). This set drives every trigger below. Fix commits made by this pipeline extend the set — later steps and the final pass (Step 10) audit the fixes too. - Clean-tree precondition. The fixers (
/qa,/design-review) need each fix to be its own atomic commit, so they stop on a dirty tree. Handle it once, here: ifgit status --porcelainis non-empty, ask the user (via AskUserQuestion) whether to commit the in-progress work now (recommended — a descriptive commit so the feature is preserved before fixes land) or stash it. Do not proceed with a dirty tree. - Never run on the base branch itself. The sub-skills' diff-aware modes
(
/review,/qa,/design-review) key off "current branch ≠ base" and diff againstmerge-base(origin/<base>, HEAD). Ifgit branch --show-currentequals the base and there are unpushed commits, create a working branch at HEAD first —git switch -c qa-full/<base>-<YYYY-MM-DD>(reuse it if a same-day branch already exists from an aborted run) — and run the whole pipeline there. Step 10 folds it back: fast-forward the base to the working branch (git switch <base> && git merge --ff-only qa-full/...) and delete the working branch. No history is rewritten; the base just gains the fix commits. If there are no unpushed commits either, there is nothing to QA. - Record at the top of the report: base branch, diff ref, working branch (if created), commit range, changed-file count, and the HEAD SHA before any fixes.
If there is no diff against base, stop and say so — there is nothing to QA.
Step 2: Tests & build (always — audit → fix → verify)
- Find the project's test/build commands from
CLAUDE.md; if absent, infer frompackage.jsonscripts,Makefile,pyproject.toml, etc. If you cannot determine them, ask rather than guess. - Audit: run the test suite and the build. Capture exact failures (test name + verbatim error in a code block).
- Fix: for each failing test or build error, follow
/debug— reproduce, root-cause, then fix the cause (not the assertion). Commit each fix. - Verify: re-run the full suite and build. Green ⇒ FIXED(n). Still red after two rounds ⇒ UNFIXED blocker with the failing test and what was tried.
If this step ends UNFIXED after two rounds, stop here and report NOT READY
with the failing test. Every later step's verify phase depends on a green
suite — running fixers on a red suite is fix → hope, not fix → verify. Mark
every downstream ledger row SKIPPED("pipeline halted at Step 2"). A working
branch from Step 1.5 stays as-is (base untouched) so the fix commits are there
for the user.
Step 3: Correctness + quality — /review then /clean-code (always)
Two halves. Both sub-skills are in-tree, so they are invocable from inside any
session or tool, and Step 1.5 guarantees you are on a non-base branch, which
/review's own branch guard requires.
Correctness — /review. /review is not a report-only audit: one
invocation reads the diff, auto-applies its mechanical (AUTO-FIX) findings to
the working tree, asks you about the rest (ASK items) via its own
AskUserQuestion, and never commits. Treat one call as one atomic
audit + fix + ask unit:
- Run
/reviewagainst the base this pipeline resolved in Step 1. It has no argument channel, so it always diffsmerge-base(origin/<base>, HEAD)— if Step 1 resolved a non-default base or a--scope, say so in the ledger evidence:/reviewreviewed the full default-base diff. - Commit what it changed as one commit attributed to
/review(e.g.review: apply AUTO-FIX + approved ASK findings), so the tree is clean before/clean-codeand nothing/reviewfixed can be lost by a later revert. If--scopewas given, stage and commit only files under scope; any out-of-scope edits/reviewmade stay uncommitted (stash them so the tree is clean, noting the stash ref) and are flagged in the ledger with that ref for the user — never silently committed. For any CRITICAL it reported but could not fix, root-cause (/debug), write the failing test first (/tdd), fix, commit atomically. - Verify: run
/reviewonce more. It re-scans the full base diff including the fix commits — that's the point. A CRITICAL still present ⇒ UNFIXED blocker. Commit anything this second pass auto-fixed the same way. Do not run it a third time in this step.
/review's adversarial section runs a free Claude subagent and, when the
Codex CLI is installed and enabled, codex exec / codex review passes that
spend OpenAI tokens. Those Codex passes are ask-first under the money rule.
You are the one executing /review's instructions, so no config change is
needed: when its Codex preflight says Codex would run — CODEX_MODE: ready
in current gstack, CODEX_AVAILABLE with OLD_CFG not disabled in older
versions — ask the user once whether to spend on Codex for this run; if
declined, do not run the codex exec / codex review commands and proceed
exactly as the section's disabled/unavailable branch describes (Claude
adversarial subagent still runs). Record
the Codex state and the user's answer in the ledger. Never flip the global
codex_reviews config on the user's behalf.
CODEX_MODE: not_authed can be a false negative: gstack's preflight only
recognises a Codex login, so a Codex CLI configured for a custom provider
(e.g. model_provider = "azure" with an API key in the environment) reads as
unauthenticated while working fine. When the preflight says not_authed but
${CODEX_HOME:-$HOME/.codex}/config.toml sets a model_provider:
-
Ask first — fold it into the one Codex question above: the probe is itself a billed call on the user's provider. Declined ⇒ skip the probe and the passes.
-
Probe the model the passes will use, bounded, so a working default model cannot hide an unusable review model and a stalled endpoint cannot hang the pipeline:
source ~/.claude/skills/gstack/bin/gstack-codex-probe 2>/dev/null if ! command -v _gstack_codex_timeout_wrapper >/dev/null 2>&1; then echo "CODEX_PROBE: broken_install (gstack-codex-probe helper not found)" else _gstack_codex_timeout_wrapper 120 codex exec -s read-only \ -c "model=\"${GSTACK_CODEX_MODEL:-gpt-6-astra}\"" "Reply with exactly: PONG" < /dev/null fi -
Answers
PONG⇒ treat Codex asreadyand run the passes with that provider and model.CODEX_PROBE: broken_install, or exit code 126/127 ⇒ treat it asbroken_install(gstack's branch: reinstall advice, no model advice). Any other error, timeout or text ⇒model_unusable: skip the passes, tell the user to setGSTACK_CODEX_MODELto a deployment their provider serves.
Record the probe command, model and result in the ledger either way.
If /review cannot run at all (the gstack install is broken), apply its
checklist
(~/.claude/skills/gstack/review/checklist.md) to origin/<base>..HEAD via a
fresh subagent, fix and re-verify the same way, and say so in the ledger — do
not skip the correctness step.
Quality — /clean-code. After correctness is green and committed, run
/clean-code <diff-ref> [--scope <paths>] with the diff ref and scope this
pipeline resolved. It audits KISS / DRY / SOLID / YAGNI against ENGINEERING_STANDARDS.md,
applies the smallest safe refactor per finding under a green suite
(characterization test first where none exists), commits each atomically,
re-audits, and reverts a failed refactor with git checkout on only the files
it touched. Its findings left UNFIXED are warnings here, not blockers — quality
debt ships with a note; bugs don't.
/code-review ultra (deep multi-agent cloud review) is billed — when a
/review finding is high-stakes (payments, auth, data loss, concurrency), ask
the user whether to launch it. Do not launch it unasked. Claude Code's
built-in /code-review and /simplify are not part of this step: they can't
be invoked from inside a session, and an optional extra pass would have no
ledger row.
Step 4: Security pipeline — /defense, /iac-scan, /pentest, /fuzz
/defense (always).
- Audit: run
/defensescoped to the changed files (OWASP Top 10 / secrets / auth / crypto / data-protection). - Fix: remediate every CRITICAL/HIGH (and cheap MEDIUMs): remove or rotate-and-externalize hardcoded secrets, add the missing authz check, parameterize the query, escape the output, switch the weak primitive, add the validation. Each fix gets a regression test where a test can express it (e.g. "unauthenticated request to X returns 401"). Commit atomically.
- Verify: re-run
/defenseon the same files; the finding must be gone.
/iac-scan (when infra/deploy config changed). Trigger on Dockerfile,
docker-compose*, *.tf/*.tfvars, k8s/Helm manifests, .github/workflows/**,
.gitlab-ci.yml, Jenkinsfile, nginx/cloud config (see /iac-scan's trigger
section for the authoritative list). Audit with the local static linters, fix
CRITICAL/HIGH misconfigs (root container → non-root user, 0.0.0.0/0 ingress →
scoped CIDR, wildcard IAM → least privilege, privileged pod → dropped, untrusted
CI trigger → pinned/guarded, baked-in secret → injected), re-scan to verify.
/pentest (triggered when /defense found CRITICAL/HIGH, or the diff touches
auth/crypto/session/token/deserialization/file-upload paths). It is an external
scanner: confirm authorization with the user first (the skill's own
questions), then run it. Fix CRITICAL/HIGH it surfaces, re-scan to verify. If the
user declines or the scanner is unavailable ⇒ SKIPPED(reason). If CLAUDE.md
marks /pentest MANDATORY, SKIPPED is a blocker.
/fuzz (triggered when the diff adds or changes endpoints, input parsing,
file-upload handling, or deserialization). Needs a running target: find the dev
URL (CLAUDE.md, or start the dev script). Run /fuzz against the new
surface; fix crashes, injections, and auth bypasses it surfaces (with a
regression test); re-fuzz to verify. No reachable target and none startable ⇒
SKIPPED(reason). If CLAUDE.md marks /fuzz MANDATORY, SKIPPED is a blocker.
/cso backstop. If the diff crosses a new trust boundary (new auth
path/endpoint/external input/deserialization) and there's no evidence a threat
model was done at plan time, run /cso on that boundary and fold any
CRITICAL/HIGH into the /defense fix round. Threat modeling belongs in
/write-plan; this is the late catch, not a substitute.
Step 5: Database pipeline — /db-optimize (auto-run if triggered)
Trigger when changed files match ORM models, migrations, query builders
(**/models/**, **/migrations/**, **/queries/**, **/*repository*,
**/*.sql), raw SQL in the diff, or new ORM calls (.find, .where,
.includes, .join, .preload).
- Audit: run
/db-optimizescoped to matched files (run/dbmapfirst if it asks for a schema map). - Fix: N+1s on hot paths → eager-load/batch (
includes/preload/select_related/dataloader); missing indexes on hot paths → add a migration for the index; obviously-redundant queries → dedupe. Add a test that asserts the query count where the ORM supports it. Commit atomically. - Verify: re-run
/db-optimize; the hot-path findings must be gone and the migration must apply cleanly in the test run.
Non-hot-path suggestions are warnings (fix if trivial). No trigger ⇒ NOT-TRIGGERED.
Step 6: Frontend perf pipeline — /web-perf (+ /perf-profile)
Trigger when the diff includes frontend code (**/*.tsx, **/*.jsx,
**/*.vue, **/*.svelte, **/components/**, **/pages/**, **/styles/**,
**/*.css, **/*.scss), new images/fonts/assets, or bundler config
(next.config.*, vite.config.*, webpack.config.*).
- Find the dev URL (
CLAUDE.md, or thedevscript inpackage.json). A human is present, so start the dev server if it isn't running. Only if no app is running and none can be started ⇒ SKIPPED("no reachable dev server, start failed: "). - Audit: run
/web-perfagainst the affected routes. Record Core Web Vitals (LCP, INP, CLS) vs. any known budget. - Fix: address the measured regressions attributable to the diff — render-blocking imports → defer/lazy, oversized image/font → optimize or preload, layout shift → reserve dimensions, long task → split/memoize. Commit atomically.
- Verify: re-run
/web-perfon the same routes; report before/after numbers.
- A budget breach that survives the fix round is a warning by default,
unless
CLAUDE.mddefines a hard perf gate — then it blocks. /perf-profile(triggered when the diff touches hot server-side paths, the change is pre-launch, or/db-optimize//web-perfpoint at a server-side bottleneck): run it against the affected endpoint/job, fix the localized bottleneck (cache, batch, move off the request path), re-profile to verify. Needs a representative workload — if none is available ⇒ SKIPPED(reason).
Step 7: Browser QA pipeline — /qa (auto-run if triggered)
Run
/qa— the full test → fix → re-verify loop — not/qa-only. This is the check that replaces manual click-through QA, and a human is present.
Trigger when the diff includes anything a human would manually QA in a browser: UI/frontend code, pages/routes, forms, route handlers serving HTML, API endpoints the UI consumes, auth/session flows, or config that changes user-facing behavior.
- Start the dev server if needed (same URL as Step 6).
- Run
/qascoped to the affected surface at the project's QA tier (CLAUDE.md, defaultstandard: critical + high + medium)./qaitself does the audit → fix → re-verify loop with atomic commits and before/after health scores — let it run to completion; don't cut it off at the report. - Fold its before/after health score, fixed-bug list (with commits), and any bugs it could not fix into the ledger.
- User-facing CRITICAL/HIGH bugs that
/qacould not fix ⇒ UNFIXED blocker. - No reachable app and none startable ⇒ SKIPPED(reason) — and note that this means the feature has not been browser-tested at all.
Step 8: Design + accessibility pipeline — /design-review, /a11y
/design-review (when the diff includes UI changes, unless CLAUDE.md opts
out). Run /design-review against the changed screens — it audits visual
consistency, hierarchy, spacing, AI-slop tells and slow interactions, then
fixes them with atomic commits and before/after screenshots. Let it complete.
Visual findings it can't fix are warnings, not blockers. If the project opted
out in CLAUDE.md, record SKIPPED("project opt-out") and move on.
/a11y (when the UI change is heavy and likely to affect assistive tech —
new/changed interactive components, forms, ARIA/role/tabindex,
focus/keyboard handling, images, color/contrast, motion; see /a11y's trigger
section).
- Audit: run the static pass on the diff, and the dynamic axe pass when the dev URL is reachable (it is, if Step 6/7 ran).
- Fix: every CRITICAL/SERIOUS — native element over ARIA-on-a-div, missing label/name, unreachable-by-keyboard control, focus trap, contrast below ratio, missing reduced-motion guard. Commit atomically.
- Verify: re-run the same pass; CRITICAL that survive ⇒ UNFIXED blocker.
Scope split: /design-review owns visual quality; /a11y owns WCAG /
assistive-tech correctness. They overlap on contrast — /a11y's measured
contrast finding is authoritative.
Step 9: Coverage pipeline — /test-coverage + /playwright
- Audit: for each changed file (including this pipeline's fix commits),
locate its test (sibling
*.test.*, paralleltests/). Use coverage data if present (coverage/,lcov.info,.coverage); else do a structural check for new exported functions / branches / error paths without an assertion. - Fix: run
/test-coverageon the diff — it writes and applies the missing unit tests (and integration tests where risk crosses a boundary), enforcing Google's Testing-on-the-Toilet practices. For user-facing flows with no e2e coverage, run/playwrightto generate and run the e2e test so a regression test is left behind. Commit atomically. - Verify: run the full suite; the new tests must pass, and the structural check must show no new public surface with zero tests.
New public surface still untested after this step ⇒ UNFIXED blocker. Internal helpers without tests are warnings.
Step 10: Final verification pass, ledger, verdict
The fix rounds changed the branch, so verify the whole result once more:
- Fresh tests + build on the final HEAD (Step 2 commands). Stale results ⇒ NOT READY.
- Re-audit the fix commits: run
/defensescoped to the files the fix commits touched, and read the fix commits themselves (git show original-HEAD..HEAD) against/review's checklist —/reviewtakes no commit range, and Step 3 already re-ran it twice. The fixes must not introduce a CRITICAL/HIGH. If they did, one more fix + re-verify, then stop. - Diff sanity:
git log --oneline <base>..HEAD— every pipeline commit should name its check/finding; nothing outside the diff scope was touched. - Fold back the working branch if Step 1.5 created one: `git switch
Then build the accounting ledger — a row per check, each resolved to RAN-CLEAN / FIXED(n) / UNFIXED / SKIPPED(reason) / NOT-TRIGGERED / MANDATORY-FAIL. The verdict cannot be SHIP-READY while any triggered check is unaccounted or UNFIXED.
Phase-5 accounting (honest scope): /qa-full is the entry to Phase 5, so it
can only enforce the pre-ship half. It cannot verify /finish-branch,
/ship, or /land-and-deploy — those run after this pipeline, so do not claim
they're done. A passing verdict is the hard precondition for ship: only on
SHIP-READY do you hand off "Proceed to /finish-branch then /ship."
Then the verdict:
- SHIP-READY — zero blockers remaining and every triggered check
accounted for and the final pass is green. List what was fixed (commits),
warnings + follow-ups, then hand off to
/finish-branch→/ship. - NOT READY — one or more blockers survived the fix rounds (or a check is
unaccounted / MANDATORY-FAIL). List each with its file:line/test-name
evidence, what was tried, and what the user needs to decide or provide.
Tell the user to resolve and re-run
/qa-full.
Blocker set (any one ⇒ NOT READY — this is the authoritative list for the
verdict; it mirrors the superskills ENGINEERING_STANDARDS.md hard gates, kept
in sync by the maintainer). Each is evaluated after the fix rounds:
- failing test or broken build, or test/build not freshly run on final HEAD (Step 2/10)
/reviewCRITICAL correctness finding still present (Step 3)/defenseCRITICAL/HIGH security finding still present (Step 4)/fuzzCRITICAL/HIGH — crash, injection, or auth bypass — still reproducible (Step 4)/pentestCRITICAL/HIGH vulnerability still present, when it ran (Step 4)/iac-scanCRITICAL/HIGH infra misconfig still present (Step 4)- N+1 / missing index on a hot path still present (Step 5)
- CRITICAL/HIGH browser-QA bug in a user-facing flow
/qacould not fix (Step 7) /a11yCRITICAL — a control unusable by screen-reader/keyboard — still present (Step 8)- new public surface with zero tests after
/test-coverage(Step 9) - a hard perf gate breach after the fix round, only if
CLAUDE.mddefines one (Step 6) - a triggered check left unaccounted — neither run nor SKIPPED with a reason
- a
CLAUDE.md-MANDATORY check that was SKIPPED rather than run
Report format
Write to qa-full-reports/<branch>-<YYYY-MM-DD>.md (create dir; add to
.gitignore). Structure:
# QA-Full — <branch> @ <YYYY-MM-DD>
Base: <base> Range: <base>..HEAD Changed files: N (+M from fixes)
HEAD before fixes: <sha> HEAD after: <sha> Fix commits: K
## VERDICT: SHIP-READY ✅ | NOT READY ⛔
### Fixed (audit → fix → verify, each with its commit)
1. <check> — <file:line> — <finding> — fixed in <sha> — re-verified by <evidence>
- (or) None needed.
### Blockers remaining (must resolve before /finish-branch)
1. <file:line> — <evidence> — <what was tried> — <what's needed from you>
- (or) None.
### Warnings (ship with a follow-up note)
- …
## Accounting ledger (RAN-CLEAN / FIXED(n) / UNFIXED / SKIPPED(reason) / NOT-TRIGGERED / MANDATORY-FAIL)
| Check | Status | Evidence / fixes / reason |
|-------|--------|---------------------------|
| Tests & build (Step 2) | RAN-CLEAN / FIXED(n) / UNFIXED | exact command + result, fix SHAs |
| /review (Step 3) | RAN-CLEAN / FIXED(n) / UNFIXED | N findings, fix SHAs, 2nd-run result, Codex passes on/off, base used, out-of-scope stash ref if any |
| /clean-code (Step 3) | RAN-CLEAN / FIXED(n) / UNFIXED | KISS/DRY/SOLID/YAGNI findings, fix SHAs, deferred-with-reason |
| /defense (Step 4) | RAN-CLEAN / FIXED(n) / UNFIXED | N findings, fix SHAs |
| /iac-scan (Step 4) | … / NOT-TRIGGERED | infra/deploy files changed? |
| /pentest (Step 4) | … / SKIPPED(reason) / NOT-TRIGGERED | authorized? findings? |
| /fuzz (Step 4) | … / SKIPPED(reason) / NOT-TRIGGERED | target URL, findings |
| /cso (Step 4) | … / NOT-TRIGGERED | new trust boundary? threat-model evidence |
| /db-optimize (Step 5) | … / NOT-TRIGGERED | N+1 / index fixes, migration |
| /web-perf (Step 6) | … / SKIPPED(reason) / NOT-TRIGGERED | before/after LCP/INP/CLS |
| /perf-profile (Step 6) | … / SKIPPED(reason) / NOT-TRIGGERED | bottleneck, before/after |
| /qa (Step 7) | … / SKIPPED(reason) / NOT-TRIGGERED | tier, health before/after, fix SHAs |
| /design-review (Step 8) | … / SKIPPED(reason) / NOT-TRIGGERED | screens, fix SHAs |
| /a11y (Step 8) | … / SKIPPED(reason) / NOT-TRIGGERED | static + dynamic, fix SHAs |
| /test-coverage + /playwright (Step 9) | RAN-CLEAN / FIXED(n) / UNFIXED | tests added, suite result |
| Final pass (Step 10) | RAN-CLEAN / FIXED(n) / UNFIXED | fresh test/build + re-audit of fix commits |
> No row may be blank or "recommend" for a check whose trigger fired — that is an
> unaccounted-check blocker. `CLAUDE.md`-MANDATORY checks must read RAN-CLEAN or FIXED.
## Ask-first / follow-up commands
- `/code-review ultra` — (billed; offer when a high-stakes correctness concern remains)
- `/review` Codex passes — (OpenAI tokens; ask before enabling them for a run)
- `/pentest` — (if it was SKIPPED for authorization and the user now wants it)
- `/fuzz` — (if SKIPPED for lack of a target and one is now available)
- `/perf-profile` — (if SKIPPED for lack of a representative workload)
- `/finish-branch` → `/ship` — (only if VERDICT is SHIP-READY)
Print the verdict, the fixed count, the remaining-blocker count, and a 5-line summary to the chat.
Anti-patterns (do not do)
- Stopping at the report. A triggered check that found something and did not
attempt a fix has not run
/qa-full. - Running
/qa-onlyor/design-auditwhere/qa//design-revieware specified. Report-only is for discovery inside a step, never the step's end. - Claiming a finding is fixed without re-running the check that found it and the test suite (fresh evidence, not assertion).
- Pushing, opening PRs, or merging — that's
/finish-branch//ship. - Fixing outside the diff: refactoring untouched modules, bumping deps, or "while I'm here" changes. Every commit must trace to a finding.
- Landing a fix that itself breaks the bar — untested public surface, a duplicated helper, a symptom patch over an unknown root cause.
- Looping without bound. Two fix rounds per check, one final pass, then report what's left honestly.
- Launching a billed run (
/code-review ultra) or an external scanner (/pentest) without the user's explicit yes. - Declaring SHIP-READY while a check was skipped without saying which and why, or while any UNFIXED blocker remains.
- Running any sub-check against the whole repo instead of the diff.
- Treating MEDIUM/LOW findings as blockers (noise) or hiding CRITICAL/HIGH in the warnings list.
Related commands
Reuses the trigger matrix from /daily-qa (see skills/daily-qa/SKILL.md
Step 7 for the canonical globs). Differences: branch-scoped, present-human,
and it fixes and verifies instead of recommending.
Auto-run (diff-scoped; audit → fix → verify):
- Tests & build — always; failures root-caused via
/debug, proven via/verify(Step 2). /review— staff-level correctness review; findings fixed by the pipeline (Step 3)./clean-code— KISS/DRY/SOLID/YAGNI refactors on the diff, test-verified (Step 3)./defense— OWASP/secrets/auth/crypto; findings fixed by the pipeline (Step 4)./iac-scan— when infra/deploy config changed; misconfigs fixed (Step 4)./fuzz— when the diff adds endpoints/input parsing and a target is reachable (Step 4)./cso— backstop when a new trust boundary reached the pipeline unmodeled (Step 4)./db-optimize— when DB/ORM/SQL changed; N+1/index fixes applied (Step 5)./web-perf— when frontend changed; dev server started if needed; regressions fixed (Step 6)./perf-profile— when hot server paths changed / pre-launch; bottleneck fixed (Step 6)./qa— when anything user-facing changed; full test → fix → re-verify loop (Step 7)./design-review— when UI changed; fixes + commits visual issues (Step 8)./a11y— static + dynamic pass when heavy UI changed; findings fixed (Step 8)./test-coverage+/playwright— write and apply the missing tests (Step 9)./tdd,/debug,/verify— the discipline every fix in the pipeline follows.
Ask-first (need the user's explicit yes):
/code-review ultra— billed multi-agent cloud review./review's Codex passes — OpenAI tokens; per-run yes required (Step 3)./pentest— external scanner; authorization confirmation, then it runs.
Follow-up (outside the pipeline):
/code-review//simplify— Claude Code built-ins overlapping Step 3; use them by hand, the pipeline uses the in-tree/review+/clean-code.
Hand-off (only when SHIP-READY):
/finish-branch— choose how to integrate the work./ship— sync, bump VERSION, changelog, PR.