qfai 2.1.1 → 2.2.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.
Files changed (185) hide show
  1. package/README.md +56 -36
  2. package/assets/defaults/agent-routing/qfai-implement.yml +9 -0
  3. package/assets/defaults/agent-routing/qfai-triage.yml +18 -0
  4. package/assets/defaults/workflows/answer-in-session.yml +8 -0
  5. package/assets/defaults/workflows/quarantine-flaky.yml +3 -0
  6. package/assets/defaults/workflows/repair-consistency.yml +1 -0
  7. package/assets/defaults/workflows/run-operation.yml +11 -0
  8. package/assets/defaults/workflows/run-owned-cleanup.yml +12 -0
  9. package/assets/defaults/workflows/write-procedure.yml +18 -0
  10. package/assets/graph/codegraph-native.mjs +174 -0
  11. package/assets/graph/graphify-native.py +72 -0
  12. package/assets/init/.claude/settings.json +9 -9
  13. package/assets/init/.codex/hooks.json +8 -8
  14. package/assets/init/.qfai/assistant/agent/frontend-engineer.md +5 -0
  15. package/assets/init/.qfai/assistant/agent/product-experience-architect.md +4 -0
  16. package/assets/init/.qfai/assistant/agent/product-surface-reviewer.md +7 -0
  17. package/assets/init/.qfai/assistant/agent/requirements-analyst.md +8 -0
  18. package/assets/init/.qfai/assistant/rule/communication.md +18 -8
  19. package/assets/init/.qfai/assistant/rule/constitution.md +31 -15
  20. package/assets/init/.qfai/assistant/rule/drift-protocol.md +119 -2
  21. package/assets/init/.qfai/assistant/rule/references/asset-authoring.md +6 -4
  22. package/assets/init/.qfai/assistant/rule/references/codex-delegation.md +27 -0
  23. package/assets/init/.qfai/assistant/rule/references/griller-recommendations.md +21 -9
  24. package/assets/init/.qfai/assistant/rule/references/worker-edit-boundary.md +48 -0
  25. package/assets/init/.qfai/assistant/rule/review-convergence.md +25 -12
  26. package/assets/init/.qfai/assistant/rule/shared-skill-delegation-baseline.md +16 -25
  27. package/assets/init/.qfai/assistant/rule/shared-skill-operating-baseline.md +16 -11
  28. package/assets/init/.qfai/assistant/rule/ui-definition-protocol.md +6 -1
  29. package/assets/init/.qfai/assistant/rule/workflow.md +2 -1
  30. package/assets/init/.qfai/assistant/skill/qfai-configure/SKILL.md +3 -3
  31. package/assets/init/.qfai/assistant/skill/qfai-discussion/SKILL.md +6 -0
  32. package/assets/init/.qfai/assistant/skill/qfai-discussion/references/discussion-completion-matrix.md +20 -15
  33. package/assets/init/.qfai/assistant/skill/qfai-discussion/references/ui-bearing-playbook.md +2 -4
  34. package/assets/init/.qfai/assistant/skill/qfai-discussion/references/ui_ux_best_practices.md +1 -6
  35. package/assets/init/.qfai/assistant/skill/qfai-discussion/templates/uiux/00_index.md +0 -16
  36. package/assets/init/.qfai/assistant/skill/qfai-grilling/SKILL.md +30 -20
  37. package/assets/init/.qfai/assistant/skill/qfai-grilling/references/delegated-session.md +4 -3
  38. package/assets/init/.qfai/assistant/skill/qfai-grilling/references/session-record.md +8 -2
  39. package/assets/init/.qfai/assistant/skill/qfai-implement/SKILL.md +16 -3
  40. package/assets/init/.qfai/assistant/skill/qfai-implement/references/parallelization-policy.md +9 -1
  41. package/assets/init/.qfai/assistant/skill/qfai-implement/references/red-admissibility.md +46 -0
  42. package/assets/init/.qfai/assistant/skill/qfai-implement/references/ui-affecting.md +5 -2
  43. package/assets/init/.qfai/assistant/skill/qfai-maintain/SKILL.md +3 -3
  44. package/assets/init/.qfai/assistant/skill/qfai-migration-v1-to-v2/SKILL.md +12 -6
  45. package/assets/init/.qfai/assistant/skill/qfai-migration-v1-to-v2/references/migration-guide.md +1 -265
  46. package/assets/init/.qfai/assistant/skill/qfai-migration-v1-to-v2/references/migration-placement.md +273 -0
  47. package/assets/init/.qfai/assistant/skill/qfai-prototyping/SKILL.md +4 -3
  48. package/assets/init/.qfai/assistant/skill/qfai-prototyping/references/review-payload-schema.md +2 -3
  49. package/assets/init/.qfai/assistant/skill/qfai-prototyping/references/reviewer-prompt.md +17 -1
  50. package/assets/init/.qfai/assistant/skill/qfai-run/SKILL.md +52 -37
  51. package/assets/init/.qfai/assistant/skill/qfai-run/references/codex-cloud-install.md +80 -0
  52. package/assets/init/.qfai/assistant/skill/qfai-run/references/evidence-delivery.md +322 -0
  53. package/assets/init/.qfai/assistant/skill/qfai-run/references/extraction.md +83 -49
  54. package/assets/init/.qfai/assistant/skill/qfai-run/references/operator-screens.md +226 -11
  55. package/assets/init/.qfai/assistant/skill/qfai-run/references/plan.md +6 -3
  56. package/assets/init/.qfai/assistant/skill/qfai-run/references/reached-step-observations.md +132 -0
  57. package/assets/init/.qfai/assistant/skill/qfai-run/references/stage-points.md +14 -0
  58. package/assets/init/.qfai/assistant/skill/qfai-run/scripts/codex-cloud-install.mjs +117 -0
  59. package/assets/init/.qfai/assistant/skill/qfai-sdd/SKILL.md +4 -3
  60. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/contract-artifact-rules.md +1 -0
  61. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/design-anti-patterns.md +23 -5
  62. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/design-md-authoring.md +20 -7
  63. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/requirements-decomposition.md +8 -0
  64. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-execution-playbook.md +29 -4
  65. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-phase-checklists.md +1 -1
  66. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-pre-draft-grilling.md +4 -1
  67. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-quality-gate.md +1 -1
  68. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-triage.md +159 -4
  69. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/spec-traceability-rules.md +14 -2
  70. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/ui-contract-guide.md +146 -0
  71. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/ui-design-contract-normalization.md +4 -29
  72. package/assets/init/.qfai/assistant/skill/qfai-sdd/templates/change-request.md +38 -1
  73. package/assets/init/.qfai/assistant/skill/qfai-sdd/templates/contracts/ui-contract.sample.yaml +52 -5
  74. package/assets/init/.qfai/assistant/skill/qfai-sdd/templates/spec/decisions.md +12 -0
  75. package/assets/init/.qfai/assistant/skill/qfai-triage/SKILL.md +34 -21
  76. package/assets/init/.qfai/assistant/skill/qfai-verify/SKILL.md +5 -4
  77. package/assets/init/.qfai/assistant/skill/qfai-verify/references/context-load.md +9 -6
  78. package/assets/init/.qfai/assistant/skill/qfai-verify/references/verify-output-contract.md +80 -15
  79. package/assets/init/.qfai/assistant/skill/web-research/SKILL.md +35 -21
  80. package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/brave-search/config.toml +2 -4
  81. package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/brave-search/mcp-config.json +9 -5
  82. package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/firecrawl/.mcp.json +1 -2
  83. package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/firecrawl/config.toml +3 -3
  84. package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/firecrawl/mcp-config.json +11 -8
  85. package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/playwright/config.toml +1 -1
  86. package/assets/init/.qfai/assistant/skill/web-research/mcp-templates/playwright/mcp-config.json +7 -3
  87. package/assets/init/.qfai/assistant/step/common-design-md/STEP.md +33 -20
  88. package/assets/init/.qfai/assistant/step/common-gate-run/STEP.md +124 -8
  89. package/assets/init/.qfai/assistant/step/common-grilling-record/STEP.md +10 -2
  90. package/assets/init/.qfai/assistant/step/common-policy-check/STEP.md +1 -0
  91. package/assets/init/.qfai/assistant/step/common-review-cycle/STEP.md +26 -9
  92. package/assets/init/.qfai/assistant/step/discussion-interview/STEP.md +15 -8
  93. package/assets/init/.qfai/assistant/step/discussion-oq/STEP.md +5 -1
  94. package/assets/init/.qfai/assistant/step/discussion-pack/STEP.md +6 -1
  95. package/assets/init/.qfai/assistant/step/discussion-research/STEP.md +2 -0
  96. package/assets/init/.qfai/assistant/step/discussion-uiux/STEP.md +6 -4
  97. package/assets/init/.qfai/assistant/step/implement-backport/STEP.md +1 -1
  98. package/assets/init/.qfai/assistant/step/implement-benchmark/STEP.md +7 -4
  99. package/assets/init/.qfai/assistant/step/implement-dep-bump/STEP.md +11 -2
  100. package/assets/init/.qfai/assistant/step/implement-diagnose/STEP.md +2 -0
  101. package/assets/init/.qfai/assistant/step/implement-oracle-parity/STEP.md +2 -2
  102. package/assets/init/.qfai/assistant/step/implement-procedure/STEP.md +69 -0
  103. package/assets/init/.qfai/assistant/step/implement-quarantine/STEP.md +24 -7
  104. package/assets/init/.qfai/assistant/step/implement-refactor/STEP.md +2 -2
  105. package/assets/init/.qfai/assistant/step/implement-regression-fix/STEP.md +7 -6
  106. package/assets/init/.qfai/assistant/step/implement-retire/STEP.md +6 -3
  107. package/assets/init/.qfai/assistant/step/implement-revert/STEP.md +4 -3
  108. package/assets/init/.qfai/assistant/step/implement-seam/STEP.md +6 -5
  109. package/assets/init/.qfai/assistant/step/implement-stress-harness/STEP.md +34 -3
  110. package/assets/init/.qfai/assistant/step/implement-sweep/STEP.md +4 -3
  111. package/assets/init/.qfai/assistant/step/implement-tdd/STEP.md +39 -5
  112. package/assets/init/.qfai/assistant/step/implement-tooling/STEP.md +22 -2
  113. package/assets/init/.qfai/assistant/step/maintain-edit/STEP.md +18 -14
  114. package/assets/init/.qfai/assistant/step/prototyping-grill/STEP.md +4 -3
  115. package/assets/init/.qfai/assistant/step/prototyping-loop/STEP.md +4 -0
  116. package/assets/init/.qfai/assistant/step/prototyping-preflight/STEP.md +9 -3
  117. package/assets/init/.qfai/assistant/step/sdd-contract/STEP.md +11 -0
  118. package/assets/init/.qfai/assistant/step/sdd-flow/STEP.md +2 -0
  119. package/assets/init/.qfai/assistant/step/sdd-story/STEP.md +10 -0
  120. package/assets/init/.qfai/assistant/step/sdd-triage/STEP.md +34 -10
  121. package/assets/init/.qfai/assistant/step/triage-answer/STEP.md +7 -6
  122. package/assets/init/.qfai/assistant/step/triage-close/STEP.md +33 -23
  123. package/assets/init/.qfai/assistant/step/triage-cluster/STEP.md +5 -3
  124. package/assets/init/.qfai/assistant/step/triage-decompose/STEP.md +2 -0
  125. package/assets/init/.qfai/assistant/step/triage-dedupe/STEP.md +4 -0
  126. package/assets/init/.qfai/assistant/step/triage-handoff/STEP.md +13 -4
  127. package/assets/init/.qfai/assistant/step/triage-investigate/STEP.md +8 -5
  128. package/assets/init/.qfai/assistant/step/triage-operate/STEP.md +50 -0
  129. package/assets/init/.qfai/assistant/step/triage-owned-cleanup/STEP.md +86 -0
  130. package/assets/init/.qfai/assistant/step/triage-request-info/STEP.md +2 -0
  131. package/assets/init/.qfai/assistant/step/triage-security-intake/STEP.md +6 -3
  132. package/assets/init/.qfai/assistant/step/verify-change-note/STEP.md +1 -0
  133. package/assets/init/.qfai/assistant/step/verify-commit/STEP.md +37 -9
  134. package/assets/init/.qfai/assistant/step/verify-external/STEP.md +5 -2
  135. package/assets/init/.qfai/assistant/step/verify-qfai-gate/STEP.md +14 -16
  136. package/assets/init/.qfai/assistant/step/verify-release-notes/STEP.md +1 -0
  137. package/assets/init/.qfai/assistant/step/verify-repeat-run/STEP.md +46 -4
  138. package/assets/init/.qfai/assistant/step/verify-repo-gate/STEP.md +133 -30
  139. package/assets/init/root/.agents/rules/ai-readable-markdown.md +2 -2
  140. package/assets/init/root/.agents/rules/api-budget.md +187 -8
  141. package/assets/init/root/.agents/rules/document-schema.md +17 -0
  142. package/assets/init/root/.agents/rules/documentation-clarity.md +163 -34
  143. package/assets/init/root/.agents/rules/graph-exploration.md +150 -0
  144. package/assets/init/root/.agents/rules/grilling.md +100 -43
  145. package/assets/init/root/.agents/rules/minimal-implementation.md +3 -3
  146. package/assets/init/root/.agents/rules/reminders.json +27 -18
  147. package/assets/init/root/.agents/rules/session-feedback.md +131 -0
  148. package/assets/init/root/.agents/rules/temporary-files.md +33 -0
  149. package/assets/init/root/.agents/rules/untrusted-content.md +2 -2
  150. package/assets/init/root/.agents/rules/user-questions.md +51 -40
  151. package/assets/init/root/.github/workflows/qfai-docs.yml +3 -3
  152. package/assets/init/root/.github/workflows/qfai-tests.yml +88 -35
  153. package/assets/init/root/.github/workflows/qfai-validate.yml +2 -2
  154. package/assets/init/root/AGENTS.md +24 -22
  155. package/assets/sandbox-templates/default-deny.yaml +9 -3
  156. package/assets/schemas/workflow/extraction.schema.json +89 -5
  157. package/assets/scripts/check-mdschema.mjs +77 -8
  158. package/assets/uix-rev/comparison-review.md +1 -1
  159. package/assets/uix-rev/contracts-review.md +1 -2
  160. package/dist/cli/index.cjs +9444 -10071
  161. package/dist/cli/index.cjs.map +1 -1
  162. package/dist/cli/index.mjs +9421 -10041
  163. package/dist/cli/index.mjs.map +1 -1
  164. package/dist/graph/cli.cjs +1568 -0
  165. package/dist/graph/cli.cjs.map +1 -0
  166. package/dist/graph/cli.d.cts +9 -0
  167. package/dist/graph/cli.d.ts +9 -0
  168. package/dist/graph/cli.mjs +1541 -0
  169. package/dist/graph/cli.mjs.map +1 -0
  170. package/dist/graph/hook.cjs +817 -0
  171. package/dist/graph/hook.cjs.map +1 -0
  172. package/dist/graph/hook.d.cts +9 -0
  173. package/dist/graph/hook.d.ts +9 -0
  174. package/dist/graph/hook.mjs +792 -0
  175. package/dist/graph/hook.mjs.map +1 -0
  176. package/dist/index.cjs +7634 -8517
  177. package/dist/index.cjs.map +1 -1
  178. package/dist/index.d.cts +146 -658
  179. package/dist/index.d.ts +146 -658
  180. package/dist/index.mjs +7462 -8318
  181. package/dist/index.mjs.map +1 -1
  182. package/dist/process-C21nTvkT.d.cts +12 -0
  183. package/dist/process-C21nTvkT.d.ts +12 -0
  184. package/package.json +4 -6
  185. package/assets/init/root/CLAUDE.md +0 -46
