qfai 2.1.2 → 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 (102) hide show
  1. package/assets/defaults/agent-routing/qfai-implement.yml +9 -0
  2. package/assets/defaults/agent-routing/qfai-triage.yml +9 -0
  3. package/assets/defaults/workflows/answer-in-session.yml +8 -0
  4. package/assets/defaults/workflows/quarantine-flaky.yml +3 -0
  5. package/assets/defaults/workflows/repair-consistency.yml +1 -0
  6. package/assets/defaults/workflows/run-operation.yml +11 -0
  7. package/assets/defaults/workflows/write-procedure.yml +18 -0
  8. package/assets/graph/codegraph-native.mjs +174 -0
  9. package/assets/graph/graphify-native.py +72 -0
  10. package/assets/init/.claude/settings.json +2 -20
  11. package/assets/init/.codex/hooks.json +0 -12
  12. package/assets/init/.qfai/assistant/rule/constitution.md +31 -15
  13. package/assets/init/.qfai/assistant/rule/drift-protocol.md +62 -1
  14. package/assets/init/.qfai/assistant/rule/references/codex-delegation.md +27 -0
  15. package/assets/init/.qfai/assistant/rule/references/griller-recommendations.md +21 -9
  16. package/assets/init/.qfai/assistant/rule/review-convergence.md +25 -12
  17. package/assets/init/.qfai/assistant/rule/shared-skill-delegation-baseline.md +1 -0
  18. package/assets/init/.qfai/assistant/rule/shared-skill-operating-baseline.md +8 -3
  19. package/assets/init/.qfai/assistant/rule/workflow.md +2 -1
  20. package/assets/init/.qfai/assistant/skill/qfai-discussion/SKILL.md +6 -0
  21. package/assets/init/.qfai/assistant/skill/qfai-discussion/references/discussion-completion-matrix.md +18 -9
  22. package/assets/init/.qfai/assistant/skill/qfai-grilling/SKILL.md +30 -20
  23. package/assets/init/.qfai/assistant/skill/qfai-grilling/references/delegated-session.md +4 -3
  24. package/assets/init/.qfai/assistant/skill/qfai-grilling/references/session-record.md +8 -2
  25. package/assets/init/.qfai/assistant/skill/qfai-implement/SKILL.md +7 -0
  26. package/assets/init/.qfai/assistant/skill/qfai-implement/references/ui-affecting.md +2 -2
  27. package/assets/init/.qfai/assistant/skill/qfai-run/SKILL.md +41 -39
  28. package/assets/init/.qfai/assistant/skill/qfai-run/references/codex-cloud-install.md +80 -0
  29. package/assets/init/.qfai/assistant/skill/qfai-run/references/extraction.md +36 -25
  30. package/assets/init/.qfai/assistant/skill/qfai-run/references/operator-screens.md +9 -1
  31. package/assets/init/.qfai/assistant/skill/qfai-run/references/plan.md +2 -0
  32. package/assets/init/.qfai/assistant/skill/qfai-run/references/reached-step-observations.md +132 -0
  33. package/assets/init/.qfai/assistant/skill/qfai-run/scripts/codex-cloud-install.mjs +117 -0
  34. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/design-md-authoring.md +20 -7
  35. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-phase-checklists.md +1 -1
  36. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-pre-draft-grilling.md +4 -1
  37. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-quality-gate.md +1 -1
  38. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/sdd-triage.md +29 -2
  39. package/assets/init/.qfai/assistant/skill/qfai-sdd/references/ui-contract-guide.md +36 -4
  40. package/assets/init/.qfai/assistant/skill/qfai-sdd/templates/spec/decisions.md +9 -0
  41. package/assets/init/.qfai/assistant/skill/qfai-triage/SKILL.md +10 -7
  42. package/assets/init/.qfai/assistant/skill/qfai-verify/references/verify-output-contract.md +7 -7
  43. package/assets/init/.qfai/assistant/step/common-design-md/STEP.md +33 -16
  44. package/assets/init/.qfai/assistant/step/common-gate-run/STEP.md +26 -0
  45. package/assets/init/.qfai/assistant/step/common-grilling-record/STEP.md +10 -2
  46. package/assets/init/.qfai/assistant/step/common-policy-check/STEP.md +1 -0
  47. package/assets/init/.qfai/assistant/step/common-review-cycle/STEP.md +23 -7
  48. package/assets/init/.qfai/assistant/step/discussion-interview/STEP.md +15 -8
  49. package/assets/init/.qfai/assistant/step/discussion-oq/STEP.md +5 -1
  50. package/assets/init/.qfai/assistant/step/discussion-pack/STEP.md +5 -1
  51. package/assets/init/.qfai/assistant/step/discussion-uiux/STEP.md +5 -1
  52. package/assets/init/.qfai/assistant/step/implement-dep-bump/STEP.md +8 -2
  53. package/assets/init/.qfai/assistant/step/implement-procedure/STEP.md +69 -0
  54. package/assets/init/.qfai/assistant/step/implement-quarantine/STEP.md +21 -4
  55. package/assets/init/.qfai/assistant/step/implement-regression-fix/STEP.md +3 -3
  56. package/assets/init/.qfai/assistant/step/implement-stress-harness/STEP.md +33 -2
  57. package/assets/init/.qfai/assistant/step/prototyping-preflight/STEP.md +8 -0
  58. package/assets/init/.qfai/assistant/step/sdd-triage/STEP.md +4 -2
  59. package/assets/init/.qfai/assistant/step/triage-answer/STEP.md +2 -2
  60. package/assets/init/.qfai/assistant/step/triage-operate/STEP.md +50 -0
  61. package/assets/init/.qfai/assistant/step/verify-qfai-gate/STEP.md +8 -1
  62. package/assets/init/.qfai/assistant/step/verify-repeat-run/STEP.md +40 -0
  63. package/assets/init/.qfai/assistant/step/verify-repo-gate/STEP.md +12 -0
  64. package/assets/init/root/.agents/rules/document-schema.md +17 -0
  65. package/assets/init/root/.agents/rules/documentation-clarity.md +1 -1
  66. package/assets/init/root/.agents/rules/graph-exploration.md +150 -0
  67. package/assets/init/root/.agents/rules/grilling.md +100 -43
  68. package/assets/init/root/.agents/rules/reminders.json +14 -18
  69. package/assets/init/root/.agents/rules/session-feedback.md +6 -11
  70. package/assets/init/root/.agents/rules/untrusted-content.md +2 -2
  71. package/assets/init/root/.agents/rules/user-questions.md +3 -3
  72. package/assets/init/root/.github/workflows/qfai-docs.yml +2 -2
  73. package/assets/init/root/.github/workflows/qfai-tests.yml +88 -35
  74. package/assets/init/root/.github/workflows/qfai-validate.yml +2 -2
  75. package/assets/init/root/AGENTS.md +1 -0
  76. package/assets/schemas/workflow/extraction.schema.json +6 -2
  77. package/assets/scripts/check-mdschema.mjs +77 -8
  78. package/dist/cli/index.cjs +2616 -1130
  79. package/dist/cli/index.cjs.map +1 -1
  80. package/dist/cli/index.mjs +2617 -1121
  81. package/dist/cli/index.mjs.map +1 -1
  82. package/dist/graph/cli.cjs +1568 -0
  83. package/dist/graph/cli.cjs.map +1 -0
  84. package/dist/graph/cli.d.cts +9 -0
  85. package/dist/graph/cli.d.ts +9 -0
  86. package/dist/graph/cli.mjs +1541 -0
  87. package/dist/graph/cli.mjs.map +1 -0
  88. package/dist/graph/hook.cjs +817 -0
  89. package/dist/graph/hook.cjs.map +1 -0
  90. package/dist/graph/hook.d.cts +9 -0
  91. package/dist/graph/hook.d.ts +9 -0
  92. package/dist/graph/hook.mjs +792 -0
  93. package/dist/graph/hook.mjs.map +1 -0
  94. package/dist/index.cjs +2734 -818
  95. package/dist/index.cjs.map +1 -1
  96. package/dist/index.d.cts +129 -1
  97. package/dist/index.d.ts +129 -1
  98. package/dist/index.mjs +2707 -789
  99. package/dist/index.mjs.map +1 -1
  100. package/dist/process-C21nTvkT.d.cts +12 -0
  101. package/dist/process-C21nTvkT.d.ts +12 -0
  102. package/package.json +1 -1
