bmad-module-skill-forge 2.2.0 → 3.0.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 (435) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +49 -49
  3. package/docs/404.md +10 -8
  4. package/docs/_data/pinned.yaml +22 -13
  5. package/docs/_internal/STABILITY.md +58 -35
  6. package/docs/agents.md +39 -53
  7. package/docs/architecture.md +65 -51
  8. package/docs/bmad-synergy.md +53 -51
  9. package/docs/campaign.md +127 -75
  10. package/docs/concepts.md +34 -28
  11. package/docs/examples.md +70 -68
  12. package/docs/forge-auto.md +34 -31
  13. package/docs/getting-started.md +118 -57
  14. package/docs/how-it-works.md +25 -21
  15. package/docs/index.md +15 -15
  16. package/docs/skill-model.md +70 -59
  17. package/docs/troubleshooting.md +135 -18
  18. package/docs/verifying-a-skill.md +83 -57
  19. package/docs/why-skf.md +24 -22
  20. package/docs/workflows.md +274 -110
  21. package/package.json +18 -10
  22. package/src/forger/preferences.yaml +8 -1
  23. package/src/knowledge/agentskills-spec.md +2 -0
  24. package/src/knowledge/ccc-bridge.md +40 -24
  25. package/src/knowledge/confidence-tiers.md +9 -5
  26. package/src/knowledge/overview.md +3 -3
  27. package/src/knowledge/progressive-capability.md +8 -8
  28. package/src/knowledge/provenance-tracking.md +9 -5
  29. package/src/knowledge/qmd-registry.md +2 -2
  30. package/src/knowledge/skf-knowledge-index.csv +2 -2
  31. package/src/knowledge/skill-lifecycle.md +18 -11
  32. package/src/knowledge/split-body-strategy.md +0 -3
  33. package/src/knowledge/tool-resolution.md +4 -2
  34. package/src/knowledge/version-paths.md +101 -15
  35. package/src/module-help.csv +3 -3
  36. package/src/module.yaml +10 -0
  37. package/src/shared/data/ast-grep-recipes.yaml +608 -0
  38. package/src/shared/data/ide-context-files.json +30 -0
  39. package/src/shared/health-check.md +32 -12
  40. package/src/shared/references/description-guard-protocol.md +12 -9
  41. package/src/shared/references/feasibility-report-schema.md +19 -13
  42. package/src/shared/references/headless-gate-convention.md +55 -3
  43. package/src/shared/references/output-contract-schema.md +19 -8
  44. package/src/shared/references/pipeline-contracts.md +94 -29
  45. package/src/shared/references/tessl-review.md +77 -0
  46. package/src/shared/scripts/schemas/skf-analyze-result-envelope.v1.json +194 -0
  47. package/src/shared/scripts/schemas/skf-audit-result-envelope.v1.json +192 -0
  48. package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +32 -4
  49. package/src/shared/scripts/schemas/skf-campaign-result-envelope.v1.json +174 -0
  50. package/src/shared/scripts/schemas/skf-create-skill-result-envelope.v1.json +284 -0
  51. package/src/shared/scripts/schemas/skf-drop-skill-result-envelope.v1.json +164 -0
  52. package/src/shared/scripts/schemas/skf-export-result-envelope.v1.json +160 -0
  53. package/src/shared/scripts/schemas/skf-quick-skill-result-envelope.v1.json +261 -0
  54. package/src/shared/scripts/schemas/skf-refine-architecture-result-envelope.v1.json +192 -0
  55. package/src/shared/scripts/schemas/skf-rename-skill-result-envelope.v1.json +179 -0
  56. package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +27 -11
  57. package/src/shared/scripts/schemas/skf-stack-result-envelope.v1.json +176 -0
  58. package/src/shared/scripts/schemas/skf-test-result-envelope.v1.json +173 -0
  59. package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +19 -5
  60. package/src/shared/scripts/schemas/skf-verify-stack-result-envelope.v1.json +180 -0
  61. package/src/shared/scripts/schemas/skill-brief.v1.json +34 -0
  62. package/src/shared/scripts/schemas/workspace-detection.v1.json +1 -1
  63. package/src/shared/scripts/skf-atomic-write.py +30 -14
  64. package/src/shared/scripts/skf-build-change-manifest.py +2203 -24
  65. package/src/shared/scripts/skf-ccc-git-hygiene.py +532 -0
  66. package/src/shared/scripts/skf-check-unit-records.py +184 -0
  67. package/src/shared/scripts/skf-check-workspace-drift.py +538 -9
  68. package/src/shared/scripts/skf-classify-changed-files.py +694 -0
  69. package/src/shared/scripts/skf-comention-pairs.py +1333 -123
  70. package/src/shared/scripts/skf-compare-file-hashes.py +1 -1
  71. package/src/shared/scripts/skf-count-imports.py +1867 -0
  72. package/src/shared/scripts/skf-count-tokens.py +1 -1
  73. package/src/shared/scripts/skf-derive-assembly-shape.py +3 -2
  74. package/src/shared/scripts/skf-description-guard.py +99 -11
  75. package/src/shared/scripts/skf-detect-docs.py +694 -2
  76. package/src/shared/scripts/skf-detect-language.py +486 -107
  77. package/src/shared/scripts/skf-detect-registry.py +887 -0
  78. package/src/shared/scripts/skf-detect-scripts-assets.py +1 -1
  79. package/src/shared/scripts/skf-detect-tools.py +209 -27
  80. package/src/shared/scripts/skf-detect-workspaces.py +506 -30
  81. package/src/shared/scripts/skf-disqualify-candidates.py +821 -182
  82. package/src/shared/scripts/skf-emit-brief-result-envelope.py +69 -191
  83. package/src/shared/scripts/skf-emit-result-envelope.py +1604 -106
  84. package/src/shared/scripts/skf-enumerate-stack-skills.py +986 -117
  85. package/src/shared/scripts/skf-extract-public-api.py +4084 -85
  86. package/src/shared/scripts/skf-extraction-inventory.py +746 -0
  87. package/src/shared/scripts/skf-extraction-snapshot.py +539 -0
  88. package/src/shared/scripts/skf-fetch-temporal.py +674 -0
  89. package/src/shared/scripts/skf-find-cycles.py +97 -29
  90. package/src/shared/scripts/skf-find-test-report.py +476 -0
  91. package/src/shared/scripts/skf-forge-tier-rw.py +444 -203
  92. package/src/shared/scripts/skf-github-fetch.py +365 -0
  93. package/src/shared/scripts/skf-github-probe.py +661 -0
  94. package/src/shared/scripts/skf-hash-content.py +166 -12
  95. package/src/shared/scripts/skf-language-corpora.py +1 -1
  96. package/src/shared/scripts/skf-load-provenance.py +159 -27
  97. package/src/shared/scripts/skf-manifest-ops.py +1 -1
  98. package/src/shared/scripts/skf-merge-ccc-exclusions.py +2307 -223
  99. package/src/shared/scripts/skf-merge-doc-urls.py +1 -1
  100. package/src/shared/scripts/skf-names-present.py +221 -0
  101. package/src/shared/scripts/skf-pair-intersect.py +119 -28
  102. package/src/shared/scripts/skf-parse-gaps.py +1384 -0
  103. package/src/shared/scripts/skf-preapply.py +1 -1
  104. package/src/shared/scripts/skf-preflight.py +161 -27
  105. package/src/shared/scripts/skf-promote-staged.py +430 -0
  106. package/src/shared/scripts/skf-provenance-gap-dispatch.py +39 -7
  107. package/src/shared/scripts/skf-qmd-classify-collections.py +229 -45
  108. package/src/shared/scripts/skf-quick-batch.py +774 -0
  109. package/src/shared/scripts/skf-rebuild-managed-sections.py +972 -88
  110. package/src/shared/scripts/skf-recommend-scope-type.py +323 -156
  111. package/src/shared/scripts/skf-render-metadata-stats.py +156 -12
  112. package/src/shared/scripts/skf-render-quick-metadata.py +132 -28
  113. package/src/shared/scripts/skf-render-stack-metadata.py +976 -0
  114. package/src/shared/scripts/skf-resolve-authoritative-files.py +128 -13
  115. package/src/shared/scripts/skf-resolve-package.py +523 -106
  116. package/src/shared/scripts/skf-rewrite-skill-name.py +433 -47
  117. package/src/shared/scripts/skf-run-lock.py +577 -0
  118. package/src/shared/scripts/skf-scan-manifests.py +998 -57
  119. package/src/shared/scripts/skf-scan-skill-md-structure.py +1341 -37
  120. package/src/shared/scripts/skf-severity-classify.py +712 -108
  121. package/src/shared/scripts/skf-shape-detect.py +298 -204
  122. package/src/shared/scripts/skf-shard-body.py +9 -8
  123. package/src/shared/scripts/skf-skill-inventory.py +2412 -89
  124. package/src/shared/scripts/skf-skills-module.py +472 -0
  125. package/src/shared/scripts/skf-source-tree.py +1796 -0
  126. package/src/shared/scripts/skf-structural-diff.py +670 -119
  127. package/src/shared/scripts/skf-tessl-review.py +706 -0
  128. package/src/shared/scripts/skf-update-active-symlink.py +5 -5
  129. package/src/shared/scripts/skf-update-run-state.py +624 -0
  130. package/src/shared/scripts/skf-validate-brief-inputs.py +92 -29
  131. package/src/shared/scripts/skf-validate-brief-schema.py +4 -1
  132. package/src/shared/scripts/skf-validate-feasibility-report.py +577 -66
  133. package/src/shared/scripts/skf-validate-frontmatter.py +103 -26
  134. package/src/shared/scripts/skf-validate-output.py +712 -64
  135. package/src/shared/scripts/skf-validate-pins.py +1 -1
  136. package/src/shared/scripts/skf-verify-no-trace.py +116 -10
  137. package/src/shared/scripts/skf-verify-provenance-completeness.py +2919 -54
  138. package/src/shared/scripts/skf-write-skill-brief.py +367 -19
  139. package/src/shared/tool-requirements.yaml +201 -0
  140. package/src/skf-analyze-source/SKILL.md +41 -36
  141. package/src/skf-analyze-source/assets/skill-brief-schema.md +7 -8
  142. package/src/skf-analyze-source/customize.toml +36 -24
  143. package/src/skf-analyze-source/references/auto-docs-only.md +58 -20
  144. package/src/skf-analyze-source/references/continue.md +2 -13
  145. package/src/skf-analyze-source/references/discover-additional-source.md +147 -0
  146. package/src/skf-analyze-source/references/generate-briefs.md +121 -55
  147. package/src/skf-analyze-source/references/headless-contract.md +42 -15
  148. package/src/skf-analyze-source/references/identify-units.md +96 -110
  149. package/src/skf-analyze-source/references/init.md +73 -71
  150. package/src/skf-analyze-source/references/map-and-detect.md +123 -105
  151. package/src/skf-analyze-source/references/map-unit-exports.md +68 -0
  152. package/src/skf-analyze-source/references/recommend.md +51 -70
  153. package/src/skf-analyze-source/references/scan-project.md +60 -84
  154. package/src/skf-analyze-source/references/scan-root.md +39 -0
  155. package/src/skf-analyze-source/references/step-auto-scope-coexistence.md +47 -0
  156. package/src/skf-analyze-source/references/step-auto-scope-corpora.md +53 -0
  157. package/src/skf-analyze-source/references/step-auto-scope-split.md +91 -0
  158. package/src/skf-analyze-source/references/step-auto-scope.md +208 -293
  159. package/src/skf-analyze-source/references/step-shape-detect.md +14 -12
  160. package/src/skf-analyze-source/references/unit-detection-heuristics.md +37 -42
  161. package/src/skf-audit-skill/SKILL.md +43 -51
  162. package/src/skf-audit-skill/assets/drift-report-template.md +27 -3
  163. package/src/skf-audit-skill/customize.toml +41 -20
  164. package/src/skf-audit-skill/references/constituent-freshness.md +91 -0
  165. package/src/skf-audit-skill/references/doc-drift.md +141 -0
  166. package/src/skf-audit-skill/references/headless-contract.md +29 -0
  167. package/src/skf-audit-skill/references/init.md +148 -210
  168. package/src/skf-audit-skill/references/re-index.md +96 -108
  169. package/src/skf-audit-skill/references/report.md +96 -33
  170. package/src/skf-audit-skill/references/semantic-diff.md +27 -18
  171. package/src/skf-audit-skill/references/severity-classify.md +79 -65
  172. package/src/skf-audit-skill/references/severity-rules.md +15 -6
  173. package/src/skf-audit-skill/references/structural-diff.md +75 -90
  174. package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
  175. package/src/skf-audit-skill/scripts/render-drift-tables.py +685 -0
  176. package/src/skf-brief-skill/SKILL.md +36 -25
  177. package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
  178. package/src/skf-brief-skill/assets/scope-templates.md +17 -24
  179. package/src/skf-brief-skill/assets/skill-brief-schema.md +29 -15
  180. package/src/skf-brief-skill/customize.toml +48 -20
  181. package/src/skf-brief-skill/references/analyze-target.md +142 -125
  182. package/src/skf-brief-skill/references/confirm-brief.md +10 -8
  183. package/src/skf-brief-skill/references/draft-checkpoint.md +36 -17
  184. package/src/skf-brief-skill/references/gather-intent-ratify.md +68 -0
  185. package/src/skf-brief-skill/references/gather-intent.md +87 -182
  186. package/src/skf-brief-skill/references/headless-args.md +84 -16
  187. package/src/skf-brief-skill/references/health-check.md +1 -1
  188. package/src/skf-brief-skill/references/invocation-contract.md +18 -13
  189. package/src/skf-brief-skill/references/portfolio-similarity-check.md +1 -1
  190. package/src/skf-brief-skill/references/qmd-collection-registration.md +7 -10
  191. package/src/skf-brief-skill/references/scope-definition.md +123 -47
  192. package/src/skf-brief-skill/references/step-auto-brief.md +24 -80
  193. package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
  194. package/src/skf-brief-skill/references/version-resolution.md +3 -2
  195. package/src/skf-brief-skill/references/write-brief.md +66 -57
  196. package/src/skf-campaign/SKILL.md +31 -34
  197. package/src/skf-campaign/assets/campaign-state-schema.json +25 -4
  198. package/src/skf-campaign/customize.toml +47 -16
  199. package/src/skf-campaign/references/campaign-contracts.md +39 -29
  200. package/src/skf-campaign/references/campaign-directive-spec.md +4 -2
  201. package/src/skf-campaign/references/health-check.md +7 -16
  202. package/src/skf-campaign/references/step-01-setup.md +46 -84
  203. package/src/skf-campaign/references/step-02-strategy.md +31 -30
  204. package/src/skf-campaign/references/step-03-pins.md +26 -18
  205. package/src/skf-campaign/references/step-04-provenance.md +24 -23
  206. package/src/skf-campaign/references/step-05-skill-loop.md +67 -48
  207. package/src/skf-campaign/references/step-06-batch.md +41 -34
  208. package/src/skf-campaign/references/step-07-capstone.md +40 -25
  209. package/src/skf-campaign/references/step-08-verify.md +28 -29
  210. package/src/skf-campaign/references/step-09-refine.md +29 -30
  211. package/src/skf-campaign/references/step-10-export.md +48 -36
  212. package/src/skf-campaign/references/step-11-maintenance.md +31 -34
  213. package/src/skf-campaign/references/step-resume.md +37 -68
  214. package/src/skf-campaign/scripts/campaign-deps.py +57 -18
  215. package/src/skf-campaign/scripts/campaign-parse-manifest.py +361 -54
  216. package/src/skf-campaign/scripts/campaign-provenance.py +96 -53
  217. package/src/skf-campaign/scripts/campaign-quality-gate.py +592 -0
  218. package/src/skf-campaign/scripts/campaign-render-batch.py +257 -49
  219. package/src/skf-campaign/scripts/campaign-render-kickoff.py +343 -50
  220. package/src/skf-campaign/scripts/campaign-report.py +204 -37
  221. package/src/skf-campaign/scripts/campaign-state.py +1128 -0
  222. package/src/skf-campaign/scripts/campaign-status.py +10 -74
  223. package/src/skf-campaign/scripts/campaign-validate-pins.py +30 -3
  224. package/src/skf-campaign/scripts/campaign-validate-state.py +34 -4
  225. package/src/skf-campaign/templates/campaign-brief-template.yaml +4 -5
  226. package/src/skf-campaign/templates/campaign-report-template.md +5 -1
  227. package/src/skf-campaign/templates/kickoff-template.md +0 -14
  228. package/src/skf-create-skill/SKILL.md +27 -20
  229. package/src/skf-create-skill/assets/compile-assembly-rules.md +6 -5
  230. package/src/skf-create-skill/assets/skill-sections.md +15 -5
  231. package/src/skf-create-skill/customize.toml +20 -8
  232. package/src/skf-create-skill/references/authoritative-files-protocol.md +41 -42
  233. package/src/skf-create-skill/references/batch-mode.md +81 -0
  234. package/src/skf-create-skill/references/ccc-index-check.md +27 -0
  235. package/src/skf-create-skill/references/compile.md +107 -29
  236. package/src/skf-create-skill/references/component-extraction.md +113 -91
  237. package/src/skf-create-skill/references/enrich.md +41 -23
  238. package/src/skf-create-skill/references/entry-points-by-hand.md +20 -0
  239. package/src/skf-create-skill/references/extract.md +200 -161
  240. package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
  241. package/src/skf-create-skill/references/extraction-patterns-tracing.md +2 -2
  242. package/src/skf-create-skill/references/extraction-patterns.md +584 -196
  243. package/src/skf-create-skill/references/generate-artifacts.md +145 -93
  244. package/src/skf-create-skill/references/health-check.md +1 -1
  245. package/src/skf-create-skill/references/load-brief.md +53 -36
  246. package/src/skf-create-skill/references/relabel-rule.md +12 -0
  247. package/src/skf-create-skill/references/report.md +28 -59
  248. package/src/skf-create-skill/references/source-resolution-protocols.md +49 -155
  249. package/src/skf-create-skill/references/step-auto-shard.md +20 -93
  250. package/src/skf-create-skill/references/step-doc-rot.md +44 -60
  251. package/src/skf-create-skill/references/step-doc-sources.md +28 -19
  252. package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
  253. package/src/skf-create-skill/references/sub/fetch-docs.md +106 -59
  254. package/src/skf-create-skill/references/sub/fetch-temporal.md +53 -166
  255. package/src/skf-create-skill/references/tier-degradation-rules.md +18 -9
  256. package/src/skf-create-skill/references/validate.md +173 -99
  257. package/src/skf-create-skill/scripts/scan-doc-rot.py +232 -99
  258. package/src/skf-create-stack-skill/SKILL.md +29 -56
  259. package/src/skf-create-stack-skill/assets/metadata-contract.md +51 -0
  260. package/src/skf-create-stack-skill/assets/provenance-map-schema.md +15 -15
  261. package/src/skf-create-stack-skill/assets/stack-skill-template.md +23 -57
  262. package/src/skf-create-stack-skill/customize.toml +23 -12
  263. package/src/skf-create-stack-skill/references/compile-stack.md +57 -66
  264. package/src/skf-create-stack-skill/references/compose-mode-rules.md +24 -44
  265. package/src/skf-create-stack-skill/references/detect-integrations.md +92 -95
  266. package/src/skf-create-stack-skill/references/detect-manifests.md +46 -71
  267. package/src/skf-create-stack-skill/references/generate-output.md +138 -128
  268. package/src/skf-create-stack-skill/references/init.md +90 -32
  269. package/src/skf-create-stack-skill/references/integration-patterns.md +1 -17
  270. package/src/skf-create-stack-skill/references/invocation-contract.md +34 -0
  271. package/src/skf-create-stack-skill/references/manifest-patterns.md +32 -20
  272. package/src/skf-create-stack-skill/references/parallel-extract.md +112 -38
  273. package/src/skf-create-stack-skill/references/rank-and-confirm.md +57 -75
  274. package/src/skf-create-stack-skill/references/report.md +39 -33
  275. package/src/skf-create-stack-skill/references/validate.md +20 -39
  276. package/src/skf-drop-skill/SKILL.md +28 -51
  277. package/src/skf-drop-skill/customize.toml +44 -30
  278. package/src/skf-drop-skill/references/execute.md +79 -146
  279. package/src/skf-drop-skill/references/invocation-contract.md +64 -0
  280. package/src/skf-drop-skill/references/report.md +46 -30
  281. package/src/skf-drop-skill/references/select.md +118 -124
  282. package/src/skf-drop-skill/scripts/dir-sizes.py +54 -26
  283. package/src/skf-drop-skill/scripts/drop-roster.py +322 -0
  284. package/src/skf-export-skill/SKILL.md +40 -62
  285. package/src/skf-export-skill/assets/managed-section-format.md +14 -50
  286. package/src/skf-export-skill/assets/snippet-format.md +3 -1
  287. package/src/skf-export-skill/customize.toml +42 -13
  288. package/src/skf-export-skill/references/generate-snippet.md +54 -46
  289. package/src/skf-export-skill/references/health-check.md +2 -0
  290. package/src/skf-export-skill/references/invocation-contract.md +15 -0
  291. package/src/skf-export-skill/references/load-skill.md +88 -62
  292. package/src/skf-export-skill/references/manifest-rebuild.md +9 -10
  293. package/src/skf-export-skill/references/multi-skill-mode.md +4 -4
  294. package/src/skf-export-skill/references/orphan-context-detection.md +13 -5
  295. package/src/skf-export-skill/references/orphan-row-detection.md +31 -22
  296. package/src/skf-export-skill/references/package.md +15 -73
  297. package/src/skf-export-skill/references/preflight-snippet-root-probe.md +51 -70
  298. package/src/skf-export-skill/references/result-envelope.md +31 -16
  299. package/src/skf-export-skill/references/summary.md +41 -17
  300. package/src/skf-export-skill/references/token-report.md +4 -12
  301. package/src/skf-export-skill/references/update-context.md +118 -237
  302. package/src/skf-forger/SKILL.md +61 -37
  303. package/src/skf-forger/bmad-skill-manifest.yaml +4 -1
  304. package/src/skf-forger/customize.toml +43 -0
  305. package/src/skf-forger/references/pipeline-mode.md +73 -18
  306. package/src/skf-forger/scripts/forge-status.py +299 -0
  307. package/src/skf-forger/scripts/parse-pipeline.py +322 -54
  308. package/src/skf-forger/scripts/pipeline-gate.py +428 -0
  309. package/src/skf-forger/scripts/pipeline-journal.py +1052 -0
  310. package/src/skf-quick-skill/SKILL.md +54 -53
  311. package/src/skf-quick-skill/assets/skill-template.md +4 -2
  312. package/src/skf-quick-skill/customize.toml +51 -20
  313. package/src/skf-quick-skill/references/batch-mode.md +74 -21
  314. package/src/skf-quick-skill/references/compile.md +30 -31
  315. package/src/skf-quick-skill/references/ecosystem-check.md +7 -57
  316. package/src/skf-quick-skill/references/finalize.md +69 -18
  317. package/src/skf-quick-skill/references/halt-contract.md +41 -29
  318. package/src/skf-quick-skill/references/health-check.md +5 -3
  319. package/src/skf-quick-skill/references/quick-extract.md +114 -45
  320. package/src/skf-quick-skill/references/registry-resolution.md +9 -64
  321. package/src/skf-quick-skill/references/resolve-target.md +116 -66
  322. package/src/skf-quick-skill/references/write-and-validate.md +79 -40
  323. package/src/skf-refine-architecture/SKILL.md +43 -53
  324. package/src/skf-refine-architecture/customize.toml +49 -20
  325. package/src/skf-refine-architecture/references/compile.md +97 -54
  326. package/src/skf-refine-architecture/references/exit-codes.md +30 -0
  327. package/src/skf-refine-architecture/references/finding-storage.md +21 -0
  328. package/src/skf-refine-architecture/references/gap-analysis.md +101 -38
  329. package/src/skf-refine-architecture/references/improvements.md +14 -20
  330. package/src/skf-refine-architecture/references/init.md +98 -57
  331. package/src/skf-refine-architecture/references/issue-detection.md +32 -39
  332. package/src/skf-refine-architecture/references/refinement-rules.md +37 -48
  333. package/src/skf-refine-architecture/references/report.md +65 -54
  334. package/src/skf-refine-architecture/scripts/skf-check-preservation.py +1619 -0
  335. package/src/skf-rename-skill/SKILL.md +19 -54
  336. package/src/skf-rename-skill/customize.toml +32 -26
  337. package/src/skf-rename-skill/references/execute.md +230 -184
  338. package/src/skf-rename-skill/references/exit-codes.md +7 -7
  339. package/src/skf-rename-skill/references/health-check.md +1 -7
  340. package/src/skf-rename-skill/references/invocation-contract.md +25 -0
  341. package/src/skf-rename-skill/references/report.md +63 -52
  342. package/src/skf-rename-skill/references/select.md +197 -115
  343. package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -21
  344. package/src/skf-setup/SKILL.md +26 -26
  345. package/src/skf-setup/customize.toml +14 -10
  346. package/src/skf-setup/references/auto-index.md +50 -63
  347. package/src/skf-setup/references/ccc-index.md +29 -90
  348. package/src/skf-setup/references/detect-and-tier.md +58 -67
  349. package/src/skf-setup/references/health-check.md +2 -0
  350. package/src/skf-setup/references/invocation-contract.md +14 -0
  351. package/src/skf-setup/references/report.md +43 -166
  352. package/src/skf-setup/references/tier-rules.md +5 -5
  353. package/src/skf-setup/references/write-config.md +34 -57
  354. package/src/skf-test-skill/SKILL.md +17 -57
  355. package/src/skf-test-skill/assets/output-section-formats.md +33 -34
  356. package/src/skf-test-skill/customize.toml +27 -13
  357. package/src/skf-test-skill/references/coherence-check.md +134 -62
  358. package/src/skf-test-skill/references/coverage-check-tiers.md +35 -0
  359. package/src/skf-test-skill/references/coverage-check.md +217 -254
  360. package/src/skf-test-skill/references/detect-mode.md +5 -5
  361. package/src/skf-test-skill/references/external-validators.md +94 -82
  362. package/src/skf-test-skill/references/health-check.md +6 -7
  363. package/src/skf-test-skill/references/init.md +163 -88
  364. package/src/skf-test-skill/references/invocation-contract.md +66 -0
  365. package/src/skf-test-skill/references/migration-section-rules.md +5 -2
  366. package/src/skf-test-skill/references/report.md +162 -142
  367. package/src/skf-test-skill/references/score.md +80 -107
  368. package/src/skf-test-skill/references/scoring-rules.md +41 -155
  369. package/src/skf-test-skill/references/source-access-protocol.md +19 -92
  370. package/src/skf-test-skill/references/step-hard-gate.md +51 -33
  371. package/src/skf-test-skill/scripts/aggregate-coherence.py +218 -30
  372. package/src/skf-test-skill/scripts/build-result-context.py +287 -0
  373. package/src/skf-test-skill/scripts/check-metadata-coherence.py +37 -4
  374. package/src/skf-test-skill/scripts/combine-external-scores.py +23 -6
  375. package/src/skf-test-skill/scripts/compute-score.py +223 -45
  376. package/src/skf-test-skill/scripts/gap-ledger.py +1381 -0
  377. package/src/skf-test-skill/scripts/hard-gate.py +203 -0
  378. package/src/skf-test-skill/scripts/load-coverage-inputs.py +760 -0
  379. package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
  380. package/src/skf-test-skill/scripts/reconcile-coverage.py +273 -79
  381. package/src/skf-test-skill/scripts/score-signatures.py +459 -0
  382. package/src/skf-test-skill/scripts/stage-helper-payload.py +148 -0
  383. package/src/skf-test-skill/scripts/validate-inventory.py +311 -16
  384. package/src/skf-test-skill/scripts/verify-declared-numerator.py +127 -52
  385. package/src/skf-test-skill/templates/test-report-template.md +21 -15
  386. package/src/skf-update-skill/SKILL.md +38 -25
  387. package/src/skf-update-skill/customize.toml +27 -12
  388. package/src/skf-update-skill/references/detect-changes.md +233 -222
  389. package/src/skf-update-skill/references/gap-driven.md +336 -0
  390. package/src/skf-update-skill/references/health-check.md +31 -5
  391. package/src/skf-update-skill/references/init.md +250 -84
  392. package/src/skf-update-skill/references/invocation-contract.md +12 -0
  393. package/src/skf-update-skill/references/manual-section-rules.md +6 -23
  394. package/src/skf-update-skill/references/merge.md +180 -47
  395. package/src/skf-update-skill/references/re-extract.md +53 -262
  396. package/src/skf-update-skill/references/report.md +100 -35
  397. package/src/skf-update-skill/references/write.md +331 -149
  398. package/src/skf-update-skill/scripts/skf-new-file-diff.py +29 -7
  399. package/src/skf-verify-stack/SKILL.md +23 -42
  400. package/src/skf-verify-stack/assets/feasibility-report-template.md +11 -5
  401. package/src/skf-verify-stack/customize.toml +55 -22
  402. package/src/skf-verify-stack/references/coverage-patterns.md +17 -8
  403. package/src/skf-verify-stack/references/coverage.md +67 -64
  404. package/src/skf-verify-stack/references/exit-codes.md +21 -8
  405. package/src/skf-verify-stack/references/init.md +107 -62
  406. package/src/skf-verify-stack/references/integration-verification-rules.md +12 -13
  407. package/src/skf-verify-stack/references/integrations.md +106 -65
  408. package/src/skf-verify-stack/references/report.md +59 -42
  409. package/src/skf-verify-stack/references/requirements.md +32 -9
  410. package/src/skf-verify-stack/references/synthesize.md +53 -39
  411. package/src/skf-verify-stack/scripts/skf-coverage-tally.py +398 -52
  412. package/src/skf-verify-stack/scripts/skf-previous-report.py +330 -0
  413. package/src/skf-verify-stack/scripts/skf-report-delta.py +453 -49
  414. package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +240 -27
  415. package/tools/cli/commands/install.js +11 -4
  416. package/tools/cli/commands/status.js +15 -3
  417. package/tools/cli/commands/update.js +11 -4
  418. package/tools/cli/lib/tool-check.js +320 -0
  419. package/tools/cli/lib/version-check.js +22 -9
  420. package/tools/cli/skf-cli.js +4 -1
  421. package/.gitattributes +0 -16
  422. package/.nvmrc +0 -1
  423. package/docs/_internal/RELEASING.md +0 -679
  424. package/release-audits/v1.0.0-launch-audit.md +0 -728
  425. package/src/skf-audit-skill/references/step-doc-drift.md +0 -177
  426. package/src/skf-brief-skill/references/headless-source-authority-detection.md +0 -26
  427. package/src/skf-campaign/manifest.yaml +0 -15
  428. package/src/skf-create-skill/assets/tessl-dismissal-rules.md +0 -106
  429. package/src/skf-create-skill/references/ecosystem-check.md +0 -74
  430. package/src/skf-drop-skill/references/headless-contract.md +0 -18
  431. package/src/skf-update-skill/references/merge-conflict-rules.md +0 -15
  432. package/src/skf-update-skill/references/remote-source-resolution.md +0 -98
  433. package/src/skf-update-skill/references/validate.md +0 -124
  434. package/tools/validate-docs-drift.js +0 -233
  435. package/tools/validate-docs-links.js +0 -665
