@nforma.ai/nforma 0.2.1

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 (215) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +1024 -0
  3. package/agents/qgsd-codebase-mapper.md +764 -0
  4. package/agents/qgsd-debugger.md +1201 -0
  5. package/agents/qgsd-executor.md +472 -0
  6. package/agents/qgsd-integration-checker.md +443 -0
  7. package/agents/qgsd-phase-researcher.md +502 -0
  8. package/agents/qgsd-plan-checker.md +643 -0
  9. package/agents/qgsd-planner.md +1182 -0
  10. package/agents/qgsd-project-researcher.md +621 -0
  11. package/agents/qgsd-quorum-orchestrator.md +628 -0
  12. package/agents/qgsd-quorum-slot-worker.md +41 -0
  13. package/agents/qgsd-quorum-synthesizer.md +133 -0
  14. package/agents/qgsd-quorum-test-worker.md +37 -0
  15. package/agents/qgsd-quorum-worker.md +161 -0
  16. package/agents/qgsd-research-synthesizer.md +239 -0
  17. package/agents/qgsd-roadmapper.md +660 -0
  18. package/agents/qgsd-verifier.md +628 -0
  19. package/bin/accept-debug-invariant.cjs +165 -0
  20. package/bin/account-manager.cjs +719 -0
  21. package/bin/aggregate-requirements.cjs +466 -0
  22. package/bin/analyze-assumptions.cjs +757 -0
  23. package/bin/analyze-state-space.cjs +921 -0
  24. package/bin/attribute-trace-divergence.cjs +150 -0
  25. package/bin/auth-drivers/gh-cli.cjs +93 -0
  26. package/bin/auth-drivers/index.cjs +46 -0
  27. package/bin/auth-drivers/pool.cjs +67 -0
  28. package/bin/auth-drivers/simple.cjs +95 -0
  29. package/bin/autoClosePtoF.cjs +110 -0
  30. package/bin/blessed-terminal.cjs +350 -0
  31. package/bin/build-phase-index.cjs +472 -0
  32. package/bin/call-quorum-slot.cjs +541 -0
  33. package/bin/ccr-secure-config.cjs +99 -0
  34. package/bin/ccr-secure-start.cjs +83 -0
  35. package/bin/check-bundled-sdks.cjs +177 -0
  36. package/bin/check-coverage-guard.cjs +112 -0
  37. package/bin/check-liveness-fairness.cjs +95 -0
  38. package/bin/check-mcp-health.cjs +123 -0
  39. package/bin/check-provider-health.cjs +395 -0
  40. package/bin/check-results-exit.cjs +24 -0
  41. package/bin/check-spec-sync.cjs +360 -0
  42. package/bin/check-trace-redaction.cjs +271 -0
  43. package/bin/check-trace-schema-drift.cjs +99 -0
  44. package/bin/compareDrift.cjs +21 -0
  45. package/bin/conformance-schema.cjs +12 -0
  46. package/bin/count-scenarios.cjs +420 -0
  47. package/bin/debt-dedup.cjs +144 -0
  48. package/bin/debt-ledger.cjs +61 -0
  49. package/bin/debt-retention.cjs +76 -0
  50. package/bin/debt-state-machine.cjs +80 -0
  51. package/bin/detect-coverage-gaps.cjs +204 -0
  52. package/bin/detect-project-intent.cjs +362 -0
  53. package/bin/export-prism-constants.cjs +164 -0
  54. package/bin/extract-annotations.cjs +633 -0
  55. package/bin/extractFormalExpected.cjs +104 -0
  56. package/bin/fingerprint-drift.cjs +24 -0
  57. package/bin/fingerprint-issue.cjs +46 -0
  58. package/bin/formal-core.cjs +519 -0
  59. package/bin/formal-ref-linker.cjs +141 -0
  60. package/bin/formal-test-sync.cjs +788 -0
  61. package/bin/generate-formal-specs.cjs +588 -0
  62. package/bin/generate-petri-net.cjs +397 -0
  63. package/bin/generate-phase-spec.cjs +249 -0
  64. package/bin/generate-proposed-changes.cjs +194 -0
  65. package/bin/generate-tla-cfg.cjs +122 -0
  66. package/bin/generate-traceability-matrix.cjs +701 -0
  67. package/bin/generate-triage-bundle.cjs +300 -0
  68. package/bin/gh-account-rotate.cjs +34 -0
  69. package/bin/initialize-model-registry.cjs +105 -0
  70. package/bin/install-formal-tools.cjs +382 -0
  71. package/bin/install.js +2424 -0
  72. package/bin/isNumericThreshold.cjs +34 -0
  73. package/bin/issue-classifier.cjs +151 -0
  74. package/bin/levenshtein.cjs +74 -0
  75. package/bin/lint-formal-models.cjs +580 -0
  76. package/bin/load-baseline-requirements.cjs +275 -0
  77. package/bin/manage-agents-core.cjs +815 -0
  78. package/bin/migrate-formal-dir.cjs +172 -0
  79. package/bin/migrate-planning.cjs +206 -0
  80. package/bin/migrate-to-slots.cjs +255 -0
  81. package/bin/nForma.cjs +2726 -0
  82. package/bin/observe-config.cjs +353 -0
  83. package/bin/observe-debt-writer.cjs +140 -0
  84. package/bin/observe-handler-grafana.cjs +128 -0
  85. package/bin/observe-handler-internal.cjs +301 -0
  86. package/bin/observe-handler-logstash.cjs +153 -0
  87. package/bin/observe-handler-prometheus.cjs +185 -0
  88. package/bin/observe-handlers.cjs +436 -0
  89. package/bin/observe-registry.cjs +131 -0
  90. package/bin/observe-render.cjs +168 -0
  91. package/bin/planning-paths.cjs +167 -0
  92. package/bin/polyrepo.cjs +560 -0
  93. package/bin/prism-priority.cjs +153 -0
  94. package/bin/probe-quorum-slots.cjs +167 -0
  95. package/bin/promote-model.cjs +225 -0
  96. package/bin/propose-debug-invariants.cjs +165 -0
  97. package/bin/providers.json +392 -0
  98. package/bin/pty-proxy.py +129 -0
  99. package/bin/qgsd-solve.cjs +2477 -0
  100. package/bin/quorum-consensus-gate.cjs +238 -0
  101. package/bin/quorum-formal-context.cjs +183 -0
  102. package/bin/quorum-slot-dispatch.cjs +934 -0
  103. package/bin/read-policy.cjs +60 -0
  104. package/bin/requirement-map.cjs +63 -0
  105. package/bin/requirements-core.cjs +247 -0
  106. package/bin/resolve-cli.cjs +101 -0
  107. package/bin/review-mcp-logs.cjs +294 -0
  108. package/bin/run-account-manager-tlc.cjs +188 -0
  109. package/bin/run-account-pool-alloy.cjs +158 -0
  110. package/bin/run-alloy.cjs +153 -0
  111. package/bin/run-audit-alloy.cjs +187 -0
  112. package/bin/run-breaker-tlc.cjs +181 -0
  113. package/bin/run-formal-check.cjs +395 -0
  114. package/bin/run-formal-verify.cjs +701 -0
  115. package/bin/run-installer-alloy.cjs +188 -0
  116. package/bin/run-oauth-rotation-prism.cjs +132 -0
  117. package/bin/run-oscillation-tlc.cjs +202 -0
  118. package/bin/run-phase-tlc.cjs +228 -0
  119. package/bin/run-prism.cjs +446 -0
  120. package/bin/run-protocol-tlc.cjs +201 -0
  121. package/bin/run-quorum-composition-alloy.cjs +155 -0
  122. package/bin/run-sensitivity-sweep.cjs +231 -0
  123. package/bin/run-stop-hook-tlc.cjs +188 -0
  124. package/bin/run-tlc.cjs +467 -0
  125. package/bin/run-transcript-alloy.cjs +173 -0
  126. package/bin/run-uppaal.cjs +264 -0
  127. package/bin/secrets.cjs +134 -0
  128. package/bin/sensitivity-report.cjs +219 -0
  129. package/bin/sensitivity-sweep-feedback.cjs +194 -0
  130. package/bin/set-secret.cjs +29 -0
  131. package/bin/setup-telemetry-cron.sh +36 -0
  132. package/bin/sweepPtoF.cjs +63 -0
  133. package/bin/sync-baseline-requirements.cjs +290 -0
  134. package/bin/task-envelope.cjs +360 -0
  135. package/bin/telemetry-collector.cjs +229 -0
  136. package/bin/unified-mcp-server.mjs +735 -0
  137. package/bin/update-agents.cjs +369 -0
  138. package/bin/update-scoreboard.cjs +1134 -0
  139. package/bin/validate-debt-entry.cjs +207 -0
  140. package/bin/validate-invariant.cjs +419 -0
  141. package/bin/validate-memory.cjs +389 -0
  142. package/bin/validate-requirements-haiku.cjs +435 -0
  143. package/bin/validate-traces.cjs +438 -0
  144. package/bin/verify-formal-results.cjs +124 -0
  145. package/bin/verify-quorum-health.cjs +273 -0
  146. package/bin/write-check-result.cjs +106 -0
  147. package/bin/xstate-to-tla.cjs +483 -0
  148. package/bin/xstate-trace-walker.cjs +205 -0
  149. package/commands/qgsd/add-phase.md +43 -0
  150. package/commands/qgsd/add-requirement.md +24 -0
  151. package/commands/qgsd/add-todo.md +47 -0
  152. package/commands/qgsd/audit-milestone.md +37 -0
  153. package/commands/qgsd/check-todos.md +45 -0
  154. package/commands/qgsd/cleanup.md +18 -0
  155. package/commands/qgsd/close-formal-gaps.md +33 -0
  156. package/commands/qgsd/complete-milestone.md +136 -0
  157. package/commands/qgsd/debug.md +166 -0
  158. package/commands/qgsd/discuss-phase.md +83 -0
  159. package/commands/qgsd/execute-phase.md +117 -0
  160. package/commands/qgsd/fix-tests.md +27 -0
  161. package/commands/qgsd/formal-test-sync.md +32 -0
  162. package/commands/qgsd/health.md +22 -0
  163. package/commands/qgsd/help.md +22 -0
  164. package/commands/qgsd/insert-phase.md +32 -0
  165. package/commands/qgsd/join-discord.md +18 -0
  166. package/commands/qgsd/list-phase-assumptions.md +46 -0
  167. package/commands/qgsd/map-codebase.md +71 -0
  168. package/commands/qgsd/map-requirements.md +20 -0
  169. package/commands/qgsd/mcp-restart.md +176 -0
  170. package/commands/qgsd/mcp-set-model.md +134 -0
  171. package/commands/qgsd/mcp-setup.md +1371 -0
  172. package/commands/qgsd/mcp-status.md +274 -0
  173. package/commands/qgsd/mcp-update.md +238 -0
  174. package/commands/qgsd/new-milestone.md +44 -0
  175. package/commands/qgsd/new-project.md +42 -0
  176. package/commands/qgsd/observe.md +260 -0
  177. package/commands/qgsd/pause-work.md +38 -0
  178. package/commands/qgsd/plan-milestone-gaps.md +34 -0
  179. package/commands/qgsd/plan-phase.md +44 -0
  180. package/commands/qgsd/polyrepo.md +50 -0
  181. package/commands/qgsd/progress.md +24 -0
  182. package/commands/qgsd/queue.md +54 -0
  183. package/commands/qgsd/quick.md +133 -0
  184. package/commands/qgsd/quorum-test.md +275 -0
  185. package/commands/qgsd/quorum.md +707 -0
  186. package/commands/qgsd/reapply-patches.md +110 -0
  187. package/commands/qgsd/remove-phase.md +31 -0
  188. package/commands/qgsd/research-phase.md +189 -0
  189. package/commands/qgsd/resume-work.md +40 -0
  190. package/commands/qgsd/set-profile.md +34 -0
  191. package/commands/qgsd/settings.md +39 -0
  192. package/commands/qgsd/solve.md +565 -0
  193. package/commands/qgsd/sync-baselines.md +119 -0
  194. package/commands/qgsd/triage.md +233 -0
  195. package/commands/qgsd/update.md +37 -0
  196. package/commands/qgsd/verify-work.md +38 -0
  197. package/hooks/dist/config-loader.js +297 -0
  198. package/hooks/dist/conformance-schema.cjs +12 -0
  199. package/hooks/dist/gsd-context-monitor.js +64 -0
  200. package/hooks/dist/qgsd-check-update.js +62 -0
  201. package/hooks/dist/qgsd-circuit-breaker.js +682 -0
  202. package/hooks/dist/qgsd-precompact.js +156 -0
  203. package/hooks/dist/qgsd-prompt.js +653 -0
  204. package/hooks/dist/qgsd-session-start.js +122 -0
  205. package/hooks/dist/qgsd-slot-correlator.js +58 -0
  206. package/hooks/dist/qgsd-spec-regen.js +86 -0
  207. package/hooks/dist/qgsd-statusline.js +91 -0
  208. package/hooks/dist/qgsd-stop.js +553 -0
  209. package/hooks/dist/qgsd-token-collector.js +133 -0
  210. package/hooks/dist/unified-mcp-server.mjs +669 -0
  211. package/package.json +95 -0
  212. package/scripts/build-hooks.js +46 -0
  213. package/scripts/postinstall.js +48 -0
  214. package/scripts/secret-audit.sh +45 -0
  215. package/templates/qgsd.json +49 -0