@@ -22,6 +22,7 @@ naming the pattern is what works.
22
22
  - Placement
23
23
  - Motion and transitions
24
24
  - Copy in the UI
25
+ - Copy that adds no meaning
25
26
  - Information architecture and flow
26
27
  - States and accessibility
27
28
  - Implementation defaults
@@ -51,11 +52,13 @@ naming the pattern is what works.
51
52
  flow_ and _States and accessibility_ do, `interface-clarity.md` and the spec
52
53
  are the rules. The entry is the form a breach of them takes on a generated
53
54
  screen.
54
- - The reviewer inside the prototyping loop does not apply this list. Root
55
- `DESIGN.md` locks the brand values that reviewer sees, so
56
- a pattern is caught where the design direction is reviewed and where
57
- `DESIGN.md` is written. No entry here is a `lap-*` detection, and none blocks
58
- the loop.
55
+ - The reviewer inside the prototyping loop does not apply the sections about
56
+ identity. Root `DESIGN.md` locks the brand values that reviewer sees, so a
57
+ pattern there is caught where the design direction is reviewed and where
58
+ `DESIGN.md` is written. That reviewer does apply _Copy that adds no meaning_,
59
+ through the criterion on explanatory text, because those patterns are about
60
+ what the text tells the user, not about a brand. No entry here is a `lap-*`
61
+ detection.
59
62
 
