qfai 1.9.2 → 1.10.0
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 +48 -2
- package/assets/init/.qfai/assistant/agents/acceptance-test-engineer.md +1 -0
- package/assets/init/.qfai/assistant/agents/backend-engineer.md +1 -0
- package/assets/init/.qfai/assistant/agents/completion-reviewer.md +13 -2
- package/assets/init/.qfai/assistant/agents/delivery-planner.md +9 -0
- package/assets/init/.qfai/assistant/agents/frontend-engineer.md +1 -0
- package/assets/init/.qfai/assistant/agents/implementation-reviewer.md +6 -0
- package/assets/init/.qfai/assistant/agents/orchestrator.md +2 -2
- package/assets/init/.qfai/assistant/agents/qa-gatekeeper.md +96 -3
- package/assets/init/.qfai/assistant/agents/test-design-analyst.md +20 -3
- package/assets/init/.qfai/assistant/catalog/cli-ux-guidelines.md +2 -2
- package/assets/init/.qfai/assistant/catalog/spec_required_files.json +2 -1
- package/assets/init/.qfai/assistant/catalog/test-layers.md +355 -14
- package/assets/init/.qfai/assistant/catalog/worklog-entry.schema.md +165 -0
- package/assets/init/.qfai/assistant/constitution/communication.md +1 -1
- package/assets/init/.qfai/assistant/constitution/drift-protocol.md +304 -10
- package/assets/init/.qfai/assistant/constitution/quality.md +35 -5
- package/assets/init/.qfai/assistant/constitution/requirements-decomposition.md +37 -0
- package/assets/init/.qfai/assistant/constitution/shared-skill-delegation-baseline.md +244 -8
- package/assets/init/.qfai/assistant/constitution/shared-skill-operating-baseline.md +122 -5
- package/assets/init/.qfai/assistant/constitution/workflow.md +53 -7
- package/assets/init/.qfai/assistant/manifest/agent-catalog.yml +316 -945
- package/assets/init/.qfai/assistant/manifest/agent-routing.yml +50 -4
- package/assets/init/.qfai/assistant/manifest/review-profiles.yml +9 -0
- package/assets/init/.qfai/assistant/process/migrations/v1.4.27-atdd-alignment.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-atdd/SKILL.md +61 -21
- package/assets/init/.qfai/assistant/skills/qfai-atdd/references/test-case-depth-checklist.md +23 -4
- package/assets/init/.qfai/assistant/skills/qfai-configure/SKILL.md +15 -7
- package/assets/init/.qfai/assistant/skills/qfai-discussion/SKILL.md +8 -4
- package/assets/init/.qfai/assistant/skills/qfai-discussion/references/design-md-brand-catalog.md +2 -2
- package/assets/init/.qfai/assistant/skills/qfai-discussion/references/discussion-completion-matrix.md +17 -7
- package/assets/init/.qfai/assistant/skills/qfai-discussion/references/rcp_footer.md +10 -4
- package/assets/init/.qfai/assistant/skills/qfai-discussion/references/review-cycle-playbook.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-discussion/references/ui-bearing-playbook.md +4 -4
- package/assets/init/.qfai/assistant/skills/qfai-discussion/references/ui_ux/review_audit_playbook.md +1 -1
- 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 +17 -7
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/01_Context.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/02_Inception-Deck.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/03_Story-Workshop.md +11 -3
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/05_Scope.md +5 -2
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/07_NFR.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/09_Constraints.md +7 -4
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/10_Policy.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/11_OQ-Register.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/12_OQ-Resolution-Log.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/14_Review-Request.md +14 -7
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/99_delta.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/review/Rxx_reviewer.md +16 -7
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/review/review_request.md +9 -6
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/uiux/40_screen_contracts.md +3 -2
- package/assets/init/.qfai/assistant/skills/qfai-discussion/templates/uiux/50_review_input_bundle.md +4 -2
- package/assets/init/.qfai/assistant/skills/qfai-implement/SKILL.md +250 -128
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/change-request-reset.md +93 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/checkpoint-verification.md +106 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/cross-spec-ownership.md +73 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/evidence-revision.md +77 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/execution-ledger.md +303 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/final-checklist.md +19 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/finding-classification.md +49 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/ledger-preconditions.md +55 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/oracle-strength.md +81 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/parallelization-policy.md +235 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/red-admissibility.md +91 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/red-not-observable.md +70 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/relevant-test-suite.md +87 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/review-artifact-layout.md +31 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/round-evidence.md +102 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/selector-granularity.md +24 -0
- package/assets/init/.qfai/assistant/skills/qfai-implement/references/volume-policy.md +149 -0
- package/assets/init/.qfai/assistant/skills/qfai-prototyping/SKILL.md +35 -18
- package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/evidence-requirements.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/generator-prompt.md +106 -7
- package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/handoff.md +40 -11
- package/assets/init/.qfai/assistant/skills/qfai-prototyping/references/iteration-loop.md +48 -1
- package/assets/init/.qfai/assistant/skills/qfai-prototyping/templates/DESIGN.md.sample +6 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/SKILL.md +82 -22
- package/assets/init/.qfai/assistant/skills/qfai-sdd/references/contract-artifact-rules.md +148 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/references/rcp_footer.md +10 -4
- package/assets/init/.qfai/assistant/skills/qfai-sdd/references/review-cycle-playbook.md +1 -1
- package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-execution-playbook.md +4 -2
- package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-phase-checklists.md +18 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-quality-gate.md +44 -3
- package/assets/init/.qfai/assistant/skills/qfai-sdd/references/sdd-triage.md +60 -7
- package/assets/init/.qfai/assistant/skills/qfai-sdd/references/spec-traceability-rules.md +157 -5
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/change-request.md +125 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/contracts/db-contract.sample.sql +6 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/evidence/sdd-spec.md +92 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/01_Objective.md +27 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/02_Initiative.md +30 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/05_Contracts.md +16 -6
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/06_Glossary.md +19 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/07_Constraints.md +25 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/08_Decisions.md +22 -2
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/_policies/11_Slice-Policy.md +37 -10
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/02_User-stories.md +20 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/03_Acceptance-Criteria.md +19 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/04_Business-Rules.md +32 -3
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/06_Test-Cases.md +56 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/07_Decisions.md +29 -2
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/10_Plan.md +41 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/16_Traceability-ledger.md +58 -0
- package/assets/init/.qfai/assistant/skills/qfai-sdd/templates/specs/spec/tdd/test-list.md +56 -0
- package/assets/init/.qfai/assistant/skills/qfai-verify/SKILL.md +57 -102
- package/assets/init/.qfai/assistant/skills/qfai-verify/references/articles.md +24 -0
- package/assets/init/.qfai/assistant/skills/qfai-verify/references/context-load.md +22 -0
- package/assets/init/.qfai/assistant/skills/qfai-verify/references/verify-output-contract.md +48 -0
- package/assets/init/.qfai/assistant/skills/qfai-verify/templates/verify-evidence.md +48 -0
- package/assets/init/.qfai/assistant/skills/web-research/SKILL.md +25 -7
- package/assets/init/.qfai/waivers.yml +11 -5
- package/assets/init/root/DESIGN.md +6 -0
- package/assets/init/root/qfai.config.yaml +15 -12
- package/dist/cli/index.cjs +11023 -7139
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.mjs +10963 -7080
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.cjs +8782 -5257
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +280 -8
- package/dist/index.d.ts +280 -8
- package/dist/index.mjs +11776 -8264
- package/dist/index.mjs.map +1 -1
- package/package.json +18 -19
|
@@ -2,8 +2,87 @@
|
|
|
2
2
|
|
|
3
3
|
This document is the SSOT for ATDD test-layer semantics and completion gates.
|
|
4
4
|
|
|
5
|
+
## Layer vocabulary crosswalk (normative)
|
|
6
|
+
|
|
7
|
+
qfai spells the same layer four ways across shipped artifacts. This table is
|
|
8
|
+
the crosswalk; every artifact MUST use the spelling in its column.
|
|
9
|
+
|
|
10
|
+
| Code | Word | Tag | Test directory | `06_Test-Cases.md#Level` | `tdd/test-list.md#Layer` |
|
|
11
|
+
| ---- | ----------- | ------------------- | --------------------------- | ------------------------ | ------------------------ |
|
|
12
|
+
| L1 | Unit | `layer-unit` | project convention | `L1` | `Unit` |
|
|
13
|
+
| L2 | Component | `layer-component` | project convention | `L2` | `Component` |
|
|
14
|
+
| L3 | Integration | `layer-integration` | `<testsDir>/integration/**` | `L3` | `Integration` |
|
|
15
|
+
| L4 | API | `layer-api` | `<testsDir>/api/**` | — | `API` |
|
|
16
|
+
| L5 | E2E | `layer-e2e` | `<testsDir>/e2e/**` | — | `E2E` |
|
|
17
|
+
|
|
18
|
+
Rules:
|
|
19
|
+
|
|
20
|
+
- **One value per cell.** A `Level` cell and a `Layer` cell each hold exactly
|
|
21
|
+
one layer. An obligation spanning two layers is two rows, not one row with
|
|
22
|
+
two values.
|
|
23
|
+
- `06_Test-Cases.md` uses the **code** (`L1`…`L3`) in its `Level` column.
|
|
24
|
+
- `tdd/test-list.md` uses the **word** in its `Layer` column.
|
|
25
|
+
- Test-strategy tags in prompts and policy files use the **tag** form.
|
|
26
|
+
- **`<testsDir>` is `paths.testsDir` from `qfai.config.yaml`**, whose default
|
|
27
|
+
is `tests` — hence the shipped `tests/integration/**`, `tests/api/**` and
|
|
28
|
+
`tests/e2e/**`. A project that repoints `paths.testsDir` moves all three at
|
|
29
|
+
once; the ATDD traceability scan follows the configured value, so never
|
|
30
|
+
hard-code the literal `tests/` prefix in a project's own artifacts.
|
|
31
|
+
- L1 and L2 have no mandated directory: unit and component tests live wherever
|
|
32
|
+
the project's own convention puts them. Only L3-L5 are directory-pinned, and
|
|
33
|
+
only those directories are scanned by the ATDD traceability rules.
|
|
34
|
+
- **A `TC-*` row's `Level` is L1-L3.** The ATDD annotation hard gate routes an
|
|
35
|
+
obligation by its ID, not by its `Level`: `US-*` is answered from
|
|
36
|
+
`<testsDir>/e2e/**` (`QFAI-ATDD-111`), `TC-*` from
|
|
37
|
+
`<testsDir>/integration/**` (`QFAI-ATDD-112`) and `CON-API-*` from
|
|
38
|
+
`<testsDir>/api/**` (`QFAI-ATDD-113`) and `CON-DB-*` from
|
|
39
|
+
`<testsDir>/integration/**` (`QFAI-ATDD-115`), while a `TC-*` reference inside
|
|
40
|
+
`<testsDir>/api/**` or `<testsDir>/e2e/**` is rejected outright
|
|
41
|
+
(`QFAI-ATDD-121` / `QFAI-ATDD-122`). L4's goal is `CON-API-*` and L5's is
|
|
42
|
+
`US-*` (see the layer definitions below), so an oracle that lands at L4 or L5
|
|
43
|
+
means the obligation is misfiled: record it as `CON-API-*` or `US-*` rather
|
|
44
|
+
than as a `TC-*` row no test directory can carry.
|
|
45
|
+
- The two code-side word lists (`tddHelpers.ts#UNIT_COMPONENT_LAYERS` /
|
|
46
|
+
`#NON_COVERAGE_LAYERS`) accept both the code and the word form for the same
|
|
47
|
+
layer; they MUST stay in step with this table.
|
|
48
|
+
|
|
49
|
+
## How this file is consumed
|
|
50
|
+
|
|
51
|
+
The layer set below is read by `core/layerPolicy.ts` and is the SSOT for two
|
|
52
|
+
checks: `QFAI-EX-005` on the legacy spec-pack layout, and `QFAI-EX-105` on the
|
|
53
|
+
layered layout `npx qfai init` produces. Until both consumed it, the file was
|
|
54
|
+
read, reported on, and then ignored on every modern project.
|
|
55
|
+
|
|
56
|
+
- A file that yields no layers raises `QFAI-SPACK-090` (error) rather than
|
|
57
|
+
silently widening to the built-in set.
|
|
58
|
+
- A declared set that disagrees with the built-in set raises `QFAI-SPACK-091`
|
|
59
|
+
(warning). Without it the two could drift in either direction and this file
|
|
60
|
+
would not be an SSOT.
|
|
61
|
+
|
|
62
|
+
## Scaffolded tests
|
|
63
|
+
|
|
64
|
+
`npx qfai atdd scaffold` writes skeletons to `<testsDir>/integration/<spec-id>/`.
|
|
65
|
+
There is deliberately no `<testsDir>/atdd/**` row below: a fourth root would
|
|
66
|
+
need a rule for which layer such a file belongs to, and qfai has none. The
|
|
67
|
+
writer targets a declared layer instead.
|
|
68
|
+
|
|
5
69
|
## Layer definitions
|
|
6
70
|
|
|
71
|
+
### L1 Unit
|
|
72
|
+
|
|
73
|
+
- Scope: pure decision logic — a single module's inputs and return values, with
|
|
74
|
+
no port collaboration and no real infrastructure.
|
|
75
|
+
- Goal: verify `TC-*` obligations whose oracle observes inputs and outputs only.
|
|
76
|
+
- Location rule: `tests/unit/**`.
|
|
77
|
+
|
|
78
|
+
### L2 Component
|
|
79
|
+
|
|
80
|
+
- Scope: collaboration with a port through a fixture adapter (fake / in-memory),
|
|
81
|
+
with no real infrastructure.
|
|
82
|
+
- Goal: verify `TC-*` obligations whose oracle observes the interaction with a
|
|
83
|
+
port rather than infrastructure state.
|
|
84
|
+
- Location rule: `tests/component/**`.
|
|
85
|
+
|
|
7
86
|
### L3 Integration
|
|
8
87
|
|
|
9
88
|
- Scope: real infrastructure integration (for example DB/queue/filesystem) within service boundaries.
|
|
@@ -22,8 +101,103 @@ This document is the SSOT for ATDD test-layer semantics and completion gates.
|
|
|
22
101
|
- Goal: verify `US-*` obligations from specs.
|
|
23
102
|
- Location rule: `tests/e2e/**`.
|
|
24
103
|
|
|
104
|
+
## Layer derivation procedure (normative)
|
|
105
|
+
|
|
106
|
+
Deciding a `TC-*`'s layer is a per-TC judgement, not a constant. Use the
|
|
107
|
+
falsifying-oracle rule:
|
|
108
|
+
|
|
109
|
+
1. **Find the oracle.** Identify the single assertion whose removal would let a
|
|
110
|
+
wrong implementation pass. That assertion, not the test's setup, is what the
|
|
111
|
+
TC verifies.
|
|
112
|
+
2. **Restrict it to the parent BR's obligations.** Anything the oracle observes
|
|
113
|
+
that the parent business rule does not own is incidental and does not raise
|
|
114
|
+
the layer.
|
|
115
|
+
3. **Read the layer off what the oracle observes:**
|
|
116
|
+
- inputs and return values only → **L1 Unit**
|
|
117
|
+
- collaboration with a port through a fixture adapter (no real
|
|
118
|
+
infrastructure) → **L2 Component**
|
|
119
|
+
- real infrastructure state — DB rows, queue messages, files → **L3 Integration**
|
|
120
|
+
- values at the service boundary — status codes, response bodies, auth and
|
|
121
|
+
error contracts → **L4 API**
|
|
122
|
+
- a full-system journey across UI/API/data → **L5 E2E**
|
|
123
|
+
|
|
124
|
+
### Worked examples
|
|
125
|
+
|
|
126
|
+
| Oracle asserts | Layer |
|
|
127
|
+
| ----------------------------------------------------------------------------- | -------------- |
|
|
128
|
+
| `price(order) === 1250` for a given input | L1 Unit |
|
|
129
|
+
| the repository port was called with the normalized key, via a fixture adapter | L2 Component |
|
|
130
|
+
| the row is present in the database after commit | L3 Integration |
|
|
131
|
+
| `POST /orders` returns `422` with `code: "OUT_OF_AREA"` | L4 API |
|
|
132
|
+
| a user can register, order, and see the order in their history | L5 E2E |
|
|
133
|
+
|
|
134
|
+
### Obligation spanning more than one layer
|
|
135
|
+
|
|
136
|
+
**Split the row.** One TC = one oracle = one layer. If an obligation is
|
|
137
|
+
observable at two layers, it is two obligations: write one TC per oracle and
|
|
138
|
+
give each its own `Level`.
|
|
139
|
+
|
|
140
|
+
- A multi-valued `Level` cell (`L3/L5`) is **illegal**. Nothing consumes it and
|
|
141
|
+
no validator can route it.
|
|
142
|
+
- If splitting is genuinely impossible, escalate through the Drift Protocol
|
|
143
|
+
rather than inventing a combined value.
|
|
144
|
+
|
|
145
|
+
### Direction of authority (anti-pattern)
|
|
146
|
+
|
|
147
|
+
The test driver follows the declared layer. **The layer is never inferred from
|
|
148
|
+
how a test happens to be driven.** A unit-level obligation — one whose oracle,
|
|
149
|
+
after step 2, observes only inputs and return values — exercised through an
|
|
150
|
+
HTTP client is still L1 badly implemented; it is not an L4 test.
|
|
151
|
+
|
|
152
|
+
**Step 2 outranks step 3.** Restriction to the parent BR's obligations runs
|
|
153
|
+
first, so a transport the parent BR does not own is incidental and never
|
|
154
|
+
raises the layer. A BR that owns only the price calculation, asserted as
|
|
155
|
+
`response.body.price` over HTTP, reads as L1: the price is the BR-owned value,
|
|
156
|
+
the response envelope is the incidental transport. Step 3's "response bodies →
|
|
157
|
+
L4" applies only when the service-boundary values are themselves what the
|
|
158
|
+
parent BR owns. Inverting this is what collapses a designed pyramid into an
|
|
159
|
+
all-integration suite.
|
|
160
|
+
|
|
161
|
+
### Annotation routing is by ID type, not by `Level`
|
|
162
|
+
|
|
163
|
+
The derived `Level` records which oracle owns the obligation. It does **not**
|
|
164
|
+
move the traceability annotation. The [ATDD annotation hard gate](#atdd-annotation-hard-gate)
|
|
165
|
+
routes by obligation ID: `US-*` is answered from `tests/e2e/**`
|
|
166
|
+
(`QFAI-ATDD-111`), `TC-*` from `tests/integration/**` (`QFAI-ATDD-112`), and
|
|
167
|
+
`CON-API-*` from `tests/api/**` (`QFAI-ATDD-113`); a `TC-*` reference inside
|
|
168
|
+
`tests/api/**` or `tests/e2e/**` is rejected outright (`QFAI-ATDD-121` /
|
|
169
|
+
`QFAI-ATDD-122`). Two consequences bind every `TC-*` row:
|
|
170
|
+
|
|
171
|
+
- **A `TC-*` row's `Level` stays within L1–L3.** L4's goal is `CON-API-*` and
|
|
172
|
+
L5's goal is `US-*` (see the layer definitions above), so an oracle that
|
|
173
|
+
derives to L4 or L5 means the obligation is misfiled, not that the TC is an
|
|
174
|
+
L4/L5 test. Re-file it as `CON-API-*` or `US-*`.
|
|
175
|
+
**Re-filing is an upstream change, never a bare row deletion.** By step 2 the
|
|
176
|
+
derivation reaches L4/L5 only when the parent `BR-*` itself owns the
|
|
177
|
+
service-boundary contract or the journey, so the `TC-*` row is removed only
|
|
178
|
+
together with the `EX-*` it verifies and the `BR-*`/`AC-*` that EX
|
|
179
|
+
concretizes. Dropping the row alone leaves the parent EX with no `EX-Ref`
|
|
180
|
+
and `npx qfai validate --profile sdd --fail-on error` reports `QFAI-COV-203`
|
|
181
|
+
(and `QFAI-COV-201` when that TC was the AC's only cover); dropping the EX
|
|
182
|
+
but keeping its BR reports `QFAI-COV-202`. Move the whole chain in one
|
|
183
|
+
change through the Drift Protocol so `04_Business-Rules.md`,
|
|
184
|
+
`05_Examples.md`, `06_Test-Cases.md` and the contract stay consistent. If the
|
|
185
|
+
parent BR keeps a spec-side obligation, split the row instead: keep a `TC-*`
|
|
186
|
+
for the part the BR owns — by step 2 that part derives to L1–L3 — and re-file
|
|
187
|
+
only the boundary assertion as `CON-API-*` / `US-*`.
|
|
188
|
+
- **An L1/L2 `Level` does not relax `QFAI-ATDD-112`, and the gate does not
|
|
189
|
+
change the `Level`.** The two are independent: the `Level` records what the
|
|
190
|
+
oracle observes and is derived before any test exists, while the
|
|
191
|
+
`QFAI:SPEC-XXXX:TC-YYYY` annotation is still owed to `tests/integration/**`.
|
|
192
|
+
Never rewrite a derived L1/L2 to L3 because no integration trace exists yet —
|
|
193
|
+
that would make the recorded oracle depend on implementation order and hide
|
|
194
|
+
the unit/component work `/qfai-implement` selects. The missing annotation is
|
|
195
|
+
an open ATDD obligation to satisfy, not evidence that the `Level` was wrong.
|
|
196
|
+
|
|
25
197
|
## TestKind resolution (single source)
|
|
26
198
|
|
|
199
|
+
- `tests/unit/**` -> Unit
|
|
200
|
+
- `tests/component/**` -> Component
|
|
27
201
|
- `tests/e2e/**` -> E2E
|
|
28
202
|
- `tests/api/**` -> API
|
|
29
203
|
- `tests/integration/**` -> Integration
|
|
@@ -31,46 +205,213 @@ This document is the SSOT for ATDD test-layer semantics and completion gates.
|
|
|
31
205
|
## Annotation schema (code-side)
|
|
32
206
|
|
|
33
207
|
- Smallest trace unit is ID.
|
|
34
|
-
- Multiple IDs per test file are allowed
|
|
208
|
+
- Multiple IDs per test file are allowed — but this is a trace rule, not
|
|
209
|
+
licence to aggregate a whole spec into one module. See Test-file granularity
|
|
210
|
+
below.
|
|
35
211
|
- AC annotations are optional (indirect coverage through TC is acceptable).
|
|
36
212
|
- Allowed forms:
|
|
37
213
|
- `QFAI:SPEC-0001:US-0001`
|
|
38
214
|
- `QFAI:SPEC-0001:TC-0001`
|
|
39
215
|
- `QFAI:CON-API-0001`
|
|
216
|
+
- `QFAI:CON-DB-0001`
|
|
40
217
|
|
|
41
218
|
## ATDD annotation hard gate
|
|
42
219
|
|
|
43
220
|
- E2E obligations:
|
|
44
|
-
- Every `US-*` in
|
|
221
|
+
- Every `US-*` in a **user-facing** spec must be referenced at least once from
|
|
222
|
+
`tests/e2e/**`. "User-facing" is the same surface **union**
|
|
223
|
+
`/qfai-prototyping` enforces. Any one of these signals puts a spec in it:
|
|
224
|
+
- frontmatter `surface_type: ui-bearing` in `01_Spec.md`;
|
|
225
|
+
- a matching UI contract `.qfai/contracts/ui/<spec-id>*.yaml` — a project
|
|
226
|
+
that declares its surfaces only through contracts is still in scope;
|
|
227
|
+
- a legacy `# … prototyping …` heading in `01_Spec.md`;
|
|
228
|
+
- the spec pinned by `qfai.config.yaml#prototyping.primarySpecId`.
|
|
229
|
+
|
|
230
|
+
A spec that declares no user-facing surface by **any** of those signals
|
|
231
|
+
owes no E2E reference, and `QFAI-ATDD-111` does not fire for it.
|
|
232
|
+
|
|
233
|
+
- Scoping applies only when the project declares at least one UI-bearing
|
|
234
|
+
spec. A project that has never declared a surface has not opted into
|
|
235
|
+
surface typing, so the obligation stays project-wide for it.
|
|
236
|
+
- Do not create an E2E tree whose only purpose is to receive annotations.
|
|
237
|
+
That is the "convert all obligations into E2E" anti-pattern below.
|
|
45
238
|
- Use `QFAI:SPEC-XXXX:US-YYYY` annotations.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
-
|
|
239
|
+
|
|
240
|
+
- Integration obligations (enforced today):
|
|
241
|
+
- Every `TC-*` in specs must be referenced at least once from the directory
|
|
242
|
+
its declared `Level` routes to: L3/Integration -> `tests/integration/**`,
|
|
243
|
+
L4/API -> `tests/api/**`, L5/E2E -> `tests/e2e/**`. A TC with no declared
|
|
244
|
+
`Level` defaults to `tests/integration/**`. This is what `QFAI-ATDD-112`
|
|
245
|
+
checks. - Use `QFAI:SPEC-XXXX:TC-YYYY` annotations.
|
|
246
|
+
- `tests/api/**` and `tests/e2e/**` must not carry `TC-*` annotations
|
|
247
|
+
(`QFAI-ATDD-121` / `QFAI-ATDD-122`), so an L4 obligation is discharged as a
|
|
248
|
+
`CON-API-*` reference, never as a `TC-*` one.
|
|
249
|
+
- Every declared `CON-DB-*` must be referenced at least once from
|
|
250
|
+
`tests/integration/**` (`QFAI-ATDD-115`). Use `QFAI:CON-DB-XXXX`
|
|
251
|
+
annotations. L3 owns this because a DB contract is only exercised against
|
|
252
|
+
real infrastructure, which is L3's declared scope; a `CON-DB` reference
|
|
253
|
+
from `tests/e2e/**` is not counted, or an end-to-end assertion that never
|
|
254
|
+
touches the schema could close the obligation. A contract outside the
|
|
255
|
+
current slice defers with a `-- x-qfai-status: planned` comment line,
|
|
256
|
+
reported at `info` by `QFAI-ATDD-116` so the deferral stays visible.
|
|
257
|
+
|
|
258
|
+
- Per-level routing (target state — **not enforced, do not follow yet**):
|
|
259
|
+
- The intended end state is one required location per declared `Level`:
|
|
260
|
+
L1 -> `tests/unit/**`, L2 -> `tests/component/**`,
|
|
261
|
+
L3 -> `tests/integration/**`. L4 stays `CON-API-*` in `tests/api/**` and
|
|
262
|
+
L5 stays `US-*` in `tests/e2e/**`.
|
|
263
|
+
- **This is not live.** `buildAtddTestGlobs` scans only
|
|
264
|
+
`tests/{e2e,api,integration}`, so an annotation placed in `tests/unit/**`
|
|
265
|
+
or `tests/component/**` is invisible to the scanner and `QFAI-ATDD-112`
|
|
266
|
+
still reports the TC as uncovered. Until the scanner and `QFAI-ATDD-112`
|
|
267
|
+
resolve per-TC, keep discharging every `TC-*` in `tests/integration/**`.
|
|
49
268
|
- API obligations:
|
|
50
269
|
- Every declared `CON-API-*` must be referenced at least once from `tests/api/**`.
|
|
51
270
|
- Use `QFAI:CON-API-XXXX` annotations.
|
|
271
|
+
- **Deferral.** `/qfai-sdd` authors contracts in Phase 0 (Contracts-first) and
|
|
272
|
+
slices them in Phase 2, so a contract legitimately exists before its slice
|
|
273
|
+
ships. A contract that declares `x-qfai-status: planned` is excluded from
|
|
274
|
+
the `QFAI-ATDD-113` obligation and reported as `QFAI-ATDD-114` (`info`)
|
|
275
|
+
instead. Remove the marker when the slice is implemented — leaving it in
|
|
276
|
+
place on a shipped slice is a review finding, not a tool finding.
|
|
277
|
+
- The marker counts only at the **document root**. The same key nested under
|
|
278
|
+
an operation defers nothing: one path must not be able to drop the
|
|
279
|
+
API-test obligation for every other `CON-API-*` the file declares.
|
|
280
|
+
- Deferral removes the test obligation, not the declaration. A deferred
|
|
281
|
+
`CON-API-*` stays a known ID, so writing its API test ahead of the slice
|
|
282
|
+
is fine and never raises `QFAI-ATDD-103`.
|
|
283
|
+
- Deferred IDs are recorded in `report/atdd-traceability/summary.{json,md}`
|
|
284
|
+
under `deferred.conApi`, so an empty `missing.conApi` can be told apart
|
|
285
|
+
from a project where every contract is still planned.
|
|
52
286
|
- Forbidden references:
|
|
53
|
-
- `tests/api/**` must not include `QFAI:SPEC-XXXX:TC-YYYY
|
|
54
|
-
|
|
287
|
+
- `tests/api/**` must not include `QFAI:SPEC-XXXX:TC-YYYY` **for a TC whose
|
|
288
|
+
declared `Level` is not L4/API**. A TC that declares an API-level
|
|
289
|
+
obligation belongs in `tests/api/**`, and its annotation there counts as
|
|
290
|
+
coverage. The rule exists to stop obligations drifting into the wrong
|
|
291
|
+
layer, not to make the correct layer unusable.
|
|
292
|
+
- `tests/e2e/**` must not include `QFAI:SPEC-XXXX:TC-YYYY` **for a TC whose
|
|
293
|
+
declared `Level` is not L5/E2E**. Same reason as above: the routing rule
|
|
294
|
+
and the forbidden rule must agree, or the layer the routing selects
|
|
295
|
+
becomes unusable.
|
|
296
|
+
- `tests/integration/**` must not include `QFAI:SPEC-XXXX:TC-YYYY` **for a TC
|
|
297
|
+
whose declared `Level` is not L3/Integration** (`QFAI-ATDD-123`). The rule
|
|
298
|
+
is symmetric so "exactly one directory" holds in both directions: an
|
|
299
|
+
annotation left behind here after the TC moved to L4/L5 is as wrong as one
|
|
300
|
+
filed early into `tests/api/**`.
|
|
55
301
|
- Unknown references (`US/TC/CON-API` not declared) are errors.
|
|
302
|
+
- A `TC-*` annotation outside the directory its `Level` routes to is a
|
|
303
|
+
misplacement, whichever directory it lands in — including the two new
|
|
304
|
+
locations `tests/unit/**` and `tests/component/**`.
|
|
56
305
|
- AC annotations are not required in code; AC coverage is treated as indirect through TC coverage.
|
|
57
306
|
- `QFAI:CON-API-*` in `tests/e2e/**` is not forbidden, but contract guarantee belongs to API tests.
|
|
58
307
|
|
|
308
|
+
## Test-file granularity
|
|
309
|
+
|
|
310
|
+
- Default: **one test module per `TC-*`**. A TDD ledger row's `Test file`
|
|
311
|
+
names that module.
|
|
312
|
+
- Grouping several `TC-*` into one module is allowed when they verify the same
|
|
313
|
+
BR and the module stays reviewable in one pass. Above that, split by BR, then
|
|
314
|
+
by AC.
|
|
315
|
+
- A single `Test file` value shared by every row of a spec is an anti-pattern:
|
|
316
|
+
it makes the per-item "relevant test suite" indistinguishable from the whole
|
|
317
|
+
spec suite, and it puts the whole spec's test code in front of every
|
|
318
|
+
in-context reviewer gate.
|
|
319
|
+
- `qfai-sdd` should emit a per-item `Test file` value, not a per-spec one.
|
|
320
|
+
|
|
59
321
|
## Volume policy
|
|
60
322
|
|
|
61
|
-
- Floors and ratios are signals, not completion gates.
|
|
323
|
+
- Floors and ratios are signals, not completion gates. This is the only
|
|
324
|
+
statement in this section: no volume observation blocks completion, and none
|
|
325
|
+
triggers a Change Request.
|
|
62
326
|
- Completion gate is validation pass with no errors:
|
|
63
|
-
- `qfai validate --fail-on error`
|
|
327
|
+
- `npx qfai validate --fail-on error`
|
|
328
|
+
|
|
329
|
+
If an observed layer distribution looks wrong:
|
|
330
|
+
|
|
331
|
+
1. Do not auto-adjust the distribution to make it look better.
|
|
332
|
+
2. Record the observed distribution and the rationale for it in the running
|
|
333
|
+
stage's evidence file under `.qfai/evidence/` — for example
|
|
334
|
+
`.qfai/evidence/atdd-<spec-id>.md` or
|
|
335
|
+
`.qfai/evidence/implement-<spec-id>.md`.
|
|
336
|
+
3. Continue. The stage is not blocked.
|
|
64
337
|
|
|
65
|
-
|
|
338
|
+
The record goes to evidence, not into the spec, on purpose.
|
|
339
|
+
`constitution/drift-protocol.md` lists `*_delta.md` and the per-spec Open
|
|
340
|
+
Questions file among the upstream SSOT a downstream stage must not edit without
|
|
341
|
+
explicit user approval, and whitelists `.qfai/evidence/**` append/update as an
|
|
342
|
+
allowed exception. Pointing this step at the spec would send ATDD and implement
|
|
343
|
+
straight back into the STOP-and-wait state the policy exists to avoid.
|
|
66
344
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
345
|
+
The owner phase (`/qfai-sdd`) is the one that may carry the note into the
|
|
346
|
+
spec's own Open Questions file on a later run: `08_Open-questions.md` in a
|
|
347
|
+
layered spec, `15_Open-questions.md` in a spec pack.
|
|
348
|
+
(`09_Open-questions.md` is the shared `_policies` file, not a per-spec one.)
|
|
349
|
+
|
|
350
|
+
A Change Request is reserved for `constitution/drift-protocol.md`-class events
|
|
351
|
+
— an actual conflict with an upstream SSOT decision. A volume observation is not
|
|
352
|
+
one, and it stays non-blocking either way. What differs is how much of it is
|
|
353
|
+
measurable:
|
|
354
|
+
|
|
355
|
+
- **No configured guardrail.** qfai ships no default floor, ratio or threshold,
|
|
356
|
+
and no validator emits a volume rule, so "unmet" is a judgement call with no
|
|
357
|
+
tool-checkable meaning. Record the observation and the reasoning.
|
|
358
|
+
- **A configured guardrail.** When a project sets
|
|
359
|
+
`validation.testStrategy.maxE2eScenarioRatio` or `maxE2eScenarioCount` to a
|
|
360
|
+
non-null value, `report.ts` measures it and reports `ratioExceeded` /
|
|
361
|
+
`countExceeded` with a warning. That is the project's own stated limit, not a
|
|
362
|
+
subjective read: record the configured value, the measured value and the
|
|
363
|
+
report warning in the evidence, so the breach is auditable rather than
|
|
364
|
+
paraphrased.
|
|
365
|
+
|
|
366
|
+
**What it counts is narrow.** These two knobs measure **Gherkin scenarios
|
|
367
|
+
parsed out of each spec's Examples file**, bucketed by their `@layer-*` tags.
|
|
368
|
+
They never inspect `<testsDir>/e2e/**` or any other code test. A project that
|
|
369
|
+
writes no Gherkin — the normal shape for a layered project whose E2E lives in
|
|
370
|
+
code — measures zero scenarios, so the guardrail stays silent however many
|
|
371
|
+
code E2E tests exist. Treat them as a guardrail over the **scenario**
|
|
372
|
+
distribution, not over the real test-layer distribution: when they are silent,
|
|
373
|
+
the observation is the judgement call above, and the evidence entry must say
|
|
374
|
+
how the distribution was counted so it is not read as a tool measurement.
|
|
375
|
+
|
|
376
|
+
Either way completion is not blocked and no Change Request is raised: a
|
|
377
|
+
user-blocking Change Request against a project's own tuning knob cannot conclude
|
|
378
|
+
anything actionable.
|
|
71
379
|
|
|
72
380
|
## Anti-patterns
|
|
73
381
|
|
|
74
382
|
- Do not treat `scenario.feature` or a coverage ledger as mandatory completion input.
|
|
75
383
|
- Do not convert all obligations into E2E.
|
|
76
384
|
- Do not inflate tests only to satisfy floor numbers.
|
|
385
|
+
- Do not over-concentrate obligations into a single layer, module, or selector. Collapsing a matrix-shaped `TC-*` into one integration module — or into one test function behind one `test-list.md` selector — is the same failure mode as converting everything into E2E, and it additionally destroys the RED observation: a test function fails once, so only the first failing assert is ever observed. Split per independently observable boundary (see `qfai-implement/references/execution-ledger.md#selector-granularity-must`).
|
|
386
|
+
- Do not re-label an existing obligation's declared layer to change how a
|
|
387
|
+
distribution reads. Re-labelling is the cheapest way to clear a signal and
|
|
388
|
+
the one that destroys the most information; the layer of an obligation is
|
|
389
|
+
determined by what it verifies, never by how the totals look.
|
|
390
|
+
|
|
391
|
+
### Concentration signals (non-gating)
|
|
392
|
+
|
|
393
|
+
Treat these as review signals in the same class as volume floors — worth a finding, never a hard gate:
|
|
394
|
+
|
|
395
|
+
- one test module holding a disproportionate share of a spec's `assert` statements
|
|
396
|
+
- a very low `test_` functions per file ratio in a module that carries many obligations
|
|
397
|
+
- a single selector whose recorded runtime grows monotonically across RED rounds
|
|
398
|
+
|
|
399
|
+
## Test stub detection (QFAI-TEST-001 / QFAI-TEST-002)
|
|
400
|
+
|
|
401
|
+
`QFAI-TEST-001` (error) reports the silent-placeholder construct of each
|
|
402
|
+
supported stack:
|
|
403
|
+
|
|
404
|
+
| Extensions | Construct |
|
|
405
|
+
| -------------------- | ------------------------------------------------------------------- |
|
|
406
|
+
| `.ts` / `.js` family | `it.todo(` / `test.todo(` / `describe.todo(` |
|
|
407
|
+
| `.py` | `pytest.skip(`, `@pytest.mark.skip/skipif/xfail`, `@unittest.skip*` |
|
|
408
|
+
| `.go` | `t.Skip*(` |
|
|
409
|
+
| `.java` / `.kt` | `@Disabled` / `@Ignore` |
|
|
410
|
+
| `.rs` | `#[ignore]` |
|
|
411
|
+
| `.rb` | a line starting `skip` / `pending` |
|
|
412
|
+
| `.cs` | `[Ignore` / `Skip = "` |
|
|
413
|
+
|
|
414
|
+
`QFAI-TEST-002` (info) names any extension the scan opened that has no dialect.
|
|
415
|
+
Without it a clean run on an unsupported stack is indistinguishable from a
|
|
416
|
+
checked one — the detector used to be JS-only while file selection was
|
|
417
|
+
stack-agnostic, so every other stack got a clean result that meant nothing.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Work-log Entry Schema Contract
|
|
2
|
+
|
|
3
|
+
- Contract scope: frontmatter and body schema for `.qfai/steering/*.md` entries
|
|
4
|
+
- Owners: the validate stage (schema enforcement), the implement stage (primary writer) and the Reviewer-Gate stage (consumer)
|
|
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)
|
|
9
|
+
|
|
10
|
+
## Storage model
|
|
11
|
+
|
|
12
|
+
- Per-project, project-root location: `.qfai/steering/`.
|
|
13
|
+
- The **surface** lives at `.qfai/steering/`, not under `.qfai/assistant/`. This
|
|
14
|
+
**schema** ships with the package and `npx qfai init` seeds it at
|
|
15
|
+
`.qfai/assistant/catalog/worklog-entry.schema.md` — the seeded README and entry
|
|
16
|
+
template used to point at an unpublished path, so the contract was
|
|
17
|
+
unresolvable on every consuming project.
|
|
18
|
+
- By default `.gitignore` excludes the directory; projects MAY opt in via override.
|
|
19
|
+
- Filename: `.qfai/steering/<id>.md` where `<id>` is kebab-case ASCII; the frontmatter `id` MUST match the filename stem.
|
|
20
|
+
- Templates live at `.qfai/steering/_templates/`; templates MUST NOT contain entry-shaped frontmatter (validator ignores `_templates/`).
|
|
21
|
+
|
|
22
|
+
## Frontmatter schema
|
|
23
|
+
|
|
24
|
+
```yaml
|
|
25
|
+
---
|
|
26
|
+
id: 2026-05-22-recut-design-call # required; string; kebab-case; matches filename stem
|
|
27
|
+
status: active # required; enum: active | handoff | archived
|
|
28
|
+
kind: decision # required; enum: see below
|
|
29
|
+
created: 2026-05-22 # required; ISO-8601 date (YYYY-MM-DD)
|
|
30
|
+
updated: 2026-05-22 # required; ISO-8601 date; >= created
|
|
31
|
+
scope: spec-0003 # required; "global" or "spec-NNNN"
|
|
32
|
+
blocking: false # required; boolean
|
|
33
|
+
promote-to: spec-0003/07_Decisions.md # required; string (path) OR null
|
|
34
|
+
links: # required; array (may be empty)
|
|
35
|
+
- spec-0003
|
|
36
|
+
- discussion-20260522081618995
|
|
37
|
+
closure-rationale: null # required when status=archived AND no promote-to satisfied; else null/omitted
|
|
38
|
+
promoted-to: null # required when status=archived AND promote-to was satisfied; value is the DR-ID (Decision Row identifier, e.g. `DR-3`) of the appended row in the target `07_Decisions.md`
|
|
39
|
+
---
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### `kind` enum (REQ-0004)
|
|
43
|
+
|
|
44
|
+
The `kind` field MUST be exactly one of:
|
|
45
|
+
|
|
46
|
+
| `kind` | Write trigger |
|
|
47
|
+
| --------------------- | ---------------------------------------------------------------------------- |
|
|
48
|
+
| `milestone` | Task milestone reached |
|
|
49
|
+
| `decision` | A decision was made during work that needs durable capture |
|
|
50
|
+
| `risk` | A risk was identified |
|
|
51
|
+
| `consultation-needed` | The skill needs user input to proceed |
|
|
52
|
+
| `unexpected` | An unexpected event occurred during work |
|
|
53
|
+
| `unscoped-discovery` | Out-of-scope concern discovered; current task continues unblocked (REQ-0016) |
|
|
54
|
+
| `handoff` | Work needs to pause; another session/operator will resume |
|
|
55
|
+
| `blocker` | The skill is stuck (e.g. root-cause hunt stalled) |
|
|
56
|
+
| `scope-up` | Work volume larger than expected |
|
|
57
|
+
| `scope-down` | Planned work is no longer required |
|
|
58
|
+
| `spike` | Exploratory investigation logged |
|
|
59
|
+
|
|
60
|
+
### `status` enum
|
|
61
|
+
|
|
62
|
+
| `status` | Meaning |
|
|
63
|
+
| ---------- | --------------------------------------------------------------------------------------------- |
|
|
64
|
+
| `active` | Open; participates in drift/promote/stale checks |
|
|
65
|
+
| `handoff` | Open and awaiting resumption; body MUST satisfy the handoff-brief schema (REQ-0017) |
|
|
66
|
+
| `archived` | Closed; either promoted (`promoted-to` set) or closed-without-promotion (`closure-rationale`) |
|
|
67
|
+
|
|
68
|
+
### `scope` semantics
|
|
69
|
+
|
|
70
|
+
- `global` — applies project-wide; visible to every skill invocation.
|
|
71
|
+
- `spec-NNNN` — applies only to the named spec. Implementation-phase skills filter on `scope ∈ {global, current-spec}` before reading.
|
|
72
|
+
|
|
73
|
+
### `promote-to` semantics
|
|
74
|
+
|
|
75
|
+
- `null` — entry will not promote.
|
|
76
|
+
- non-`null` — string of the form `spec-NNNN/07_Decisions.md` (target Decisions row to append). The promote-gate surfaces `W-PENDING-PROMOTION` until satisfied (REQ-0007).
|
|
77
|
+
|
|
78
|
+
### `links` array
|
|
79
|
+
|
|
80
|
+
Each element MUST resolve to one of:
|
|
81
|
+
|
|
82
|
+
- `spec-NNNN` — an existing spec directory under `.qfai/specs/`
|
|
83
|
+
- `discussion-*` — an existing discussion pack under `.qfai/discussion/`
|
|
84
|
+
- `<entry-id>` — another `.qfai/steering/<id>.md` entry
|
|
85
|
+
|
|
86
|
+
Broken links surface `W-WORKLOG-BROKEN-LINK` (REQ-0015).
|
|
87
|
+
|
|
88
|
+
## Body schema
|
|
89
|
+
|
|
90
|
+
The body (everything after the closing `---`) is free-form Markdown except for two `kind`-specific schemas below.
|
|
91
|
+
|
|
92
|
+
### `kind: handoff` body — required sections (REQ-0017)
|
|
93
|
+
|
|
94
|
+
```markdown
|
|
95
|
+
## State of the task
|
|
96
|
+
|
|
97
|
+
<one paragraph: where am I, what is done, what remains>
|
|
98
|
+
|
|
99
|
+
## Next single action
|
|
100
|
+
|
|
101
|
+
<one bullet: the very next thing to do on resume>
|
|
102
|
+
|
|
103
|
+
## Constraints to preserve
|
|
104
|
+
|
|
105
|
+
- <bulleted list of invariants that the next operator MUST preserve>
|
|
106
|
+
|
|
107
|
+
## Open questions
|
|
108
|
+
|
|
109
|
+
- <bulleted list; may be empty>
|
|
110
|
+
|
|
111
|
+
## References to consult first
|
|
112
|
+
|
|
113
|
+
- <bulleted list of entry IDs / spec IDs / discussion IDs>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Reviewer Gate emits `R-HANDOFF-INCOMPLETE` if any of the five sections is missing or empty.
|
|
117
|
+
|
|
118
|
+
### `kind: decision` body — recommended sections
|
|
119
|
+
|
|
120
|
+
```markdown
|
|
121
|
+
## Context
|
|
122
|
+
|
|
123
|
+
<what triggered the decision>
|
|
124
|
+
|
|
125
|
+
## Decision
|
|
126
|
+
|
|
127
|
+
<what was decided>
|
|
128
|
+
|
|
129
|
+
## Alternatives considered
|
|
130
|
+
|
|
131
|
+
<bulleted; mark each as accepted | rejected | deferred>
|
|
132
|
+
|
|
133
|
+
## Rationale
|
|
134
|
+
|
|
135
|
+
<why this option>
|
|
136
|
+
|
|
137
|
+
## Consequences
|
|
138
|
+
|
|
139
|
+
<what changes downstream>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The body is consulted by Reviewer Gate when emitting `R-WORKLOG-DRIFT`; the structured shape improves the false-positive rate.
|
|
143
|
+
|
|
144
|
+
## Unit-test obligations (NFR-0010)
|
|
145
|
+
|
|
146
|
+
`parseEntry.ts` MUST have ≥ 12 unit tests covering:
|
|
147
|
+
|
|
148
|
+
1. Well-formed entry
|
|
149
|
+
2. Missing required field (e.g. omitted `kind`)
|
|
150
|
+
3. Invalid enum value
|
|
151
|
+
4. Broken YAML (parse error)
|
|
152
|
+
5. UTF-8 BOM tolerated
|
|
153
|
+
6. CRLF line endings tolerated
|
|
154
|
+
7. `scope: spec-NNNN`
|
|
155
|
+
8. `scope: global`
|
|
156
|
+
9. `promote-to: null`
|
|
157
|
+
10. `promote-to: spec-NNNN/07_Decisions.md`
|
|
158
|
+
11. `links: []`
|
|
159
|
+
12. `links` array with broken reference (parser returns ok; validator emits `W-WORKLOG-BROKEN-LINK`)
|
|
160
|
+
|
|
161
|
+
≥ 90 % line coverage of `parseEntry.ts` in CI.
|
|
162
|
+
|
|
163
|
+
## Distributed-surface obligations
|
|
164
|
+
|
|
165
|
+
The seeded `_templates/entry.md`, and any sample entry shipped via `assets/init/`, MUST carry no internal spec ids, version markers or trace ids. The authoritative list of forbidden shapes is the scanner itself; entries use placeholder ids and dates only.
|
|
@@ -36,7 +36,7 @@ When an agent needs to ask the user a question, the following rules apply (see a
|
|
|
36
36
|
All SKILL.md files MUST include a
|
|
37
37
|
`## User Questions (AskUserQuestion Protocol)` section with MUST-level wording.
|
|
38
38
|
SSOT: `packages/qfai/assets/init/.qfai/assistant/skills/*/SKILL.md`.
|
|
39
|
-
Deployed copy (updated by `qfai init`): `.qfai/assistant/skills/*/SKILL.md`.
|
|
39
|
+
Deployed copy (updated by `npx qfai init`): `.qfai/assistant/skills/*/SKILL.md`.
|
|
40
40
|
|
|
41
41
|
## Error handling
|
|
42
42
|
|