@@ -0,0 +1,565 @@
1
+ ---
2
+ name: qgsd:solve
3
+ description: Orchestrator skill that migrates legacy .formal/ layouts, diagnoses consistency gaps, dispatches to remediation skills for each gap type, and converges via diagnose-remediate-rediagnose loop with before/after comparison
4
+ argument-hint: [--report-only] [--max-iterations=N] [--json] [--verbose]
5
+ allowed-tools:
6
+ - Read
7
+ - Write
8
+ - Edit
9
+ - Bash
10
+ - Glob
11
+ - Grep
12
+ - Agent
13
+ - Skill
14
+ ---
15
+
16
+ <objective>
17
+ Run the QGSD consistency solver as a full orchestrator. Sweeps 7 layer transitions (R->F, F->T, C->F, T->C, F->C, R->D, D->C), computes a residual vector showing gaps at each boundary, and automatically dispatches to the correct remediation skill/script for each gap type. Re-diagnoses after each remediation round and iterates until convergence or max iterations reached. Returns before/after residual comparison.
18
+ </objective>
19
+
20
+ <execution_context>
21
+ AUTONOMY REQUIREMENT: This skill runs FULLY AUTONOMOUSLY. Do NOT ask the user
22
+ any questions. Do NOT stop for human input. If a sub-skill fails, log the
23
+ failure and continue to the next gap. The only valid reason to stop is:
24
+ all iterations exhausted, or total residual is zero.
25
+
26
+ This is a self-contained orchestrator skill. It runs the diagnostic engine (bin/qgsd-solve.cjs) and orchestrates higher-level remediation via sub-skills and scripts. No external quorum dispatch is needed — quorum enforcement, if required, is the responsibility of the sub-skills being called.
27
+
28
+ BULK REMEDIATION: For F->T and R->D gaps, the solve skill writes PLAN.md files
29
+ directly and dispatches qgsd-executor agents — it does NOT invoke
30
+ /qgsd:quick for bulk remediation. This avoids per-batch quorum overhead while
31
+ maintaining quality through the convergence loop's before/after verification.
32
+ The solve skill IS the planner for these mechanical remediation tasks.
33
+
34
+ RAM BUDGET: Never exceed 3 concurrent subagent Tasks at any point during
35
+ execution. Each Task subprocess consumes ~1GB RAM. With MCP servers and the
36
+ parent process, 3 parallel tasks keeps total usage under ~20GB. Dispatch in
37
+ sequential waves of 3, waiting for each wave to finish before the next.
38
+ </execution_context>
39
+
40
+ <process>
41
+
42
+ ## Step 0: Legacy .formal/ Migration
43
+
44
+ Before running the diagnostic sweep, check for a legacy `.formal/` directory at the project root (next to `.planning/`). This is the OLD layout from before formal verification was consolidated under `.planning/formal/`.
45
+
46
+ Run the migration script using absolute paths (or fall back to CWD-relative):
47
+
48
+ ```bash
49
+ MIGRATE=$(node ~/.claude/qgsd-bin/migrate-formal-dir.cjs --json --project-root=$(pwd) 2>&1)
50
+ ```
51
+
52
+ If `~/.claude/qgsd-bin/migrate-formal-dir.cjs` does not exist, fall back to `bin/migrate-formal-dir.cjs` (CWD-relative).
53
+ If neither exists, skip this step silently — the migration script is optional for projects that never had a legacy layout.
54
+
55
+ Parse the JSON output:
56
+ - If `legacy_found` is `false`: log `"Step 0: No legacy .formal/ found — skipping migration"` and proceed to Step 1.
57
+ - If `legacy_found` is `true`: log the migration summary: `"Step 0: Migrated legacy .formal/ — {copied} files copied, {skipped} conflicts (canonical .planning/formal/ preserved)"`. The legacy `.formal/` directory is NOT auto-removed — the user can run `node bin/migrate-formal-dir.cjs --remove-legacy --project-root=$(pwd)` manually after verifying the migration.
58
+
59
+ **Important:** This step is fail-open. If the migration script errors or is not found, log the issue and proceed to Step 1. Migration failure must never block the diagnostic sweep.
60
+
61
+ ## Step 1: Initial Diagnostic Sweep
62
+
63
+ Run the diagnostic solver using absolute paths (or fall back to CWD-relative):
64
+
65
+ ```bash
66
+ BASELINE=$(node ~/.claude/qgsd-bin/qgsd-solve.cjs --json --report-only --project-root=$(pwd))
67
+ ```
68
+
69
+ If ~/.claude/qgsd-bin/qgsd-solve.cjs does not exist, fall back to bin/qgsd-solve.cjs (CWD-relative).
70
+ If neither exists, error with: "QGSD solve scripts not installed. Run `node bin/install.js --claude --global` from the QGSD repo."
71
+
72
+ Parse the JSON output to extract the `residual_vector` object. Key fields:
73
+ - `residual_vector.r_to_f.residual` — count of requirements lacking formal coverage
74
+ - `residual_vector.f_to_t.residual` — count of formal invariants lacking test backing
75
+ - `residual_vector.c_to_f.residual` — count of constant mismatches (Code vs Formal)
76
+ - `residual_vector.t_to_c.residual` — count of failing unit tests
77
+ - `residual_vector.f_to_c.residual` — count of failing formal checks
78
+ - `residual_vector.r_to_d.residual` — count of requirements not documented in developer docs
79
+ - `residual_vector.d_to_c.residual` — count of stale structural claims in docs
80
+ - `residual_vector.total` — total residual across all layers
81
+
82
+ Store the parsed baseline residual as `baseline_residual` for the before/after comparison at the end.
83
+
84
+ Display the baseline residual in human-readable format:
85
+ ```
86
+ Layer Transition Baseline Health
87
+ ────────────────────────────────────────
88
+ R -> F (Req->Formal) N [status]
89
+ F -> T (Formal->Test) N [status]
90
+ C -> F (Code->Formal) N [status]
91
+ T -> C (Test->Code) N [status]
92
+ F -> C (Formal->Code) N [status]
93
+ R -> D (Req->Docs) N [status]
94
+ D -> C (Docs->Code) N [status]
95
+ Total N
96
+ ```
97
+
98
+ Health status: GREEN (0), YELLOW (1-3), RED (4+), or UNKNOWN (error).
99
+
100
+ ## Step 2: Report-Only Gate
101
+
102
+ If `--report-only` flag was passed:
103
+ - Display the baseline residual vector only
104
+ - STOP — do not proceed to remediation
105
+ - Exit with status based on whether residual is zero (0) or non-zero (1)
106
+
107
+ This preserves the read-only diagnostic mode.
108
+
109
+ ## Step 3: Remediation Dispatch (Ordered by Dependency)
110
+
111
+ **Important:** Dispatch remediation in this strict order because R->F coverage is a prerequisite for F->T test stubs. New formal specs create new invariants needing test backing.
112
+
113
+ For each gap type with `residual > 0`, dispatch in this exact order:
114
+
115
+ ### 3a. R->F Gaps (residual_vector.r_to_f.residual > 0)
116
+
117
+ Extract the list of uncovered requirement IDs from `residual_vector.r_to_f.detail.uncovered_requirements`.
118
+
119
+ If the list has 10 or fewer IDs, dispatch:
120
+ ```
121
+ /qgsd:close-formal-gaps --batch --ids=REQ-01,REQ-02,...
122
+ ```
123
+
124
+ If the list has more than 10 IDs, dispatch:
125
+ ```
126
+ /qgsd:close-formal-gaps --batch --all
127
+ ```
128
+
129
+ Log: `"Dispatching R->F remediation: close-formal-gaps for {N} uncovered requirements"`
130
+
131
+ Wait for the skill to complete. If it fails, log the failure and continue to the next gap type.
132
+
133
+ **IMPORTANT — Verify generated models:** After close-formal-gaps completes, run the model checkers on every newly created model:
134
+ - **TLA+**: `java -cp <tla2tools.jar> tlc2.TLC -config <MC*.cfg> <*.tla> -workers 1` in `.planning/formal/tla/`
135
+ - **Alloy**: `java -jar <alloy.jar> exec --output - --type text --quiet <*.als>` in `.planning/formal/alloy/`
136
+
137
+ If a model fails verification (syntax error, counterexample, scope error), fix it immediately and re-run. Up to 3 fix attempts per model. Models that pass are confirmed; models that fail after 3 attempts are logged as needing manual review.
138
+
139
+ Find tool JARs at: `.planning/formal/tla/tla2tools.jar` (or `~/.claude/.planning/formal/tla/tla2tools.jar`) and `.planning/formal/alloy/org.alloytools.alloy.dist.jar` (or `~/.claude/.planning/formal/alloy/org.alloytools.alloy.dist.jar`).
140
+
141
+ ### 3b. F->T Gaps (residual_vector.f_to_t.residual > 0)
142
+
143
+ **Phase 1 — Generate stubs:** Run the formal-test-sync script to generate test stubs and update traceability sidecars:
144
+ ```bash
145
+ node ~/.claude/qgsd-bin/formal-test-sync.cjs --project-root=$(pwd)
146
+ ```
147
+
148
+ If ~/.claude/qgsd-bin/formal-test-sync.cjs does not exist, fall back to bin/formal-test-sync.cjs (CWD-relative).
149
+
150
+ Log: `"F->T phase 1: formal-test-sync generated {N} stubs"`
151
+
152
+ **Phase 1b — Validate recipes:** After stubs are generated, count recipe files and check completeness:
153
+ ```bash
154
+ node -e "
155
+ const fs = require('fs');
156
+ const dir = '.planning/formal/generated-stubs';
157
+ const recipes = fs.readdirSync(dir).filter(f => f.endsWith('.stub.recipe.json'));
158
+ const incomplete = recipes.filter(f => {
159
+ const r = JSON.parse(fs.readFileSync(dir + '/' + f, 'utf8'));
160
+ return !r.source_files.length || !r.formal_property.definition;
161
+ });
162
+ console.log('[solve] Recipes: ' + recipes.length + ' total, ' + incomplete.length + ' incomplete');
163
+ "
164
+ ```
165
+ Incomplete recipes (missing source_files or definition) produce lower-quality tests but do NOT block dispatch.
166
+
167
+ **Phase 2 — Implement stubs via direct parallel executor dispatch:** Stubs alone do not close the gap — they contain `assert.fail('TODO')`. The solver dispatches `qgsd-executor` agents directly to implement real test logic — it does NOT use `/qgsd:quick` for bulk stub implementation.
168
+
169
+ 1. **Load context:** Parse `.planning/formal/formal-test-sync-report.json` for each stub's `requirement_id`, `formal_properties[].model_file`, `formal_properties[].property`. Also verify recipe files exist at `.planning/formal/generated-stubs/{ID}.stub.recipe.json` — these contain pre-resolved context (requirement text, property definition, source files, import hints, test strategy).
170
+
171
+ 2. **Group into batches** by category prefix (e.g., all `ACT-*`, all `CONF-*`), max 5 stubs per batch. **No cap per iteration** — process ALL stubs. The convergence loop handles failures.
172
+
173
+ 3. **Write PLAN.md files directly** — The solve skill IS the planner for these mechanical tasks. For each batch, write a PLAN.md to `.planning/quick/solve-ft-batch-{iteration}-{B}/PLAN.md` with:
174
+ - YAML frontmatter: `autonomous: true`, `requirements: [IDs]`, `files_modified: [stub paths]`
175
+ - Objective: implement stubs by reading formal model + requirement text + finding source module
176
+ - Task block per batch with `<action>/<verify>/<done>` fields
177
+ - Each task specifies: stub file path, formal model path, property name, requirement text
178
+
179
+ PLAN.md template for each batch:
180
+ ```markdown
181
+ ---
182
+ phase: solve-ft-batch-{iteration}-{B}
183
+ plan: 01
184
+ type: execute
185
+ wave: 1
186
+ depends_on: []
187
+ files_modified:
188
+ - .planning/formal/generated-stubs/{ID1}.stub.test.js
189
+ - .planning/formal/generated-stubs/{ID2}.stub.test.js
190
+ autonomous: true
191
+ requirements: [{ID1}, {ID2}]
192
+ formal_artifacts: none
193
+ ---
194
+
195
+ <objective>
196
+ Implement {N} test stubs for {category} requirements.
197
+
198
+ For each stub, read its recipe JSON for pre-resolved context, then replace
199
+ assert.fail('TODO') with real test logic using node:test + node:assert/strict.
200
+
201
+ Formal context:
202
+ - {ID1}: model={model_file} property={property_name} text="{requirement text}"
203
+ recipe=.planning/formal/generated-stubs/{ID1}.stub.recipe.json
204
+ - {ID2}: ...
205
+ </objective>
206
+
207
+ <tasks>
208
+ <task type="auto">
209
+ <name>Implement stubs: {ID1}, {ID2}, ... {IDn}</name>
210
+ <files>.planning/formal/generated-stubs/{ID1}.stub.test.js, ...</files>
211
+ <action>
212
+ For each stub:
213
+ 1. Read .planning/formal/generated-stubs/{ID}.stub.recipe.json
214
+ 2. Read the stub file (.stub.test.js)
215
+ 3. Use recipe.formal_property.definition as the property under test
216
+ 4. Import from recipe.import_hint (adjust relative path if needed)
217
+ 5. Follow recipe.test_strategy:
218
+ - structural: assert function/export exists with correct signature
219
+ - behavioral: call function with known input, assert output matches formal property
220
+ - constant: assert code constant === formal value from property definition
221
+ 6. If recipe.source_files is empty, use Grep to find the implementing module
222
+ 7. Replace assert.fail('TODO') with real test logic using node:test + node:assert/strict
223
+ </action>
224
+ <verify>node --test .planning/formal/generated-stubs/{ID1}.stub.test.js</verify>
225
+ <done>No assert.fail('TODO') remains. Each stub has real test logic.</done>
226
+ </task>
227
+ </tasks>
228
+ ```
229
+
230
+ 4. **Spawn executors in sequential waves of 3** — To avoid OOM on developer machines (each executor consumes ~1GB RAM), dispatch at most 3 parallel executors at a time. Wait for each wave to finish before starting the next:
231
+ ```
232
+ Wave 1: Task(subagent_type="qgsd-executor", description="F->T stubs batch 1"), batch 2, batch 3
233
+ [wait for all 3 to complete]
234
+ Wave 2: Task(subagent_type="qgsd-executor", description="F->T stubs batch 4"), batch 5, batch 6
235
+ [wait for all 3 to complete]
236
+ ... continue until all batches dispatched
237
+ ```
238
+ MAX_PARALLEL_EXECUTORS = 3. This is a hard limit — never exceed it regardless of batch count.
239
+
240
+ 5. **Run tests once:** `node --test .planning/formal/generated-stubs/*.stub.test.js`. Log pass/fail counts. Failed stubs are handled by T->C in the next iteration.
241
+
242
+ 6. Log: `"F->T phase 2: spawned {N} executors in waves of 3 for {M} stubs (no quorum overhead)"`
243
+
244
+ ### 3c. T->C Gaps (residual_vector.t_to_c.residual > 0)
245
+
246
+ The T->C residual counts both failures and skipped tests. Extract detail:
247
+ - `detail.failed` — tests that ran and failed
248
+ - `detail.skipped` — tests marked skip (still count as unresolved gaps)
249
+ - `detail.todo` — tests marked todo (informational, do not inflate residual)
250
+
251
+ Dispatch the fix-tests skill:
252
+ ```
253
+ /qgsd:fix-tests
254
+ ```
255
+
256
+ This will discover and autonomously fix failing AND skipped tests. Skipped tests often indicate incomplete implementations or platform-specific guards that need resolution.
257
+
258
+ Log: `"Dispatching T->C remediation: fix-tests for {failed} failing + {skipped} skipped tests"`
259
+
260
+ If it fails, log the failure and continue.
261
+
262
+ ### 3d. C->F Gaps (residual_vector.c_to_f.residual > 0)
263
+
264
+ Constant mismatches between code and formal specs. Display the mismatch table, then dispatch `/qgsd:quick` to align them:
265
+
266
+ ```
267
+ C->F: {N} constant mismatch(es) — dispatching quick task to align
268
+ ```
269
+
270
+ Display detail table:
271
+ ```
272
+ Constant Source Formal Value Config Value
273
+ ─────────────────────────────────────────────────────────────
274
+ constant_name formal_spec_file formal_val config_val
275
+ ```
276
+
277
+ Dispatch:
278
+ ```
279
+ /qgsd:quick Fix C->F constant mismatches: update formal specs OR code config to align these values: {mismatch_summary}
280
+ ```
281
+
282
+ If the mismatch has `intentional_divergence: true`, skip it and log as intentional.
283
+
284
+ ### 3e. F->C Gaps (residual_vector.f_to_c.residual > 0)
285
+
286
+ First, run the formal verification using absolute paths to get fresh failure data:
287
+ ```bash
288
+ node ~/.claude/qgsd-bin/run-formal-verify.cjs --project-root=$(pwd)
289
+ ```
290
+
291
+ If ~/.claude/qgsd-bin/run-formal-verify.cjs does not exist, fall back to bin/run-formal-verify.cjs (CWD-relative).
292
+
293
+ Then parse `.planning/formal/check-results.ndjson` and classify each failure:
294
+
295
+ | Classification | Criteria | Dispatch |
296
+ |---------------|----------|----------|
297
+ | **Syntax error** | Summary contains "Syntax error", "parse error" | `/qgsd:quick Fix Alloy/TLA+ syntax error in {model_file}: {error_detail}` |
298
+ | **Scope error** | Summary contains "scope", "sig" | `/qgsd:quick Fix scope declaration in {model_file}: {error_detail}` |
299
+ | **Conformance divergence** | check_id contains "conformance" | `/qgsd:quick Fix conformance trace divergences in {model_file}: {error_detail}` |
300
+ | **Verification failure** | Counterexample found | `/qgsd:quick Fix formal verification counterexample in {check_id}: {summary}` |
301
+ | **Missing tool** | "not found", "not installed" | Log as infrastructure gap, skip |
302
+ | **Inconclusive** | result = "inconclusive" | Skip — not a failure |
303
+
304
+ Dispatch each fixable failure **sequentially** (one at a time) to the appropriate skill. Process syntax/scope errors first (they're usually quick fixes), then conformance/verification failures (require deeper investigation). Wait for each dispatch to complete before starting the next.
305
+
306
+ Log: `"F->C: {total} checks, {pass} pass, {fail} fail — dispatching {syntax_count} to quick, {debug_count} to debug, {skip_count} skipped"`
307
+
308
+ Each dispatch is independent — if one fails, log and continue to the next. Do NOT dispatch F->C fixes in parallel.
309
+
310
+ ### 3f. R->D Gaps (residual_vector.r_to_d.residual > 0)
311
+
312
+ Requirements that shipped but are not mentioned in developer docs (docs/dev/).
313
+ User docs (docs/) are human-controlled and are never auto-modified.
314
+
315
+ Display the undocumented requirement IDs from `residual_vector.r_to_d.detail.undocumented_requirements`:
316
+
317
+ ```
318
+ R->D: {N} requirement(s) undocumented in developer docs:
319
+ - REQ-01
320
+ - REQ-02
321
+ ...
322
+ ```
323
+
324
+ Then auto-remediate by dispatching a single `qgsd-executor` agent directly — it does NOT use `/qgsd:quick` for bulk doc generation.
325
+
326
+ 1. Read `.planning/formal/requirements.json` to get the text/description for each undocumented requirement ID.
327
+ 2. For each undocumented ID, identify the most relevant source file(s) by grepping the codebase for the requirement ID and its key terms (use Grep tool).
328
+ 3. **Write ONE PLAN.md** to `.planning/quick/solve-rd-{iteration}/PLAN.md` covering all undocumented requirements (up to 100). The plan has multiple `<task>` blocks (one per group of ~15 IDs) for natural checkpointing. Each task specifies: requirement IDs, requirement text, relevant source files, and the output format for `docs/dev/requirements-coverage.md`.
329
+
330
+ Each task block's action should instruct the executor to append sections following this format:
331
+ ```
332
+ ## {REQ-ID}: {requirement title or first 80 chars of text}
333
+
334
+ **Requirement:** {full requirement text}
335
+
336
+ **Implementation:** {1-3 sentence summary of how the codebase satisfies this requirement, citing specific files/functions}
337
+
338
+ **Source files:** {comma-separated list of relevant source files}
339
+ ```
340
+
341
+ Do NOT modify docs/ (user docs). Only write to docs/dev/requirements-coverage.md.
342
+
343
+ 4. **Spawn ONE executor:**
344
+ ```
345
+ Task(subagent_type="qgsd-executor", description="R->D: generate doc entries for {N} requirements")
346
+ ```
347
+ Wait for it to complete. If it fails, log the failure and continue.
348
+
349
+ Log: `"R->D: spawned 1 executor for {N} requirements (no quorum overhead)"`
350
+
351
+ ### 3g. D->C Gaps (residual_vector.d_to_c.residual > 0)
352
+
353
+ Stale structural claims in documentation — file paths, CLI commands, or dependencies referenced in docs that no longer exist in the codebase. This is a manual-review-only gap.
354
+
355
+ Display the broken claims table from `residual_vector.d_to_c.detail.broken_claims`:
356
+
357
+ ```
358
+ D->C: {N} stale structural claim(s) in docs:
359
+ Doc File Line Type Value Reason
360
+ ──────────────────────────────────────────────────────────────────────────
361
+ README.md 42 file_path bin/old-script.cjs file not found
362
+ docs/setup.md 15 cli_command node bin/missing.cjs script not found
363
+ docs/deps.md 8 dependency old-package not in package.json
364
+ ```
365
+
366
+ Log: `"D->C: {N} stale structural claim(s) in docs — manual review required"`
367
+
368
+ Do NOT dispatch any skill — this is informational only.
369
+
370
+ ### 3h. Reverse Traceability Discovery (C→R + T→R + D→R)
371
+
372
+ This step surfaces implementation artifacts that have no requirement backing. Unlike forward layers (which auto-remediate), reverse layers use a **two-step pattern**: autonomous discovery followed by human approval.
373
+
374
+ **Phase 1 — Discovery (autonomous):**
375
+
376
+ Extract reverse residuals from the diagnostic sweep (already computed in Step 1):
377
+ - `residual_vector.c_to_r.detail.untraced_modules` — source files in bin/ and hooks/ with no requirement tracing
378
+ - `residual_vector.t_to_r.detail.orphan_tests` — test files with no @req annotation or formal-test-sync mapping
379
+ - `residual_vector.d_to_r.detail.unbacked_claims` — doc capability claims without requirement backing
380
+
381
+ The diagnostic engine runs `assembleReverseCandidates()` automatically, which:
382
+ 1. Merges candidates from all 3 scanners
383
+ 2. Deduplicates (e.g., if test/foo.test.cjs and bin/foo.cjs are both untraced, merge into 1 candidate)
384
+ 3. Filters out .planning/ files, generated stubs, and node_modules paths
385
+ 4. Removes candidates present in `.planning/formal/acknowledged-not-required.json`
386
+ 5. Caps at 200 candidates maximum
387
+
388
+ If `assembled_candidates.candidates` is empty after dedup + filtering: Log `"Reverse discovery: 0 candidates after dedup/filtering"` and skip Phase 2.
389
+
390
+ **Phase 2 — Human Approval (interactive):**
391
+
392
+ Present the deduplicated candidate list to the user:
393
+
394
+ ```
395
+ Discovered {N} candidate requirement(s) from reverse traceability:
396
+
397
+ # Source Evidence Candidate
398
+ ─────────────────────────────────────────────────────────────────
399
+ 1 C→R bin/check-provider-health.cjs Provider health probe module
400
+ 2 C→R,T→R bin/validate-traces.cjs + test/... Trace validation module
401
+ 3 D→R README.md:42 "supports automatic OAuth rotation"
402
+ ...
403
+
404
+ Accept: [a]ll / [n]one / comma-separated numbers (e.g. 1,3,5) / [s]kip this cycle
405
+ ```
406
+
407
+ Wait for user input via AskUserQuestion. Route based on response:
408
+
409
+ - **Numbers or "all"**: For each accepted candidate, dispatch `/qgsd:add-requirement` with the candidate evidence as context. The add-requirement skill handles ID assignment, duplicate checks, and semantic conflict detection. Approved candidates enter the forward flow (R→F→T→C) in the next iteration.
410
+
411
+ - **"none"**: Write ALL candidates to `.planning/formal/acknowledged-not-required.json` so they are not resurfaced in future runs. Each entry:
412
+ ```json
413
+ {
414
+ "file_or_claim": "<candidate file or claim text>",
415
+ "source_scanners": ["C→R", "T→R"],
416
+ "acknowledged_at": "<ISO timestamp>",
417
+ "reason": "user-rejected"
418
+ }
419
+ ```
420
+
421
+ - **"skip"**: Do nothing — candidates will resurface in the next solve run. This is the default if the user does not respond.
422
+
423
+ Log: `"Reverse discovery: {N} candidates presented, {M} approved, {K} rejected, {J} skipped"`
424
+
425
+ ## Step 4: Re-Diagnostic Sweep
426
+
427
+ After all remediations in Step 3 complete, run the diagnostic again using absolute paths:
428
+ ```bash
429
+ POST=$(node ~/.claude/qgsd-bin/qgsd-solve.cjs --json --report-only --project-root=$(pwd))
430
+ ```
431
+
432
+ If ~/.claude/qgsd-bin/qgsd-solve.cjs does not exist, fall back to bin/qgsd-solve.cjs (CWD-relative).
433
+
434
+ Parse the result as `post_residual`.
435
+
436
+ ## Step 5: Convergence Check
437
+
438
+ Compare the baseline total residual against the post-remediation total:
439
+
440
+ - If `post_residual.total == 0`: Report `"✓ All layers converged to zero. System is fully consistent."` and EXIT.
441
+ - If `post_residual.total < baseline_residual.total`: Report improvement `"✓ Improvement: {baseline} → {post} gaps remaining"` and continue to Step 6.
442
+ - If `post_residual.total >= baseline_residual.total`: Report stasis `"⚠ Residual did not decrease. {baseline} → {post}. Remaining gaps may need manual attention."` and continue to Step 6.
443
+
444
+ ### Iteration Loop (if --max-iterations > 1)
445
+
446
+ If `--max-iterations=N` was passed and N > 1:
447
+ - Increment iteration counter
448
+ - Compute `automatable_residual` = r_to_f + f_to_t + c_to_f + t_to_c + f_to_c + r_to_d (exclude d_to_c which is manual-only)
449
+ - If iterations < max_iterations AND automatable_residual > 0 AND at least one automatable layer changed: loop back to Step 3
450
+ - If iterations >= max_iterations OR automatable_residual == 0 OR no automatable layer changed: proceed to Step 6
451
+
452
+ **IMPORTANT — Cascade-aware convergence:** Do NOT use total residual for the loop condition. Fixing R→F creates F→T gaps (total goes UP), but the system is making progress. Use per-layer change detection instead: if ANY automatable layer's residual changed (up or down) since the previous iteration, there is still work to do. Only stop when all automatable layers are stable (unchanged between iterations) or at zero.
453
+
454
+ Default behavior (no `--max-iterations` flag): max iterations = 5.
455
+
456
+ ## Step 6: Before/After Summary
457
+
458
+ Display a comprehensive before/after comparison table:
459
+
460
+ ```
461
+ Layer Transition Before After Delta Status
462
+ ─────────────────────────────────────────────────────────
463
+ R -> F (Req→Formal) {N} {M} {delta} [GREEN|YELLOW|RED]
464
+ F -> T (Formal→Test) {N} {M} {delta} [GREEN|YELLOW|RED]
465
+ C -> F (Code→Formal) {N} {M} {delta} [GREEN|YELLOW|RED]
466
+ T -> C (Test→Code) {N} {M} {delta} [GREEN|YELLOW|RED]
467
+ F -> C (Formal→Code) {N} {M} {delta} [GREEN|YELLOW|RED]
468
+ R -> D (Req→Docs) {N} {M} {delta} [AUTO]
469
+ D -> C (Docs→Code) {N} {M} {delta} [MANUAL]
470
+ ──────────────────────────────────────────────────────────
471
+ Total {N} {M} {delta}
472
+ ```
473
+
474
+ **IMPORTANT — Expand non-zero layers:** For any layer with residual > 0, display the full detail below the table. The residual number alone hides severity. For example, F→C residual=1 might mean "1 check failed with 7,086 individual divergences." Always show:
475
+
476
+ - **R→F**: List all uncovered requirement IDs
477
+ - **F→T**: Count of formal properties without test backing
478
+ - **T→C**: Show counts with symbols (fail, skip, todo) and list failing test names with error summaries. Format: `N failed, N skipped, N todo (of M total)`
479
+ - **C→F**: Table of each constant mismatch (name, formal value, config value)
480
+ - **F→C**: For each failing check: check_id, summary (including counts like "7086 divergences"), affected requirement IDs. Also list inconclusive checks separately.
481
+ - **R→D**: List all undocumented requirement IDs
482
+ - **D→C**: Table of each broken claim (doc_file, line, type, value, reason)
483
+
484
+ Example F→C expansion:
485
+ ```
486
+ F → C Detail:
487
+ ✗ ci:conformance-traces — 7086 divergence(s) in 20199 traces
488
+ ⚠ ci:liveness-fairness-lint — fairness declarations missing for 10 properties
489
+ ```
490
+
491
+ Example T→C expansion:
492
+ ```
493
+ T -> C Detail:
494
+ Tests: 2 failed, 3 skipped, 1 todo (of 42 total)
495
+ ```
496
+
497
+ If any gaps remain after convergence, append a summary of what couldn't be auto-fixed and why.
498
+
499
+ Note: R->D gaps are auto-remediated by generating developer doc entries in docs/dev/requirements-coverage.md. D->C gaps (stale file paths, CLI commands, dependencies) require manual review.
500
+
501
+ ## Step 7: Full Formal Verification Detail Table
502
+
503
+ **ALWAYS display this table** — it shows every individual check from `run-formal-verify.cjs`, not just the solver-tracked layer residuals. The solver layer table (Step 6) can show all-green while real formal model failures hide underneath.
504
+
505
+ After the before/after table, run the full formal verification using absolute paths if not already run during Step 3e:
506
+ ```bash
507
+ node ~/.claude/qgsd-bin/run-formal-verify.cjs --project-root=$(pwd)
508
+ ```
509
+
510
+ If ~/.claude/qgsd-bin/run-formal-verify.cjs does not exist, fall back to bin/run-formal-verify.cjs (CWD-relative).
511
+
512
+ Parse `.planning/formal/check-results.ndjson` and display **every check** grouped by result:
513
+
514
+ ```
515
+ Formal Verification Detail ({pass}/{total} passed):
516
+ ─────────────────────────────────────────────────────────
517
+ CHECK RESULT DETAIL
518
+ ─────────────────────────────────────────────────────────
519
+ ✓ check_id PASS (optional note)
520
+ ...
521
+ ✗ check_id FAIL summary of failure
522
+ ...
523
+ ⚠ check_id INCONC reason for inconclusive
524
+ ...
525
+ ─────────────────────────────────────────────────────────
526
+ ```
527
+
528
+ Rules for the detail column:
529
+ - **PASS**: Leave blank unless there's a notable caveat (e.g., "low-confidence — 0 traces", "empirical timing only")
530
+ - **FAIL**: Show the full summary from the check result (e.g., "7271 divergence(s) in 20651 traces", "MCMCPEnv model check failed", "tp_rate=0.49, unavail=0.45")
531
+ - **INCONCLUSIVE**: Show the reason (e.g., "fairness missing: PropertyName1, PropertyName2", "verifyta not installed")
532
+
533
+ Display checks in this order: PASS first (alphabetical), then FAIL (alphabetical), then INCONCLUSIVE (alphabetical). This puts failures and inconclusives at the bottom where they're visually prominent.
534
+
535
+ After the table, if there are any FAIL or INCONCLUSIVE checks, add a brief actionability note:
536
+ ```
537
+ {fail_count} check(s) failing, {inconc_count} inconclusive.
538
+ Failing checks need investigation — use /qgsd:quick to dispatch fixes for syntax/scope errors or conformance divergences.
539
+ Inconclusive checks are not failures but indicate incomplete verification (usually missing fairness declarations or tools).
540
+ ```
541
+
542
+ This table is mandatory even when the solver layer residuals are all zero — because formal model failures (Alloy, TLA+, PRISM) may exist outside the solver's tracked CI checks.
543
+
544
+ ## Important Constraints
545
+
546
+ 1. **bin/qgsd-solve.cjs is NOT modified** — it remains the diagnostic engine. This skill orchestrates remediation at the skill/script level.
547
+
548
+ 2. **Convergence loop is at skill level** — when the skill calls diagnostic again in Step 4, it uses `--json --report-only` to get fresh data. The skill then decides whether to loop back to Step 3 or exit. The script's internal auto-close loop is bypassed.
549
+
550
+ 3. **Error handling** — each remediation dispatch is wrapped in error handling. If a sub-skill or script fails, log the failure and continue to the next gap type. Do not let one failure abort the entire solve cycle.
551
+
552
+ 4. **Ordering** — remediation order is strict because R→F must precede F→T (new formal specs create new invariants needing test backing). T→C fixes must happen before F→C verification (tests must pass before checking formal properties against code).
553
+
554
+ 5. **Full skill arsenal** — the solver dispatches to the right skill for each gap type. It never stops at "stubs generated" or "manual review required" if a skill exists that can attempt the fix. The hierarchy is:
555
+ - **close-formal-gaps --batch** for missing formal models (R->F), then **run model checkers** to verify them
556
+ - **formal-test-sync** to generate stubs (F->T phase 1), then **direct parallel executor dispatch** to implement real test logic (F->T phase 2)
557
+ - **fix-tests** for failing tests (T->C)
558
+ - **quick** for constant mismatches (C->F), syntax/scope errors, conformance divergences (F->C)
559
+ - **direct executor dispatch** for R->D documentation generation
560
+
561
+ 6. **Cascade awareness** — fixing one layer often creates gaps in the next (e.g., new formal models → new F→T gaps → new stubs → new T→C gaps). The iteration loop handles this naturally. Expect the total to fluctuate between iterations before converging. Reverse discovery candidates that get approved also feed into the forward flow (R→F→T→C) in subsequent iterations.
562
+
563
+ 7. **Reverse flows are discovery-only** — C→R, T→R, and D→R never auto-remediate. They surface candidates for human approval. The human gate prevents unbounded requirement expansion (if C→R auto-added requirements, those would trigger R→F→T→C, generating more code, triggering more C→R — an infinite loop). Reverse residuals do NOT count toward the automatable total or affect the convergence check in Step 5.
564
+
565
+ </process>