## 90-second read

- What: a config gate `pipeline.qa` (default off) inserts a `qa` stage at all-tasks-done. The app is already up on the dev's machine during `work` — so run a cheap first live pass before a human opens the PR.
- Lean + agentic: net-new flowctl is a single config-key default — no new subcommand, engine, or persisted artifact. The host derives scenarios in-context and drives the live app, reusing the existing `/flow-next:qa` executor.
- Evidence-aware: reads `work`'s recorded evidence and subtracts only AC proven by a deterministic re-runnable check (mapped to the R-ID) — always live-running runtime/UI/integration AC even when work narrated it done.
- Surface, don't block: idempotent (a `head_sha` freshness gate runs it at most once per head); routes on `qa_outcome` (not the Ralph `verdict` projection). SHIP/NA/BLOCKED advance; NEEDS_WORK still advances to the draft PR + surfaces findings. Merge stays human + land.

## R-ID → evidence

R-ID | Criterion | Task | Commit
--- | --- | --- | ---
`R1` | Config gate `pipeline.qa` (default off) inserts `qa` at all-done | .2 | `116603e`
`R1b` | Idempotent — classify `qa` only when no fresh `qa_verdict` receipt (`id` + `head_sha`) | .2 | `116603e`
`R2` | Lean+agentic — no new flowctl subcommand/engine (one config default), no artifact | .1 | `8c945e9`
`R3` | Reverses "QA never a stage" only under the gate; other five stay forbidden | .2 | `116603e`
`R4` | Evidence-aware — subtract only mapped+deterministic AC; runtime/UI always live | .1 | `8c945e9`
`R5` | SHIP needs captured live evidence; work narration never counts | .1 | `8c945e9`
`R6` | Augmenting, local-dev scope; BLOCKED/NA advance; not a CI/staging/manual replacement | .2 | `116603e`
`R7` | Verdict surfaced not loop-blocked — routes on `qa_outcome`; NEEDS_WORK → draft PR | .2 | `116603e`
`R8` | Receipts only at hand-off — existing `qa_verdict` gains additive fields, no new artifact | .1 | `8c945e9`
`R9` | Autonomy-safe + full doc sweep (4 repos) + Codex mirror | .3 | `3540744`

9/9 covered — no uncovered acceptance criteria.

## Churn map · by review intent

File | Intent | Churn
--- | --- | ---
`skills/flow-next-qa/workflow.md` | Evidence-aware subtraction + autonomous-mode + receipt writer — read first | +124/−30
`skills/flow-next-pilot/workflow.md` | The `qa` stage: classify / idempotence / dispatch / verify | +84/−1
`skills/flow-next-make-pr/workflow.md` | New `## Live QA` section reads the receipt into the PR body | +68/−2
`scripts/flowctl.py` (×2 copies) | The one flowctl touch — `pipeline.qa` config default | +14
`tests/test_pipeline_qa_config.py` NEW + `test_qa_receipt.py` | Regression: gate default, routing, receipt fields | +321
`codex/skills/…` | Codex mirror (sync-codex.sh) | regen
`docs/ralph.md`, `docs/README.md`, `README.md`, `CHANGELOG.md`, `docs/flowctl.md` | Pipeline docs + `## Unreleased` entry | +17

## Where to look

- The gate routes on `qa_outcome`, NOT `verdict` — the qa workflow projects `BLOCKED→verdict=NEEDS_WORK` for Ralph; the pilot gate must read `qa_outcome` so BLOCKED advances. Confirm in `pilot/workflow.md` classify/verify.
- Idempotence — `qa` classified only when no fresh `qa_verdict` (`receipt.id == spec` AND `head_sha == spec-branch head` AND terminal `qa_outcome`); a fresh receipt falls through to make-pr. Single-tick pilot would otherwise re-classify forever.
- Conservative evidence subtraction (`qa/workflow.md` §2.0) — only an AC whose R-ID is `satisfies`-mapped AND covered by a deterministic re-runnable test is dropped; `verification_summary`/commits/files never subtract.
- make-pr `## Live QA` — reads `.flow/review-receipts/qa-<id>.json` (guarded), surfaces `qa_outcome` + `open_p0p1` objects + `rid_coverage`. jq-read only, no shell-JSON interpolation.
- Config default — `pipeline.qa: "off"` (string enum, not bool) in `get_default_config()`; both `flowctl.py` copies in lockstep (dual-copy invariant).

## Risk register

- default off With the gate off, pilot's stage set is byte-for-byte unchanged — zero overhead, opt-in only.
- augments This is a cheap first live pass, not a replacement for CI/staging/manual QA — it reduces human work agentically and surfaces problems to humans, who still own go/no-go. Framing sharpened across the docs.
- never blocks `NEEDS_WORK` still ships the draft PR with the findings surfaced; `BLOCKED` (no live app) advances cleanly. The loop never hard-stalls on QA (DORA: advisory > blocking gates).
- deferred No version bump — staged under `## Unreleased`; flow-next.dev / AI×SDLC / GF microsite committed but not pushed (batched with fn-71's docs).

Generated by /flow-next:make-pr from fn-72-qa-as-an-optional-pipeline-stage-spec against origin/main · 2026-06-27 · regenerable; the markdown PR body is the record.