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.
- package/README.md +95 -25
- package/assets/init/.qfai/assistant/README.md +27 -0
- package/assets/init/.qfai/assistant/agents/completion-reviewer.md +17 -1
- package/assets/init/.qfai/assistant/agents/delivery-planner.md +8 -0
- package/assets/init/.qfai/assistant/agents/implementation-reviewer.md +12 -1
- package/assets/init/.qfai/assistant/agents/orchestrator.md +2 -2
- package/assets/init/.qfai/assistant/agents/product-experience-architect.md +2 -1
- package/assets/init/.qfai/assistant/agents/product-surface-reviewer.md +1 -1
- package/assets/init/.qfai/assistant/agents/qa-gatekeeper.md +99 -14
- package/assets/init/.qfai/assistant/agents/test-design-analyst.md +4 -1
- package/assets/init/.qfai/assistant/catalog/cli-ux-guidelines.md +3 -0
- package/assets/init/.qfai/assistant/catalog/test-layers-ci-lanes.md +60 -0
- package/assets/init/.qfai/assistant/catalog/test-layers.md +169 -87
- package/assets/init/.qfai/assistant/catalog/worklog-entry.schema.md +4 -3
- package/assets/init/.qfai/assistant/constitution/agent-selection.md +7 -1
- package/assets/init/.qfai/assistant/constitution/communication.md +1 -1
- package/assets/init/.qfai/assistant/constitution/constitution.md +8 -2
- package/assets/init/.qfai/assistant/constitution/drift-protocol.md +177 -14
- package/assets/init/.qfai/assistant/constitution/review-convergence.md +121 -0
- package/assets/init/.qfai/assistant/constitution/shared-skill-delegation-baseline.md +205 -89
- package/assets/init/.qfai/assistant/constitution/shared-skill-operating-baseline.md +59 -5
- package/assets/init/.qfai/assistant/manifest/agent-catalog.yml +145 -21
- package/assets/init/.qfai/assistant/manifest/agent-routing.yml +69 -3
- package/assets/init/.qfai/assistant/skills/qfai-atdd/SKILL.md +131 -74
- package/assets/init/.qfai/assistant/skills/qfai-atdd/references/credential-reuse.md +146 -0
- package/assets/init/.qfai/assistant/skills/qfai-atdd/references/red-provenance.md +498 -0
- package/assets/init/.qfai/assistant/skills/qfai-atdd/references/review-fix-rounds.md +128 -0
- package/assets/init/.qfai/assistant/skills/qfai-atdd/references/scaffolding.md +71 -0
- package/assets/init/.qfai/assistant/skills/qfai-atdd/references/shared-test-artifacts.md +124 -0
- package/assets/init/.qfai/assistant/skills/qfai-atdd/references/stale-manifest.md +34 -0
- package/assets/init/.qfai/assistant/skills/qfai-atdd/references/test-case-depth-checklist.md +38 -1
- package/assets/init/.qfai/assistant/skills/qfai-configure/SKILL.md +4 -3
- package/assets/init/.qfai/assistant/skills/qfai-discussion/SKILL.md +10 -8
- package/assets/init/.qfai/assistant/skills/qfai-discussion/references/discussion-completion-matrix.md +23 -2
- package/assets/init/.qfai/assistant/skills/qfai-discussion/references/review-cycle-playbook.md +16 -1
- package/assets/init/.qfai/assistant/skills/qfai-discussion/references/ui-bearing-playbook.md +47 -11
- package/assets/init/.qfai/assistant/skills/qfai-discussion/references/ui_ux/trend_scan_playbook.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-discussion/references/ui_ux_best_practices.md +6 -4
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/01_Context.md +2 -2
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/03_Story-Workshop.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/04_Sources.md +40 -6
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/14_Review-Request.md +7 -7
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/review/Rxx_reviewer.md +3 -3
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/review/review_request.md +4 -3
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/review/summary.json +3 -0
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/uiux/00_index.md +14 -5
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/uiux/40_screen_contracts.md +17 -1
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/uiux/50_review_input_bundle.md +13 -8
- package/assets/init/.qfai/assistant/skills/qfai-implement/SKILL.md +83 -84
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/checkpoint-verification.md +339 -39
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/cross-spec-ownership.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/evidence-revision.md +348 -15
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/execution-ledger.md +203 -32
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/final-checklist.md +159 -12
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/finding-classification.md +70 -5
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/ledger-preconditions.md +55 -14
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/parallelization-policy.md +92 -3
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/red-not-observable.md +48 -6
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/relevant-test-suite.md +13 -1
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/review-artifact-layout.md +71 -9
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/round-evidence.md +31 -7
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/upstream-artifact-ordering.md +33 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/volume-policy.md +19 -12
- package/assets/init/.qfai/assistant/skills/qfai-prototyping/SKILL.md +76 -8
- package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/design-md-spec.md +20 -0
- package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/evidence-requirements.md +7 -4
- package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/generator-prompt.md +83 -22
- package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/reviewer-prompt.md +29 -4
- package/assets/init/.qfai/assistant/skills/qfai-sdd/SKILL.md +134 -20
- package/assets/init/.qfai/assistant/skills/qfai-sdd/references/contract-artifact-rules.md +31 -3
- package/assets/init/.qfai/assistant/skills/qfai-sdd/references/review-cycle-playbook.md +22 -1
- package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-execution-playbook.md +41 -5
- package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-phase-checklists.md +16 -4
- package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-triage.md +77 -7
- package/assets/init/.qfai/assistant/skills/qfai-sdd/references/spec-traceability-rules.md +60 -11
- package/assets/init/.qfai/assistant/skills/qfai-sdd/references/ui-design-contract-normalization.md +9 -3
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/change-request.md +14 -1
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/contracts/ui-contract.sample.yaml +13 -3
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/evidence/sdd-spec.md +5 -1
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/report/preflight_summary.md +3 -2
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/04_Business-Flow.md +4 -1
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/05_Contracts.md +12 -5
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/11_Slice-Policy.md +8 -9
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/02_User-stories.md +9 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/tdd/test-list.md +68 -23
- package/assets/init/.qfai/assistant/skills/qfai-verify/SKILL.md +4 -4
- package/assets/init/.qfai/assistant/skills/qfai-verify/references/articles.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-verify/references/validate-json-schema.md +79 -0
- package/assets/init/.qfai/assistant/skills/web-research/SKILL.md +3 -2
- package/assets/init/root/.github/workflows/qfai-tests.yml +318 -0
- package/assets/init/root/.github/workflows/qfai-validate.yml +327 -24
- package/assets/init/root/qfai.config.yaml +11 -2
- package/dist/cli/index.cjs +25083 -11488
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.mjs +25216 -11589
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.cjs +16731 -8386
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +407 -17
- package/dist/index.d.ts +407 -17
- package/dist/index.mjs +16701 -8370
- package/dist/index.mjs.map +1 -1
- 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.
|