@@ -2,9 +2,11 @@
2
2
  nextStepFile: 'step-05-skill-loop.md'
3
3
  stateSchemaFile: 'assets/campaign-state-schema.json'
4
4
  stateFile: '{campaignWorkspacePath}/_campaign-state.yaml'
5
- backupFile: '{campaignWorkspacePath}/_campaign-state.yaml.bak'
6
5
  briefFile: '{campaignWorkspacePath}/campaign-brief.yaml'
6
+ provenanceResultsFile: '{campaignWorkspacePath}/_provenance-results.json'
7
+ decisionLogFile: '{campaignWorkspacePath}/_campaign-decision-log.md'
7
8
  provenanceScript: 'scripts/campaign-provenance.py'
9
+ stateScript: 'scripts/campaign-state.py'
8
10
  validateScript: 'scripts/campaign-validate-state.py'
9
11
  ---
10
12
 
@@ -18,46 +20,45 @@ Verify that all target repositories are accessible and record the exact commit S
18
20
 
19
21
  ## RULES
20
22
 
21
- - This step uses the **read-backup-modify-write** pattern.
22
- - Reads the brief for `repo_url` (not in state — `repo_url` is NOT part of the state schema).
23
- - Any inaccessible repo halts the campaign — all targets must be reachable before skill processing begins.
24
- - Validate state on load via `uv run {validateScript} --state-file {stateFile}`; HALT (exit 3) on non-zero.
25
- - Update `campaign.current_stage` to `3`.
26
- - Update `campaign.last_updated` to current ISO-8601 with timezone on every write.
27
- - If `{headless_mode}` is true, auto-proceed through confirmation gates with the default action and log each auto-decision.
23
+ - Write `campaign.current_stage` = 3 only in this stage's final state write, after every gate: step-resume resumes at `current_stage + 1`, so an early write skips unfinished work.
24
+ - Write state and decision-log entries only through `{stateScript}`, and on a non-zero exit HALT with the same code (State Contract in `references/campaign-contracts.md`). A log entry is `uv run {stateScript} log --log-file {decisionLogFile} --type <decision|auto|event> --text '<entry>'`.
25
+ - Any inaccessible repo halts the campaign: all targets must be reachable before skill processing begins. The brief holds each `repo_url` (the state schema has no place for it).
26
+ - If `{headless_mode}` is true, emit this stage's progress events, and at any HARD HALT the error envelope, per `references/campaign-contracts.md`.
28
27
 
