qfai 1.10.0 → 1.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +95 -25
  2. package/assets/init/.qfai/assistant/README.md +27 -0
  3. package/assets/init/.qfai/assistant/agents/completion-reviewer.md +17 -1
  4. package/assets/init/.qfai/assistant/agents/delivery-planner.md +8 -0
  5. package/assets/init/.qfai/assistant/agents/implementation-reviewer.md +12 -1
  6. package/assets/init/.qfai/assistant/agents/orchestrator.md +2 -2
  7. package/assets/init/.qfai/assistant/agents/product-experience-architect.md +2 -1
  8. package/assets/init/.qfai/assistant/agents/product-surface-reviewer.md +1 -1
  9. package/assets/init/.qfai/assistant/agents/qa-gatekeeper.md +99 -14
  10. package/assets/init/.qfai/assistant/agents/test-design-analyst.md +4 -1
  11. package/assets/init/.qfai/assistant/catalog/cli-ux-guidelines.md +3 -0
  12. package/assets/init/.qfai/assistant/catalog/test-layers-ci-lanes.md +60 -0
  13. package/assets/init/.qfai/assistant/catalog/test-layers.md +169 -87
  14. package/assets/init/.qfai/assistant/catalog/worklog-entry.schema.md +4 -3
  15. package/assets/init/.qfai/assistant/constitution/agent-selection.md +7 -1
  16. package/assets/init/.qfai/assistant/constitution/communication.md +1 -1
  17. package/assets/init/.qfai/assistant/constitution/constitution.md +8 -2
  18. package/assets/init/.qfai/assistant/constitution/drift-protocol.md +177 -14
  19. package/assets/init/.qfai/assistant/constitution/review-convergence.md +121 -0
  20. package/assets/init/.qfai/assistant/constitution/shared-skill-delegation-baseline.md +205 -89
  21. package/assets/init/.qfai/assistant/constitution/shared-skill-operating-baseline.md +59 -5
  22. package/assets/init/.qfai/assistant/manifest/agent-catalog.yml +145 -21
  23. package/assets/init/.qfai/assistant/manifest/agent-routing.yml +69 -3
  24. package/assets/init/.qfai/assistant/skills/qfai-atdd/SKILL.md +131 -74
  25. package/assets/init/.qfai/assistant/skills/qfai-atdd/references/credential-reuse.md +146 -0
  26. package/assets/init/.qfai/assistant/skills/qfai-atdd/references/red-provenance.md +498 -0
  27. package/assets/init/.qfai/assistant/skills/qfai-atdd/references/review-fix-rounds.md +128 -0
  28. package/assets/init/.qfai/assistant/skills/qfai-atdd/references/scaffolding.md +71 -0
  29. package/assets/init/.qfai/assistant/skills/qfai-atdd/references/shared-test-artifacts.md +124 -0
  30. package/assets/init/.qfai/assistant/skills/qfai-atdd/references/stale-manifest.md +34 -0
  31. package/assets/init/.qfai/assistant/skills/qfai-atdd/references/test-case-depth-checklist.md +38 -1
  32. package/assets/init/.qfai/assistant/skills/qfai-configure/SKILL.md +4 -3
  33. package/assets/init/.qfai/assistant/skills/qfai-discussion/SKILL.md +10 -8
  34. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/discussion-completion-matrix.md +23 -2
  35. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/review-cycle-playbook.md +16 -1
  36. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/ui-bearing-playbook.md +47 -11
  37. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/ui_ux/trend_scan_playbook.md +1 -1
  38. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/ui_ux_best_practices.md +6 -4
  39. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/01_Context.md +2 -2
  40. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/03_Story-Workshop.md +1 -1
  41. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/04_Sources.md +40 -6
  42. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/14_Review-Request.md +7 -7
  43. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/review/Rxx_reviewer.md +3 -3
  44. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/review/review_request.md +4 -3
  45. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/review/summary.json +3 -0
  46. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/uiux/00_index.md +14 -5
  47. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/uiux/40_screen_contracts.md +17 -1
  48. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/uiux/50_review_input_bundle.md +13 -8
  49. package/assets/init/.qfai/assistant/skills/qfai-implement/SKILL.md +83 -84
  50. package/assets/init/.qfai/assistant/skills/qfai-implement/references/checkpoint-verification.md +339 -39
  51. package/assets/init/.qfai/assistant/skills/qfai-implement/references/cross-spec-ownership.md +1 -1
  52. package/assets/init/.qfai/assistant/skills/qfai-implement/references/evidence-revision.md +348 -15
  53. package/assets/init/.qfai/assistant/skills/qfai-implement/references/execution-ledger.md +203 -32
  54. package/assets/init/.qfai/assistant/skills/qfai-implement/references/final-checklist.md +159 -12
  55. package/assets/init/.qfai/assistant/skills/qfai-implement/references/finding-classification.md +70 -5
  56. package/assets/init/.qfai/assistant/skills/qfai-implement/references/ledger-preconditions.md +55 -14
  57. package/assets/init/.qfai/assistant/skills/qfai-implement/references/parallelization-policy.md +92 -3
  58. package/assets/init/.qfai/assistant/skills/qfai-implement/references/red-not-observable.md +48 -6
  59. package/assets/init/.qfai/assistant/skills/qfai-implement/references/relevant-test-suite.md +13 -1
  60. package/assets/init/.qfai/assistant/skills/qfai-implement/references/review-artifact-layout.md +71 -9
  61. package/assets/init/.qfai/assistant/skills/qfai-implement/references/round-evidence.md +31 -7
  62. package/assets/init/.qfai/assistant/skills/qfai-implement/references/upstream-artifact-ordering.md +33 -0
  63. package/assets/init/.qfai/assistant/skills/qfai-implement/references/volume-policy.md +19 -12
  64. package/assets/init/.qfai/assistant/skills/qfai-prototyping/SKILL.md +76 -8
  65. package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/design-md-spec.md +20 -0
  66. package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/evidence-requirements.md +7 -4
  67. package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/generator-prompt.md +83 -22
  68. package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/reviewer-prompt.md +29 -4
  69. package/assets/init/.qfai/assistant/skills/qfai-sdd/SKILL.md +134 -20
  70. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/contract-artifact-rules.md +31 -3
  71. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/review-cycle-playbook.md +22 -1
  72. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-execution-playbook.md +41 -5
  73. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-phase-checklists.md +16 -4
  74. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-triage.md +77 -7
  75. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/spec-traceability-rules.md +60 -11
  76. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/ui-design-contract-normalization.md +9 -3
  77. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/change-request.md +14 -1
  78. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/contracts/ui-contract.sample.yaml +13 -3
  79. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/evidence/sdd-spec.md +5 -1
  80. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/report/preflight_summary.md +3 -2
  81. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/04_Business-Flow.md +4 -1
  82. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/05_Contracts.md +12 -5
  83. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/11_Slice-Policy.md +8 -9
  84. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/02_User-stories.md +9 -0
  85. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/tdd/test-list.md +68 -23
  86. package/assets/init/.qfai/assistant/skills/qfai-verify/SKILL.md +4 -4
  87. package/assets/init/.qfai/assistant/skills/qfai-verify/references/articles.md +1 -1
  88. package/assets/init/.qfai/assistant/skills/qfai-verify/references/validate-json-schema.md +79 -0
  89. package/assets/init/.qfai/assistant/skills/web-research/SKILL.md +3 -2
  90. package/assets/init/root/.github/workflows/qfai-tests.yml +318 -0
  91. package/assets/init/root/.github/workflows/qfai-validate.yml +327 -24
  92. package/assets/init/root/qfai.config.yaml +11 -2
  93. package/dist/cli/index.cjs +25083 -11488
  94. package/dist/cli/index.cjs.map +1 -1
  95. package/dist/cli/index.mjs +25216 -11589
  96. package/dist/cli/index.mjs.map +1 -1
  97. package/dist/index.cjs +16731 -8386
  98. package/dist/index.cjs.map +1 -1
  99. package/dist/index.d.cts +407 -17
  100. package/dist/index.d.ts +407 -17
  101. package/dist/index.mjs +16701 -8370
  102. package/dist/index.mjs.map +1 -1
  103. package/package.json +6 -1
