qfai 1.10.1 → 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 (90) hide show
  1. package/README.md +77 -22
  2. package/assets/init/.qfai/assistant/agents/completion-reviewer.md +1 -1
  3. package/assets/init/.qfai/assistant/agents/implementation-reviewer.md +3 -3
  4. package/assets/init/.qfai/assistant/agents/orchestrator.md +2 -2
  5. package/assets/init/.qfai/assistant/agents/product-experience-architect.md +2 -1
  6. package/assets/init/.qfai/assistant/agents/product-surface-reviewer.md +1 -1
  7. package/assets/init/.qfai/assistant/agents/qa-gatekeeper.md +5 -5
  8. package/assets/init/.qfai/assistant/agents/test-design-analyst.md +3 -2
  9. package/assets/init/.qfai/assistant/catalog/cli-ux-guidelines.md +3 -0
  10. package/assets/init/.qfai/assistant/catalog/test-layers.md +87 -81
  11. package/assets/init/.qfai/assistant/catalog/worklog-entry.schema.md +4 -3
  12. package/assets/init/.qfai/assistant/constitution/agent-selection.md +7 -1
  13. package/assets/init/.qfai/assistant/constitution/communication.md +1 -1
  14. package/assets/init/.qfai/assistant/constitution/constitution.md +7 -1
  15. package/assets/init/.qfai/assistant/constitution/drift-protocol.md +117 -9
  16. package/assets/init/.qfai/assistant/constitution/review-convergence.md +121 -0
  17. package/assets/init/.qfai/assistant/constitution/shared-skill-delegation-baseline.md +32 -91
  18. package/assets/init/.qfai/assistant/constitution/shared-skill-operating-baseline.md +59 -5
  19. package/assets/init/.qfai/assistant/manifest/agent-catalog.yml +17 -15
  20. package/assets/init/.qfai/assistant/skills/qfai-atdd/SKILL.md +12 -12
  21. package/assets/init/.qfai/assistant/skills/qfai-atdd/references/red-provenance.md +59 -17
  22. package/assets/init/.qfai/assistant/skills/qfai-atdd/references/scaffolding.md +42 -0
  23. package/assets/init/.qfai/assistant/skills/qfai-atdd/references/shared-test-artifacts.md +29 -1
  24. package/assets/init/.qfai/assistant/skills/qfai-atdd/references/test-case-depth-checklist.md +21 -12
  25. package/assets/init/.qfai/assistant/skills/qfai-configure/SKILL.md +3 -2
  26. package/assets/init/.qfai/assistant/skills/qfai-discussion/SKILL.md +10 -8
  27. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/discussion-completion-matrix.md +23 -2
  28. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/review-cycle-playbook.md +14 -3
  29. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/ui-bearing-playbook.md +47 -11
  30. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/ui_ux/trend_scan_playbook.md +1 -1
  31. package/assets/init/.qfai/assistant/skills/qfai-discussion/references/ui_ux_best_practices.md +6 -4
  32. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/01_Context.md +2 -2
  33. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/03_Story-Workshop.md +1 -1
  34. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/04_Sources.md +40 -6
  35. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/14_Review-Request.md +7 -7
  36. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/review/Rxx_reviewer.md +3 -3
  37. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/review/review_request.md +4 -3
  38. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/review/summary.json +1 -0
  39. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/uiux/00_index.md +14 -5
  40. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/uiux/40_screen_contracts.md +17 -1
  41. package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/uiux/50_review_input_bundle.md +13 -8
  42. package/assets/init/.qfai/assistant/skills/qfai-implement/SKILL.md +52 -53
  43. package/assets/init/.qfai/assistant/skills/qfai-implement/references/checkpoint-verification.md +216 -20
  44. package/assets/init/.qfai/assistant/skills/qfai-implement/references/evidence-revision.md +145 -26
  45. package/assets/init/.qfai/assistant/skills/qfai-implement/references/execution-ledger.md +94 -9
  46. package/assets/init/.qfai/assistant/skills/qfai-implement/references/final-checklist.md +147 -9
  47. package/assets/init/.qfai/assistant/skills/qfai-implement/references/finding-classification.md +70 -5
  48. package/assets/init/.qfai/assistant/skills/qfai-implement/references/ledger-preconditions.md +55 -14
  49. package/assets/init/.qfai/assistant/skills/qfai-implement/references/parallelization-policy.md +92 -3
  50. package/assets/init/.qfai/assistant/skills/qfai-implement/references/relevant-test-suite.md +13 -1
  51. package/assets/init/.qfai/assistant/skills/qfai-implement/references/review-artifact-layout.md +56 -7
  52. package/assets/init/.qfai/assistant/skills/qfai-implement/references/round-evidence.md +20 -12
  53. package/assets/init/.qfai/assistant/skills/qfai-implement/references/volume-policy.md +19 -12
  54. package/assets/init/.qfai/assistant/skills/qfai-prototyping/SKILL.md +76 -8
  55. package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/design-md-spec.md +20 -0
  56. package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/evidence-requirements.md +7 -4
  57. package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/generator-prompt.md +83 -22
  58. package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/reviewer-prompt.md +29 -4
  59. package/assets/init/.qfai/assistant/skills/qfai-sdd/SKILL.md +127 -18
  60. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/contract-artifact-rules.md +31 -3
  61. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/review-cycle-playbook.md +20 -3
  62. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-execution-playbook.md +41 -5
  63. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-phase-checklists.md +16 -4
  64. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-triage.md +77 -7
  65. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/spec-traceability-rules.md +39 -3
  66. package/assets/init/.qfai/assistant/skills/qfai-sdd/references/ui-design-contract-normalization.md +9 -3
  67. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/change-request.md +14 -1
  68. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/contracts/ui-contract.sample.yaml +13 -3
  69. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/evidence/sdd-spec.md +5 -1
  70. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/report/preflight_summary.md +3 -2
  71. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/04_Business-Flow.md +4 -1
  72. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/05_Contracts.md +12 -5
  73. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/11_Slice-Policy.md +8 -9
  74. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/02_User-stories.md +9 -0
  75. package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/tdd/test-list.md +68 -23
  76. package/assets/init/.qfai/assistant/skills/qfai-verify/SKILL.md +4 -4
  77. package/assets/init/.qfai/assistant/skills/qfai-verify/references/validate-json-schema.md +79 -0
  78. package/assets/init/.qfai/assistant/skills/web-research/SKILL.md +3 -2
  79. package/assets/init/root/qfai.config.yaml +11 -2
  80. package/dist/cli/index.cjs +13628 -3175
  81. package/dist/cli/index.cjs.map +1 -1
  82. package/dist/cli/index.mjs +13835 -3365
  83. package/dist/cli/index.mjs.map +1 -1
  84. package/dist/index.cjs +20060 -13315
  85. package/dist/index.cjs.map +1 -1
  86. package/dist/index.d.cts +262 -9
  87. package/dist/index.d.ts +262 -9
  88. package/dist/index.mjs +17052 -10315
  89. package/dist/index.mjs.map +1 -1
  90. package/package.json +2 -1