29
28
  ## TASKS
30
29
 
31
- ### §1 — Read + Validate State
30
+ ### §1: Read + Validate State
32
31
 
33
32
  Load `{stateFile}`. Run `uv run {validateScript} --state-file {stateFile}`; on non-zero, HALT (exit 3) with the script's `errors[]`.
34
33
 
35
- ### §2 — Read Brief
34
+ ### §2: Read Brief
36
35
 
37
36
  Load `{briefFile}` only to confirm it parses (the provenance script reads it directly). HALT (exit code 8, `missing-brief`) if the brief is missing or unreadable.
38
37
 
39
- ### §3 — Backup State
38
+ ### §3: Verify Repo Access + Record Commit SHAs
40
39
 
41
- Copy `{stateFile}` to `{backupFile}` before any modification.
42
-
43
- ### §4 — Verify Repo Access + Record Commit SHAs
44
-
45
- Run the deterministic provenance check — do not parse repo URLs or shell out to `gh` by hand:
40
+ Run the deterministic provenance check, keeping its JSON output in `{provenanceResultsFile}` for §5; do not parse repo URLs or call `gh` by hand:
46
41
 
47
42
  ```
48
- uv run {provenanceScript} --state-file {stateFile} --brief-file {briefFile}
43
+ uv run {provenanceScript} --state-file {stateFile} --brief-file {briefFile} > {provenanceResultsFile}
49
44
  ```
