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,60 @@
|
|
|
1
|
+
# Test layers to CI lanes
|
|
2
|
+
|
|
3
|
+
A crosswalk between the test layers in [`test-layers.md`](./test-layers.md) and the CI lanes
|
|
4
|
+
the shipped workflows run. It exists so that "which job runs my L3 tests" has one answer a
|
|
5
|
+
reader can find, instead of being rediscovered from a workflow file each time.
|
|
6
|
+
|
|
7
|
+
**The layer policy loader does not read this file.** (Written without a hyphen on purpose: the
|
|
8
|
+
loader extracts anything matching `layer-<word>` from the file it parses, and while it does not
|
|
9
|
+
parse this one, a catalog-directory file carrying such a token is a hazard waiting for the day
|
|
10
|
+
someone widens the loader to scan the directory.) It resolves `catalog/test-layers.md` by
|
|
11
|
+
exact path and reads nothing else in this directory, so nothing written here can widen or
|
|
12
|
+
narrow the layer vocabulary. That is deliberate: this document is a map, and a map that could
|
|
13
|
+
change the territory would be a second source of truth for something that already has one. If
|
|
14
|
+
you need to change what layers exist, change `test-layers.md` — this file follows.
|
|
15
|
+
|
|
16
|
+
## The mapping
|
|
17
|
+
|
|
18
|
+
| Layer | What it exercises | Shipped CI lane |
|
|
19
|
+
| -------------- | --------------------------------------------- | --------------- |
|
|
20
|
+
| L1 Unit | one module, no I/O | `unit` |
|
|
21
|
+
| L2 Component | one component and its immediate collaborators | `component` |
|
|
22
|
+
| L3 Integration | several modules across a real boundary | `integration` |
|
|
23
|
+
| L4 API | a running interface, contract-first | `api` |
|
|
24
|
+
| L5 E2E | the product as a user reaches it | `e2e` |
|
|
25
|
+
|
|
26
|
+
Two lanes in the shipped workflow are not layers and have no row above:
|
|
27
|
+
|
|
28
|
+
- **`detection`** decides which of the lanes above need to run for a given change, and
|
|
29
|
+
publishes that decision as job outputs. It is infrastructure, not a test level.
|
|
30
|
+
- **`verdict`** aggregates the lanes into the single status a branch-protection rule can name.
|
|
31
|
+
It runs unconditionally so that a run where every lane was skipped is still distinguishable
|
|
32
|
+
from a run where nothing was verified.
|
|
33
|
+
|
|
34
|
+
## Lane names are a project's choice
|
|
35
|
+
|
|
36
|
+
The names in the third column are the ones the shipped workflow uses. They are not a contract:
|
|
37
|
+
a project that calls its integration lane `service-tests` is not violating anything, and this
|
|
38
|
+
table is not a rename list. What matters is that each layer a project uses has some lane that
|
|
39
|
+
runs it, and that the lane's name stays put once branch protection refers to it — a check name
|
|
40
|
+
is a repository setting, and renaming one silently makes a required check unsatisfiable.
|
|
41
|
+
|
|
42
|
+
## Per-level routing is not enforced
|
|
43
|
+
|
|
44
|
+
`test-layers.md` marks per-level annotation routing as a target state and says plainly: not
|
|
45
|
+
enforced, do not follow yet. This document does not change that and does not activate it. The
|
|
46
|
+
live traceability gate reads one directory for annotations, and it is the gate — not this
|
|
47
|
+
table — that decides where an annotation counts.
|
|
48
|
+
|
|
49
|
+
So: read this file to find out which lane runs a layer. Do not read it as instructions about
|
|
50
|
+
where anything belongs in the tree. That question is settled by the gate's own scope, and by
|
|
51
|
+
`test-layers.md` for the vocabulary.
|
|
52
|
+
|
|
53
|
+
## Keeping this file honest
|
|
54
|
+
|
|
55
|
+
- Every layer code here also appears in `test-layers.md`'s crosswalk. If you add a layer there
|
|
56
|
+
and not here, this table is incomplete; if you add one here and not there, you have invented
|
|
57
|
+
a layer nothing enforces.
|
|
58
|
+
- The lane column describes the shipped workflow. If the shipped workflow's job set changes,
|
|
59
|
+
this table is stale, and stale is worse than absent for a document whose only job is to save
|
|
60
|
+
someone a lookup.
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
This document is the SSOT for ATDD test-layer semantics and completion gates.
|
|
4
4
|
|
|
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 policy
|
|
7
|
+
loader reads this file and not that one, so nothing there can change the vocabulary declared below.
|
|
8
|
+
|
|
5
9
|
## Layer vocabulary crosswalk (normative)
|
|
6
10
|
|
|
7
11
|
qfai spells the same layer four ways across shipped artifacts. This table is
|
|
@@ -31,27 +35,30 @@ Rules:
|
|
|
31
35
|
- L1 and L2 have no mandated directory: unit and component tests live wherever
|
|
32
36
|
the project's own convention puts them. Only L3-L5 are directory-pinned, and
|
|
33
37
|
only those directories are scanned by the ATDD traceability rules.
|
|
34
|
-
- **A `TC-*` row's `Level` is L1-L3.**
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
`<testsDir>/
|
|
39
|
-
`<testsDir>/
|
|
40
|
-
`<testsDir>/
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
- **A `TC-*` row's `Level` is L1-L3.** Of those, only L3 owes an ATDD
|
|
39
|
+
annotation: L1 and L2 have no mandated directory, so `QFAI-ATDD-112` does not
|
|
40
|
+
apply to them and `QFAI-ATDD-117` (`info`) names them instead. Their gate is
|
|
41
|
+
`tdd/test-list.md` / `TDDLIST_TC_NOT_COVERED`, under `/qfai-implement`.
|
|
42
|
+
`US-*` is answered from `<testsDir>/e2e/**` (`QFAI-ATDD-111`), `CON-API-*`
|
|
43
|
+
from `<testsDir>/api/**` (`QFAI-ATDD-113`) and `CON-DB-*` from
|
|
44
|
+
`<testsDir>/integration/**` (`QFAI-ATDD-115`) — those three are fixed by the
|
|
45
|
+
ID type. A `TC-*` is answered from the directory **its own declared `Level`**
|
|
46
|
+
names, which for a correctly filed row is `<testsDir>/integration/**`; see
|
|
47
|
+
[Annotation routing](#annotation-routing) for the full table and the
|
|
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.
|
|
45
52
|
- The two code-side word lists (`tddHelpers.ts#UNIT_COMPONENT_LAYERS` /
|
|
46
53
|
`#NON_COVERAGE_LAYERS`) accept both the code and the word form for the same
|
|
47
54
|
layer; they MUST stay in step with this table.
|
|
48
55
|
|
|
49
56
|
## How this file is consumed
|
|
50
57
|
|
|
51
|
-
|
|
52
|
-
checks
|
|
53
|
-
layered layout `npx qfai init` produces. Until both
|
|
54
|
-
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.
|
|
55
62
|
|
|
56
63
|
- A file that yields no layers raises `QFAI-SPACK-090` (error) rather than
|
|
57
64
|
silently widening to the built-in set.
|
|
@@ -73,7 +80,7 @@ writer targets a declared layer instead.
|
|
|
73
80
|
- Scope: pure decision logic — a single module's inputs and return values, with
|
|
74
81
|
no port collaboration and no real infrastructure.
|
|
75
82
|
- Goal: verify `TC-*` obligations whose oracle observes inputs and outputs only.
|
|
76
|
-
-
|
|
83
|
+
- Convention: `tests/unit/**`. L1 has no mandated directory and owes no ATDD annotation — see the crosswalk and "Unit and Component owe no ATDD annotation".
|
|
77
84
|
|
|
78
85
|
### L2 Component
|
|
79
86
|
|
|
@@ -81,25 +88,25 @@ writer targets a declared layer instead.
|
|
|
81
88
|
with no real infrastructure.
|
|
82
89
|
- Goal: verify `TC-*` obligations whose oracle observes the interaction with a
|
|
83
90
|
port rather than infrastructure state.
|
|
84
|
-
-
|
|
91
|
+
- Convention: `tests/component/**`. L2 has no mandated directory and owes no ATDD annotation — see the crosswalk and "Unit and Component owe no ATDD annotation".
|
|
85
92
|
|
|
86
93
|
### L3 Integration
|
|
87
94
|
|
|
88
95
|
- Scope: real infrastructure integration (for example DB/queue/filesystem) within service boundaries.
|
|
89
96
|
- Goal: verify `TC-*` obligations from specs.
|
|
90
|
-
- Location rule:
|
|
97
|
+
- Location rule: `<testsDir>/integration/**`.
|
|
91
98
|
|
|
92
99
|
### L4 API
|
|
93
100
|
|
|
94
101
|
- Scope: service-boundary contracts (HTTP/gRPC/etc), auth, and error contracts.
|
|
95
102
|
- Goal: verify `CON-API-*` obligations from contracts.
|
|
96
|
-
- Location rule:
|
|
103
|
+
- Location rule: `<testsDir>/api/**`.
|
|
97
104
|
|
|
98
105
|
### L5 E2E
|
|
99
106
|
|
|
100
107
|
- Scope: representative full-system journeys across UI/API/data.
|
|
101
108
|
- Goal: verify `US-*` obligations from specs.
|
|
102
|
-
- Location rule:
|
|
109
|
+
- Location rule: `<testsDir>/e2e/**`.
|
|
103
110
|
|
|
104
111
|
## Layer derivation procedure (normative)
|
|
105
112
|
|
|
@@ -137,8 +144,23 @@ falsifying-oracle rule:
|
|
|
137
144
|
observable at two layers, it is two obligations: write one TC per oracle and
|
|
138
145
|
give each its own `Level`.
|
|
139
146
|
|
|
140
|
-
- A multi-valued `Level` cell (`L3/L5`) is **illegal**.
|
|
141
|
-
no
|
|
147
|
+
- A multi-valued `Level` cell (`L3/L5`, `L1/L2`, `L1, L3`) is **illegal**. It
|
|
148
|
+
matches no entry in the crosswalk, so no rule can read a layer out of it.
|
|
149
|
+
- **What a reader does with one: split the row.** One TC per oracle, each with
|
|
150
|
+
its own single `Level`. Nothing else is a fix — in particular, do not record
|
|
151
|
+
a normalization that "drops one half": no tool performs one, and a note
|
|
152
|
+
saying an `L3/L5` row "normalizes to `L3`" is a claim about a value that only
|
|
153
|
+
`06_Test-Cases.md` can make.
|
|
154
|
+
- **What the validators do with one, until it is split.** They neither guess
|
|
155
|
+
nor let it through:
|
|
156
|
+
- `QFAI-ATDD-112` routes the TC to the same place a TC with no declared
|
|
157
|
+
`Level` goes — `<testsDir>/integration/**` — and keeps the obligation.
|
|
158
|
+
Unreadable is deliberately not "excused": if a cell qfai cannot read
|
|
159
|
+
discharged the obligation, `L1/L2` would be a one-keystroke way to delete
|
|
160
|
+
any TC from the gate. That default is where the obligation is _reported_,
|
|
161
|
+
not where the obligation _belongs_.
|
|
162
|
+
- `TDDLIST_UNKNOWN_LEVEL` (`warning`) names the cell, and the TC stays a
|
|
163
|
+
coverage target, so `tdd/test-list.md` still owes it a row.
|
|
142
164
|
- If splitting is genuinely impossible, escalate through the Drift Protocol
|
|
143
165
|
rather than inventing a combined value.
|
|
144
166
|
|
|
@@ -158,15 +180,40 @@ L4" applies only when the service-boundary values are themselves what the
|
|
|
158
180
|
parent BR owns. Inverting this is what collapses a designed pyramid into an
|
|
159
181
|
all-integration suite.
|
|
160
182
|
|
|
161
|
-
### Annotation routing
|
|
162
|
-
|
|
163
|
-
The derived `Level` records which oracle owns the obligation
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
(`QFAI-ATDD-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
`
|
|
183
|
+
### Annotation routing
|
|
184
|
+
|
|
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) |
|
|
200
|
+
|
|
201
|
+
**(note)** A `TC-*` **should not be** at L4 or L5 — the first bullet below says
|
|
202
|
+
why and what to do instead. The gate routes it there rather than rejecting it so
|
|
203
|
+
a misfiled row is reported once, by the rule that names the real cause, instead
|
|
204
|
+
of twice as "uncovered in integration" and "forbidden in api".
|
|
205
|
+
|
|
206
|
+
**(note2)** A `Level` the crosswalk does not list — a typo, a project's own
|
|
207
|
+
word, or the illegal multi-valued cell — falls to the same default as an
|
|
208
|
+
undeclared one, and keeps its obligation. The default is the conservative
|
|
209
|
+
answer to a cell qfai cannot read, never a supported spelling: fix the cell
|
|
210
|
+
(see [Obligation spanning more than one layer](#obligation-spanning-more-than-one-layer)).
|
|
211
|
+
`TDDLIST_UNKNOWN_LEVEL` (`warning`) names such a cell on the ledger side.
|
|
212
|
+
|
|
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:
|
|
170
217
|
|
|
171
218
|
- **A `TC-*` row's `Level` stays within L1–L3.** L4's goal is `CON-API-*` and
|
|
172
219
|
L5's goal is `US-*` (see the layer definitions above), so an oracle that
|
|
@@ -185,22 +232,29 @@ routes by obligation ID: `US-*` is answered from `tests/e2e/**`
|
|
|
185
232
|
parent BR keeps a spec-side obligation, split the row instead: keep a `TC-*`
|
|
186
233
|
for the part the BR owns — by step 2 that part derives to L1–L3 — and re-file
|
|
187
234
|
only the boundary assertion as `CON-API-*` / `US-*`.
|
|
188
|
-
- **An L1/L2 `Level`
|
|
189
|
-
change the `Level`.** The two are independent: the `Level` records what
|
|
190
|
-
oracle observes and is derived before any test exists, while
|
|
191
|
-
`QFAI
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
235
|
+
- **An L1/L2 `Level` carries no `QFAI-ATDD-112` obligation, and the gate does
|
|
236
|
+
not change the `Level`.** The two are independent: the `Level` records what
|
|
237
|
+
the oracle observes and is derived before any test exists, while
|
|
238
|
+
`QFAI-ATDD-112` asks only about the layers ATDD owns. Never rewrite a derived
|
|
239
|
+
L1/L2 to L3 to make a gate quieter — that would make the recorded oracle
|
|
240
|
+
depend on implementation order and hide the unit/component work
|
|
241
|
+
`/qfai-implement` selects. An L1/L2 row's obligation is discharged through
|
|
242
|
+
`tdd/test-list.md` and `TDDLIST_TC_NOT_COVERED`, not through an annotation in
|
|
243
|
+
a directory ATDD scans.
|
|
244
|
+
|
|
245
|
+
## Directory → AtddTestKind (code-side, derived from the crosswalk)
|
|
246
|
+
|
|
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.
|
|
204
258
|
|
|
205
259
|
## Annotation schema (code-side)
|
|
206
260
|
|
|
@@ -219,7 +273,7 @@ routes by obligation ID: `US-*` is answered from `tests/e2e/**`
|
|
|
219
273
|
|
|
220
274
|
- E2E obligations:
|
|
221
275
|
- Every `US-*` in a **user-facing** spec must be referenced at least once from
|
|
222
|
-
|
|
276
|
+
`<testsDir>/e2e/**`. "User-facing" is the same surface **union**
|
|
223
277
|
`/qfai-prototyping` enforces. Any one of these signals puts a spec in it:
|
|
224
278
|
- frontmatter `surface_type: ui-bearing` in `01_Spec.md`;
|
|
225
279
|
- a matching UI contract `.qfai/contracts/ui/<spec-id>*.yaml` — a project
|
|
@@ -233,40 +287,59 @@ routes by obligation ID: `US-*` is answered from `tests/e2e/**`
|
|
|
233
287
|
- Scoping applies only when the project declares at least one UI-bearing
|
|
234
288
|
spec. A project that has never declared a surface has not opted into
|
|
235
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.
|
|
236
291
|
- Do not create an E2E tree whose only purpose is to receive annotations.
|
|
237
292
|
That is the "convert all obligations into E2E" anti-pattern below.
|
|
238
293
|
- Use `QFAI:SPEC-XXXX:US-YYYY` annotations.
|
|
239
294
|
|
|
240
295
|
- Integration obligations (enforced today):
|
|
241
|
-
- Every `TC-*` in specs must be referenced at least once from the directory
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
-
|
|
247
|
-
|
|
248
|
-
`
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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.
|
|
301
|
+
- Use `QFAI:SPEC-XXXX:TC-YYYY` annotations.
|
|
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.
|
|
317
|
+
|
|
318
|
+
- **Unit and Component owe no ATDD annotation.** A `TC-*` whose declared
|
|
319
|
+
`Level` is L1 or L2 is outside `QFAI-ATDD-112` entirely: it is not required
|
|
320
|
+
in any directory, and an annotation for it inside a scanned directory is not
|
|
321
|
+
a violation either. `QFAI-ATDD-117` (`info`) names the excluded TCs on every
|
|
322
|
+
run so the exclusion is visible rather than silent.
|
|
323
|
+
- This is the only reading consistent with the rest of the package.
|
|
324
|
+
`qfai-atdd/SKILL.md` puts Unit and Component out of its scope, and the
|
|
325
|
+
crosswalk above gives L1/L2 no mandated directory — only L3-L5 are
|
|
326
|
+
directory-pinned and only those three roots are scanned.
|
|
327
|
+
- Previously L1/L2 fell through to `<testsDir>/integration/**` — the fallback for
|
|
328
|
+
a spec with no `Level` column at all — so every declared Unit and Component
|
|
329
|
+
TC was an `error` demanding an annotation in a directory this file says is
|
|
330
|
+
not its home. `QFAI-WAIVER-002` refuses waivers on `error` rules, so a
|
|
331
|
+
project that filed unit tests where L1's own entry says to had no exit, and
|
|
332
|
+
the only validator-clean path was duplicating every annotation into
|
|
333
|
+
`<testsDir>/integration/**` — the all-integration collapse named under
|
|
334
|
+
Anti-patterns below.
|
|
335
|
+
- **They are still gated, by the other stage.** Every coverage-target `TC-*`
|
|
336
|
+
owes a `tdd/test-list.md` row, and `TDDLIST_TC_NOT_COVERED` (`error`)
|
|
337
|
+
reports a missing one. L1/L2 belong to `/qfai-implement`, which is the
|
|
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.
|
|
268
341
|
- API obligations:
|
|
269
|
-
- Every declared `CON-API-*` must be referenced at least once from
|
|
342
|
+
- Every declared `CON-API-*` must be referenced at least once from `<testsDir>/api/**`.
|
|
270
343
|
- Use `QFAI:CON-API-XXXX` annotations.
|
|
271
344
|
- **Deferral.** `/qfai-sdd` authors contracts in Phase 0 (Contracts-first) and
|
|
272
345
|
slices them in Phase 2, so a contract legitimately exists before its slice
|
|
@@ -284,26 +357,28 @@ routes by obligation ID: `US-*` is answered from `tests/e2e/**`
|
|
|
284
357
|
under `deferred.conApi`, so an empty `missing.conApi` can be told apart
|
|
285
358
|
from a project where every contract is still planned.
|
|
286
359
|
- Forbidden references:
|
|
287
|
-
-
|
|
360
|
+
- `<testsDir>/api/**` must not include `QFAI:SPEC-XXXX:TC-YYYY` **for a TC whose
|
|
288
361
|
declared `Level` is not L4/API**. A TC that declares an API-level
|
|
289
|
-
obligation belongs in
|
|
362
|
+
obligation belongs in `<testsDir>/api/**`, and its annotation there counts as
|
|
290
363
|
coverage. The rule exists to stop obligations drifting into the wrong
|
|
291
364
|
layer, not to make the correct layer unusable.
|
|
292
|
-
-
|
|
365
|
+
- `<testsDir>/e2e/**` must not include `QFAI:SPEC-XXXX:TC-YYYY` **for a TC whose
|
|
293
366
|
declared `Level` is not L5/E2E**. Same reason as above: the routing rule
|
|
294
367
|
and the forbidden rule must agree, or the layer the routing selects
|
|
295
368
|
becomes unusable.
|
|
296
|
-
-
|
|
369
|
+
- `<testsDir>/integration/**` must not include `QFAI:SPEC-XXXX:TC-YYYY` **for a TC
|
|
297
370
|
whose declared `Level` is not L3/Integration** (`QFAI-ATDD-123`). The rule
|
|
298
371
|
is symmetric so "exactly one directory" holds in both directions: an
|
|
299
372
|
annotation left behind here after the TC moved to L4/L5 is as wrong as one
|
|
300
|
-
filed early into
|
|
373
|
+
filed early into `<testsDir>/api/**`.
|
|
301
374
|
- Unknown references (`US/TC/CON-API` not declared) are errors.
|
|
302
375
|
- A `TC-*` annotation outside the directory its `Level` routes to is a
|
|
303
|
-
misplacement, whichever directory it lands in
|
|
304
|
-
|
|
376
|
+
misplacement, whichever directory it lands in. **This applies to L3-L5 only.**
|
|
377
|
+
L1 and L2 route nowhere — they carry no ATDD annotation obligation at all — so
|
|
378
|
+
an annotation for one is neither required nor misplaced, in
|
|
379
|
+
`tests/unit/**`, `tests/component/**` or anywhere else.
|
|
305
380
|
- AC annotations are not required in code; AC coverage is treated as indirect through TC coverage.
|
|
306
|
-
- `QFAI:CON-API-*` in
|
|
381
|
+
- `QFAI:CON-API-*` in `<testsDir>/e2e/**` is not forbidden, but contract guarantee belongs to API tests.
|
|
307
382
|
|
|
308
383
|
## Test-file granularity
|
|
309
384
|
|
|
@@ -396,10 +471,9 @@ Treat these as review signals in the same class as volume floors — worth a fin
|
|
|
396
471
|
- a very low `test_` functions per file ratio in a module that carries many obligations
|
|
397
472
|
- a single selector whose recorded runtime grows monotonically across RED rounds
|
|
398
473
|
|
|
399
|
-
## Test stub detection (QFAI-TEST-001 /
|
|
474
|
+
## Test stub detection (QFAI-TEST-001 / -002 / -003)
|
|
400
475
|
|
|
401
|
-
`QFAI-TEST-001` (error) reports the silent-placeholder construct of each
|
|
402
|
-
supported stack:
|
|
476
|
+
`QFAI-TEST-001` (error) reports the silent-placeholder construct of each supported stack:
|
|
403
477
|
|
|
404
478
|
| Extensions | Construct |
|
|
405
479
|
| -------------------- | ------------------------------------------------------------------- |
|
|
@@ -411,6 +485,14 @@ supported stack:
|
|
|
411
485
|
| `.rb` | a line starting `skip` / `pending` |
|
|
412
486
|
| `.cs` | `[Ignore` / `Skip = "` |
|
|
413
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
|
+
|
|
414
496
|
`QFAI-TEST-002` (info) names any extension the scan opened that has no dialect.
|
|
415
497
|
Without it a clean run on an unsupported stack is indistinguishable from a
|
|
416
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
|
-
-
|
|
8
|
-
-
|
|
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
|
|
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:
|
|
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
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# QFAI Constitution (Non‑Negotiable)
|
|
2
2
|
|
|
3
3
|
This document defines **non‑negotiable operating rules** for QFAI agents and subagents.
|
|
4
|
-
It is inspired by proven “constitution / articles / guardrails” patterns in existing SDD toolchains, but
|
|
4
|
+
It is inspired by proven “constitution / articles / guardrails” patterns in existing SDD toolchains, but adapted to QFAI’s minimal workflow.
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -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
|
|
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.
|