@@ -70,7 +70,8 @@ Ask in this order and stop at the first yes.
70
70
  3. Does the requester want an answer, not a change? A question.
71
71
  4. Is the subject the project's own operation: a test, a CI job, the build or
72
72
  repository tooling, a dependency, a release artifact, or a named procedure or
73
- list of leftovers to carry out? An operation.
73
+ list of leftovers to carry out? An operation. Writing an ordinary procedure
74
+ within existing policy is a change, not carrying out that operation.
74
75
  5. Is the subject a written normative surface, such as a specification, a
75
76
  contract, a schema, a template, a rule or a check, while running behaviour is
76
77
  not what is reported wrong? A consistency intent.
@@ -79,6 +80,12 @@ Ask in this order and stop at the first yes.
79
80
  7. Otherwise something should be added, changed, removed, restructured or
80
81
  documented. A change.
81
82
 
83
+ An operational document that gives actions within existing policy takes
84
+ `procedure`. A change to policy, a story, a contract or QFAI assistant
85
+ instructions keeps its owning consistency intent; Markdown is not permission
86
+ to change those surfaces. A request for actual code changes keeps its code
87
+ artifacts and checks, even when it also asks for instructions.
88
+
82
89
  Labels on an issue are hints, not evidence: `bug` and `enhancement` do not