60
63
  ## Color and background
61
64
 
@@ -269,6 +272,21 @@ naming the pattern is what works.
269
272
  - The screen shows technical detail nobody asked for, such as GPU status or
270
273
  average generation time.
271
274
 
275
+ ## Copy that adds no meaning
276
+
277
+ These patterns are judged against the screen's tasks and the `supplements` its UI
278
+ contract declares, in SDD, in implementation and in every surface review. A chosen
279
+ visual direction does not exempt them. A disclosure about demo data, cost, storage
280
+ or transmission that is true and shown where the user decides is not one of them:
281
+ judge where it sits and what it lets the user do, not the word.
282
+
283
+ - A second heading or a sentence repeats the main heading, an action label, a
284
+ state, or the content beside it.
285
+ - A condition the user already knows is explained again where it adds nothing to
286
+ the decision being made.
287
+ - Production copy carries a development instruction, implementation commentary,
288
+ or a demo note repeated on screen after screen.
289
+
272
290
  ## Information architecture and flow
273
291
 
274
292
  - Sections follow the stock order: hero, logos, three features, stats or
@@ -25,9 +25,10 @@ this flow's provenance names:
25
25
  | `uiux/00_index.md`, `uiux/40_screen_contracts.md` | the screen-level sidecars |
26
26
 
27
27
  `01_Context.md#Design Direction` is the decision the user made: the adopted
28
- theme, what departs from it, and what stays ordinary. A UI-bearing pack that
29
- records none leaves the brand unchosen — stop and ask rather than pick one,
30
- which is the same rule an imported specification gets.
28
+ theme, what departs from it, and what stays ordinary. For initial authoring of
29
+ a missing file, a UI-bearing pack that records no design direction leaves the
30
+ brand unchosen — stop and ask rather than pick one, which is the same rule an
31
+ imported specification gets.
31
32
 
32
33
  Each registry entry carries what was adopted, what was rejected, and how it
33
34
  was translated. The competitor registry feeds brand and tokens; the component
@@ -116,7 +117,19 @@ to touch a colour has nothing to be consistent with.
116
117
 
117
118
  ## When the file already exists
118
119
 