@@ -3,9 +3,8 @@
3
3
  This document is the SSOT for ATDD test-layer semantics and completion gates.
4
4
 
5
5
  For which CI lane runs which layer, see the sibling map
6
- [`test-layers-ci-lanes.md`](./test-layers-ci-lanes.md). That file is a crosswalk only — the
7
- policy loader reads this file and not that one, so nothing there can change the
8
- vocabulary declared below.
6
+ [`test-layers-ci-lanes.md`](./test-layers-ci-lanes.md). That file is a crosswalk only — the policy
7
+ loader reads this file and not that one, so nothing there can change the vocabulary declared below.
9
8
 
10
9
  ## Layer vocabulary crosswalk (normative)
11
10
 
@@ -46,21 +45,20 @@ Rules:
46
45
  ID type. A `TC-*` is answered from the directory **its own declared `Level`**
47
46
  names, which for a correctly filed row is `<testsDir>/integration/**`; see
48
47
  [Annotation routing](#annotation-routing) for the full table and the
49
- misplacement rules.
50
- L4's goal is `CON-API-*` and L5's is `US-*` (see the layer definitions
51
- below), so an oracle that lands at L4 or L5 means the obligation is misfiled:
52
- record it as `CON-API-*` or `US-*` rather than leaving a `TC-*` row at a
53
- layer whose goal is another ID type.
48
+ misplacement rules. L4's goal is `CON-API-*` and L5's is `US-*` (see the
49
+ layer definitions below), so an oracle that lands at L4 or L5 means the
50
+ obligation is misfiled: record it as `CON-API-*` or `US-*` rather than
51
+ leaving a `TC-*` row at a layer whose goal is another ID type.
54
52
  - The two code-side word lists (`tddHelpers.ts#UNIT_COMPONENT_LAYERS` /
55
53
  `#NON_COVERAGE_LAYERS`) accept both the code and the word form for the same
56
54
  layer; they MUST stay in step with this table.
57
55
 
58
56
  ## How this file is consumed
59
57
 
60
- The layer set below is read by `core/layerPolicy.ts` and is the SSOT for two
61
- checks: `QFAI-EX-005` on the legacy spec-pack layout, and `QFAI-EX-105` on the
62
- layered layout `npx qfai init` produces. Until both consumed it, the file was
63
- read, reported on, and then ignored on every modern project.
58
+ This file is the SSOT for the layer set below: `npx qfai validate` reads the layers
59
+ from here and applies them to two checks — `QFAI-EX-005` on the legacy spec-pack
60
+ layout, and `QFAI-EX-105` on the layered layout `npx qfai init` produces. Until both
61
+ consumed it, the file was read, reported on, and then ignored on every modern project.
64
62
 
65
63
  - A file that yields no layers raises `QFAI-SPACK-090` (error) rather than
66
64
  silently widening to the built-in set.
@@ -96,19 +94,19 @@ writer targets a declared layer instead.
96
94
 
97
95
  - Scope: real infrastructure integration (for example DB/queue/filesystem) within service boundaries.
98
96
  - Goal: verify `TC-*` obligations from specs.
99
- - Location rule: `tests/integration/**`.
97
+ - Location rule: `<testsDir>/integration/**`.
100
98
 
101
99
  ### L4 API
102
100
 
103
101
  - Scope: service-boundary contracts (HTTP/gRPC/etc), auth, and error contracts.
104
102
  - Goal: verify `CON-API-*` obligations from contracts.
105
- - Location rule: `tests/api/**`.
103
+ - Location rule: `<testsDir>/api/**`.
106
104
 
107
105
  ### L5 E2E
108
106
 
109
107
  - Scope: representative full-system journeys across UI/API/data.
110
108
  - Goal: verify `US-*` obligations from specs.
111
- - Location rule: `tests/e2e/**`.
109
+ - Location rule: `<testsDir>/e2e/**`.
112
110
 
113
111
  ## Layer derivation procedure (normative)
114
112
 
@@ -184,22 +182,21 @@ all-integration suite.
184
182
 
185
183
  ### Annotation routing
186
184
 
187
- The derived `Level` records which oracle owns the obligation, and the
188
- [ATDD annotation hard gate](#atdd-annotation-hard-gate) routes each obligation
189
- ID to exactly one directory. `US-*` is answered from `tests/e2e/**`
190
- (`QFAI-ATDD-111`) and `CON-API-*` from `tests/api/**` (`QFAI-ATDD-113`); those
191
- two are fixed by the ID type. A `TC-*` is answered from the directory **its own
192
- declared `Level`** names (`QFAI-ATDD-112`):
193
-
194
- | `Level` | Answered from |
195
- | ----------------------------- | ------------------------------ |
196
- | `L1`/`Unit` | no ATDD obligation |
197
- | `L2`/`Component` | no ATDD obligation |
198
- | `L3`/`Integration` | `tests/integration/**` |
199
- | `L4`/`API` | `tests/api/**` (note) |
200
- | `L5`/`E2E` | `tests/e2e/**` (note) |
201
- | none declared | `tests/integration/**` |
202
- | anything else — typo, `L3/L5` | `tests/integration/**` (note2) |
185
+ The derived `Level` records which oracle owns the obligation, and the [ATDD annotation hard
186
+ gate](#atdd-annotation-hard-gate) routes each obligation ID to exactly one directory. `US-*` is
187
+ answered from `<testsDir>/e2e/**` (`QFAI-ATDD-111`) and `CON-API-*` from `<testsDir>/api/**`
188
+ (`QFAI-ATDD-113`); those two are fixed by the ID type. A `TC-*` is answered from the directory **its
189
+ own declared `Level`** names (`QFAI-ATDD-112`):
190
+
191
+ | `Level` | Answered from |
192
+ | ----------------------------- | ----------------------------------- |
193
+ | `L1`/`Unit` | no ATDD obligation |
194
+ | `L2`/`Component` | no ATDD obligation |
195
+ | `L3`/`Integration` | `<testsDir>/integration/**` |
196
+ | `L4`/`API` | `<testsDir>/api/**` (note) |
197
+ | `L5`/`E2E` | `<testsDir>/e2e/**` (note) |
198
+ | none declared | `<testsDir>/integration/**` |
199
+ | anything else — typo, `L3/L5` | `<testsDir>/integration/**` (note2) |
203
200
 
204
201
  **(note)** A `TC-*` **should not be** at L4 or L5 — the first bullet below says
205
202
  why and what to do instead. The gate routes it there rather than rejecting it so
@@ -213,12 +210,10 @@ answer to a cell qfai cannot read, never a supported spelling: fix the cell
213
210
  (see [Obligation spanning more than one layer](#obligation-spanning-more-than-one-layer)).
214
211
  `TDDLIST_UNKNOWN_LEVEL` (`warning`) names such a cell on the ledger side.
215
212
 
216
- Exactly one directory, never two: an annotation outside the one its `Level`
217
- names is both uncovered and rejected (`QFAI-ATDD-121` / `QFAI-ATDD-122` /
218
- `QFAI-ATDD-123`), and
219
- the rejection is symmetric — an annotation left in `tests/integration/**` after
220
- its TC moved to `L4`/`L5` is rejected the same way an early one in
221
- `tests/api/**` is. Two consequences bind every `TC-*` row:
213
+ Exactly one directory, never two: an annotation outside the one its `Level` names is both uncovered
214
+ and rejected (`QFAI-ATDD-121` / `QFAI-ATDD-122` / `QFAI-ATDD-123`), and the rejection is symmetric —
215
+ an annotation left in `<testsDir>/integration/**` after its TC moved to `L4`/`L5` is rejected the
216
+ same way an early one in `<testsDir>/api/**` is. Two consequences bind every `TC-*` row:
222
217
 
223
218
  - **A `TC-*` row's `Level` stays within L1–L3.** L4's goal is `CON-API-*` and
224
219
  L5's goal is `US-*` (see the layer definitions above), so an oracle that
@@ -247,13 +242,19 @@ its TC moved to `L4`/`L5` is rejected the same way an early one in
247
242
  `tdd/test-list.md` and `TDDLIST_TC_NOT_COVERED`, not through an annotation in
248
243
  a directory ATDD scans.
249
244
 
250
- ## TestKind resolution (single source)
245
+ ## Directory → AtddTestKind (code-side, derived from the crosswalk)
251
246
 
252
- - `tests/unit/**` -> Unit
253
- - `tests/component/**` -> Component
254
- - `tests/e2e/**` -> E2E
255
- - `tests/api/**` -> API
256
- - `tests/integration/**` -> Integration
247
+ Derived from `## Layer vocabulary crosswalk (normative)`, which is the
248
+ authority for this mapping. This list only restates the three kinds the ATDD
249
+ scan can resolve:
250
+
251
+ - `<testsDir>/integration/**` -> Integration
252
+ - `<testsDir>/api/**` -> API
253
+ - `<testsDir>/e2e/**` -> E2E
254
+
255
+ L1 Unit and L2 Component resolve to no kind. They follow project convention, no
256
+ directory maps to them, and none of them is scanned — see the crosswalk rules
257
+ and `**Unit and Component owe no ATDD annotation.**` above.
257
258
 
258
259
  ## Annotation schema (code-side)
259
260
 
@@ -272,7 +273,7 @@ its TC moved to `L4`/`L5` is rejected the same way an early one in
272
273
 
273
274
  - E2E obligations:
274
275
  - Every `US-*` in a **user-facing** spec must be referenced at least once from
275
- `tests/e2e/**`. "User-facing" is the same surface **union**
276
+ `<testsDir>/e2e/**`. "User-facing" is the same surface **union**
276
277
  `/qfai-prototyping` enforces. Any one of these signals puts a spec in it:
277
278
  - frontmatter `surface_type: ui-bearing` in `01_Spec.md`;
278
279
  - a matching UI contract `.qfai/contracts/ui/<spec-id>*.yaml` — a project
@@ -286,37 +287,33 @@ its TC moved to `L4`/`L5` is rejected the same way an early one in
286
287
  - Scoping applies only when the project declares at least one UI-bearing
287
288
  spec. A project that has never declared a surface has not opted into
288
289
  surface typing, so the obligation stays project-wide for it.
290
+ - **Deferral.** A story whose acceptance cannot be observed at E2E in the current slice defers with a `- x-qfai-status: planned` meta line inside its own `US-XXXX` block (a `##`-or-deeper heading, or its catalog list entry) in `02_User-stories.md` — the same token the two contract kinds use. It leaves `QFAI-ATDD-111` and is reported as `QFAI-ATDD-118` (`info`); remove the marker when the slice is implemented. It counts only inside the story block it is written in, so one above the first `US-XXXX` heading defers nothing — one line must not drop the obligation for a whole file. It removes the test obligation, not the declaration. A deferred `US-*` stays a known ID, so an early E2E test is counted, not an unknown reference. This is per story, unlike the surface-type scoping above, a whole-spec property that would erase the siblings too.
289
291
  - Do not create an E2E tree whose only purpose is to receive annotations.
290
292
  That is the "convert all obligations into E2E" anti-pattern below.
291
293
  - Use `QFAI:SPEC-XXXX:US-YYYY` annotations.
292
294
 
293
295
  - Integration obligations (enforced today):
294
- - Every `TC-*` in specs must be referenced at least once from the directory
295
- its declared `Level` routes to: L3/Integration -> `tests/integration/**`,
296
- L4/API -> `tests/api/**`, L5/E2E -> `tests/e2e/**`. A TC with no declared
297
- `Level` defaults to `tests/integration/**`. **L1/Unit and L2/Component owe
298
- no reference at all** — see "Unit and Component owe no ATDD annotation"
299
- below. This is what `QFAI-ATDD-112` checks.
296
+ - Every `TC-*` in specs must be referenced at least once from the directory its declared `Level`
297
+ routes to: L3/Integration -> `<testsDir>/integration/**`, L4/API -> `<testsDir>/api/**`, L5/E2E
298
+ -> `<testsDir>/e2e/**`. A TC with no declared `Level` defaults to `<testsDir>/integration/**`.
299
+ **L1/Unit and L2/Component owe no reference at all** — see "Unit and Component owe no ATDD
300
+ annotation" below. This is what `QFAI-ATDD-112` checks.
300
301
  - Use `QFAI:SPEC-XXXX:TC-YYYY` annotations.
301
- - A `TC-*` annotation outside the directory its declared `Level` names is
302
- rejected (`QFAI-ATDD-121` / `QFAI-ATDD-122` / `QFAI-ATDD-123`). The rule is
303
- `Level`-relative,
304
- not a blanket ban: a `TC-*` in `tests/api/**` is rejected **unless** that TC
305
- declares `L4`/`API`, and in `tests/e2e/**` unless it declares `L5`/`E2E` —
306
- an annotation matching its own `Level` is what discharges the obligation
307
- there. A `TC-*` should not be at L4 or L5 in the first place (see
308
- "Annotation routing"): re-file that obligation as `CON-API-*` or `US-*`.
309
- But while the row exists at that `Level`, its annotation belongs in the one
310
- directory the `Level` names, and putting it anywhere else leaves the TC
311
- uncovered as well as forbidden.
312
- - Every declared `CON-DB-*` must be referenced at least once from
313
- `tests/integration/**` (`QFAI-ATDD-115`). Use `QFAI:CON-DB-XXXX`
314
- annotations. L3 owns this because a DB contract is only exercised against
315
- real infrastructure, which is L3's declared scope; a `CON-DB` reference
316
- from `tests/e2e/**` is not counted, or an end-to-end assertion that never
317
- touches the schema could close the obligation. A contract outside the
318
- current slice defers with a `-- x-qfai-status: planned` comment line,
319
- reported at `info` by `QFAI-ATDD-116` so the deferral stays visible.
302
+ - A `TC-*` annotation outside the directory its declared `Level` names is rejected
303
+ (`QFAI-ATDD-121` / `QFAI-ATDD-122` / `QFAI-ATDD-123`). The rule is `Level`-relative, not a
304
+ blanket ban: a `TC-*` in `<testsDir>/api/**` is rejected **unless** that TC declares `L4`/`API`,
305
+ and in `<testsDir>/e2e/**` unless it declares `L5`/`E2E` — an annotation matching its own
306
+ `Level` is what discharges the obligation there. A `TC-*` should not be at L4 or L5 in the first
307
+ place (see "Annotation routing"): re-file that obligation as `CON-API-*` or `US-*`. But while
308
+ the row exists at that `Level`, its annotation belongs in the one directory the `Level` names,
309
+ and putting it anywhere else leaves the TC uncovered as well as forbidden.
310
+ - Every declared `CON-DB-*` must be referenced at least once from `<testsDir>/integration/**`
311
+ (`QFAI-ATDD-115`). Use `QFAI:CON-DB-XXXX` annotations. L3 owns this because a DB contract is
312
+ only exercised against real infrastructure, which is L3's declared scope; a `CON-DB` reference
313
+ from `<testsDir>/e2e/**` is not counted, or an end-to-end assertion that never touches the
314
+ schema could close the obligation. A contract outside the current slice defers with a
315
+ `-- x-qfai-status: planned` comment line, reported at `info` by `QFAI-ATDD-116` so the
316
+ deferral stays visible.
320
317
 
321
318
  - **Unit and Component owe no ATDD annotation.** A `TC-*` whose declared
322
319
  `Level` is L1 or L2 is outside `QFAI-ATDD-112` entirely: it is not required
@@ -327,20 +324,22 @@ its TC moved to `L4`/`L5` is rejected the same way an early one in
327
324
  `qfai-atdd/SKILL.md` puts Unit and Component out of its scope, and the
328
325
  crosswalk above gives L1/L2 no mandated directory — only L3-L5 are
329
326
  directory-pinned and only those three roots are scanned.
330
- - Previously L1/L2 fell through to `tests/integration/**` — the fallback for
327
+ - Previously L1/L2 fell through to `<testsDir>/integration/**` — the fallback for
331
328
  a spec with no `Level` column at all — so every declared Unit and Component
332
329
  TC was an `error` demanding an annotation in a directory this file says is
333
330
  not its home. `QFAI-WAIVER-002` refuses waivers on `error` rules, so a
334
331
  project that filed unit tests where L1's own entry says to had no exit, and
335
332
  the only validator-clean path was duplicating every annotation into
336
- `tests/integration/**` — the all-integration collapse named under
333
+ `<testsDir>/integration/**` — the all-integration collapse named under
337
334
  Anti-patterns below.
338
335
  - **They are still gated, by the other stage.** Every coverage-target `TC-*`
339
336
  owes a `tdd/test-list.md` row, and `TDDLIST_TC_NOT_COVERED` (`error`)
340
337
  reports a missing one. L1/L2 belong to `/qfai-implement`, which is the
341
338
  stage that writes unit and component tests.
339
+
340
+ - **An annotation carrier is not a test.** The scan reads `.feature` and `.md` too, and a file's kind is read from its body: a `.feature` with a `Scenario:` declares a test, a `.md` never does, and a `.test.ts` holding only the annotation is the same ledger renamed. An obligation no carrier declares a test for clears `QFAI-ATDD-111` / `-112` / `-113` / `-115` with nothing behind it, so `QFAI-ATDD-119` (`info`) names it — a legitimate placeholder that must not read as coverage. A repo-wide gate reads `missing.<kind>` **and** `coveredByCarrierOnly` in `summary.json`, never `missing` alone; a `--spec` gate reads the narrowed `QFAI-ATDD-119` in `validate.spec-<id>.json`, because `summary.json` is repo-wide under every scope. A skipped test still counts as declared, and the partition is suppressed, not empty, when `scan.truncated` says the scan was cut short.
342
341
  - API obligations:
343
- - Every declared `CON-API-*` must be referenced at least once from `tests/api/**`.
342
+ - Every declared `CON-API-*` must be referenced at least once from `<testsDir>/api/**`.
344
343
  - Use `QFAI:CON-API-XXXX` annotations.
345
344
  - **Deferral.** `/qfai-sdd` authors contracts in Phase 0 (Contracts-first) and
346
345
  slices them in Phase 2, so a contract legitimately exists before its slice
@@ -358,20 +357,20 @@ its TC moved to `L4`/`L5` is rejected the same way an early one in
358
357
  under `deferred.conApi`, so an empty `missing.conApi` can be told apart
359
358
  from a project where every contract is still planned.
360
359
  - Forbidden references:
361
- - `tests/api/**` must not include `QFAI:SPEC-XXXX:TC-YYYY` **for a TC whose
360
+ - `<testsDir>/api/**` must not include `QFAI:SPEC-XXXX:TC-YYYY` **for a TC whose
362
361
  declared `Level` is not L4/API**. A TC that declares an API-level
363
- obligation belongs in `tests/api/**`, and its annotation there counts as
362
+ obligation belongs in `<testsDir>/api/**`, and its annotation there counts as
364
363
  coverage. The rule exists to stop obligations drifting into the wrong
365
364
  layer, not to make the correct layer unusable.
366
- - `tests/e2e/**` must not include `QFAI:SPEC-XXXX:TC-YYYY` **for a TC whose
365
+ - `<testsDir>/e2e/**` must not include `QFAI:SPEC-XXXX:TC-YYYY` **for a TC whose
367
366
  declared `Level` is not L5/E2E**. Same reason as above: the routing rule
368
367
  and the forbidden rule must agree, or the layer the routing selects
369
368
  becomes unusable.
370
- - `tests/integration/**` must not include `QFAI:SPEC-XXXX:TC-YYYY` **for a TC
369
+ - `<testsDir>/integration/**` must not include `QFAI:SPEC-XXXX:TC-YYYY` **for a TC
371
370
  whose declared `Level` is not L3/Integration** (`QFAI-ATDD-123`). The rule
372
371
  is symmetric so "exactly one directory" holds in both directions: an
373
372
  annotation left behind here after the TC moved to L4/L5 is as wrong as one
374
- filed early into `tests/api/**`.
373
+ filed early into `<testsDir>/api/**`.
375
374
  - Unknown references (`US/TC/CON-API` not declared) are errors.
376
375
  - A `TC-*` annotation outside the directory its `Level` routes to is a
377
376
  misplacement, whichever directory it lands in. **This applies to L3-L5 only.**
@@ -379,7 +378,7 @@ its TC moved to `L4`/`L5` is rejected the same way an early one in
379
378
  an annotation for one is neither required nor misplaced, in
380
379
  `tests/unit/**`, `tests/component/**` or anywhere else.
381
380
  - AC annotations are not required in code; AC coverage is treated as indirect through TC coverage.
382
- - `QFAI:CON-API-*` in `tests/e2e/**` is not forbidden, but contract guarantee belongs to API tests.
381
+ - `QFAI:CON-API-*` in `<testsDir>/e2e/**` is not forbidden, but contract guarantee belongs to API tests.
383
382
 
384
383
  ## Test-file granularity
385
384
 
@@ -472,10 +471,9 @@ Treat these as review signals in the same class as volume floors — worth a fin
472
471
  - a very low `test_` functions per file ratio in a module that carries many obligations
473
472
  - a single selector whose recorded runtime grows monotonically across RED rounds
474
473
 
475
- ## Test stub detection (QFAI-TEST-001 / QFAI-TEST-002)
474
+ ## Test stub detection (QFAI-TEST-001 / -002 / -003)
476
475
 
477
- `QFAI-TEST-001` (error) reports the silent-placeholder construct of each
478
- supported stack:
476
+ `QFAI-TEST-001` (error) reports the silent-placeholder construct of each supported stack:
479
477
 
480
478
  | Extensions | Construct |
481
479
  | -------------------- | ------------------------------------------------------------------- |
@@ -487,6 +485,14 @@ supported stack:
487
485
  | `.rb` | a line starting `skip` / `pending` |
488
486
  | `.cs` | `[Ignore` / `Skip = "` |
489
487
 
488
+ `QFAI-TEST-003` (warning) is the JS/TS `.skip` family — `it.skip(` / `test.skip(` /
489
+ `describe.skip(`, chained `.each` spellings included. It is its own rule, not a graded-down
490
+ `QFAI-TEST-001`: a waiver is judged against the highest severity its rule produced in the run,
491
+ so sharing one code would let a single `.todo` promote the pair to `error` and take the
492
+ per-path waiver in `.qfai/waivers.yml` away from every `.skip`. The fix differs too — a `.skip`
493
+ keeps its body (it is what `npx qfai atdd scaffold` emits for a skeleton awaiting
494
+ implementation), so drop the modifier rather than delete the test.
495
+
490
496
  `QFAI-TEST-002` (info) names any extension the scan opened that has no dialect.
491
497
  Without it a clean run on an unsupported stack is indistinguishable from a
492
498
  checked one — the detector used to be JS-only while file selection was
@@ -3,9 +3,10 @@
3
3
  - Contract scope: frontmatter and body schema for `.qfai/steering/*.md` entries
4
4
  - Owners: the validate stage (schema enforcement), the implement stage (primary writer) and the Reviewer-Gate stage (consumer)
5
5
  - Used-by: All implementation/review-phase skills, `npx qfai validate`, Reviewer subagents
6
- - SSOT modules:
7
- - `packages/qfai/src/core/worklog/parseEntry.ts` (pure parser: `string → Result<Entry, SchemaError>`)
8
- - `packages/qfai/src/core/worklog/validateLinks.ts` (link-integrity check)
6
+ - SSOT modules (shipped inside the QFAI package, run by `npx qfai validate`):
7
+ - the work-log entry parser (`string → Result<Entry, SchemaError>`)
8
+ - the work-log link-integrity check
9
+ - The field checks, enums and required headings are compiled into the CLI, not read from this file: this document is their reference, so editing it does not change what `validate` accepts. Report a divergence as a QFAI bug instead of customizing the schema here.
9
10
 
10
11
  ## Storage model
11
12
 
@@ -15,9 +15,15 @@ version: 2.0.0
15
15
 
16
16
  # エージェント選択ガイド(QFAI Toolkit)
17
17
 
18
- QFAI のサブエージェントは、**agent-catalog + agent-routing + review-profiles** を SSOT とする。
18
+ QFAI のサブエージェントの**選定**は、**agent-catalog + agent-routing + review-profiles** を SSOT とする。
19
19
  選定は「成果物の種類」と「phase の役割」で行い、skill 本文の直感では決めない。
20
20
 
21
+ ただしエージェントの**本文(mission / responsibilities / stop conditions 等)**の SSOT は
22
+ `.qfai/assistant/agents/<id>.md` である。`agent-catalog.yml` の `developer_instructions`
23
+ はそこから導出される派生コピーであり、そこに新しい内容を書き起こさない。本文を変更するときは
24
+ markdown 側を編集し、その `## Mission` 見出し以降をそのままブロックへ写して一致させる
25
+ (乖離もブロックの欠落も `QFAI-AGENT-014` が警告する)。
26
+
21
27
  ## 中核原則
22
28
 
23
29
  - 司令塔は常に `orchestrator`
@@ -35,7 +35,7 @@ When an agent needs to ask the user a question, the following rules apply (see a
35
35
 
36
36
  All SKILL.md files MUST include a
37
37
  `## User Questions (AskUserQuestion Protocol)` section with MUST-level wording.
38
- SSOT: `packages/qfai/assets/init/.qfai/assistant/skills/*/SKILL.md`.
38
+ SSOT: the skill templates shipped inside the QFAI package.
39
39
  Deployed copy (updated by `npx qfai init`): `.qfai/assistant/skills/*/SKILL.md`.
40
40
 
41
41
  ## Error handling
@@ -160,10 +160,16 @@ This article survives context compaction because `constitution.md` is a P1 reloa
160
160
 
161
161
  All temporary files, scratch scripts, and intermediate build artifacts **MUST** be placed under the repository‑root `tmp/` directory.
162
162
 
163
+ Scope: this article is about files written **into the working tree** — scratch
164
+ scripts, intermediate build artifacts, downloaded fixtures, notes. A sandbox a
165
+ test creates with `mkdtemp` under the OS temporary directory is **not** covered:
166
+ it lives outside the repository, so it cannot put a file in any of the
167
+ directories Rule 1 protects, and the test that created it removes it.
168
+
163
169
  Rules:
164
170
 
165
171
  1. **Never** create temporary files in the repository root, `src/`, `.qfai/specs/`, or any other production/artifact directory.
166
172
  2. Use `tmp/` (repository root) as the sole staging area. Create subdirectories as needed (e.g., `tmp/glossary/`, `tmp/build/`).
167
173
  3. `tmp/` MUST be listed in `.gitignore` so temporary files are never committed.
168
174
  4. Clean up `tmp/` contents when the task that created them is complete.
169
- 5. If a temporary file is found outside `tmp/`, treat it as a defect and move or delete it immediately.
175
+ 5. If a temporary file is found outside `tmp/` **in the working tree**, treat it as a defect and move or delete it immediately. A test's `mkdtemp` sandbox is not one — see Scope above.
@@ -13,7 +13,12 @@ Upstream artifacts include, at minimum:
13
13
  - `10_Plan.md` and other owner-phase planning outputs
14
14
  - Legacy spec-pack SSOT files when present: `spec.md`, `delta.md`, `plan.md`, `traceability-matrix.md`, `scenario.feature`, `case-catalogue.md`, and numbered pack files (for example `01_Spec.md`..`18_delta.md`)
15
15
  - contracts and schema decisions owned by earlier phases
16
- - outputs of discussion/sdd/review stages
16
+ - outputs of the sdd and review stages. A **discussion pack is NOT upstream
17
+ SSOT** — it is non-normative discovery material, and `.qfai/specs/**` is the
18
+ behaviour and design SSOT it feeds. A defect found in one downstream is fixed
19
+ in the SDD-owned artifact, the discrepancy recorded in delta/evidence. This
20
+ reclassifies ONLY the pack: genuine upstream is still repaired upstream-first.
21
+
17
22
  - **test or production artifacts another spec's completed implement run
18
23
  certifies** — a file named in another `tdd/test-list.md`'s `Test file` column
19
24
  on a `done` row. Changing one is not forbidden (the codebase is not
@@ -71,7 +76,7 @@ Any exception beyond this list requires explicit user approval.
71
76
  `/qfai-implement` must write `tdd/test-list.md` after every phase transition,
72
77
  and the file lives inside `.qfai/specs/**`. The protocol never classified it in
73
78
  either direction, but `#core-rule`'s list is explicitly open-ended ("at minimum")
74
- and sweeps in "outputs of discussion/sdd/review stages" — and the ledger's schema
79
+ and sweeps in "outputs of the sdd and review stages" — and the ledger's schema
75
80
  is documented in `skills/qfai-sdd/references/spec-traceability-rules.md`, an
76
81
  SDD-stage reference. On the natural reading the ledger _is_ an sdd-stage output,
77
82
  so "Downstream skills must not patch upstream SSOT directly" applied to it.
@@ -332,17 +337,36 @@ is a defect.
332
337
  - Every reviewer finding declares a `Traces to:` value. See
333
338
  `shared-skill-delegation-baseline.md#finding-provenance-must` for the response schema. Legal
334
339
  values:
335
- - an upstream obligation (`AC-*`, `BR-*`, `TC-*`, `CON-*`) or a named constitution/catalog rule;
340
+ - an upstream obligation (`AC-*`, `BR-*`, `TC-*`, `CON-*`) or a named constitution/catalog rule
341
+ **that governs the product's behaviour**;
336
342
  - `defect:correctness`, `defect:security`, or `defect:code-quality` — the deliverable-defect
337
343
  classes above, each of which MUST carry the concrete evidence in the changed artifacts that
338
344
  demonstrates it;
345
+ - `record:<CODE>` — a defect in the run's own record rather than in the product;
339
346
  - `none` — reviewer-originated scope.
340
- - The first two are **blocking** and gate `done`.
347
+ - The first two are **blocking** and gate `done`. `record:*` and `none` are not.
348
+ - `Traces to: record:<CODE>` is a record defect: the ledger, a round block, an evidence anchor or
349
+ the provenance prose is wrong while the product is not. It MUST be recorded as `advisory`, MUST
350
+ NOT be `blocking`, and settles in the spec's record-defect queue (`#the-record-defect-queue`)
351
+ rather than by re-running the row. `record:unchecked` is a bug report against `validateTddList`,
352
+ not against the item — a record rule worth a round is worth a validator code.
353
+ - **A record that misrepresents the run is not a record defect.** Evidence copied from a previous
354
+ round or a sibling row, an evidence anchor resolving to a run other than the one it names, and a
355
+ false `Authored/edited under review` attestation do not merely mis-state the work — they claim
356
+ work that was not done, or independence the reviewer did not have. `agents/qa-gatekeeper.md`
357
+ rejects the first two outright and
358
+ `shared-skill-delegation-baseline.md#reviewer-response-template` forbids a `PASS` on the third,
359
+ so classifying them `record:*` would let an advisory-only review return `PASS` and release
360
+ `done` over the very evidence the gate exists to reject. They stay **blocking** as
361
+ `defect:code-quality` and MUST NOT be filed as `record:*`. `record:*` covers a record that is
362
+ honestly produced and merely wrong — a tier missing from an Evidence cell, a `Satisfied-by`
363
+ naming the wrong sibling row, an unlabelled round block.
341
364
  - `Traces to: none` is reviewer-originated scope. It is **drift**, and it is **not satisfiable
342
365
  downstream**: encoding it as production code plus a hard test assertion is the same violation as
343
366
  patching upstream SSOT, inverted. It MUST be recorded as `advisory`, MUST NOT be `blocking`, and
344
367
  is routed to the Change Request / Open Question path — never to the implementer.
345
- - Routing an advisory finding:
368
+ - Routing a `none` advisory (a `record:*` advisory takes `#the-record-defect-queue` instead — the
369
+ Change Request path adjudicates product obligations and cannot repair a record):
346
370
  1. The reviewer records it in its response under `Advisory / Change Request proposals`, with
347
371
  enough context for the owner phase to adjudicate. The reviewer does **not** write it into
348
372
  `08_Open-questions.md`: that file is upstream SSOT (see `#core-rule`) and is owned by
@@ -363,10 +387,94 @@ is a defect.
363
387
  Completing against an obligation that is known to be under revision would ship a knowingly
364
388
  inconsistent SSOT.
365
389
 
390
+ ### The record-defect queue
391
+
392
+ Making `record:*` advisory removes the round it used to force. It does not remove the defect, so
393
+ the class is only honest if the defect lands somewhere with an owner and is consumed. That place is
394
+ one queue per spec, and it is defined by a destination, an owner, an entry shape and a drain.
395
+
396
+ - **Where.** A `## Record defects` section in the evidence file the reviewing stage's **own
397
+ completion contract** names. For a `/qfai-implement` review that is
398
+ `.qfai/evidence/implement-<spec-id>.md` when that file exists, otherwise
399
+ `.qfai/evidence/atdd-<spec-id>.md` — the same file rule the spec-level checkpoint boundary uses,
400
+ so a spec never has this queue in two places. **Do not derive the path from a
401
+ `<stage>-<spec-id>.md` pattern.** Each stage names its own evidence file and not every one of
402
+ them is spec-scoped — `/qfai-configure` writes `.qfai/evidence/configure-<run-id>.md`, one per
403
+ run, and has no `configure-<spec-id>.md` at all — so the pattern named files no stage creates.
404
+ Never `08_Open-questions.md`: that file is upstream SSOT owned by `/qfai-sdd` (see
405
+ `#core-rule`), and a record defect is not a product obligation.
406
+ - **The class needs a drain, so a stage whose completion contract has none does not use it.** Every
407
+ stage sharing `shared-skill-delegation-baseline.md` reads the provenance rules, but an entry is
408
+ only worth filing where something consumes it, and the queue above is defined as much by the
409
+ drain as by the destination. The test is textual and local: **that stage's own completion
410
+ conditions must require this queue drained before it declares completion.** `/qfai-implement`
411
+ states it (`skills/qfai-implement/SKILL.md#spec-completion-conditions`), and no other stage's
412
+ completion conditions mention the queue at all — so `/qfai-sdd`, `/qfai-atdd`, `/qfai-configure`,
413
+ `/qfai-verify`, `/qfai-discussion` and `/web-research` reviewers MUST NOT classify a finding
414
+ `record:*`; it keeps the class it would have had, blocking under the rule it names. A stage gains
415
+ the class by adding the drain to its completion conditions, never by being named here. A class
416
+ whose entries are written where nothing drains them is the round-dropped-and-defect-dropped
417
+ outcome this queue exists to prevent, and it is worse in the stages that never gained the queue
418
+ than the round ever was.
419
+ - **Who.** The reviewer records the finding in its response as an advisory, as for any advisory.
420
+ The **orchestrator** that dispatched the review appends it to the queue when the round closes —
421
+ the same role that owns the ledger. A finding that stays in the reviewer response and never
422
+ reaches the queue is an unrouted advisory, which the review gate already forbids.
423
+ - **Entry.** One line per defect: the `<CODE>`, the row or artifact it is against, what the record
424
+ says against what the run actually did, and the round it came from. That is what makes it
425
+ repairable later by someone who did not watch the round.
426
+ - **Drain, at the spec boundary.** Before spec-level completion is declared, every open entry is
427
+ **repaired in place**: the record is corrected to what the run did, with no row re-run and no
428
+ status change. Repair is the only close. When the rule the entry names is one no validator
429
+ checks, the entry **also** produces a validator bug report per the `record:unchecked` ratchet
430
+ above — that report tracks the missing check and does not stand in for the repair. Closing an
431
+ entry on the report alone leaves the wrong record exactly as wrong as it was, with the round
432
+ that found it already spent: a missing tier stays missing, and the item stays complete. The two
433
+ are different obligations against different backlogs. Completion is not declared while an entry
434
+ is open. This gates the **spec** boundary only: a `record:*` finding still never holds an
435
+ individual row out of `done`, which is the whole point of the class.
436
+ - **When the record cannot be repaired honestly.** Repair means writing what the run actually did,
437
+ which needs the round's artifacts to still say what that was. Where they do not — nothing
438
+ reconciles the entry with any run — the finding was never a record defect: what is missing is
439
+ not a correct record of the work but any evidence the work happened, which is the integrity case
440
+ above. Reclassify it as `defect:code-quality`, blocking, and take the ordinary REVISE path.
441
+ There is no third exit: an entry closes on a corrected record or on a blocking finding.
442
+ - **Re-attest a repair in a pack of its own; never re-run it, and never edit a sealed one.** A
443
+ defect inside a `Satisfied-by`, a round block or any other phase-authored field sits inside the
444
+ exact bytes a reviewer's `Audited evidence hash` covers, and the completion gate recomputes that
445
+ hash — so repairing in place makes a correct PASS read as stale, and skipping the recomputation
446
+ would accept evidence nobody read. Repair the record, then have a reviewer **of the role that
447
+ issued the verdict** re-read the repaired entry and emit a **record re-attestation**: the
448
+ `TDD-ID`, the same `Reviewed revision`, the same `Result`, a recomputed `Audited evidence hash`,
449
+ and the queue entry's `<CODE>`.
450
+ - **The re-attestation is a new review pack, and the pack it supersedes is left untouched.** A
451
+ verdict lives in a `review-<timestamp>/` pack fixed by a `Review pack seal` the completion gate
452
+ recomputes, so replacing that verdict's `Audited evidence hash` line where it is stored breaks
453
+ the seal by construction, and replacing only the evidence file's copy leaves the sealed reviewer
454
+ response carrying a hash nothing agrees with. Write the re-attestation as its own
455
+ `review-<timestamp>/` pack, sealed by the same procedure. The superseded verdict keeps the hash
456
+ it recorded — it was correct over the bytes it read — and its pack keeps recomputing. The
457
+ evidence entry records `Record re-attestation` beside the verdict it supersedes, with its own
458
+ `Record re-attestation pack` and `Record re-attestation pack seal`; the completion gate
459
+ recomputes the superseding hash and both seals, which is what makes the re-attestation an
460
+ artifact a validator can see rather than an untraceable edit. No code runs, no row changes
461
+ status, and it spends no round — it opens none, so it is not a `Round N:` pack. The revision a
462
+ verdict names excludes `.qfai/evidence/**`, so by construction nothing outside the record moved.
463
+ **A repair that would move the revision is not a record repair**: it is a change to the
464
+ deliverable and takes the ordinary path. A repaired entry whose verdict carries no
465
+ re-attestation is still an open entry.
466
+
467
+ An unconsumed queue would make the class worse than what it replaced: the round is gone and the
468
+ defect is gone with it. The drain is what pays for dropping the round.
469
+
366
470
  ### Which evidence is committed
367
471
 
368
- - **Regenerable** — stage evidence (`.qfai/evidence/<stage>-<spec-id>.md`),
369
- run logs, reports. Reproducible by rerunning the owner skill; not committed.
472
+ - **Durable per-item TDD evidence** — `.qfai/evidence/implement-<spec-id>.md`
473
+ and `.qfai/evidence/atdd-<spec-id>.md`. Ledger `Evidence` cells point to
474
+ anchors in these files, and validation resolves those anchors on a fresh
475
+ clone, so the managed `.gitignore` block re-includes and commits them.
476
+ - **Regenerable** — other stage logs, run logs, and reports. Reproducible by
477
+ rerunning the owner skill; not committed.
370
478
  - **Governance record** — Change Requests (`.qfai/decisions/CR-*.md`) and
371
479
  durable decision records (`.qfai/evidence/decisions/*.json`). They carry
372
480
  user approval and cannot be regenerated, so they are committed. The managed
@@ -380,8 +488,8 @@ is a defect.
380
488
  — diffs the branch against `baseBranch` and emits `QFAI-DRIFT-001` (`error`)
381
489
  for every changed file under `paths.contractsDir`, under `_policies/`, or
382
490
  matching a protected spec-pack filename. A Change Request at `Status:
383
- approved` that **names the changed path** silences it; an `open` CR does not,
384
- because an open CR authorises nothing. The check does not run in the `sdd`
491
+ approved` whose **`## Impact scope` names the changed path** silences it — not
492
+ a path named elsewhere in it, not a contract ID, and never an `open` CR. The check does not run in the `sdd`
385
493
  profile: `/qfai-sdd` owns these files.
386
494
  - Downstream reviewers must not originate binding obligations that upstream SSOT does not contain.
387
495
  - If approval is not available, stay in STOP state **for that CR's blocked set**