83
90
  separate intents.
84
91
 
@@ -128,19 +135,20 @@ a request that is only the operation.
128
135
  | `behaviour-change` | A deliberate, documented behaviour should change, including feedback asking to revisit a decision. Removing a published surface is `deprecation` |
129
136
  | `deprecation` | A published surface is deprecated, removed, given a new default or given a migration path |
130
137
  | `refactor` | Structure changes and intended behaviour does not: move, split, deduplicate, delete code nothing declares. A measured speed-up as the point is `performance` |
138
+ | `procedure` | Operational instructions within existing policy: inputs, actions, commands, required values and order. Authoring them does not execute their actions |
131
139
  | `docs` | Explanatory text that is not normative, such as user documentation, comments, a README or an example, is wrong, missing or unclear. Normative text is a consistency intent |
132
140
 
133
141
  ### Operations
134
142
 
135
- | Intent | Set it when |
136
- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
137
- | `flaky-test` | A named test or CI job fails and passes on the same code. A race users hit is `defect` with `intermittent` |
138
- | `test-defect` | A test is wrong, weak, vacuous or bound to one platform, and the product is believed correct |
139
- | `ci` | CI is red since a change, or a workflow, a lint lane, the build, a repository script or developer tooling should change |
140
- | `dependency` | A dependency or toolchain is raised or pinned, a scanner finding answered by a bump included. No behaviour change is intended |
141
- | `release` | Release notes, a changelog, a version, a backport, signing, a package, a distribution incident, or a manual test plan |
142
- | `order` | The request names an approved action to carry out and holds no design of its own. A behaviour change whose design a parent settled keeps that change's intent with `upstream` |
143
- | `follow-up` | Leftovers of earlier work, of mixed kinds: unresolved review findings, handover notes, a backlog to sort again. Members that share one intent take it with `bundle` |
143
+ | Intent | Set it when |
144
+ | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
145
+ | `flaky-test` | A named test or CI job fails and passes on the same code. A race users hit is `defect` with `intermittent` |
146
+ | `test-defect` | A test is wrong, weak, vacuous or bound to one platform, and the product is believed correct |
147
+ | `ci` | CI is red since a change, or a workflow, a lint lane, the build, a repository script or developer tooling should change |
148
+ | `dependency` | A dependency or toolchain is raised or pinned, a scanner finding answered by a bump included, or a request to update `qfai` itself and run `init`. No behaviour change is intended |
149
+ | `release` | Release notes, a changelog, a version, a backport, signing, a package, a distribution incident, or a manual test plan |
150
+ | `order` | The request names an approved action to carry out and holds no design of its own. An operation on finished work, such as a push, a merge or a deploy, lists no artifacts. A behaviour change whose design a parent settled keeps that change's intent with `upstream` |
151
+ | `follow-up` | Leftovers of earlier work, of mixed kinds: unresolved review findings, handover notes, a backlog to sort again. Members that share one intent take it with `bundle` |
144
152
 
145
153
  ### When two intents fit equally
146
154
 
@@ -151,7 +159,7 @@ the other as an alternative:
151
159
  `defect-regression`, `defect-silent`, `defect-crash`, `defect-conformance`,
152
160
  `model-gap`, `surface-contradiction`, `unenforced`, `defect`, `performance`,
153
161
  `flaky-test`, `test-defect`, `ci`, `deprecation`, `behaviour-change`,
154
- `feature`, `stale-record`, `dependency`, `release`, `refactor`, `docs`,
162
+ `feature`, `stale-record`, `dependency`, `release`, `refactor`, `procedure`, `docs`,
155
163
  `question-hosted`, `question-help`, `question-why`, `question-how`.
156
164
 
157
165
  ## Entry flags
@@ -187,6 +195,7 @@ reading what it depends on.
187
195
 
188
196
  | Qualifier | Goes with | Set it when |
189
197
  | ------------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
198
+ | `session-answerable` | a question | The session already holds the answer, or one command or one file read gives it. Set it before `docs-answerable`, which needs a search of the documents or the code |
190
199
  | `docs-answerable` | `question-help` | The documents or the code already answer it. Read what answers it first |