119
- `npx qfai init` seeds the sample at the project root and never overwrites it,
120
- and a project may have authored its own. Write only when the file is missing.
121
- An existing file is validated as it stands, except that an unreplaced sample
122
- is refused.
120
+ `npx qfai init` writes no root `DESIGN.md`; the sample is shipped only as a
121
+ skill template. A root file that exists was authored by `common-design-md` or
122
+ copied from that template on purpose, and a project may have authored its own.
123
+ Write a missing file from the recorded direction. Repair an existing file only when SDD triage names its exact path
124
+ and the requested change, and a new WIP change request authorizes both. Apply
125
+ only the authorized change; preserve existing brand and tokens unless their
126
+ change is authorized and supported by recorded direction or named theme
127
+ values. Record the source of each changed value and leave unrelated content
128
+ unchanged. Stop without writing a value neither source supplies. Without that
129
+ authorization, validate the existing file without an overwrite; an inherited
130
+ DONE row authorizes no new change. An unreplaced sample is refused.
131
+
132
+ For an existing valid file, validation and authorized repairs that preserve
133
+ its brand and tokens require no new brand selection. An authorized brand or
134
+ token change still needs recorded direction or named theme values for each
135
+ changed value; without either source, stop without writing the change.
@@ -25,6 +25,14 @@ Use source-backed discussion requirements to write one connected, testable story
25
25
  - An EX is one concrete input and expected result for exactly one AC. Split examples whose paths can pass or fail independently.
26
26
  - A BR is one independently falsifiable constraint. If removing a clause leaves another complete rule, split it.
27
27
 
28
+ A capacity-only sibling may represent the same actual actor goal within the
29
+ same BF when requested AC or EX additions exceed the source story's remaining
30
+ capacity. Prefer preserving published cases and IDs, and place only new,
31
+ cohesive incoming cases under their own covering change request. Confirm
32
+ retired-inclusive capacity and the owning approval before writing; this
33
+ exception invents no new product outcome and grants no future creation or move
34
+ permission.
35
+
28
36
  Allocate each ID as the highest ID of its kind in its defined scope plus one, counting retired IDs. Never reuse an ID. The scopes and widths are in the `ID allocation` section of the triage reference.
29
37
 
30
38
  ## Ambiguity
@@ -4,10 +4,35 @@ Use this sequence for /qfai-sdd. The shipped templates under ../templates/spec/
4
4
 
5
5
  ## Stage 0: source inventory
6
6
 
7
- 1. Run npx qfai sdd preflight and read its selectedInputPath and source. Respect an explicitly selected discussion pack, including one older than the newest pack.
8
- 2. Read the selected pack, completed reviews that target it, explicit user requirements, and the existing story tree. A pack is reference and provenance material. Disposition its applicable review advice in the SDD report, a decision row, or an open question. A pack discrepancy does not itself block SDD.
9
- 3. Stop if there is no usable input source. Stop on an unresolved product decision that cannot safely be inferred; record the question in open-questions.md.
10
- 4. If no discussion pack exists and an imported specification does, run npx qfai sdd preflight --import <path> with that file, which selects it as the source. An explicit user requirement is used as it is and named in the SDD report. Do not manufacture a discussion pack.
7
+ 1. Use the launcher established by
8
+ `.qfai/assistant/rule/shared-skill-operating-baseline.md#canonical-qfai-launcher-mandatory`.
9
+ Record its resolved package path and version in the SDD report. Check that
10
+ the installed Stage 0 instructions support the procedure being used.
11
+ 2. Run `npx qfai sdd preflight` and read its `selectedInputPath` and `source`.
12
+ Respect an explicitly selected discussion pack, including one older than the
13
+ newest pack.
14
+ 3. Read the selected pack, completed reviews that target it, explicit user
15
+ requirements, and the existing story tree. A pack is reference and provenance
16
+ material. Disposition its applicable review advice in the SDD report, a decision
17
+ row, or an open question. A pack discrepancy does not itself block SDD. For
18
+ the current request, read the existing purpose in
19
+ `<paths.specsDir>/01_policy/objective.md` and inspect related flows and stories.
20
+ 4. A missing discussion pack does not mean that specifications are missing. If
21
+ an existing readable specification is authoritative for this request, run
22
+ `npx qfai sdd preflight --import <path>` with that file. The fallback does
23
+ not replace a selected pack or bypass unsafe pack names, unreadable files,
24
+ invalid active pointers, config errors, or a mismatched tool.
25
+ 5. Use an explicit user requirement as supplied and name it in the SDD report.
26
+ Do not invent an import file from conversation. Without a file, CLI preflight
27
+ can remain blocked while SDD assesses that explicit requirement.
28
+ 6. Use `/qfai-discussion` only when no usable source exists; stop SDD until one
29
+ is available. Stop on an unresolved product decision that cannot safely be
30
+ inferred; record the question in `open-questions.md`. Do not manufacture or
31
+ regenerate a past discussion pack, or regenerate the existing purpose,
32
+ merely to clear preflight.
33
+ 7. Import-lite readiness identifies the input source. It does not establish
34
+ complete requirements or a validation PASS. Keep the existing purpose and
35
+ current request while updating only affected flow and story content.
11
36
 
12
37
  ## Stage 1: triage and decisions
13
38
 
@@ -56,7 +56,7 @@ Follow the cycle the `sdd-cycle` step sets out.
56
56
  - Every affected BF passed npx qfai validate --profile sdd --fail-on error --flow BF-NNNN with error=0.
57
57
  - Every document written passes its document schema. A failure was fixed by reshaping the document, not by adding to it.
58
58
  - The log path and result for each BF are in the SDD report.
59
- - Each entered design-writing stage has a pre-draft grilling checkpoint before its first mutation. The final report lists each decision a checkpoint adopted; unanswered critical decisions remain open and block completion.
59
+ - Each entered design-writing stage has a pre-draft grilling checkpoint before its first mutation. A checkpoint that finds no open decision holds no session. The final report lists each decision a checkpoint adopted; unanswered critical decisions remain open and block completion.
60
60
  - Reviewers are independent of the authors, and every finding of the one review is fixed or answered.
61
61
  - Rejected options remain excluded, or a documented reopening decision exists.
62
62
  - Remaining risks and next actions are explicit in the SDD report.
@@ -1,6 +1,9 @@
1
1
  # Pre-draft Grilling
2
2
 
3
- Before an SDD stage makes a design decision, the session agent gathers the stage's open decisions into one frontier and settles them in a delegated grilling session under `.qfai/assistant/rule/review-convergence.md#agent-to-agent-grilling-must`, using the `qfai-grilling` method. It asks the user each critical decision the frontier holds.
3
+ Before an SDD stage makes a design decision, the session agent gathers the stage's open decisions into one frontier.
4
+ When the frontier holds a design decision the repository cannot settle, the agent settles the frontier in a delegated grilling session under `.qfai/assistant/rule/review-convergence.md#agent-to-agent-grilling-must`, using the `qfai-grilling` method. It asks the user each critical decision the frontier holds.
5
+
6
+ When the request, the story tree, the contracts and the recorded decisions already settle every decision of the stage, the frontier is empty. Then no session is held and no griller starts. The stage writes what is settled, and its final report lists no adopted decision for the checkpoint.
4
7
 
5
8
  ## Checkpoints
6
9
 