@@ -0,0 +1,498 @@
1
+ # RED Provenance for an ATDD-owned Ledger Row
2
+
3
+ `.qfai/specs/<spec-id>/tdd/test-list.md` is `/qfai-implement`'s execution
4
+ ledger, and `qfai-implement/SKILL.md` states the split: **`Layer = E2E`,
5
+ `Layer = API` and `Layer = Integration` rows are tracked there, but their tests
6
+ are authored here.** This skill therefore writes into a ledger whose status
7
+ lifecycle it does not define.
8
+
9
+ ## What this skill produces
10
+
11
+ - **Evidence, not ledger cells.** `/qfai-implement` writes `Status`, `DR-ID`
12
+ and `Evidence` for every row — one writer, as
13
+ `constitution/drift-protocol.md` grants it. This stage produces the evidence
14
+ those cells point at, in `.qfai/evidence/atdd-<spec-id>.md` under
15
+ `## Ledger rows advanced`, and hands it over.
16
+ - The lifecycle is
17
+ `../../qfai-implement/references/execution-ledger.md#allowed-transitions`. It is
18
+ forward-only from `todo`, and `todo -> red` requires an **admissible RED**: an
19
+ assertion inside the row's own selector raised the failure, observed before
20
+ the production code that makes it pass exists
21
+ (`../../qfai-implement/references/red-admissibility.md`).
22
+
23
+ ## Why the stage order makes this a real question
24
+
25
+ Work Orders build the API and integration surfaces a journey needs (P3, P4). A
26
+ journey written _after_ its surface passes on the first run, so there is nothing
27
+ to watch fail — and `qfai-implement/SKILL.md` classifies a test that
28
+ unexpectedly passes as an anomaly bound for `exception`.
29
+
30
+ Left unaddressed, that makes `exception` the only terminal state an ATDD-owned
31
+ row can reach, and a spec closes with its journeys recorded as anomalies rather
32
+ than as completed work.
33
+
34
+ ## The three branches (MUST)
35
+
36
+ Take the first that applies, and record which one in the evidence file.
37
+
38
+ 1. **Observed RED (preferred).** Write the journey or API test **against the
39
+ current tree**, before this cycle builds any surface it needs.
40
+ 1. **Ask `/qfai-implement` for the minimal seam first — for a surface that does not exist.** A row that reached branch 1 from branch 2's first-run check has its surface already; skip to step 2 and read the note there. A test for a route
41
+ that does not exist yet fails with a 404 or an import error, and that is a
42
+ missing seam, not a RED — but the seam is production code, and this stage
43
+ owns none: its `red` phase is `acceptance-test-engineer` and
44
+ `qa-gatekeeper`, with no backend or frontend agent. Hand the row over for
45
+ its Phase Red step 3a — register the route, or add the export the test
46
+ imports, so it **resolves but does not satisfy the row's predicate** — and
47
+ come back with the seam in place. Skipping it makes the first failure of
48
+ any new-surface row a resolution error by construction; writing it here
49
+ is the ownership breach step 5 exists to prevent.
50
+
51
+ **The seam must not return the contracted status.** When the row's
52
+ predicate _is_ the status — `201` on create, `204` on delete, `403` on a
53
+ refusal — a handler registered with "the declared status" passes the
54
+ assertion the moment it exists, so there is no RED left to observe and the
55
+ row's behaviour was implemented before its test failed, which is what
56
+ branch 1 exists to prevent. Answer with a not-implemented sentinel the
57
+ contract does not use (`501`, or `500` from an explicit
58
+ `NotImplementedError`) and a **schema-compatible neutral body** — the
59
+ shape the selector decodes, with the contracted predicate absent or at a
60
+ value the row does not own. Not an empty body: a selector that decodes
61
+ JSON before asserting raises a parse error, which the admissibility rule
62
+ a few lines below rejects as a non-assertion failure, so the gate could
63
+ not accept the RED and P1c stopped. Routing resolves, the status
64
+ assertion fails on the predicate the row owns, and the RED is admissible.
65
+ If the contract genuinely uses that sentinel too, pick another status
66
+ outside its declared set — the requirement is that no assertion in this
67
+ row's selector can pass against the seam.
68
+
69
+ **Neutral, not empty.** The seam has to fail the row's predicate while
70
+ still satisfying what the selector needs to _reach_ it. An empty body
71
+ raises a parse error in a test that decodes JSON before asserting, and a
72
+ handler that throws does the same in a server that re-raises — both are
73
+ non-assertion failures
74
+ `../../qfai-implement/references/red-admissibility.md` rejects, so the row
75
+ cannot obtain an admissible RED at all. Return the status, headers and
76
+ body _shape_ the selector assumes, with only the contracted predicate
77
+ withheld.
78
+
79
+ 2. **With the scope approved (step 3), run the test.** An admissible failure is an assertion — or an
80
+ expected-status check — inside this row's own selector, naming the
81
+ predicate the row owns. Record the command and output as the row's RED
82
+ pair, **and the revision it was observed at** — `git rev-parse HEAD` for
83
+ a clean tree. An uncommitted tree is the ordinary case here, and it needs
84
+ a **content** address rather than a status one: `git status --porcelain`
85
+ names the changed paths and their states, so editing the very file under
86
+ test after the RED leaves the digest identical and a stale observation
87
+ reads as fresh. Record `working-tree+<content hash>` by the **one** procedure in
88
+ `../../qfai-implement/references/evidence-revision.md` — do not restate
89
+ it here — **the record shape least of all**: restated as
90
+ `path + NUL + blob hash` it fell behind the canonical's `kind` and `mode`,
91
+ and two spellings give a producer and a gatekeeper different addresses for
92
+ one tree. It excludes the ledger and `.qfai/evidence/**`, and a
93
+ producer hashing all of `git diff HEAD` instead got a different value from
94
+ the `qa-gatekeeper` reviewing the same tree — in the ordinary multi-row
95
+ loop, where the previous row's evidence is already written, the two
96
+ observations of one RED tree could not be matched up at all. **Not
97
+ `git stash create`** — it has no `-u`, so the tree it builds omits
98
+ untracked files, and a brand-new acceptance test is untracked in exactly
99
+ the case this address exists for.
100
+
101
+ **Record the test's own content hash as well.** The working-tree hash
102
+ covers everything at once, and Phase Green necessarily changes the
103
+ production files in it — so the reviewer cannot recompute it from the
104
+ final tree, and cannot tell "only production changed, as it should" from
105
+ "the acceptance test was edited after the handoff, so the RED is stale".
106
+ Record `RED test hash` alongside `RED revision`: a hash over the contents
107
+ of the files the row's **`Test file`** column names, plus the
108
+ acceptance-test-owned artifacts those files read — fixtures, snapshots,
109
+ expected-value JSON, test helpers. Not the production tree. Limiting it to
110
+ the test module let an edit to a snapshot or a fixture reshape the
111
+ assertion after the handoff with the hash unchanged, which is the same
112
+ stale-RED the field exists to catch; and since the working-tree hash cannot
113
+ be recomputed from the final tree, nothing else would have caught it.
114
+
115
+ **Record the manifest, not only the hash.** `RED test manifest` lists the
116
+ repo-relative path of every file that went into it, sorted, one per line —
117
+ and the hash is taken over `path + NUL + kind + NUL + mode + NUL + blob hash`
118
+ in that order, the same shape the revision manifest uses. `kind` and `mode`
119
+ are in it for the reason they are in that one, and more so here: after
120
+ Phase Green the original `RED revision` cannot be recomputed, so this hash
121
+ is the only thing still watching the test-owned artifacts — without them a
122
+ `chmod +x` on an acceptance script, or a file swapped for a symlink with
123
+ the same payload, changes how the test runs and moves nothing. Naming the _kinds_ of file is not enough:
124
+ the consumer recomputes this before GREEN, and two readers who choose
125
+ different sets get different values from an unchanged tree, so the gate
126
+ either loops or passes an edit it never looked at.
127
+
128
+ **Every entry is a file.** A directory is not an entry: it hashes to a
129
+ value that never moves, so listing `tests/fixtures/` would leave every
130
+ fixture under it free to change with the RED hash unchanged — the exact
131
+ staleness the manifest exists to catch. List each file, and keep every
132
+ parent component a real directory: a path that reaches its bytes through
133
+ a symlinked parent addresses a tree the manifest does not describe, which
134
+ a fresh clone cannot reproduce. The gate rejects both.
135
+
136
+ Not the `Selector` — that column is a test _name_ in the ordinary case
137
+ (`../../qfai-implement/references/checkpoint-verification.md` runs
138
+ `<Test file> -t '<Selector>'`), so keying the hash on it yields an empty
139
+ or guessed value and detects no edit at all. That hash **is** recomputable
140
+ later — Phase Green does not touch those files — so it is what makes the
141
+ freshness claim checkable rather than asserted.
142
+
143
+ **Both are recorded when observed, never reconstructed.**
144
+ `/qfai-implement` Phase Green changes the tree, and its completion gate
145
+ requires the handed-over RED to name the revision it was taken at
146
+ (`../../qfai-implement/references/evidence-revision.md`). A value worked
147
+ out afterwards is a guess, and a guess fails the freshness gate exactly as
148
+ a missing one does.
149
+
150
+ 3. **Scope approval — obtained before step 2 runs, listed here for the
151
+ contract it carries.** Take it first: this step requires a scope REVISE to
152
+ be settled _before_ the RED is submitted, and a REVISE changes the test or
153
+ its selector — so a RED recorded ahead of approval is evidence for a scope
154
+ that no longer exists, and its `RED test hash` addresses a file the
155
+ repair rewrites. Approve, then run.
156
+ `qfai-implement/SKILL.md` makes it the only authority on whether a
157
+ selector covers a sufficient slice of its obligation, and requires a scope
158
+ REVISE to be settled _before_ the RED is submitted. Approving the RED
159
+ first leaves the planner nothing but "keep the PASS and open a new row",
160
+ which cannot repair a handoff at the wrong granularity — the row has to be
161
+ split before its RED is taken, not after.
162
+ 4. **Submit that run to `qa-gatekeeper` (routing phase `red`) before any
163
+ production code exists, and wait for PASS.** `qfai-implement/SKILL.md`
164
+ requires an independent reviewer to confirm the RED while the surface is
165
+ still absent; a confirmation sought after it is built is post-hoc
166
+ self-attestation of a state nobody can re-observe. Record the verdict
167
+ beside the pair.
168
+ 5. **Stop there. Do not build the surface.** This skill owns acceptance
169
+ tests, not production code — `agent-routing.yml` gives its implementation
170
+ phase `acceptance-test-engineer` and no backend or frontend agent. The
171
+ surface is built by `/qfai-implement` Phase Green from this handover, and
172
+ the GREEN pair is recorded there. Branch 1's output is the RED pair, its
173
+ `qa-gatekeeper` PASS, and the `Oracle proof` plan.
174
+
175
+ Stage gate **P1b** is where steps 1-4 happen.
176
+
177
+ 2. **Falsifiability (the surface is there and the test passes on its first
178
+ run).** The usual shape when the surface predates this cycle, or this cycle
179
+ built it before the journey was written — branch 1's seam step was not taken,
180
+ or the work order sequenced surfaces first.
181
+
182
+ **Run the test before choosing this branch.** Surface existence is not the
183
+ condition; a first-run **pass** is. A surface that exists can still be wrong,
184
+ and a correct test against a buggy one fails naturally — that is an observed
185
+ RED, and the row belongs in branch 1 — **at its step 2**. Only step 1 is
186
+ skipped: the surface exists, so there is no seam to ask for. Steps 3 and 4
187
+ still run — `delivery-planner` still approves the slice before the RED is
188
+ confirmed, and `qa-gatekeeper` still passes it, because the handover table
189
+ requires that PASS on every `observed-red` entry. What the gatekeeper
190
+ confirms is not "no production code exists" but that the failure is an
191
+ assertion inside this row's selector, naming the predicate the row owns,
192
+ observed **against the tree before the fix**. Record that pair, get the
193
+ PASS, hand the fix to `/qfai-implement` Phase Green, and take the GREEN
194
+ from the corrected surface. Record the branch as `observed-red` with a note
195
+ that the surface existed and was wrong. Choosing branch 2 from existence alone sends a real,
196
+ legitimately observed defect to `exception` or to a stop, because the
197
+ mutation step cannot run against a test that is already failing and there is
198
+ no GREEN to restore to.
199
+
200
+ When it does pass: do **not** weaken it to manufacture a failure.
201
+
202
+ **The mutation is production code, so `/qfai-implement` applies it.** This
203
+ stage's `evidence` phase is `devops-ci-engineer` and `qa-gatekeeper`, and
204
+ neither owns production source — the same ownership boundary branch 1 step 5
205
+ states. Hand the row over naming the predicate to break: its Phase Red
206
+ **step 3c** applies the mutation, runs this row's selector, captures the
207
+ failure, reverts, and writes the trio into this row's entry here. The row
208
+ is not deferred waiting for evidence only that step can produce. Writing
209
+ the mutation here to "just take the evidence" is the breach the boundary
210
+ exists to prevent, and the alternative — stopping because no agent may
211
+ touch the file — sends a row with a perfectly good falsifiability story to
212
+ `exception`.
213
+
214
+ Use the shared path in
215
+ `../../qfai-implement/references/red-not-observable.md`: record `Satisfied-by`,
216
+ mutate the production predicate the journey asserts on, run this row's test
217
+ and confirm it fails, restore, and record `Falsifiability command` /
218
+ `Falsifiability result` beside the GREEN pair. `qa-gatekeeper` accepts this
219
+ form as the row's minimum evidence, and the row proceeds to `green` and
220
+ `done` normally.
221
+
222
+ **`Satisfied-by` takes whatever already implements the predicate.** The
223
+ shared reference names a sibling `TDD-NNNN` because that is its usual case,
224
+ but an ATDD surface often has none — a pre-existing route, or one this cycle
225
+ built outside the ledger. Record what actually satisfies it: a `TDD-NNNN`
226
+ when there is one, otherwise the production **path and symbol**
227
+ (`src/api/routes/evaluations.py::register`). What the field has to answer is
228
+ "what would I mutate to falsify this row", and a path and symbol answer it as
229
+ well as a row id does. **A commit id does not**, and is not an alternative
230
+ form: a commit that touches several routes and a helper names no single
231
+ predicate, so `qa-gatekeeper`'s boundary — owned code is the predicate
232
+ `Satisfied-by` names — cannot be applied to it, and it either REVISEs a
233
+ correct mutation or accepts an unrelated one. Add the commit alongside if it
234
+ helps whoever reads the row later; it does not stand in for the symbol.
235
+
236
+ **The row still moves `todo -> red -> green`.** Falsifiability _is_ the RED
237
+ for this row — `red-not-observable.md` says so for its own case and
238
+ `qa-gatekeeper` accepts it as the row's minimum evidence — so the mutation
239
+ run satisfies `todo -> red` and the restored passing run is the GREEN. There
240
+ is no `todo -> green` edge and none is needed. Hand the pair over in that
241
+ order, so `/qfai-implement` writes the same two transitions it writes for
242
+ any other row.
243
+
244
+ 3. **Neither is possible.** Only then is the row an `exception`, with a `DR-*`
245
+ naming what made both branches unavailable. An obligation with no persisted
246
+ form, or one genuinely unobservable at L5, belongs here — but "the surface
247
+ was built first in this same cycle" does not, because branch 1 or 2 covers
248
+ it.
249
+
250
+ Branch 3 is the last resort, not the default. A stage that routes every row it
251
+ owns to `exception` has not measured anything; it has recorded that it did not
252
+ try branches 1 and 2.
253
+
254
+ ## Evidence shape
255
+
256
+ Exactly one form per row, never both and never neither:
257
+
258
+ | Branch | Recorded |
259
+ | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
260
+ | Observed RED | Row identity (`Layer`, `Test file`, `Selector`) and the obligation reference the `Layer` selects (`TC-ref` / `US-ref` / `CON-API-ref`), RED command+result, `RED failure mode`, `RED revision`, **`RED test hash` and its manifest**, `qa-gatekeeper` PASS, the `Oracle proof` plan |
261
+ | Falsifiability | Row identity (as above), `Satisfied-by`, `Falsifiability command`, `Falsifiability result`, `RED failure mode: falsifiability`, **`RED test hash` and its manifest**, **`Falsifiability revision`**, **`qa-gatekeeper` PASS**, GREEN pair |
262
+ | `exception` | Row identity (`Layer`, `Test file`, `Selector`) and the obligation reference the `Layer` selects, recorded **before** P1d routes the gate — its audit subject is those plus the `DR-ID` and the DR artifact, so a row without them has nothing reproducible for `qa-gatekeeper` to hash. Then write `todo -> exception` with the `DR-*` the stage recorded; do not re-derive it, and do not enter Phase Green. |
263
+
264
+ `RED failure mode` is on both rows because the consumer's per-item contract
265
+ requires it before the reviewers run, and neither branch was recording it — an
266
+ otherwise correct ATDD-owned row reached the completion gate missing a mandatory
267
+ field. On an observed RED it is the kind the failure actually was
268
+ (`assertion` | `expected-error`); on branch 2 it is `falsifiability`, which is
269
+ what that form is.
270
+
271
+ Every branch carries the row identity and the obligation reference: the audit
272
+ subject hashes them and the gatekeeper judges before `/qfai-implement` can add
273
+ anything, so recorded later they move a stored hash and left out they can be repointed.
274
+
275
+ **On a Phase 2b-seeded row the identity comes from the authored test, not from
276
+ the ledger.** That row was seeded before any test existed, so its `Test file`
277
+ and `Selector` cells are `-`; record the path and selector of the test this
278
+ stage wrote, which is the only place they exist yet. `/qfai-implement` Phase Red
279
+ step 3b writes both from this entry into the ledger in the same edit that
280
+ advances the row, so gate item 10 then compares two equal values. Copying the
281
+ `-` instead leaves the row with no writer for those cells at all — nothing later
282
+ in the chain authors the test, and the `green` existence check has no path to
283
+ check.
284
+
285
+ **Where each form lives.** The `## Ledger rows advanced` table is an index: one
286
+ row per `TDD-*`, holding the branch and an anchor. The commands and their output
287
+ go in that row's own `### TDD-NNNN` section, in fenced blocks. They cannot go in
288
+ a table cell: a GFM row is one physical line and a cell ends at every unescaped
289
+ `|`, so a multi-line run, a shell pipe or a regex alternation in the output
290
+ either truncates the proof or breaks every row below it
291
+ (`../../qfai-implement/references/execution-ledger.md#evidence-cell-contract`).
292
+
293
+ `qa-gatekeeper` requires an `Oracle proof` on **every** item — a named
294
+ production mutation that makes the test fail, or a recorded `equivalent-mutant`
295
+ — because a passing run does not show the test depends on the behaviour the row
296
+ owns. A natural RED is not a substitute: it shows the test failed before the
297
+ code existed, not that it discriminates once the code does. Branch 2 satisfies
298
+ this with the mutation it already performs; branch 1 names the mutation it
299
+ intends and `/qfai-implement` records the run at GREEN, when there is production
300
+ code to mutate.
301
+ Criteria: `../../qfai-implement/references/oracle-strength.md`.
302
+
303
+ The `Evidence` cell is a pointer; the payload lives in
304
+ `.qfai/evidence/atdd-<spec-id>.md` under `## Ledger rows advanced`
305
+ (`../../qfai-implement/references/execution-ledger.md#evidence-cell-encoding`).
306
+
307
+ ## Handover to /qfai-implement
308
+
309
+ `/qfai-implement` Phase Red step 3b routes an `E2E` / `API` row here instead of
310
+ through its own steps 4 and 5. Those steps re-run the test and watch it fail —
311
+ but by the time that skill reaches the row, the surface exists, so the run
312
+ passes and step 5 classifies it as an anomaly bound for `exception`. That is the
313
+ terminal state branch 2 exists to avoid, reached through the branch itself.
314
+
315
+ Read the row's entry and take the branch it names:
316
+
317
+ | Branch | What `/qfai-implement` does |
318
+ | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
319
+ | `observed-red` | Verify the RED pair names this row's selector and the predicate it owns and that `qa-gatekeeper` passed it, write `todo -> red` from it, then run Phase Green normally — the surface does not exist yet, and building it is this skill's work. Do **not** re-run for a second RED. |
320
+ | `falsifiability` | If the trio is present, verify it and treat the mutation run as `todo -> red` with the restored run as GREEN. If it is not — the ordinary case, since only this skill owns the production code the mutation touches — Phase Red **step 3c** performs it and writes it here first. |
321
+ | `exception` | Write `todo -> exception` with the `DR-*` the stage recorded; do not re-derive it, and do not enter Phase Green. |
322
+
323
+ **A branch-2 row whose evidence is not written yet is not a stop, and not a defer either.** P1b fixes every row branch; the mutation needs production code this stage does not own, so `/qfai-implement` performs it at Phase Red step 3c and records it here. Treating the empty trio as a malformed handoff stopped the run on the first such row; deferring it left nobody able to produce the evidence, since the only phase with a production agent was waiting for it.
324
+
325
+ ## A shared test artifact outlives the row that recorded it
326
+
327
+ P1c closes one row before the next test is written, so a `done` row’s
328
+ `RED test manifest` addresses a fixture, snapshot or helper a later row may still
329
+ edit — and a `done` row has no re-entry edge of its own. Where those artifacts
330
+ are stabilised, what a later row that must edit one owes the rows that read it,
331
+ and how the resulting hash mismatch is cleared: `shared-test-artifacts.md`.
332
+
333
+ ## A spec with no ATDD-owned rows
334
+
335
+ `/qfai-sdd` Phase 2b seeds a `Layer = E2E` row per **active** `US-*` and a
336
+ `Layer = API` row per **active** `CON-API-*` **the spec owns** — ownership being
337
+ the lowest-numbered spec whose own `spec-*/01..10` / `16_*` files name that
338
+ contract — alongside its rows for
339
+ coverage-target `TC-*`. A spec that merely references a `CON-API-*` another spec
340
+ owns therefore carries no row for it, and that absence is correct, not an
341
+ incomplete Phase 2b: the row exists once, in the owner's ledger.
342
+ Both obligations are exempt in cases
343
+ `catalog/test-layers.md` names: a spec that declares no user-facing surface
344
+ owes no E2E reference for its `US-*`, and a contract at `x-qfai-status: planned`
345
+ is excluded from `QFAI-ATDD-113`. The surface exemption is itself conditional —
346
+ `QFAI-ATDD-111` is scoped by surface type **only in a project that declares at
347
+ least one UI-bearing spec**, so in a project that never declared one the
348
+ obligation stays project-wide and every `US-*` is active. A spec whose
349
+ obligations are all exempt therefore finds **zero** `Layer = E2E` /
350
+ `Layer = API` rows, legitimately, and this stage cannot create them — it is not
351
+ the ledger's writer under any circumstance — and so does a spec whose only
352
+ active `CON-API-*` belong to other specs. A spec with an **active** obligation
353
+ **it owns** finds a row, and this stage's primary procedure enumerates it and
354
+ builds the handoff from it.
355
+
356
+ Zero is a count, not "nothing to do". The US and CON-API coverage obligations
357
+ are this skill's own (Success Criteria) and are discharged by the tests and
358
+ their annotations, not by ledger rows. Report the row count as zero with that
359
+ reason and carry on with the obligations.
360
+
361
+ **Do not raise it as a request for rows.** Check the exemption and ownership
362
+ first: a spec
363
+ with no user-facing surface signal — in a project where some spec does declare
364
+ one — and no owned `CON-API-*` outside
365
+ `x-qfai-status: planned`, is _supposed_ to have none — so the request returns
366
+ nothing and the spec is handed back and forth for rows Phase 2b is right not to
367
+ seed. A genuinely missing row for an **active** obligation **this spec owns** is
368
+ an incomplete
369
+ Phase 2b: record it in this stage's report and carry on; it does not become
370
+ writable here. Writing them
371
+ here is not the alternative either: that would make this stage a second writer
372
+ of a single-writer artifact. What the completion gate actually requires is
373
+ `QFAI-ATDD-111` / `QFAI-ATDD-113` clean, which the annotations discharge and
374
+ which this stage does own
375
+ (`../../qfai-implement/SKILL.md`, spec completion conditions).
376
+
377
+ ## A project without the `red` phase
378
+
379
+ `npx qfai init --force` regenerates `assistant/skills/**` and
380
+ `assistant/agents/**` but leaves `assistant/manifest/**` alone, so an existing
381
+ project can take this skill's update without the `red` phase it relies on — and
382
+ without the `agent-catalog.yml` role contracts the reviewers read. The gate
383
+ still applies. What is stale, why routing it by hand is not enough on its own,
384
+ and how to bring both files forward: `stale-manifest.md`.
385
+
386
+ ## What the nested run owes
387
+
388
+ P1c hands a branch-1 row to `/qfai-implement` and gets it to GREEN and its
389
+ checkpoint **before** P5 and P6; **P4b hands a branch-2 row over on the same
390
+ terms**, and it too sits before P5/P6, so both are covered by everything below.
391
+ Naming only P1c here left the falsifiability rows stopped at `refactor` by the
392
+ completion inputs their own stage had not produced yet. Either run is an **item
393
+ cycle**, not this spec's completion: its blocking reviewers judge the row's own RED/GREEN evidence, and
394
+ the completion-gate inputs — `.qfai/report/validate.log`, the coverage reports,
395
+ runtime evidence — are P5/P6 artifacts that do not exist yet and are not owed
396
+ here. **That applies to every blocking reviewer of the nested run, not only
397
+ `qa-gatekeeper`**: `completion-reviewer` is mandatory and blocking there too and
398
+ requires validate evidence, so exempting one and not the other left the first
399
+ branch-1 row stopped at the same gate for a different reason. In an item-cycle
400
+ invocation each of them judges the row's own phase-authored evidence and nothing
401
+ else (`../../../agents/qa-gatekeeper.md` and
402
+ `../../../agents/completion-reviewer.md`, the note above their completion-gate
403
+ inputs).
404
+
405
+ Requiring them would strand the first branch-1 row at `refactor`, which Phase
406
+ Red does not re-select, and P2 would never be reached — the gate blocking on
407
+ artifacts its own ordering produces later.
408
+
409
+ ## Branch 3 does not close a spec on its own
410
+
411
+ `exception` is a legal terminal status for a row and a legal outcome for this
412
+ stage. It is **not** a completion: `qfai-implement/SKILL.md` lists `exception`
413
+ as a blocking output and forbids declaring completion while one stands, unless
414
+ the row carries a **user-approved accepted-risk waiver** — a `TDDLIST-001` entry
415
+ in `.qfai/waivers.yml`.
416
+
417
+ So a branch-3 row ends in one of two places, and the stage has to say which:
418
+
419
+ - **the waiver is obtained** — user approval is a decision this stage asks for,
420
+ never one it makes. Raise it with the `DR-*` in hand: what could not be
421
+ observed, why neither branch was available, and what risk is being accepted;
422
+ - **the row is parked and the spec stays open** — recorded as such, not reported
423
+ as done.
424
+
425
+ Recording the `DR-*` and handing the row over discharges the _branch_. Treating
426
+ that as closing the spec leaves a spec that can never legally close, because
427
+ nothing later in the flow can produce the approval retroactively.
428
+
429
+ ## A `review-fix` row comes back here for a new RED
430
+
431
+ A reviewer's REVISE that asks for a change to the acceptance test returns the
432
+ row to this stage: `/qfai-implement` does not author those tests and its `red`
433
+ phase has no `acceptance-test-engineer`. What the corrected test owes — a fresh
434
+ RED when it fails, the no-round path plus a re-addressed manifest and a proof
435
+ marked stale when it passes, and where the round block goes — is in
436
+ `review-fix-rounds.md`.
437
+
438
+ ## Which stage hands a row over
439
+
440
+ All three branches are handed to `/qfai-implement`. None of them writes its own
441
+ ledger transition — that skill owns `Status` / `DR-ID` / `Evidence` for every
442
+ row — so a row `/qfai-atdd` never hands over stays at `todo` however complete
443
+ its work is. What differs is _when_, and a run consisting only of branch-2 or
444
+ only of branch-3 rows has to hand them over just as a branch-1 run does.
445
+
446
+ | Branch | Handed over | Why then |
447
+ | ---------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
448
+ | `observed-red` | P1c, one row at a time | The row ends with a deliberately failing test and no production code, and P5-P8 need a green suite. A second deliberate RED left open elsewhere fails the first full-suite checkpoint that reaches it. |
449
+ | `falsifiability` | P4b, after P4 and before P6 | The trio is produced by Phase Red **step 3c**, the only step that runs the mutation, and the mutation needs the surface P2-P4 build. The trio is the row's RED payload, so P6 has nothing to capture and P8 nothing to judge until step 3c has run. |
450
+ | `exception` | P1d, once the `DR-*` is written | Only `/qfai-implement` can write `todo -> exception`. A run with no branch-1 row otherwise ends with the Decision Record recorded and the ledger untouched. |
451
+
452
+ A branch-2 row is _passed over_ by `/qfai-implement` when it is not the named
453
+ row — see the note above — which is neither a stop nor a defer of the branch:
454
+ P4b hands it over in its turn.
455
+
456
+ ### What each stage gate owes
457
+
458
+ **P1b — choose, for every row.** A row with no branch chosen is the one that
459
+ leaves P1b with no legal transition out of `todo`. **The choice is provisional
460
+ until the row's own handoff**: re-run the test against the tree as it stands
461
+ immediately before handing the row over and take the branch that result names.
462
+ An earlier branch-1 row's production code can satisfy a later row's predicate,
463
+ so a branch recorded at P1b as `observed-red` can have no observable RED left by
464
+ the time that row's turn comes.
465
+
466
+ **P1b and P1c are one loop per `TDD-ID`**, not two phases. P1c takes each row through
467
+ GREEN and its checkpoint before the next row's failing test is written; completing every
468
+ branch-1 RED in P1b first would leave several deliberate failures open at once, and any
469
+ checkpoint that runs the full suite sees all of them. This file does not restate which
470
+ rows those are, or how often they come: the cadence is defined only in
471
+ `../../qfai-implement/references/relevant-test-suite.md#checkpoint-boundaries` and
472
+ this file states no condition of its own. Deferring the RED does not escape it either — a
473
+ spec cannot be declared complete without the spec-level boundary, which runs the full
474
+ suite unconditionally — so a stray RED is reached at the latest there, and the row whose
475
+ checkpoint it fails is then stranded at `refactor`, which Phase Red does not re-select.
476
+
477
+ **P1c — discharge branch 1, one row at a time.** Branch 1 ends with a
478
+ deliberately failing test and no production code, and this stage does not write
479
+ that code. P5-P8 require the suite and the repo quality gates to pass, which
480
+ the RED makes impossible, so the handover is not deferred to the end: run
481
+ `/qfai-implement` for the row now, let its Phase Green build the surface and
482
+ take the GREEN, and return with the tree green. Name the row in the handoff —
483
+ `/qfai-implement` passes over a branch-2 row sitting above it rather than
484
+ stopping, which is what keeps this round-trip from deadlocking against its own
485
+ P6.
486
+
487
+ **What the blocking `qa-gatekeeper` judges.** The `red` phase's gatekeeper
488
+ judges the rows that have evidence at P1b — the branch 1 ones. It cannot judge a
489
+ branch 2 row there: that row's payload is the falsifiability trio, which does
490
+ not exist yet by the same rule that lets the row leave P1b. A run whose rows are
491
+ all branch 2 passes P1b with nothing submitted, and its rows are gated when the
492
+ trio lands.
493
+
494
+ If the entry is absent, names no branch, or is malformed in any other way, the
495
+ row **stays at `todo`** and `/qfai-implement` **stops with a handoff note**.
496
+ Writing `red` first and discovering the gap afterwards parks a `red` row with
497
+ no RED behind it; inventing one for a test it did not author is a drift
498
+ violation, not a recovery.
@@ -0,0 +1,128 @@
1
+ # A `review-fix` row comes back here for a new RED
2
+
3
+ `/qfai-implement` Phase Red step 3b sends a `review-fix` row back when the
4
+ blocking reviewer's REVISE asks for a change to the acceptance test itself: that
5
+ skill does not author these tests and its `red` phase has no
6
+ `acceptance-test-engineer`. The three branches above define the **first**
7
+ handoff of a `todo` row, so this one needs its own contract.
8
+
9
+ - **Invocation.** Named by `TDD-ID`, with the reviewer's REVISE and its round
10
+ number. The row stays at `review-fix` throughout — this stage writes no
11
+ ledger cell, and `review-fix -> red` is not a transition.
12
+ - **What this stage does.** Correct the test the REVISE names, then **run it and
13
+ let the result choose the path** — the same first-run check branch 1 makes,
14
+ for the same reason.
15
+ - **It fails.** Take that as the fresh RED, exactly as branch 1 does: record
16
+ the pair, the `RED revision` and the `RED test hash`, and get
17
+ `qa-gatekeeper` PASS on that run.
18
+ - **It passes.** Many REVISEs ask for no new behaviour at all — splitting a
19
+ selector, renaming a test, making an expectation explicit — so the corrected
20
+ test passes on the first run and there is no RED to take. Demanding one
21
+ stranded the row at `review-fix`. Record the run and its revision, and
22
+ take the **no-new-behaviour path** of
23
+ `../../qfai-implement/references/round-evidence.md`: no round is opened, and
24
+ the row returns on that basis.
25
+
26
+ **A changed test invalidates the proof — on either branch.** A row whose
27
+ branch was `falsifiability` carries a proof taken against the _old_ test, and
28
+ Phase Green step 2a skips the mutation on a RED-not-observable row as
29
+ already taken, so a fresh RED on the corrected test would go to re-review
30
+ without anyone checking that it still fails when the predicate breaks. Mark
31
+ the recorded proof `stale — test replaced` whenever this stage changed the
32
+ test, whichever branch follows, and `/qfai-implement` re-takes it under the
33
+ corrected selector before the GREEN.
34
+
35
+ **Name the new identity in the handback — on either branch.** A REVISE
36
+ can ask for real behaviour _and_ a split selector at once, so the failing
37
+ branch moves the row too; the rule below is not about whether a RED came
38
+ out of it. Splitting a selector or
39
+ renaming a test changes the row's `Selector` or `Test file`, and this stage
40
+ does not write the ledger — so leaving them is a ledger that cannot run the
41
+ corrected test, and letting `/qfai-implement` update the ledger alone leaves
42
+ the evidence entry's identity copy disagreeing with it, which gate item 10
43
+ fails by construction. Hand back the new values; `/qfai-implement` writes
44
+ them to **both** the ledger and the entry's copy before the re-review, so
45
+ the check compares two updated values rather than one.
46
+
47
+ **Re-address the test.** The REVISE changed the test, so the `RED test hash`
48
+ recorded at handoff still addresses the manifest before the edit, and the
49
+ consumer checks it against the current one before the reviews
50
+ (`../../qfai-implement/SKILL.md`, the field contract) — a mismatch is sent
51
+ back here for a fresh RED, which is this same passing no-round path, for
52
+ ever. Recompute the manifest and the hash over the corrected test and
53
+ **replace** the recorded pair, marked `test-only replacement` with the
54
+ reviewer verdict that asked for it. That is what the consumer accepts in
55
+ place of a fresh RED: the reviewer judged that no new production behaviour
56
+ is owed, so there is no RED to take, and the hash's job — telling "the test
57
+ moved under the RED" from "only production changed" — is discharged by
58
+ naming the verdict that moved it.
59
+
60
+ **The transient revision moves with it.** `RED revision` on an
61
+ `observed-red` row, and `Falsifiability revision` on a `falsifiability` one,
62
+ address the tree the observation was taken against — which included the
63
+ test as it was. `../../qfai-implement/references/evidence-revision.md` makes a later change to the test
64
+ invalidate exactly that evidence, so leaving them alone either stalls the
65
+ repair for ever or pairs an old observation with a new test hash. The revision of the tree that proof ran against is recorded **by the stage
66
+ that runs it**, in a field of its own — `Replacement proof revision` — and
67
+ **not over `RED revision`**. On an `observed-red` row that RED is the
68
+ natural failure taken before the production code existed, and the round
69
+ block still describes it; overwriting its revision with the tree a later
70
+ mutation ran against made the RED subject hash a pair and a revision from
71
+ two different trees as one observation, and the pre-edit RED then stood as
72
+ evidence for the current test. Mark the field `test-only replacement` with
73
+ the verdict that asked for it and hand it over empty; `/qfai-implement`
74
+ writes the value when it re-takes the proof, exactly as step 3c does on a
75
+ first pass — this stage owns no production mutation, so it cannot know it. Recording it here would
76
+ have named the tree **before** the mutation, which is not what the
77
+ gatekeeper judged. That is
78
+ what ties the replacement to the observation a consumer can check: one
79
+ verdict, one re-taken proof, one revision, one manifest.
80
+
81
+ **Re-take the proof as well, on a row that has one.** A new hash over the
82
+ old `Oracle proof` / falsifiability result says only that somebody edited
83
+ the test; it does not say the _edited_ test still fails when the predicate
84
+ `Satisfied-by` names is broken. Clarifying an expectation or splitting a
85
+ selector can weaken an assertion by accident, and the pair would then pass
86
+ the consumer's check with a proof taken against the assertion that is gone.
87
+ So the recorded proof is **stale**, and this stage says so rather than
88
+ re-taking it: the mutation rewrites a production predicate, which is the
89
+ one thing this stage owns no agent for — the paragraph below says exactly
90
+ that about the same operation. Mark the proof `stale — test replaced`
91
+ beside the new manifest and hash, and name it in the handback. Re-running
92
+ the same mutation under the corrected selector, and the GREEN after it,
93
+ happen in `/qfai-implement`'s rework, where the production owners are
94
+ routed and where the fix and the re-review already happen. Production
95
+ behaviour is unchanged — that is what keeps this a no-round path — and this
96
+ is the evidence that the corrected test still discriminates, which no hash
97
+ can carry.
98
+
99
+ **Not falsifiability.** That form needs a production mutation, which this
100
+ stage owns no agent for and cannot hand over either: Phase Red step 3b
101
+ excludes a `review-fix` row by name and step 3c is reachable only from a
102
+ `todo` falsifiability entry, so there is nobody to produce the trio and the
103
+ row would sit at `review-fix` again. A REVISE whose repair genuinely needs
104
+ new production behaviour is not this case — that one's corrected test fails,
105
+ and the branch above applies.
106
+
107
+ - **Where it goes.** A `### Round N` block in
108
+ `.qfai/evidence/atdd-<spec-id>.md`, in the shape
109
+ `../../qfai-implement/references/round-evidence.md` defines. Not a second
110
+ `## Ledger rows advanced` entry: that section is the record of a first
111
+ handoff, and appending to it would read as one.
112
+
113
+ **Which N.** The REVISE closed the round it was given on, so a fresh RED
114
+ opens the **next** one — round `N+1` where `N` is the round the reviewer
115
+ ruled on. Writing it into the reviewer's own round mixed the original
116
+ cycle and the rework into one block, and then no reader could tell which
117
+ RED/GREEN pair the next reviewer audited. The no-round path above opens
118
+ none, so it leaves the numbering where it is. Name the number in the
119
+ handback either way.
120
+
121
+ - **Handing back.** Return to `/qfai-implement` naming the round. The
122
+ production fix and the re-review happen there, and the row leaves
123
+ `review-fix` by that skill's own path. **A proof marked
124
+ `stale — test replaced` is part of that handback**: the mutation is re-run
125
+ under the corrected selector there, before the re-review.
126
+
127
+ A REVISE that does **not** touch the acceptance test never reaches this stage;
128
+ it is production rework and stays where it is.