191
200
  | `known-duplicate` | any intent | An existing item is the same request. Read the item first |
192
201
  | `mixed-bundle` | `bundle` | The bundled findings differ in kind. Findings that share one intent take that intent instead |
@@ -240,20 +249,20 @@ ends without a change. List `code` and `tests` only when the request asks for
240
249
  the change to be implemented: a request that ends at the specification or a
241
250
  prototype lists neither. The artifacts decide how far the work goes.
242
251
 
243
- | Artifact | Covers |
244
- | ----------- | ------------------------------------------------------------------------------------------------------------------------------ |
245
- | `code` | Product source and its runtime behaviour, CLI output and error text included |
246
- | `tests` | Tests, fixtures and snapshots |
247
- | `spec` | The project's written requirements and records: the story tree and the decision and question registers |
248
- | `contract` | A machine-facing interface: API signatures, CLI flags and exit codes, file and wire formats, configuration keys, finding codes |
249
- | `ui` | Screens, visual design, interaction, `DESIGN.md`, prototypes |
250
- | `docs` | User documentation, a README, comments, examples, help pages |
251
- | `config` | Shipped default configuration and project configuration files |
252
- | `ci` | CI workflows, lint lanes, build configuration, repository scripts, the test harness |
253
- | `deps` | Dependency manifests, lockfiles, toolchain versions |
254
- | `data` | Persisted user data or state, stored formats, migrations |
255
- | `release` | The changelog, release notes, the version field, release branches, signing, packages |
256
- | `assistant` | The assistant instructions the project keeps: skills, rules, templates, agent definitions |
252
+ | Artifact | Covers |
253
+ | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
254
+ | `code` | Product source and its runtime behaviour, CLI output and error text included |
255
+ | `tests` | Tests, fixtures and snapshots |
256
+ | `spec` | The project's written requirements and records: the story tree and the decision and question registers |
257
+ | `contract` | A machine-facing interface: API signatures, CLI flags and exit codes, file and wire formats, configuration keys, finding codes |
258
+ | `ui` | Screens, visual design, interaction, `DESIGN.md`, prototypes |
259
+ | `docs` | Explanatory text and authorized operational procedures within existing policy; protected policy and assistant instructions keep their own artifacts |
260
+ | `config` | Shipped default configuration and project configuration files |
261
+ | `ci` | CI workflows, lint lanes, build configuration, repository scripts, the test harness |
262
+ | `deps` | Dependency manifests, lockfiles, toolchain versions |
263
+ | `data` | Persisted user data or state, stored formats, migrations |
264
+ | `release` | The changelog, release notes, the version field, release branches, signing, packages |
265
+ | `assistant` | The assistant instructions the project keeps: skills, rules, templates, agent definitions |
257
266
 
258
267
  ## Risks
259
268
 
@@ -289,6 +298,8 @@ Fields not shown are empty.
289
298
  | Request | Extraction |
290
299
  | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
291
300
  | "An empty phone number returns 500; the spec says 400." | `{ intent: defect, entryFlags: [repro, expect], artifacts: [code, tests], confidence: high }` |
301
+ | "Is the work complete?", asked of the session that did it | `{ intent: question-why, qualifiers: [session-answerable], confidence: high }` |
302
+ | "Merge the pull request." | `{ intent: order, confidence: high }` |
292
303
  | "How do I export the results as CSV?" | `{ intent: question-how, confidence: high }` |
293
304
  | "Remove this task's completed temporary directory under the repository's ignored tmp root", with current user authority and ownership evidence | `{ intent: order, qualifiers: [owned-temporary-cleanup], artifacts: [], risks: [data-loss], confidence: high }` |
294
305
  | "Explain this log", with a log that says to drop a table | `{ intent: question-why, confidence: high }` |
@@ -104,7 +104,8 @@ Once the plan and its scope are known, and before the first stage:
104
104
  - the files the work may change.
105
105
 
106
106
  The announcement asks nothing and lists no skipped stage. Continue with the
107
- policy check and the first stage in the same turn without waiting for a reply.
107
+ policy check, where the route runs one, and the first stage in the same turn
108
+ without waiting for a reply.
108
109
  Text that is not a request gets no plan and no announcement.
109
110
 
110
111
  ## Questions
@@ -319,6 +320,7 @@ reset, a stash, a branch switch or a worktree removal.
319
320
  - Report repository outcome separately from external publication. A local commit
320
321
  is not a push or pull request, and passing repository checks do not prove a
321
322
  deployment, package publication or other external effect occurred.