@@ -38,7 +38,7 @@ Do not use a sibling's in-flight findings to hold or clear the current flow. Rec
38
38
 
39
39
  ## Review and evidence
40
40
 
41
- - A pre-draft grilling checkpoint ran before the first write of every design-writing stage entered, and each critical decision it held was put to the user.
41
+ - A pre-draft grilling checkpoint ran before the first write of every design-writing stage entered. It held a grilling session only where it found a decision the repository cannot settle, and each critical decision it held was put to the user.
42
42
  - The final report lists each decision a checkpoint adopted, with its reason.
43
43
  - Reviewers are independent of authors, and every finding of the one review is fixed or answered under `.qfai/assistant/rule/review-convergence.md`, with no re-review.
44
44
  - Evidence records the source, changed IDs and files, contract executability, commands, reviewer verdicts, rejected options excluded, and remaining risks.
@@ -7,6 +7,8 @@ Triage selects the smallest story-tree change that answers each incoming require
7
7
  - Inputs
8
8
  - Operation choice
9
9
  - Decision and question rows
10
+ - Published decision prefix recovery
11
+ - Merge-added identical decision copy recovery
10
12
  - Approval and no-question mode
11
13
  - Retiring an EX, AC or BR
12
14
  - ID allocation
@@ -34,7 +36,9 @@ Inspect the impact cascade: policy → BF → US → AC → EX → enforcing con
34
36
  ## Decision and question rows
35
37
 
36
38
  Use <paths.specsDir>/decisions.md and <paths.specsDir>/open-questions.md, each with exactly ID, Content, Approach, Status. Append a row; later only Status may change, including to `PARTLY SUPERSEDED (by DEC-NNNN)` when a later row narrows a decision without replacing it.
37
- Do not edit the first three cells or remove the row. Use the next highest ID in the table plus one. A retired item still reserves its BF or US ID.
39
+ Do not edit the first three cells or remove the row, except for explicit branch-added decision renumbering under ID allocation below
40
+ or the bounded published decision prefix recovery below, and remove a row only as a proven surplus copy under the merge-added
41
+ identical decision copy recovery below. Inherited rows retain those cells. Use the next highest ID in the table plus one. A retired item still reserves its BF or US ID.
38
42
 
39
43
  decisions.md records only what the user decided: each change request the user approved or declined,
40
44
  and each critical decision the user made. A row is appended once the user has decided what it records.
@@ -58,6 +62,69 @@ whose Content opens Unadjudicated:, at TODO until decided. A justified test exce
58
62
  decision Content with Test exception:, names the exact BF, AC, or EX it exempts, and puts the reason
59
63
  in Approach. It takes effect only at DONE; it never exempts descendant items.
60
64
 
65
+ A test annotation may remain pending only when authority to change the
66
+ specification covers that state and the test deferral is approved. Record the
67
+ specification change in its own `Change request:` row. Record the deferral as a
68
+ `Test exception:` decision naming the exact AC at DONE. Its Approach states
69
+ the reason, untested scope, owner, next decision date and condition for restoring
70
+ the annotation.
71
+
72
+ DONE establishes the exception decision; it does not mean test completion.
73
+ The existing info finding names the exempted AC and its decision without
74
+ claiming test execution or coverage. The exception never exempts descendant EX
75
+ obligations or authorizes changes to EX or BR scope. Do not silently substitute
76
+ an EX or prose rewrite for an approved specification change. Use the next
77
+ decision date for manual review; there is no automatic expiry and no automatic
78
+ warning.
79
+
80
+ When specification changes are forbidden or either authority is missing, first
81
+ append an `Unadjudicated:` OQ at TODO. Name the affected IDs, expected versus
82
+ actual behavior, implementation-change evidence, owner and required permission.
83
+ Stop dependent AC, EX and BR edits; independent authorized work may continue.
84
+
85
+ ## Published decision prefix recovery
86
+
87
+ When an approved request names a published malformed decision added by the
88
+ branch, read `.qfai/assistant/rule/drift-protocol.md#published-decision-prefix-recovery`.
89
+ That rule defines the source, byte boundaries, exact prefix and stop conditions.
90
+ Approval of the generic protocol alone authorizes no target; append a separate
91
+ new target-specific recovery change request using `templates/change-request.md`.
92
+
93
+ Record the fixed base and unique common ancestor, absence of the target in both,
94
+ the published source commit's ancestry, raw Approach digests and the exact
95
+ approved prefix. Immediately before writing, recheck the unique current row,
96
+ its original ID, Content and Status, and its old digest. Preserve every original
97
+ Approach byte as the suffix and leave every other row unchanged. Recheck the
98
+ existing form and validation; status or supersession clears no malformed form.
99
+ Record actual results, including any stopped recovery, without claiming an
100
+ automatic repair. Inherited records and open-question rows remain excluded.
101
+ Rollback follows the recorded new-digest check and restores the original form
102
+ failure; it never resets, amends or force pushes.
103
+
104
+ ## Merge-added identical decision copy recovery
105
+
106
+ When a merge left a second byte-identical copy of an inherited decision and the
107
+ duplicate-ID check rejects it, read
108
+ `.qfai/assistant/rule/drift-protocol.md#merge-added-identical-decision-copy-recovery`.
109
+ That rule defines the lineage, the raw-row proof and the stop conditions.
110
+ Approval of the generic protocol alone authorizes no target; append a separate
111
+ new target-specific change request using `templates/change-request.md`.
112
+
113
+ The request names the exact path, the ID, the bad merge, both parents, the
114
+ common ancestor, the base and its comparison ancestor, each occurrence's
115
+ location, the raw SHA-256 including the line ending and the retain/remove
116
+ mapping. Fresh evidence, reviewed independently after the request is appended,
117
+ fixes the actual write HEAD, the complete preimage and replacement hashes and
118
+ the current authority. Immediately before writing, recheck refs, path,
119
+ authority, counts, mapping and bytes; stale or changed proof stops the
120
+ recovery. Remove only the mapped surplus copies. Keep one original and every
121
+ other row, reference and byte. Open-question rows, rows that differ in any cell,
122
+ padding or line ending, and surplus the base already holds stay excluded.
123
+ Duplicate, drift and Status rules apply as before. The result is no whole-target
124
+ PASS, and the request stays WIP while any named action or required check is
125
+ unfinished. Rollback restores the recorded preimage only while the file still
126
+ equals the replacement; it never resets, amends or force pushes.
127
+
61
128
  ## Approval and no-question mode
62
129
 
63
130
  Use the shared user-question protocol for CREATE, DELETE, SPLIT, MERGE, SUPERSEDE, and UPDATE:REMOVE. Present the target and rationale. Do not self-approve. A request from the user in the session that names the operation and its effect is the approval, and no second question is asked.