50
45
 
51
- The script resolves `{owner}/{repo}` from each `repo_url` (tolerating `.git`/trailing slashes/SSH form), picks the ref (the skill's `pin`, else the repo default branch), runs `gh repo view` + `gh api commits`, and emits `results[]` with `commit_sha` and `status` per skill, plus `all_accessible`, `inaccessible_count`, and `systemic_hint`. Exit 0 = all accessible, 1 = one or more inaccessible, 2 = error (missing files, bad YAML, `gh` not installed). On script exit 2, HALT (exit code 2, `invalid-input`) surfacing the error — repo access cannot be verified without `gh`.
46
+ It writes `results[]`, one per skill with its `commit_sha` (of the skill's `pin`, else the default branch), `status`, `error` and `error_class` (`unauthenticated`, `not-found`, `rate-limited`, `forbidden`, `network`, or `other` for a target it could not look up), plus `all_accessible`, `inaccessible_count` and `systemic_hint`. Exit 0 = all accessible, 1 = one or more inaccessible, 2 = error (missing files, bad YAML, `gh` not installed, or `INVALID_BRIEF`: a brief that is no mapping or holds a target with no `name` or no `repo_url`). On script exit 2, HALT (exit code 2, `invalid-input`) surfacing the error; only when `gh` is what is missing, add that repo access cannot be verified without it.
47
+
48
+ ### §4: Handle Inaccessible Repos
52
49
 
53
- ### §5 — Handle Inaccessible Repos
50
+ If `all_accessible` is `false` (script exit 1), HALT (exit code 6, `inaccessible-repo`) and list each inaccessible repo with its URL, its `error_class` and its `error`. When the script returns a non-null `systemic_hint` (every target failed the same way: unauthenticated `gh`, no network, a rate limit, an organization's SSO policy), show that root-cause line first, above the per-repo errors, never in their place. Do NOT partially proceed: all repos must be verified before writing state.
54
51
 
55
- If `all_accessible` is `false` (script exit 1), HALT (exit code 6, `inaccessible-repo`). When the script returns a non-null `systemic_hint` (every target failed the same way — e.g. unauthenticated `gh`, no network, rate limit), present that single root-cause line instead of a wall of near-identical per-repo errors. Otherwise list each inaccessible repo, its URL, and its error. Do NOT partially proceed — all repos must be verified before writing state.
52
+ ### §5: Write State
56
53
 
57
- ### §6 — Write State
54
+ Write every commit SHA and the stage in one write:
55
+
56
+ ```
57
+ uv run {stateScript} apply-provenance --state-file {stateFile} --results-file {provenanceResultsFile} --stage 3
58
+ ```
58
59
 
59
- Set each skill's `commit_sha` from the script's `results[]`. Set `campaign.current_stage` to `3`. Set `campaign.last_updated` to current ISO-8601 with timezone. Write to `{stateFile}`.
60
+ It sets each skill's `commit_sha` from `results[]` and refuses results that hold an inaccessible repo (exit 6, nothing written: HALT as in §4); on exit 3, HALT (exit code 3, `invalid-state`).
60
61
 
61
62
  ## OUTPUT
62
63
 
63
- Display provenance summary — for each target, show name, repo URL, and recorded commit SHA. Chain to `{nextStepFile}`.
64
+ Display provenance summary: for each target, show name, repo URL, and recorded commit SHA. Chain to `{nextStepFile}`.
@@ -2,11 +2,15 @@
2
2
  nextStepFile: 'step-06-batch.md'
3
3
  stateSchemaFile: 'assets/campaign-state-schema.json'
4
4
  stateFile: '{campaignWorkspacePath}/_campaign-state.yaml'
5
- backupFile: '{campaignWorkspacePath}/_campaign-state.yaml.bak'
6
5
  briefFile: '{campaignWorkspacePath}/campaign-brief.yaml'
6
+ decisionLogFile: '{campaignWorkspacePath}/_campaign-decision-log.md'
7
+ preapplyLogFile: '{campaignWorkspacePath}/preapply-log.json'
8
+ factsFile: '{campaignWorkspacePath}/_facts.json'
7
9
  depsScript: 'scripts/campaign-deps.py'
8
10
  kickoffTemplate: '{kickoffTemplatePath}'
9
11
  kickoffScript: 'scripts/campaign-render-kickoff.py'
12
+ gateScript: 'scripts/campaign-quality-gate.py'
13
+ stateScript: 'scripts/campaign-state.py'
10
14
  validateScript: 'scripts/campaign-validate-state.py'
11
15
  ---
12
16
 
@@ -20,85 +24,100 @@ Iterate skills in `dependency_graph.execution_order`, processing each Tier A ski
20
24
 
21
25
  ## RULES
22
26
 
23
- - This step uses the **read-backup-modify-write** pattern.
24
- - Validate state on load via `uv run {validateScript} --state-file {stateFile}`; HALT (exit 3) on non-zero.
25
- - Update `campaign.current_stage` to `4`.
26
- - Update `campaign.last_updated` to current ISO-8601 with timezone on every write.
27
- - Write state after EACH skill completes (not just at end) — context death between skills must be survivable.
28
- - The per-skill pipeline body (§5.2) runs inline, not in a delegated subagent: AN→BS→CS→TS are nested skill activations, and a subagent cannot spawn further subagents — running inline keeps the full pipeline reachable and writes each skill's state before the next begins.
29
- - If `{headless_mode}` is true, auto-proceed through confirmation gates. Dependency gate blocks default to HALT (safest — never silently skip dependencies).
27
+ - Write `campaign.current_stage` = 4 only in this stage's final state write (§6), after every skill: step-resume resumes at `current_stage + 1`, so an early write skips unfinished work. An interrupted skill needs no stage write: it stays `active`, and resume sends an active Tier A skill back to this stage.
28
+ - Write state and decision-log entries only through `{stateScript}`, and on a non-zero exit HALT with the same code (State Contract in `references/campaign-contracts.md`). A log entry is `uv run {stateScript} log --log-file {decisionLogFile} --type <decision|auto|event> --text '<entry>'`.
29
+ - Write state after EACH skill completes (not just at end): context death between skills must be survivable.
30
+ - The per-skill pipeline body (§5.2) runs inline, not in a delegated subagent: BS→CS→TS are nested skill activations, and a subagent cannot spawn further subagents, so running inline keeps the full pipeline reachable and writes each skill's state before the next begins.
31
+ - If `{headless_mode}` is true, auto-proceed through confirmation gates; at a blocked skill, headless takes §4.6's `default_action` and never forces a dependency. Emit this stage's progress events, and at any HARD HALT the error envelope, per `references/campaign-contracts.md`.
30
32
 
31
33
  ## TASKS
32
34
 
33
- ### §1 — Read + Validate State
35
+ ### §1: Read + Validate State
34
36
 
35
37
  Load `{stateFile}`. Run `uv run {validateScript} --state-file {stateFile}`; on non-zero, HALT (exit 3) with the script's `errors[]`.
36
38
 
37
- ### §2 — Read Brief
39
+ ### §2: Read Brief
38
40
 
39
- Load `{briefFile}`. Build a lookup map from `targets[].name` to `targets[].repo_url`. HALT (exit code 8, `missing-brief`) if the brief is missing or unreadable.
41
+ Load `{briefFile}` only to confirm it parses (the kickoff script reads it directly). HALT (exit code 8, `missing-brief`) if the brief is missing or unreadable.
40
42
 
41
- ### §3 — Read Directive
43
+ ### §3: Read Directive
42
44
 
43
- If `campaign.directive_path` is set in state, load the file at that path and apply its contents as campaign-wide context for all skill processing, per the directive contract in `references/campaign-directive-spec.md`. If the file is not found, continue without error (directive is optional).
45
+ If `campaign.directive_path` is set in state, the directive steers this stage through two scripts, so apply none of it by hand: the gate script's resolve calls read its `## Skip List` and `## Quality Overrides` for each skill (§4 and §5, re-reading the file, so an edit between skills takes effect), and the kickoff script inlines the whole file into each kickoff (§5), where its other sections are the campaign-wide context the directive contract in `references/campaign-directive-spec.md` describes. If the file is not found, continue without error (directive is optional).
44
46
 
45
- ### §4 — Dependency Gate Check
47
+ ### §4: Dependency Gate Check
46
48
 
47
49
  For each skill in `dependency_graph.execution_order`, before processing:
48
50
 
49
- 1. Skip Tier B skills — they are processed in step-06 via batch mode.
51
+ 1. Skip Tier B skills: they are processed in step-06 via batch mode.
50
52
  2. Skip skills whose status is already `"completed"`, `"failed"`, or `"skipped"` (resume support).
51
- 3. Run `uv run {depsScript} --check --state-file {stateFile} --skill {skill_name}`.
52
- 4. If `ready: true` — proceed to §5 for this skill.
53
- 5. If `ready: false` — present the blocked skill and its unmet dependencies:
54
- - `[S]kip` — mark skill as `"skipped"`, backup and write state, continue to next skill.
55
- - `[F]orce` — re-run with `--force`, proceed to §5 despite unmet deps.
56
- - `[H]alt` — stop the campaign loop. (Default in headless mode.)
57
- 6. **Deadlock detection:** after iterating through all remaining skills and finding none ready, present the same recovery menu as §4.5, scoped to the mutually-blocked set (this is the strictly harder situation, so it must not get worse UX than a single blocked skill):
53
+ 3. Resolve the skill's run, passing `--directive-file` when state sets `campaign.directive_path`:
54
+
55
+ ```
56
+ uv run {gateScript} resolve --state-file {stateFile} --skill {skill_name} --brief-file {briefFile} [--directive-file <campaign.directive_path>]
57
+ ```
58
+
59
+ When `skip` is true, the directive's Skip List names the skill: mark it skipped (`uv run {stateScript} set-skill --state-file {stateFile} --skill {skill_name} --status skipped`), log "directive Skip List: {skill_name} ({skip_reason})" (type `event`), and continue to the next skill. Otherwise keep its `brief_skill`, the brief-skill inputs §5.2 copies. Its `unparsed` entries and `warnings` lines describe the directive, not the skill: log them to the decision log once per stage, from the first resolve call, and again only when a later call reports different ones. On exit 2, HALT with its `error`: exit code 8 (`missing-brief`) when its `code` is `BRIEF_NOT_FOUND`, `BRIEF_UNREADABLE` or `TARGET_NOT_FOUND` (the brief has no target for the skill), else exit code 2 (`invalid-input`): an override that breaks the gate, or a directive that cannot be read.
60
+ 4. Run `uv run {depsScript} --check --state-file {stateFile} --skill {skill_name}`.
61
+ 5. If `ready: true`, proceed to §5 for this skill.
62
+ 6. If `ready: false`, present the blocked skill and each unmet dependency with its status (`unmet_status`):
63
+ - `[S]kip`: mark the skill skipped with the `set-skill --status skipped` call above, log it, continue to the next skill.
64
+ - `[F]orce`: re-run with `--force`, proceed to §5 despite unmet deps.
65
+ - `[H]alt`: stop the campaign with exit code 13 (`dependency-blocked`); state is intact and resumable.
66
+
67
+ **GATE [default: `default_action`]**: headless, take `default_action`. `skip` (every unmet dependency failed or was skipped, so none can complete in this run) runs `[S]kip` and logs "headless: skipped {skill_name}: {dependency} is {status}" for each unmet dependency, so the independent skills after it still run. `halt` (a dependency is still pending or active, an order the loop cannot follow) runs `[H]alt`. In execution order every dependency comes first, so `halt` is defensive: only a `--from` resume or a hand-edited state leaves a dependency pending.
68
+ 7. **Deadlock detection** (defensive: Strategy rejects every order the loop cannot follow and §4.6 settles each blocked skill as the loop reaches it, so only a hand-edited state gets here): after iterating through all remaining skills and finding none ready, present the same recovery menu as §4.6, scoped to the mutually-blocked set (this is the strictly harder situation, so it must not get worse UX than a single blocked skill):
58
69
  - List the blocked skills and their unmet dependencies.
59
- - `[F]orce one` — choose a skill to re-run with `--force` and resume the loop from it.
60
- - `[S]kip one` — choose a skill to mark `"skipped"`, backup and write state, then re-evaluate readiness.
61
- - `[H]alt` — stop the campaign loop with exit code 7 (`dependency-deadlock`). **Default in headless mode** (never silently force or skip a dependency). Log the chosen action to the decision log.
70
+ - `[F]orce one`: choose a skill to re-run with `--force` and resume the loop from it.
71
+ - `[S]kip one`: choose a skill to mark skipped (`set-skill --status skipped`), then re-evaluate readiness.
72
+ - `[H]alt`: stop the campaign loop with exit code 7 (`dependency-deadlock`).
62
73
 
63
- ### §5 — Per-Skill Processing
74
+ **GATE [default: HALT]**: headless takes `[H]alt` (exit code 7, `dependency-deadlock`) and never forces a dependency. Log the chosen action to the decision log.
75
+
76
+ ### §5: Per-Skill Processing
64
77
 
65
78
  For each ready Tier A skill:
66
79
 
67
- 1. **Activate** — set `status` to `"active"`, set `started_at` to current ISO-8601 with timezone. Backup and write state.
80
+ 1. **Activate:** `uv run {stateScript} set-skill --state-file {stateFile} --skill {skill_name} --status active`. It stamps `started_at` from the clock, or keeps the start of a run an interruption left `active`.
68
81
  2. **Execute pipeline:**
69
- - **Pre-apply** — apply known workarounds before generation by running the shared pre-apply helper against the skill's working directory:
82
+ - **Pre-apply:** apply known workarounds before generation by running the shared pre-apply helper against the skill's working directory:
70
83
  ```
71
84
  uv run {project-root}/_bmad/skf/shared/scripts/skf-preapply.py --target-dir <skill-working-dir> --log-dir {campaignWorkspacePath}
72
85
  ```
73
- (During development the helper lives at `src/shared/scripts/skf-preapply.py`.) Parse `applied[]` from the JSON output and capture the list of applied workarounds. Pre-apply is best-effort: if the helper is missing or exits non-zero, log a warning and proceed — it is not a gate.
74
- - **Kickoff emit** — render the mechanical placeholders deterministically, then fill the three judgment slots. Run:
86
+ (During development, with no `{project-root}/_bmad/skf/shared/scripts/skf-preapply.py` installed, the helper lives at `{project-root}/src/shared/scripts/skf-preapply.py`.) It writes its `applied[]` workarounds to `{preapplyLogFile}`, which the kickoff script reads. Pre-apply is best-effort: if the helper is missing or exits non-zero, log a warning and proceed (it is not a gate), and leave `--workarounds-file` out of the kickoff call below, so an earlier skill's log is never listed for this one.
87
+ - **Kickoff emit:** render the whole kickoff message with the kickoff script, which fills every placeholder of the template. The customization resolver pipes the persistent facts into it:
75
88
  ```
76
- uv run {kickoffScript} --state-file {stateFile} --brief-file {briefFile} --skill {skill_name} --template {kickoffTemplate} --workarounds '<JSON list of applied workarounds from pre-apply>'
89
+ uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow.persistent_facts | uv run {kickoffScript} --state-file {stateFile} --brief-file {briefFile} --skill {skill_name} --template {kickoffTemplate} [--workarounds-file {preapplyLogFile}] --facts-json - --project-root {project-root} [--directive-file <campaign.directive_path>]
77
90
  ```
78
- The script fills `{{campaign_name}}`, `{{current_stage}}`, `{{quality_gate_summary}}`, `{{skill_name}}`, `{{skill_tier}}`, `{{pin}}`, `{{commit_sha}}`, `{{repo_url}}`, `{{workarounds_list}}`, and `{{dependency_status_table}}` from state + brief. Then fill the three judgment slots that remain in the rendered output:
79
- - `{{brief_summary}}` — a concise summary of this target's brief entry (name, repo_url, tier, pin, depends_on). The per-skill brief does NOT exist yet at kickoff — BS produces it during this pipeline run (see below), so do not read `brief_path`; summarize the campaign brief's target entry instead.
80
- - `{{persistent_facts}}` — the campaign-wide persistent facts resolved in On Activation (literal sentences and loaded `file:` contents), as a bullet list, or "None" if empty. This is how house style/guardrails reach every skill's pipeline.
81
- - `{{directive_content}}` — raw content of the file at `campaign.directive_path`, or "No directive configured" if unset/missing.
82
- Present the completed kickoff message as the context for the skill's pipeline run.
83
- - **AN → BS → CS → TS** — standard forge pipeline for this skill. When BS (Brief Synthesis) produces the skill's brief, set `skills[current].brief_path` to the brief path from the BS result envelope so the field the schema declares is populated and available for resume and reporting.
84
- - **Doc-rot check** — **record** what CS step 5c already produced; do not re-derive it. Because the pipeline body runs inline (see the §5 note above), that step's context is directly readable here: `corrections_added`, `correction_matches` (the enriched match records — `source`, `pattern`, `category`, `context_line`, `affected`), `corrections_deduped` and `corrections_capped`. Append one `[doc-rot]`-prefixed entry per `correction_matches` record to the skill's `workarounds_applied` array so they survive state write and are available for §6 propagation. When step 5c took its skip branch (`doc_rot_triggered: false`, `corrections_added: 0`), there is nothing to record — append nothing and move on.
91
+ - `--facts-json -` takes `workflow.persistent_facts` from the resolver unchanged. When the resolver is missing or fails, write the `persistent_facts` list of `{skill-root}/customize.toml`, as written, to `{factsFile}` as a JSON list with your file-writing tool, and replace the pipe with `< {factsFile}`: no fact or workaround ever passes through shell quoting.
92
+ - `--workarounds-file` is passed when pre-apply exited 0 for this skill; the script lists each workaround it applied (the file, the fingerprint and its fix, the severity).
93
+ - `--directive-file` is passed when state sets `campaign.directive_path`.
94
+
95
+ Present the script's output unchanged as the context for the skill's pipeline run, and fill nothing in by hand. An exit 2 with no JSON on stderr is a usage error from a mangled call, not invalid input: fix the call and run it again. An exit 2 with JSON names its `code`: on `BAD_WORKAROUNDS` or `BAD_FACTS` this call's input is wrong, so correct it and run the call again; on `BRIEF_NOT_FOUND` or `BRIEF_UNREADABLE`, HALT (exit code 8, `missing-brief`); on any other code, HALT (exit code 2, `invalid-input`) with its `error`. Correct a call once only: when the corrected call fails too, HALT (exit code 2, `invalid-input`).
96
+ - **BS → CS → TS**: the forge pipeline for a named skill, the chain the forger's `forge` alias runs. Run each sub-skill with `--headless`, so no nested gate waits and each prints its result envelope. A sub-skill that fails ends the pipeline, and the skill fails (§5.3) with its `halt_reason`. Campaign runs no analyze-source pass: brief-skill scopes the named skill itself, while analyze-source names its briefs from the repository, so brief-skill would overwrite or never read them.
97
+ - **BS** (`skf-brief-skill`): `--headless --force` with each non-null field of §4's `brief_skill` as the input of that name (`target_repo`, `skill_name`, `target_version`, `language_hint`, `scope_hint`); copy them, never read them out of the kickoff. `target_version` is the skill's pin: Setup accepts only an X.Y.Z version as a Tier A pin, and brief-skill refuses any other shape with `input-invalid`, so a pin never silently drops out of the build. `--force` replaces a brief an earlier attempt wrote under this name. Record the `brief_path` of its SKF_BRIEF_RESULT_JSON at once, so resume and the report have it: `uv run {stateScript} set-skill --state-file {stateFile} --skill {skill_name} --brief-path <brief_path>`. An envelope with `status` `error`, or none, fails the skill.
98
+ - **CS** (`skf-create-skill`): `--headless` with that `brief_path`. CS prints an SKF_CREATE_SKILL_RESULT_JSON line (on stderr) only when it halts; that line fails the skill with its `summary.halt_reason`. On success, keep the `{skill_package}` its report names (the compiled skill's folder): §5.3 records it.
99
+ - **TS** (`skf-test-skill`): first resolve the gate again, right before the test, so a directive edit made during this skill counts and the threshold never has to survive the nested runs in conversation context: `uv run {gateScript} resolve --state-file {stateFile} --skill {skill_name} [--directive-file <campaign.directive_path>]` (exit 2 HALTs as at §4). Then run `{skill_name} --headless --threshold={threshold}` with that call's `threshold`, and `pipeline_alias` set to `campaign` in its data context (the explicit threshold wins over test-skill's per-pipeline default). TS settles its verdict, caps and 80% floor fallback itself; §5.3 reads the result.
100
+ - **Doc-rot check:** **record** what CS step 5c already produced; do not re-derive it. Because the pipeline body runs inline (see the RULES note on inline execution), that step's context is directly readable here. Its `correction_matches` holds only the corrections step 5c's judgment pass kept and wrote as `## CORRECTION` blocks, each with `source`, `pattern`, `candidate_category`, `context_line` and `affected`; the candidates the pass rejected are not corrections, so they are never recorded. Append one entry per `correction_matches` record to the skill's `workarounds_applied` array, written as `[doc-rot] {affected}: {candidate_category}`, so they survive in state: `uv run {stateScript} append-workarounds --state-file {stateFile} --skill {skill_name} --entry '<entry>'`, one single-quoted `--entry` per record (an entry the skill already holds is not added twice, so a resumed skill records each correction once). When step 5c took its skip branch (`doc_rot_triggered: false`, `corrections_added: 0`), there is nothing to record: append nothing and move on.
85
101
 
86
102
  **Do not hand-grep the feeder artifacts here, and do not re-run the scan.** `skf-create-skill/references/step-doc-rot.md` §2 requires the scan to run in its helper precisely so identical feeders yield identical matches; a second pass in this loop is free to disagree with the corrections CS actually wrote. It would also be self-contaminating: step 5c has already written `## CORRECTION` blocks into the compiled SKILL.md, and the helper's exclusion windows cover only that file's frontmatter and its Migration & Deprecation Warnings section — so re-scanning it would re-match the blocks 5c itself authored and record them as fresh findings.
87
- 3. **Record results:**
88
- - On success: set `status` to `"completed"`, set `completed_at` to current ISO-8601 with timezone, record `quality_score`. Backup and write state.
89
- - On failure: set `status` to `"failed"`. Log the failure reason (the sub-skill's `halt_reason`/exit code, or "unparseable result envelope") to the decision log so `campaign status` and the report surface *why* a skill failed without the operator opening sub-skill logs. Backup and write state. Downstream skills whose `depends_on` does NOT include the failed skill continue processing normally; those that DO depend on it are blocked at §4's dependency gate.
103
+ 3. **Record results:** settle the skill from its test verdict, never from an envelope's `status` (TS reports `success` for a scored FAIL too). Pipe the SKF_TEST_RESULT_JSON line TS printed (on stdout for a scored run, on stderr when it halted) to the gate script, and nothing when it printed none:
90
104
 
91
- ### §6 — Propagate Findings
105
+ ```
106
+ uv run {gateScript} record --skill {skill_name} <<'SKF_RESULT'
107
+ <the SKF_TEST_RESULT_JSON line TS printed>
108
+ SKF_RESULT
109
+ ```
92
110
 
93
- After each completed skill, propagate quality findings and doc-rot corrections to campaign-level tracking (`workarounds_applied`, `quality_score`).
111
+ - `status` `completed` (verdict PASS, a threshold-fallback PASS included): `uv run {stateScript} set-skill --state-file {stateFile} --skill {skill_name} --status completed --quality-score <quality_score> --skill-path <skill_package>`, with its `quality_score` and the `{skill_package}` CS named; the helper stamps `completed_at`. Whether the skill exports is decided at Export (step-10), against its gate.
112
+ - `status` `failed` (FAIL, INCONCLUSIVE, pass-with-drift, an error envelope or no readable result), or an earlier sub-skill failed: `uv run {stateScript} set-skill --state-file {stateFile} --skill {skill_name} --status failed [--quality-score <quality_score>]`, with `--quality-score` when it has one. Log the failure reason as an `event` (the record's `reason`, the failing sub-skill's `halt_reason`/exit code, or "unparseable result envelope") to the decision log so `campaign status` and the report surface *why* a skill failed without the operator opening sub-skill logs. Downstream skills whose `depends_on` does NOT include the failed skill continue processing normally; those that DO depend on it are blocked at §4's dependency gate, where headless skips them.
94
113
 
95
- ### §7 — Loop Completion
114
+ ### §6: Loop Completion
96
115
 
97
- When all Tier A skills in `execution_order` are processed (completed, failed, or skipped):
116
+ When all Tier A skills in `execution_order` are processed (completed, failed, or skipped), write the stage:
98
117
 
99
- 1. Set `campaign.current_stage` to `4`.
100
- 2. Set `campaign.last_updated` to current ISO-8601 with timezone.
101
- 3. Backup and write state.
118
+ ```
119
+ uv run {stateScript} set-stage --state-file {stateFile} --stage 4
120
+ ```
102
121
 
103
122
  ## OUTPUT
104
123
 
@@ -2,10 +2,13 @@
2
2
  nextStepFile: 'step-07-capstone.md'
3
3
  stateSchemaFile: 'assets/campaign-state-schema.json'
4
4
  stateFile: '{campaignWorkspacePath}/_campaign-state.yaml'
5
- backupFile: '{campaignWorkspacePath}/_campaign-state.yaml.bak'
6
5
  briefFile: '{campaignWorkspacePath}/campaign-brief.yaml'
7
6
  batchFile: '{campaignWorkspacePath}/_batch-input.txt'
7
+ batchMapFile: '{campaignWorkspacePath}/_batch-map.json'
8
+ batchResultsFile: '{campaignWorkspacePath}/_batch-results.json'
9
+ decisionLogFile: '{campaignWorkspacePath}/_campaign-decision-log.md'
8
10
  batchScript: 'scripts/campaign-render-batch.py'
11
+ stateScript: 'scripts/campaign-state.py'
9
12
  validateScript: 'scripts/campaign-validate-state.py'
10
13
  ---
11
14
 
@@ -19,43 +22,43 @@ Batch all Tier B skills through QS `--batch` mode, recording per-skill results i
19
22
 
20
23
  ## RULES
21
24
 
22
- - This step uses the **read-backup-modify-write** pattern.
23
- - Validate state on load via `uv run {validateScript} --state-file {stateFile}`; HALT (exit 3) on non-zero.
24
- - Update `campaign.last_updated` to current ISO-8601 with timezone on every write.
25
- - Update `campaign.current_stage` to `5`.
26
- - If `{headless_mode}` is true, auto-proceed through confirmation gates. QS `--batch` implies headless.
25
+ - Write `campaign.current_stage` = 5 only in this stage's final state write, after every result is recorded: step-resume resumes at `current_stage + 1`, so an early write skips unfinished work. An interrupted batch needs no stage write: its skills stay `active`, and resume sends an active Tier B skill back to this stage.
26
+ - Write state and decision-log entries only through `{stateScript}`, and on a non-zero exit HALT with the same code (State Contract in `references/campaign-contracts.md`). A log entry is `uv run {stateScript} log --log-file {decisionLogFile} --type <decision|auto|event> --text '<entry>'`.
27
+ - If `{headless_mode}` is true, emit this stage's progress events, and at any HARD HALT the error envelope, per `references/campaign-contracts.md`. QS `--batch` implies headless.
27
28
 
28
29
  ## TASKS
29
30
 
30
- ### §1 — Read + Validate State
31
+ ### §1: Read + Validate State
31
32
 
32
33
  Load `{stateFile}`. Run `uv run {validateScript} --state-file {stateFile}`; on non-zero, HALT (exit 3) with the script's `errors[]`.
33
34
 
34
- ### §2 — Read Directive
35
+ ### §2: Read Directive
35
36
 
36
- If `campaign.directive_path` is set in state, load the file at that path and apply its contents as campaign-wide context for this stage's processing, per the directive contract in `references/campaign-directive-spec.md`. If the file is not found, continue without error (directive is optional).
37
+ If `campaign.directive_path` is set in state, the batch script applies its `## Skip List` itself (§3), so do not filter skills by hand. Read any other section as campaign-wide context, per the directive contract in `references/campaign-directive-spec.md`. If the file is not found, continue without error (directive is optional).
37
38
 
38
- ### §3 — Identify Tier B Skills
39
+ ### §3: Select Tier B Skills and Write the Batch File
39
40
 
40
- Filter `skills[]` for entries where `tier == "B"` and `status == "pending"`. Skip skills with status `"completed"`, `"failed"`, or `"skipped"` (resume support — a previous run may have partially completed the batch).
41
+ The batch script selects the Tier B skills (pending ones, and active ones an interrupted batch left behind), leaves out the ones the directive's Skip List names, and writes the batch file and its line-to-skill map: select and format nothing by hand. Pass `--directive-file` when state sets `campaign.directive_path`:
41
42
 
42
- If no Tier B skills need processing, skip to §7 (Stage Completion) — the batch stage completes immediately when all Tier B skills are already handled.
43
+ ```
44
+ uv run {batchScript} --state-file {stateFile} --brief-file {briefFile} -o {batchFile} --map {batchMapFile} [--directive-file <campaign.directive_path>]
45
+ ```
43
46
 
44
- ### §4 — Generate Batch File
47
+ Its JSON summary on stderr gives `count`, the skill of each line in order (`skills`), the skills the Skip List left out (`skipped_by_directive`, each with its `reason`) and the hints left off a line (`dropped_hints`: a language or scope hint quick-skill could not read as one word).
45
48
 
46
- Generate the QS `--batch` input file deterministically:
49
+ HALT on non-zero exit: exit code 8 (`missing-brief`) when the brief is missing/unreadable **or** a selected Tier B skill has no matching brief target; exit code 2 (`invalid-input`) on a state file/parse error or a directive that cannot be read.
47
50
 
48
- ```
49
- uv run {batchScript} --state-file {stateFile} --brief-file {briefFile} -o {batchFile}
50
- ```
51
+ Log each `skipped_by_directive` entry as "directive Skip List: {name} ({reason})" and each `dropped_hints` entry as "batch: {skill} built without its {hint} `{value}` (quick-skill reads a hint as one word)", both type `event`.
51
52
 
52
- The script filters `skills[]` for `tier == "B" && status == "pending"`, looks up each skill's `repo_url` from the brief's `targets[]` (repo URLs live in the brief, not the state schema), and writes one line per skill at `{batchFile}` in the exact single-target shape QS parses (see `src/skf-quick-skill/references/batch-mode.md`) — the line format is owned once by the script, not re-derived here. It emits a JSON summary (`written`, `count`, `skipped_non_tierB`, `skipped_non_pending`) on stderr.
53
+ ### §4: Execute QS Batch
53
54
 
54
- HALT on non-zero exit: exit code 8 (`missing-brief`) when the brief is missing/unreadable **or** a pending Tier B skill has no matching brief target; exit code 2 (`invalid-input`) on a state file/parse error.
55
+ Record the batch's start from the map, so no skill is marked by hand:
55
56
 
56
- ### §5 — Execute QS Batch
57
+ ```
58
+ uv run {stateScript} apply-batch --state-file {stateFile} --map-file {batchMapFile} --start
59
+ ```
57
60
 
58
- Set each pending Tier B skill to `status: "active"` and `started_at` to current ISO-8601 with timezone. Backup `{stateFile}` to `{backupFile}`, then write the updated state.
61
+ It marks each `skipped_by_directive` skill `skipped` and each batched skill `active`, stamping `started_at` from the clock unless an interrupted batch already set it. If the §3 `count` is 0, add `--stage 5` to this call and chain to `{nextStepFile}`: the batch stage completes at once when every Tier B skill is already handled.
59
62
 
60
63
  Invoke QS in `--batch` mode with the generated batch file:
61
64
 
@@ -63,25 +66,29 @@ Invoke QS in `--batch` mode with the generated batch file:
63
66
  skf-quick-skill --batch {batchFile}
64
67
  ```
65
68
 
66
- QS `--batch` implies `--headless`. Capture per-skill results from the QS batch output — each target reports success/failure, skill path, and quality score.
69
+ QS `--batch` implies `--headless`. When the batch ends it prints a `batch_summary` event on stderr: keep its `summary_path`, the batch summary file that holds each target's result.
70
+
71
+ ### §5: Record Results
67
72
 
68
- ### §6 — Record Results
73
+ Join the batch summary to the skills by line number, never by matching QS output to skills by hand:
69
74
 
70
- For each Tier B skill in the batch:
75
+ ```
76
+ uv run {batchScript} --record <summary_path> --map {batchMapFile} > {batchResultsFile}
77
+ ```
71
78
 
72
- 1. If QS reports success:
73
- - Set `status` to `"completed"`
74
- - Set `completed_at` to current ISO-8601 with timezone
75
- - Record `quality_score` from QS output
76
- - Record `skill_path` from QS output
77
- 2. If QS reports failure:
78
- - Set `status` to `"failed"`
79
+ When that call exits 0, record the results and the stage in one write:
79
80
 
80
- After all updates: backup `{stateFile}` to `{backupFile}`, then write the updated state.
81
+ ```
82
+ uv run {stateScript} apply-batch --state-file {stateFile} --map-file {batchMapFile} --results-file {batchResultsFile} --stage 5
83
+ ```
81
84
 
82
- ### §7 — Stage Completion
85
+ A `completed` result sets the skill `completed`, with `completed_at` from the clock, its `quality_score` (the skill-check score QS records, not a test-skill score) and its `skill_path`; a `failed` one sets it `failed`. Log each entry of the helper's `failed[]` with its `error_code` (`no-batch-result` when the summary holds no result for its line), type `event`.
83
86
 
84
- Set `campaign.current_stage` to `5`. Update `campaign.last_updated` to current ISO-8601 with timezone. Backup `{stateFile}` to `{backupFile}`, then write the updated state.
87
+ When QS printed no `batch_summary` event (run no record call), or the record call exits 2 (a missing summary or map, or a summary that belongs to another batch file), fail every skill the map lists instead, and log why: never guess which target built which skill.
88
+
89
+ ```
90
+ uv run {stateScript} apply-batch --state-file {stateFile} --map-file {batchMapFile} --no-results --stage 5
91
+ ```
85
92
 
86
93
  ## OUTPUT
87
94
 
@@ -2,7 +2,10 @@
2
2
  nextStepFile: 'step-08-verify.md'
3
3
  stateSchemaFile: 'assets/campaign-state-schema.json'
4
4
  stateFile: '{campaignWorkspacePath}/_campaign-state.yaml'
5
- backupFile: '{campaignWorkspacePath}/_campaign-state.yaml.bak'
5
+ decisionLogFile: '{campaignWorkspacePath}/_campaign-decision-log.md'
6
+ gateScript: 'scripts/campaign-quality-gate.py'
7
+ manifestScript: 'scripts/campaign-parse-manifest.py'
8
+ stateScript: 'scripts/campaign-state.py'
6
9
  validateScript: 'scripts/campaign-validate-state.py'
7
10
  ---
8
11
 
@@ -12,51 +15,63 @@ validateScript: 'scripts/campaign-validate-state.py'
12
15
 
13
16
  ## STEP GOAL:
14
17
 
15
- Compose a capstone stack skill from all completed individual skills using SS compose-mode. The capstone represents the final integrated view of all campaign skills — a single stack skill that documents how the constituent libraries connect.
18
+ Compose a capstone stack skill from the completed individual skills that clear the quality gate, using SS compose-mode. The capstone represents the final integrated view of the campaign's exported skills: a single stack skill that documents how the constituent libraries connect.
16
19
 
17
20
  ## RULES
18
21
 
19
- - This step uses the **read-backup-modify-write** pattern.
20
- - Validate state on load via `uv run {validateScript} --state-file {stateFile}`; HALT (exit 3) on non-zero.
21
- - Update `campaign.last_updated` to current ISO-8601 with timezone on every write.
22
- - Update `campaign.current_stage` to `6`.
23
- - If `{headless_mode}` is true, auto-proceed through confirmation gates. SS compose-mode supports headless.
22
+ - Write `campaign.current_stage` = 6 only in this stage's final state write (§4), after the capstone is recorded: step-resume resumes at `current_stage + 1`, so an early write skips unfinished work.
23
+ - Write state and decision-log entries only through `{stateScript}`, and on a non-zero exit HALT with the same code (State Contract in `references/campaign-contracts.md`). A log entry is `uv run {stateScript} log --log-file {decisionLogFile} --type <decision|auto|event> --text '<entry>'`.
24
+ - If `{headless_mode}` is true, emit this stage's progress events, and at any HARD HALT the error envelope, per `references/campaign-contracts.md`. SS compose-mode runs headless.
24
25
 
25
26
  ## TASKS
26
27
 
27
- ### §1 — Read + Validate State
28
+ ### §1: Read + Validate State
28
29
 
29
30
  Load `{stateFile}`. Run `uv run {validateScript} --state-file {stateFile}`; on non-zero, HALT (exit 3) with the script's `errors[]`.
30
31
 
31
- ### §2 — Collect Completed Skills
32
+ ### §2: Collect Completed Skills
32
33
 
33
- Gather all skills from `skills[]` with `status == "completed"` — this includes both Tier A skills (processed in step-05) and Tier B skills (processed in step-06). Extract their `skill_path` values.
34
+ Classify the completed skills (Tier A from step-05, Tier B from step-06) against the quality gate as Export will, passing `--directive-file` when state sets `campaign.directive_path`; never compare scores by hand:
34
35
 
35
- If no completed skills exist, do NOT HALT — a campaign where everything failed is exactly when the operator most needs the downstream diagnostic report. Set `campaign.capstone` to `null`, warn ("No completed skills — skipping capstone composition; verification and the campaign report will still run so failures are explained"), log the skip to the decision log, and skip directly to §5 (Stage Completion) so the chain continues to verify → … → the report. step-10 (export) and step-11 (report) already handle the zero-completed case.
36
+ ```
37
+ uv run {gateScript} classify --state-file {stateFile} [--directive-file <campaign.directive_path>]
38
+ ```
36
39
 
37
- ### §3 — Invoke SS Compose-Mode
40
+ The capstone composes the skills in its `export[]` (the `pass` and `fallback` verdicts), so it never describes a skill the gate keeps from export: log each `excluded[]` skill as "capstone: {name} left out, below the quality gate ({reason})". Name each composed skill by the `export_name` of its row in `skills[]` (the skill folder its build wrote), as Export does. On exit 2 (an override that breaks the gate, or a directive that cannot be read), HALT (exit code 2, `invalid-input`) with its `error`.
38
41
 
39
- Invoke `skf-create-stack-skill` in compose-mode with:
42
+ If `export[]` is empty (no completed skill, or none clears the gate), do NOT HALT: a campaign where everything failed is exactly when the operator most needs the downstream diagnostic report. Warn ("No skill clears the quality gate: skipping capstone composition; verification and the campaign report will still run so failures are explained"), log the skip (type `event`), and go to §4 with no capstone, so the chain continues to verify, refine, export and the report. step-10 (export) and step-11 (report) already handle the zero-completed case.
40
43
 
41
- - The collected `skill_path` values as input skills
42
- - `campaign.name` as the stack identifier
44
+ ### §3: Invoke SS Compose-Mode
43
45
 
44
- Capture the result: stack skill path and quality score from the SS result output (`SKF_STACK_RESULT_JSON`).
46
+ Invoke `skf-create-stack-skill` with `--headless` and these inputs, so it asks nothing and prints its result envelope:
45
47
 
46
- ### §4 — Record Capstone Results
48
+ - `mode`: `compose`
49
+ - `skills`: the §2 `export_name` values, comma-separated (compose mode takes them as its constituent skill folders)
50
+ - `stack_name`: the `stack_name` that `uv run {manifestScript} --stack-name {stateFile}` prints, the campaign name as a skill name cut to leave room for the `-stack` SS appends; when it prints null, leave the input out and SS names the stack `{project_name}-stack`
51
+ - `architecture_doc_path`: `campaign.architecture_doc_path`, only when state sets it
47
52
 
48
- Persist the capstone outcome to `campaign.capstone` in the state (campaign-level summary; the composed skill itself lives at `skill_path`):
53
+ Keep the `SKF_STACK_RESULT_JSON` line it prints for §4, which records it. On `status` `error`, or no envelope, log its `halt_reason` (or "no result envelope", type `event`): verification and the campaign report still run.
49
54
 
50
- - `campaign.capstone.skill_path` — stack skill path (from SS result)
51
- - `campaign.capstone.quality_score` — quality score (from SS result)
52
- - `campaign.capstone.verified` — `null` for now; set by the verify stage (step-08) once the stack is checked
53
- - `campaign.capstone.completed_at` — current ISO-8601 with timezone
55
+ ### §4: Record the Capstone and Complete the Stage
54
56
 
55
- The capstone is a derived artifact — it is **not** tracked as a skill entry in the `skills[]` array. Its campaign-level summary lives in `campaign.capstone`; the constituent skill list and any verbose detail are reported in the step output and are available to downstream steps (verify, refine).
57
+ Record the capstone outcome and the stage in one write, passing the §3 envelope line to the helper, which reads it (never copy its fields by hand):
56
58
 
57
- ### §5 — Stage Completion
59
+ ```
60
+ uv run {stateScript} set-campaign --state-file {stateFile} --capstone - --stage 6 <<'SKF_RESULT'
61
+ <the SKF_STACK_RESULT_JSON line SS printed>
62
+ SKF_RESULT
63
+ ```
58
64
 
59
- Set `campaign.current_stage` to `6`. Update `campaign.last_updated` to current ISO-8601 with timezone. Backup `{stateFile}` to `{backupFile}`, then write the updated state (including `campaign.capstone` from §4).
65
+ From a `success` envelope it sets `campaign.capstone`, the campaign-level summary (the composed skill itself lives at `skill_path`):
66
+
67
+ - `campaign.capstone.skill_path`: `skill_package` from the SS envelope
68
+ - `campaign.capstone.quality_score`: `quality_score` from the SS envelope (the skill-check score SS records, null when skill-check did not run; it is not a test-skill score)
69
+ - `campaign.capstone.verified`: `null` for now; set by the verify stage (step-08) once the stack is checked
70
+ - `campaign.capstone.completed_at`: the time of the write, from the clock
71
+
72
+ An `error` envelope sets `campaign.capstone` to `null` (the helper names it in `not_recorded`). When §2 found no skill to compose, or SS printed no envelope, record no capstone instead: `uv run {stateScript} set-campaign --state-file {stateFile} --no-capstone --stage 6`.
73
+
74
+ The capstone is a derived artifact: it is **not** tracked as a skill entry in the `skills[]` array. The constituent skill list and any verbose detail are reported in the step output and are available to downstream steps (verify, refine).
60
75
 
61
76
  ## OUTPUT
62
77