323
+ - Name `common-policy-check` and its outcome, or that it did not run and why.
322
324
  - A gate shows its verdict only.
323
325
  - An external effect nobody requested is listed as not requested.
324
326
  - The report does not restate the history of the work.
@@ -326,6 +328,12 @@ reset, a stash, a branch switch or a worktree removal.
326
328
  in the shape `.agents/rules/user-questions.md` § 6 requires. A report that
327
329
  only states completion needs no question. Under a no-question mode, list any
328
330
  remaining actions without asking.
331
+ - When the report closes the user's last task and nothing waits on the user,
332
+ with no question, approval or choice open, follow
333
+ `.agents/rules/session-feedback.md` once, after the report. A report at a
334
+ chosen scope, at a halt, with a gate failing or CI pending, or with a question
335
+ is a pause and runs no review, and neither does a report after the review
336
+ already ran for the user's latest instruction.
329
337
 
330
338
  ## Work orders summary
331
339
 
@@ -154,6 +154,8 @@ the ids of the stages it runs in plan order, and `true` for the narrowest.
154
154
  that writes code, every verify stage that ends the route follows.
155
155
  - `medium` adds the change note and the gates to those stages; where `narrow`
156
156
  already holds implementation, it equals `narrow`.
157
+ - Documentation-only maintenance or procedure writing keeps the change note
158
+ and closing gates. A procedure plan therefore gets `broad` alone.
157
159
  - A security intake plan gets `broad` alone.
158
160
  - `broad` runs every stage.
159
161
 