@@ -81,7 +148,7 @@ A story-tree or contract file changes only on the user's approval:
81
148
  records who approved it, when, and the label of the option chosen.
82
149
  3. Move the row to DONE once every change it names is written.
83
150
 
84
- A row present before the stage started keeps its ID, Content and Approach.
151
+ A row present before the stage started keeps its ID, Content and Approach, except for explicit branch-added decision renumbering under ID allocation below or published decision prefix recovery above. Inherited rows keep those cells without exception; the merge-added identical decision copy recovery above removes only surplus copies and keeps the original.
85
152
  Only a row this stage appended changes its Status.
86
153
 
87
154
  ## Retiring an EX, AC or BR
@@ -104,12 +171,74 @@ Read all IDs of the kind in the relevant scope, including IDs named by retiremen
104
171
  A contract number spans every contract kind, and a BR is numbered inside its contract. DEC and OQ each span their table.
105
172
  Empty numeric scopes begin at 0001, and AC/EX tails begin at 01. Do not reuse an ID because its file was removed or a row was rejected.
106
173
 
174
+ ### Capacity before writing
175
+
176
+ AC and EX tails stay two digits, from 01 through 99. Before writing a planned
177
+ batch, report each affected kind and story, its high-water number H (0 when
178
+ empty), remaining capacity 99-H and the number of requested additions. Count
179
+ valid IDs in the tree and decisions, including retired IDs, plus observed
180
+ published parallel heads and known reservations under the project's existing
181
+ method. Name the fixed observation and what it did not cover. A snapshot
182
+ reserves nothing and cannot cover unpublished concurrent work.
183
+
184
+ If requested additions exceed 99-H, stop before any partial allocation or
185
+ invalid declaration. Never fill gaps, reuse retired IDs or emit tail 100.
186
+ An empty scope has capacity 99. H = 98 allows one addition at tail 99, not two;
187
+ a retired 99 still exhausts the scope. Recheck newly published claims or
188
+ collisions before publication.
189
+
190
+ ### Capacity partition
191
+
192
+ Only additions exceeding an actual AC or EX scope's remaining 99-H qualify for
193
+ a capacity-only story partition. Record the source story, affected kind, H,
194
+ remainder and requested count first. Prefer leaving every published case and ID
195
+ in place and putting a cohesive incoming group in a capacity-checked sibling
196
+ under the same BF and actual actor goal. An in-force owning change request must
197
+ explicitly approve this partition and its affected paths before writing.
198
+
199
+ State the sibling's truthful cohesive scope and settle each criterion's owner;
200
+ do not invent a new product outcome, duplicate an obligation or weaken it.
201
+ A different actor, goal, flow or intended behavior needs its existing owning
202
+ approval path. Additions that fit the original scope do not qualify. Missing
203
+ authority, insufficient destination capacity or no truthful partition stops
204
+ the dependent write. This prospective split places new overflow cases; moving
205
+ an existing case also needs the complete map below. These instructions approve
206
+ no future specific creation, move or split.
207
+
208
+ ### Actual moves and incoming collisions
209
+
210
+ Before an approved actual AC/EX move or incoming collision repair, make a
211
+ complete one-to-one map of:
212
+
213
+ - the fixed source commit and declaration path;
214
+ - each original BF/US/AC/EX identity and its case meaning;
215
+ - destination story, AC/EX IDs and paths;
216
+ - every affected active BR citation and counted adjacent test declaration;
217
+ - unaffected cases and the input, expected outcome and executable assertion
218
+ each mapped case preserves.
219
+
220
+ Check both scopes' retired-inclusive capacity. Each destination EX needs one
221
+ existing destination AC; each AC needs an EX. Preserve every moved EX's
222
+ owning BR link and counted test obligation. An ID change alone proves no
223
+ coverage. Retire old moved IDs in a new approved record and never refill them.
224
+ Inherited published DEC ID, Content and Approach cells and their old-ID
225
+ references remain historical and unchanged; update only approved active
226
+ references.
227
+
228
+ Keep unaffected published cases and IDs. Identify same-number branch cases by
229
+ fixed provenance and meaning, and change only the provably incoming item,
230
+ without blanket replacement. Unknown ownership, ambiguous collisions,
231
+ uncovered declarations, missing counted test links, changed assertions or an
232
+ incomplete map stops the move without a completion claim. This is a manual
233
+ approval and mapping procedure, not a relocation executor or mapping schema.
234
+
107
235
  Two branches can take the same next ID. When a merge leaves one ID on two items:
108
236
 
109
237
  1. The merge target's item keeps the ID. Renumber the incoming item, the one the merge brings in.
110
238
  2. Give it the next ID of its scope.
111
239
  A renumbered BF or US takes its child IDs and its directory names with it, as a move to another BF does below.
112
- 3. Change every citation of the old ID in the same commit.
240
+ 3. Change every citation belonging to the incoming item in the same commit.
241
+ For a decision, leave inherited references unchanged.
113
242
  4. State the old ID, the new ID and the renamed record's subject or path in the commit message.
114
243
  A citation of the old ID elsewhere is then told apart from the item that kept it.
115
244
 
@@ -118,7 +247,33 @@ A row the incoming branch added takes the next ID of its table.
118
247
  An ID that two merged records already share is not renumbered:
119
248
  ask the user for a change request row that states which record each citation meant.
120
249
 
121
- A move to another BF changes the story's US ID and all child AC and EX IDs. Record the old IDs as retired, allocate new IDs in the destination scope, and update every citation before the move is complete.
250
+ For a unique decision added by the incoming branch, repair its ID before merging:
251
+
252
+ ```text
253
+ qfai sdd renumber-decision --from <old-DEC-ID> --to <new-DEC-ID> --base <local-ref>
254
+ ```
255
+
256
+ The explicit base and HEAD must resolve locally and have one common ancestor
257
+ that declares no source row. The base may already use that ID; the current
258
+ tree must declare it only once. Choose an unused destination above both story trees'
259
+ highest decision number, retired IDs included, within the four-digit grammar.
260
+ The command reserves no number and chooses no final number automatically.
261
+
262
+ Read the preview's fixed SHAs, IDs, relative paths and replacement lines or
263
+ counts. It writes nothing and dumps no original lines or full files. Each
264
+ invocation builds its own plan. Run with `--apply` to recheck that invocation's
265
+ fixed refs and original bytes before writing; changed refs after a preview can
266
+ produce a different plan. Preflight-only
267
+ `--format`, `--fail-on`, `--import` and `--assume` are not accepted here.
268
+ Only provably branch-added exact references change. Inherited references stay
269
+ fixed; ambiguous ownership, dirty or linked candidates, unsupported text or
270
+ failed reads stop the whole plan before writing. Unrelated links and dirty
271
+ files are not candidates. Apply rechecks original bytes before each write.
272
+ Rollback restores a changed file only if its bytes still match this invocation's
273
+ replacement, preserving concurrent changes and naming any unrestored path.
274
+ These checks guarantee neither atomic concurrency nor power-loss safety.
275
+
276
+ A move to another BF changes the story's US ID and all child AC and EX IDs. It follows the existing approval path, not the same-BF capacity exception. Apply the complete map above to approved active citations and retire old IDs in a new approved record; inherited DEC cells and their historical references stay unchanged.
122
277
 