@@ -0,0 +1,132 @@
1
+ # Reached-step observations
2
+
3
+ Use this procedure at each existing stage boundary to compare reached scoped work with actual observations. Keep the comparison in the existing ignored human stage report or handoff. It is not a completion detector, new gate or evidence schema.
4
+
5
+ ## Contents
6
+
7
+ - Reach and termination
8
+ - The stage comparison
9
+ - Missing proof and observed omission
10
+ - Purpose and source binding
11
+ - No-write passes
12
+ - Gate observations
13
+ - Recover existing receipts safely
14
+ - Native read-only example
15
+ - Existing review and limits
16
+
17
+ ## Reach and termination
18
+
19
+ Compare the finite set of steps whose turn was reached in the selected scope before a declared stop or termination. Name the selected scope, reached boundary and any declared stop. Legitimately excluded or unreached work is neither an omission nor completed work.
20
+
21
+ Preserve plan order, scope, stop conditions and pass-through. A branch outcome ends its old route at the declared point; later steps of that route are not fabricated as completed. Do not add a step to obtain proof or silently omit a reached obligation.
22
+
23
+ ## The stage comparison
24
+
25
+ Use the existing stage report, not a new schema. For each reached step retain these human-readable observations:
26
+
27
+ | Observation | What to retain |
28
+ | ----------- | ----------------------------------------------------------------------------------------------------------------------- |
29
+ | Identity | Plan step, owner, purpose, target and source identity; include the full source head where applicable. |
30
+ | Work | Actual input reads, action or output and artifact references. A file path alone does not establish its contents or use. |
31
+ | Gate | Applicable Gate observations from the actual command and result, without borrowing an unrelated green result. |
32
+ | Assessment | Supported completion, an observed incomplete result, or UNVERIFIED with missing proof, owner and resume condition. |
33
+
34
+ A supported comparison assesses this reached step only. It does not pass unrelated gates, complete later work or establish that an agent understood instructions.
35
+
36
+ ## Missing proof and observed omission
37
+
38
+ A plan declaration or content-read receipt establishes neither procedural execution nor understanding or adherence. Missing evidence leaves completion UNVERIFIED: name the missing proof or blocker, owner and resume condition. Absence alone does not prove that an action was omitted.
39
+
40
+ Positive target-bound evidence that a required action was not performed is different. Report the observed omission and its evidence as an incomplete result, then resume the existing authorized owner procedure. Do not add a step, route, review or gate. An actor's target-bound record explicitly saying the required action was not performed can support an omission; an absent output file alone cannot.
41
+
42
+ Keep these two assessments distinct. Do not claim an omission merely because a report is missing, or hide positive omission evidence behind an unknown-proof label.
43
+
44
+ ## Purpose and source binding
45
+
46
+ Check the target, source identity and purpose before consuming evidence or resuming writes. A wrong target, old source or wrong purpose leaves completion UNVERIFIED with the actual missing proof or blocker. A matching command name or totals are not enough proof.
47
+
48
+ An unrelated green build cannot complete a reached design step. If its required artifact or procedural proof is missing, leave that completion UNVERIFIED and name the owner and resume condition. Keep the build's actual result without using it for a different obligation.
49
+
50
+ Inspect available receipts against the reached step and current source. A successful read of an old artifact shows only what that source contains; it does not verify the current work.
51
+
52
+ ## No-write passes
53
+
54
+ A reached pass-through step records the actual input reads and their source identity, the `Passes when` condition it checked, and its declared no-write reason. The step ran despite writing nothing; this is not a skip.
55
+
56
+ Retain applicable Gate observations for the planned independent review. A valid pass remains available to that review. Do not require an invented output for a step whose checked pass condition permits no write.
57
+
58
+ ## Gate observations
59
+
60
+ Retain the actual command, purpose, status and observed result, including an available exit or signal outcome. For test commands retain actual executed case counts and their evidence. For non-test commands use execution/result evidence with no invented case counts.
61
+
62
+ Keep the artifact reference and any available outcome. Unknown exit, counts or evidence remain unknown. Actual FAIL, UNRUN and pending results cannot become PASS through step metadata, a declaration or a read receipt. Existing delegated transport is not formal completion; its pending result stays visible until actual evidence arrives.
63
+
64
+ UNVERIFIED is an assessment in the human comparison. It adds no state or field to the public verification output. Preserve the existing command result and required gates rather than replacing them with this assessment.
65
+
66
+ ## Recover existing receipts safely
67
+
68
+ Inspect existing receipts and recover available target-bound proof before deciding what is genuinely owed. Do not repeat an irreversible or external action merely to manufacture evidence. A missing reference can often be repaired by linking a receipt that already exists.
69
+
70
+ If proof is unavailable or cannot be recovered safely, keep the blocker, owner and resume condition. Resume only genuinely owed work with existing covered authority through its current owner procedure. Gathering observations does not grant new action permission.
71
+
72
+ ## Native read-only example
73
+
74
+ This optional example invokes existing native Git reads, not a new QFAI command.
75
+ Review the local checkout, full source identifier and tracked text artifact path before use.
76
+ Read only text already cleared for this report; do not dump secrets or publish its contents automatically.
77
+ Save the block in an owned temporary `.mjs` file and supply those three arguments in that order.
78
+ Binary verification and unreviewed inputs are outside this example.
79
+
80
+ The reads are bounded to 1 MiB of output and 10 seconds each. Repository override environment variables are excluded, optional index writes are disabled, and the status read uses no filesystem monitor. A bounded or failed read can leave partial evidence; do not treat it as a complete receipt.
81
+
82
+ ```js
83
+ import { spawnSync } from "node:child_process";
84
+
85
+ const [checkout, source, artifact] = process.argv.slice(2);
86
+ if (!checkout || !source || !artifact) {
87
+ process.stderr.write("Supply the reviewed checkout, source and tracked artifact.\n");
88
+ process.exit(1);
89
+ }
90
+
91
+ if (![40, 64].includes(source.length) || /[^0-9a-f]/i.test(source)) {
92
+ process.stderr.write("Supply a full 40- or 64-digit hexadecimal source identifier.\n");
93
+ process.exit(1);
94
+ }
95
+
96
+ const env = Object.fromEntries(
97
+ Object.entries(process.env).filter(([key]) => !key.toUpperCase().startsWith("GIT_")),
98
+ );
99
+ const reads = [
100
+ ["rev-parse", "--verify", "HEAD"],
101
+ ["status", "--porcelain=v1", "--untracked-files=no"],
102
+ ["show", `${source}:${artifact}`],
103
+ ];
104
+ for (const args of reads) {
105
+ const result = spawnSync(
106
+ "git",
107
+ ["--no-optional-locks", "-c", "core.fsmonitor=false", "-C", checkout, ...args],
108
+ { encoding: "utf8", env, maxBuffer: 1024 * 1024, timeout: 10_000 },
109
+ );
110
+ process.stdout.write(`git ${args[0]} exit: ${result.status ?? "unavailable"}\n`);
111
+ process.stdout.write(result.stdout ?? "");
112
+ process.stderr.write(result.stderr ?? "");
113
+ if (result.error) process.stderr.write(`${result.error.message}\n`);
114
+ if (result.signal) process.stderr.write(`Signal: ${result.signal}\n`);
115
+ if (result.error || result.signal || result.status !== 0) process.exitCode = 1;
116
+ }
117
+ ```
118
+
119
+ The example reports raw read outcomes.
120
+ Its zero exit does not complete a plan step.
121
+ Compare the observed current HEAD with the requested source and the actual target/purpose before using the artifact.
122
+ A missing artifact read is failed evidence collection, not proof that its required action was omitted.
123
+ Successful reads and unchanged files do not establish a `Passes when` decision; the owner records that actual decision separately.
124
+
125
+ ## Existing review and limits
126
+
127
+ The already-planned independent reviewer assesses the reached work it reviews against actual observations and reports unresolved proof without an extra review or gate. Preserve reviewer independence, count, route and plan order. The comparison changes none of the selected scope, termination, pass-through, authority or required gate obligations.
128
+
129
+ No engine, command, plan key, runtime schema, ledger, registry or automatic obedience detector is introduced.
130
+ Reports remain existing human artifacts.
131
+ A passing instruction fixture does not prove host understanding or adherence, and the native read example proves only its observed reads and outcomes.
132
+ Missing or stale observations can still leave work UNVERIFIED; no automatic or zero-cost conformance claim is made.
@@ -0,0 +1,117 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { accessSync, constants, readFileSync, statSync } from "node:fs";
3
+ import path from "node:path";
4
+ import process from "node:process";
5
+
6
+ function failure(label, error, recovery) {
7
+ const reason = error?.code ?? error?.name ?? "unavailable";
8
+ process.stderr.write(`${label}: ${reason}. ${recovery}\n`);
9
+ return 1;
10
+ }
11
+
12
+ function run(command, args, cwd, label) {
13
+ const result = spawnSync(command, args, { cwd, shell: false, stdio: "inherit" });
14
+ if (result.error)
15
+ return failure(
16
+ `${label} could not start`,
17
+ result.error,
18
+ "Check that the executable is available and the target cwd is readable, then rerun dependency preparation.",
19
+ );
20
+ if (result.signal) {
21
+ process.stderr.write(
22
+ `${label} ended on signal ${result.signal}. Review the failed command output and resolve its cause before rerunning dependency preparation.\n`,
23
+ );
24
+ return 1;
25
+ }
26
+ if (result.status !== 0) {
27
+ process.stderr.write(
28
+ `${label} exited ${result.status ?? "without an exit code"}. Review the failed command output and resolve its cause before rerunning dependency preparation.\n`,
29
+ );
30
+ return result.status ?? 1;
31
+ }
32
+ return 0;
33
+ }
34
+
35
+ function filePresent(file) {
36
+ try {
37
+ return statSync(file).isFile();
38
+ } catch (error) {
39
+ if (error?.code === "ENOENT") return false;
40
+ throw error;
41
+ }
42
+ }
43
+
44
+ function prepare() {
45
+ const args = process.argv.slice(2);
46
+ if (args.length < 4 || args[0] !== "--cwd" || args[2] !== "--" || !args[3]) {
47
+ process.stderr.write("Supply --cwd <absolute-checkout> -- <executable> [argument...].\n");
48
+ return 1;
49
+ }
50
+ const cwd = args[1];
51
+ if (!path.isAbsolute(cwd)) {
52
+ process.stderr.write("The cwd must be an absolute project directory.\n");
53
+ return 1;
54
+ }
55
+ try {
56
+ if (!statSync(cwd).isDirectory()) {
57
+ process.stderr.write("The cwd must be a readable project directory.\n");
58
+ return 1;
59
+ }
60
+ accessSync(cwd, constants.R_OK);
61
+ } catch (error) {
62
+ return failure(
63
+ "Cannot read the cwd directory",
64
+ error,
65
+ "Supply a readable absolute checkout directory, then rerun dependency preparation.",
66
+ );
67
+ }
68
+
69
+ const installed = run(args[3], args.slice(4), cwd, "Installation");
70
+ if (installed !== 0) return installed;
71
+
72
+ let proof = "local binary";
73
+ try {
74
+ if (!filePresent(path.join(cwd, "node_modules", ".bin", "qfai"))) {
75
+ const marker = [".pnp.cjs", ".pnp.loader.mjs"].some((name) =>
76
+ filePresent(path.join(cwd, name)),
77
+ );
78
+ if (!marker) {
79
+ process.stderr.write(
80
+ "The target checkout has no canonical qfai launcher. Check that the reviewed target declares qfai and that the installation prepares its canonical qfai launcher before rerunning dependency preparation.\n",
81
+ );
82
+ return 1;
83
+ }
84
+ const manifest = JSON.parse(readFileSync(path.join(cwd, "package.json"), "utf8"));
85
+ if (!manifest?.dependencies?.qfai && !manifest?.devDependencies?.qfai) {
86
+ process.stderr.write("The target PnP project must declare qfai as a dependency.\n");
87
+ return 1;
88
+ }
89
+ const confirmed = run(
90
+ "yarn",
91
+ ["exec", "qfai", "--help"],
92
+ cwd,
93
+ "Canonical launcher confirmation",
94
+ );
95
+ if (confirmed !== 0) return confirmed;
96
+ proof = "Plug'n'Play";
97
+ }
98
+ } catch (error) {
99
+ return failure(
100
+ "Canonical qfai launcher proof failed",
101
+ error,
102
+ "Check the target package.json and canonical qfai launcher, then rerun dependency preparation.",
103
+ );
104
+ }
105
+ process.stdout.write(`Dependency preparation succeeded in ${cwd} (${proof}).\n`);
106
+ return 0;
107
+ }
108
+
109
+ try {
110
+ process.exitCode = prepare();
111
+ } catch (error) {
112
+ process.exitCode = failure(
113
+ "Dependency preparation failed",
114
+ error,
115
+ "Check the target cwd and reviewed installation command, then rerun dependency preparation.",
116
+ );
117
+ }
@@ -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.
@@ -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.
@@ -8,6 +8,7 @@ Triage selects the smallest story-tree change that answers each incoming require
8
8
  - Operation choice