123
278
  ## Completion of triage
124
279
 
@@ -89,14 +89,26 @@ The table holds no rule. A behaviour a layer must show is a BR in the contract t
89
89
 
90
90
  Use highest existing number plus one in the scope. Count IDs named in retired-item decisions, so deletion never frees an ID. Empty scopes begin at 0001 or, for AC and EX tails, 01. Directory names match their BF and US IDs. Do not add a CLI allocator.
91
91
 
92
+ AC/EX tails remain two digits with upper bound 99. Before planned additions,
93
+ compare requested additions with the retired-inclusive remaining 99-H. Stop an
94
+ over-capacity batch before partial declarations. For an approved capacity-only
95
+ sibling or actual move, apply the owning stage's capacity preflight and complete
96
+ map before writing; no larger ID or new product outcome is a substitute for the
97
+ required scope.
98
+
92
99
  Constraint IDs are the exception. `TC-NN`, `OC-NN` and `BC-NN` in constraint.md are positional: each section numbers its rows from 01 in table order. No other document cites one, so a removed row closes the gap and the rows after it are renumbered. `npx qfai validate` reports a constraint ID that is not its row's place.
93
100
 
94
- Moving a story to another flow changes its US ID and every child AC and EX ID. Update all indexes, contract citations, and decision references in the same change. Record the old IDs as retired so they cannot be issued again.
101
+ Moving a story to another flow changes its US ID and every child AC and EX ID
102
+ under its existing approval path. Preserve case meanings and assertions through
103
+ the complete fixed-source map, update approved active indexes, contract citations
104
+ and counted test references. Record the old IDs as retired in a new approved
105
+ record so they cannot be issued again. Inherited DEC ID, Content and Approach
106
+ cells and their old-ID references stay historical and unchanged.
95
107
 
96
108
  ## Edge rules
97
109
 
98
110
  1. business-flows.md cites each actual BF. Each business-flow.md states its BF in its H1, gives its purpose, and draws its main path as exactly one Mermaid flowchart or sequenceDiagram under `## Flow`.
99
- 2. user-stories.md cites each US under that flow. A user story declares its US in its H1. Its parent BF is the directory it sits in, and no line of the file restates it. Keep each observable outcome in its own story.
111
+ 2. user-stories.md cites each US under that flow. A user story declares its US in its H1. Its parent BF is the directory it sits in, and no line of the file restates it. Keep each observable outcome in its own story, except the explicitly approved same-BF, same-actor-goal capacity-only partition above.
100
112
  3. 02_Acceptance-Criteria.md states each AC under that US as an `# AC-NNNN-NNNN-NN` comment followed by exactly one Gherkin `Scenario:`.
101
113
  4. Each EX row in 03_Example.md has exactly one AC-Ref. It names an AC in that story. Every AC has at least one EX.
102
114
  5. Each BR lives in an enforcing contract and cites one or more full EX IDs that already exist. Every EX is cited by at least one BR. Several BRs may cite an EX, and one BR may cite several EXs.
@@ -11,6 +11,7 @@ The flows a UI contract serves are the flows whose examples its rules cite; the
11
11
  - `elements[].label` is inspection-target text
12
12
  - `data-qfai` marker convention
13
13
  - Prototype metadata
14
+ - Purposeful copy: `supplements` and `structure`
14
15
  - Screen contract rules
15
16
  - Template
16
17
  - Typical failures
@@ -143,6 +144,142 @@ evidence records nothing against it — an entry is a note between the contract'
143
144
  author and whoever reviews the prototype. Follow the shape
144
145
  `templates/contracts/ui-contract.sample.yaml` shows.
145
146
 