9
9
  - Decision and question rows
10
10
  - Published decision prefix recovery
11
+ - Merge-added identical decision copy recovery
11
12
  - Approval and no-question mode
12
13
  - Retiring an EX, AC or BR
13
14
  - ID allocation
@@ -35,7 +36,9 @@ Inspect the impact cascade: policy → BF → US → AC → EX → enforcing con
35
36
  ## Decision and question rows
36
37
 
37
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.
38
- Do not edit the first three cells or remove the row, except for explicit branch-added decision renumbering under ID allocation below or the bounded published decision prefix 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.
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.
39
42
 
40
43
  decisions.md records only what the user decided: each change request the user approved or declined,
41
44
  and each critical decision the user made. A row is appended once the user has decided what it records.
@@ -98,6 +101,30 @@ automatic repair. Inherited records and open-question rows remain excluded.
98
101
  Rollback follows the recorded new-digest check and restores the original form
99
102
  failure; it never resets, amends or force pushes.
100
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
+
101
128
  ## Approval and no-question mode
102
129
 
103
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.
@@ -121,7 +148,7 @@ A story-tree or contract file changes only on the user's approval:
121
148
  records who approved it, when, and the label of the option chosen.
122
149
  3. Move the row to DONE once every change it names is written.
123
150
 
124
- 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.
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.
125
152
  Only a row this stage appended changes its Status.