147
+ ## Purposeful copy: `supplements` and `structure`
148
+
149
+ A screen states the words it shows, so that implementation adds none the contract
150
+ did not ask for and review can compare the rendered screen with what was agreed.
151
+ The words are the screen `title` (its one heading), the labels of `elements` and
152
+ `actions`, the group headings, and the supplements below. Two keys carry them,
153
+ beside `primary_tasks`, `elements` and `actions`, which stay as they are.
154
+
155
+ ### `supplements` (required)
156
+
157
+ Every text the screen shows beyond its `title`, group headings and labels: a
158
+ sentence under a field, a notice, an empty-state message, a disclosure, the result
159
+ of a save or a send, the instruction after a failure, the consequence of an action
160
+ that cannot be undone. Each is an entry with exactly these keys, all non-empty:
161
+
162
+ | Key | Holds |
163
+ | ------ | ----------------------------------------------------------------------------------------- |
164
+ | `id` | stable key, unique in the screen |
165
+ | `near` | the `id` of the element, action or structure group the text sits with |
166
+ | `when` | the state it shows in: `default`, `empty`, `loading`, `error` or `success` |
167
+ | `text` | the words as displayed |
168
+ | `why` | what the user could not know or do without it, and why a label or structure is not enough |
169
+
170
+ `supplements: []` says the screen shows none. Most screens need few, and a screen
171
+ need not have any. Two kinds of text are not supplements: the message of a field
172
+ rule is owned by the `validations` of its element, and data the product shows or
173
+ the user types is not copy the contract authors. A field message that says more
174
+ than its rule does is a supplement with `when: error`.
175
+
176
+ The list is the whole inventory in both directions. Text the screen shows that is
177
+ not listed is excess. A listed text the screen does not show is an unmet need, so
178
+ a necessary condition, cost, destination, result, recovery step or consequence
179
+ that is written here cannot be dropped by a later tidy-up; removing it is a
180
+ change to the contract, which goes back to `/qfai-sdd`.
181
+
182
+ Write `why` for the point of decision. "Explains the Save button" is a reason to
183
+ delete the text. "After the click the user cannot see where the draft went" is a
184
+ reason to keep it.
185
+
186
+ ### `structure` (optional)
187
+
188
+ The groups the screen is read in, in reading order. Each is an entry with exactly
189
+ `id`, `tasks`, `members` and, when the group shows a heading, `heading`:
190
+
191
+ | Key | Holds |
192
+ | --------- | ------------------------------------------------------------------ |
193
+ | `id` | stable key, unique in the screen |
194
+ | `tasks` | the `primary_tasks[].id` values the group serves, at least one |
195
+ | `members` | the `elements[].id` and `actions[].id` values it holds, in order |
196
+ | `heading` | the displayed heading; leave the key out when the group shows none |
197
+
198
+ An id belongs to one group, and an element or action may be left out of every
199
+ group. `structure` is optional only for a screen that shows no heading beyond its
200
+ `title`. A screen that shows any other heading, at any level, has one group with a
201
+ `heading` for each, so a screen with several `h2` headings writes `structure`.
202
+ Leaving the key out says the screen shows no such heading; it never says the
203
+ screen may show one without a group. A group needs a task and a member, so the
204
+ heading must head something the user reads or acts on: declare the table or list
205
+ that shows data as an element, and the group holds it. A heading over prose or
206
+ supplements alone has neither a task nor a member, and does not belong on the
207
+ screen. `npx qfai validate` does not check this, so the
208
+ reviewer compares the rendered headings with the groups. A group heading is
209
+ not the screen title: a second heading above or beside the real one repeats it.
210
+ A group that serves no task does not belong on the screen; name the task it
211
+ enables, or leave the heading and the group out.
212
+
213
+ ### Which key holds which text
214
+
215
+ Every text the screen shows has one home. The table applies the definitions above
216
+ to the text authors and reviewers most often disagree about:
217
+
218
+ | Rendered text | Home |
219
+ | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
220
+ | The one page heading (`h1`) | `title` |
221
+ | A heading over a group of elements or actions (`h2`, `h3`) | `structure[].heading` of that group |
222
+ | A small line above or beside a heading (eyebrow, kicker) | a supplement with `near` set to the group; it is not a heading and not a label |
223
+ | The text of a field, button or other control | `label` of that element or action |
224
+ | Link text | `label` of a `navigate` action |
225
+ | A table column header | recommended: `label` of an element declared for that column, as elements are the display fields |
226
+ | A figure caption | a supplement with `near` set to the element it describes |
227
+ | An item of a list the product writes (a fixed checklist) | a supplement |
228
+ | An item of a list made of data the product shows | outside the contract: data is not copy the contract authors |
229
+ | Product or site-identity text (a name, a tagline) | `label` when it is a link or control, otherwise a supplement |
230
+ | The message of a field rule | `validations` of that element |
231
+
232
+ Nothing is outside the contract merely because it repeats across screens. Text that
233
+ repeats on every screen is listed on each, and when no `why` that names a decision
234
+ can be written for it, the text is a candidate for removal from the screen rather
235
+ than a reason to leave it unlisted.
236
+
237
+ ### A worked example
238
+
239
+ The sample at `templates/contracts/ui-contract.sample.yaml` shows a complete
240
+ screen. Its draft action reads "Save draft", and no paragraph says what Save draft
241
+ does. What the label cannot say is declared instead: `Saved to Drafts` after the
242
+ click, and `Not saved. Your entries are still here. Try again.` after a failure.
243
+ The user learns where the draft went and what a failure means, and nothing is
244
+ written twice.
245
+
246
+ ### What a necessary text looks like
247
+
248
+ Subtraction removes text that adds no meaning. It never removes:
249
+
250
+ - a condition, cost, storage or transmission destination, or the result of an
251
+ action that is not visible otherwise (a demo-data notice that is true and
252
+ shown where the user decides is one of these);
253
+ - error recovery, and the consequence of an action that cannot be undone;
254
+ - labels, accessible names, roles and states.
255
+
256
+ Moving such text into a tooltip or a placeholder does not keep it. A word or
257
+ character count never approves or rejects a screen; a count is an observation
258
+ a finding may cite.
259
+
260
+ ### What validate checks
261
+
262
+ `QFAI-CONTRACT-043` reports `supplements` absent, a key that is not a list, an
263
+ entry that is not a mapping, a missing, empty or extra key, a `when` outside the
264
+ five states, and a repeated `id`; the same for `structure` when it is written.
265
+ `QFAI-CONTRACT-044` reports a `members`, `tasks` or `near` that names an id
266
+ the screen does not declare, and an element or action in two groups.
267
+ `QFAI-CONTRACT-045` warns when a group heading is the screen title, or a
268
+ supplement's text is the title, a group heading, the label of what it sits near, or
269
+ another supplement's text near the same target in the same state; case, spacing and
270
+ closing punctuation do not make a text different. Whether a sentence is needed is
271
+ judged against the task by the reviewer; validate compares ids and exact wording
272
+ only.
273
+
274
+ A contract written before these keys was valid without them. Add
275
+ `supplements` to each screen: `supplements: []` is the answer for a screen that
276
+ shows nothing beyond its title and labels. Keep `structure` out while the screen
277
+ shows no heading beyond its title; the first such heading needs its group.
278
+
279
+ Two contracts that state the same screen `id` each hold their own `supplements`
280
+ and `structure`; the project-wide screen list compares `title`, `route` and
281
+ `primary_tasks` only.
282
+
146
283
  ## Screen contract rules
147
284
 
148
285
  `screens[].elements[]` are the display fields:
@@ -185,6 +322,13 @@ Render the element with that marker, or remove the marker from the contract.
185
322
  **A label does not match.** Update the contract label, then the rendered text or
186
323
  marker mapping. Updating one side leaves the two out of step.
187
324
 
325
+ **`QFAI-CONTRACT-043` names a screen with no `supplements`.** Add `supplements: []`
326
+ if the screen shows no text beyond its title, group headings and labels, or list each
327
+ text with its `near`, `when`, `text` and `why`.
328
+
329
+ **`QFAI-CONTRACT-045` warns that a supplement repeats a label.** Delete the supplement,
330
+ or word it so it tells the user something the label does not.
331
+
188
332
  **The discussion pack already has screen contracts, so this looks redundant.**
189
333
  It is not. A discussion pack is discovery output and is non-normative; the
190
334
  downstream skills and every validate lane read `<paths.contractsDir>/ui/*.yaml`.
@@ -207,4 +351,6 @@ For a UI-bearing visual flow, the root `DESIGN.md` is authored and validated by
207
351
  - [ ] Every UI-bearing contract has one full declared ID, at least one screen, and a matching `contracts.md` row.
208
352
  - [ ] Screen IDs, routes, primary tasks, labels, markers, and actions are stable and testable.
209
353
  - [ ] Every declared action has an observable effect, including relevant failure states.
354
+ - [ ] Every screen declares `supplements` (`[]` when none), each with the reason the text is needed, and its `structure` names every heading beyond the title.
355
+ - [ ] No supplement restates a label, heading or action the screen already shows, and none is development commentary.
210
356
  - [ ] Prototyping coverage uses full contract IDs and the current cycle-0 fields.