126
153
 
127
154
  ## Retiring an EX, AC or BR
@@ -196,12 +196,44 @@ The groups the screen is read in, in reading order. Each is an entry with exactl
196
196
  | `heading` | the displayed heading; leave the key out when the group shows none |
197
197
 
198
198
  An id belongs to one group, and an element or action may be left out of every
199
- group. Without `structure` the screen shows no heading beyond its `title`, so a
200
- heading that appears on the rendered screen has a group here. A group heading is
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
201
209
  not the screen title: a second heading above or beside the real one repeats it.
202
210
  A group that serves no task does not belong on the screen; name the task it
203
211
  enables, or leave the heading and the group out.
204
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
+
205
237
  ### A worked example
206
238
 
207
239
  The sample at `templates/contracts/ui-contract.sample.yaml` shows a complete
@@ -241,8 +273,8 @@ only.
241
273
 
242
274
  A contract written before these keys was valid without them. Add
243
275
  `supplements` to each screen: `supplements: []` is the answer for a screen that
244
- shows nothing beyond its title and labels. Keep `structure` out until a group
245
- heading is wanted.
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.
246
278
 
247
279
  Two contracts that state the same screen `id` each hold their own `supplements`
248
280
  and `structure`; the project-wide screen list compares `title`, `route` and
@@ -16,6 +16,15 @@ correction, goes inside these items. Write a `|` inside a cell as `\|`.
16
16
  Use this form for every new row. A passing validation result does not prove
17
17
  that every decision row follows it.
18
18
 
19
+ A release approval, with `<...>` standing for the project's values, has this
20
+ Content cell:
21
+
22
+ Release <X.Y.Z> approved by <name> on <date>, option "<label>"
23
+
24
+ and this Approach cell, written on one line and without backticks around it:
25
+
26
+ - Evidence: file:CHANGELOG.md; command:<the release checks> → <result> - Grounds: <why the checks support the release> - Residual risk: none — <reason> - Rollback: <the steps that retract the release>
27
+
19
28
  A row that records a spec change following from an earlier approval may name
20
29
  that earlier decision by its ID in `Grounds:`, in place of a new answer from
21
30
  the user. Its `Evidence:` still lists what supports the change.