bmad-module-skill-forge 2.1.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 +51 -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 +14 -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 +117 -9
  75. package/src/shared/scripts/skf-detect-docs.py +892 -4
  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 +215 -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 +17 -6
  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 +55 -18
  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 -57
  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 -89
  348. package/src/skf-setup/references/detect-and-tier.md +58 -66
  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 -645
  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
@@ -1,11 +1,10 @@
1
1
  ---
2
- tierRulesData: 'references/tier-rules.md'
3
2
  nextStepFile: 'health-check.md'
4
3
  # `{emitEnvelopeHelper}` = first existing path in `{emitEnvelopeProbeOrder}`;
5
- # halt if neither exists when the headless envelope must be emitted. The script
6
- # is the source of truth for the SKF_SETUP_RESULT_JSON contract — do not
7
- # inline-render the envelope from prose (LLM schema drift is the bug this
8
- # script exists to prevent).
4
+ # halt if neither exists when section 4 emits the envelope. The script is the
5
+ # source of truth for the SKF_SETUP_RESULT_JSON contract: do not render the
6
+ # envelope from prose (LLM schema drift is the bug this script exists to
7
+ # prevent).
9
8
  emitEnvelopeProbeOrder:
10
9
  - '{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py'
11
10
  - '{project-root}/src/shared/scripts/skf-emit-result-envelope.py'
@@ -17,196 +16,74 @@ emitEnvelopeProbeOrder:
17
16
 
18
17
  ## STEP GOAL:
19
18
 
20
- Display the forge status report with positive capability framing, surface tier changes and tool-set deltas on re-runs, prominently flag a required-tier miss, and (when headless) emit the schema-locked `SKF_SETUP_RESULT_JSON` envelope via `{emitEnvelopeHelper}`.
19
+ Stage the run's report payload, display the FORGE STATUS banner that `{emitEnvelopeHelper}` renders from it (tier, tools, an upgrade for each tool below its minimum version, tier changes and tool-set deltas on re-runs, and a REQUIRED TIER NOT MET block on a required-tier miss), and (when headless or quiet) emit the schema-locked `SKF_SETUP_RESULT_JSON` envelope from the same payload.
21
20
 
22
21
  ## Rules
23
22
 
24
23
  - Focus only on display + envelope emission
25
- - Do not use negative framing ("missing", "lacking", "unavailable")
26
- - Do not list tools that are not available
27
- - Use tier capability descriptions from tier-rules.md
24
+ - The FORGE STATUS lines come from `render-report`: display them (translated when needed), and never compose, add or drop a line yourself
28
25
  - Never inline-render the envelope JSON — the script owns the schema; drift breaks pipelines
29
26
  - Chains to the local health-check step via `{nextStepFile}` after completion — the user-facing status report is not the terminal step
27
+ - Display messages only when `{quiet_mode}` is false; the one exception is the envelope line section 4 builds, which section 5 displays on a tier miss and the shared health check displays last otherwise
28
+ - When `{quiet_mode}` is true, write no assistant text at all between tool calls: no status, progress or step-transition notes, however brief
29
+ - If section 4 finds no existing path in `emitEnvelopeProbeOrder`, halt with phase `step 4:helper-missing`, `path` set to its first entry, and reason `Setup cannot proceed: skf-emit-result-envelope.py was not found. Reinstall SKF, then re-run /skf-setup.` With no envelope helper to call, display that reason alone as the run's one line (the SKILL.md halt contract)
30
30
 
31
31
  ## MANDATORY SEQUENCE
32
32
 
33
- ### 1. Load Capability Descriptions
33
+ ### 1. Stage the Report Payload
34
34
 
35
- Load and read {tierRulesData} for the tier capability descriptions and re-run messages. Needed by section 2.
35
+ Sections 2 and 4 read the helper outputs the run folder holds (`detect-tools.json`, `ccc-exclusions.json`, `qmd-classify.json`, `qmd-remove.json` and `clean-stale.json`, each when its step ran the helper), take the run's paths from `--project-root`, `--sidecar-path` and `--forge-data-folder` (the folders On Activation bound from preflight), and read one payload file with what neither gives, staged here on every run through a quoted heredoc:
36
36
 
37
- ### 2. Display Forge Status Report (skip when `{headless_mode}` or `{quiet_mode}` is true)
38
-
39
- **Format the report as follows:**
40
-
41
- ```
42
- ═══════════════════════════════════════
43
- FORGE STATUS
44
- ═══════════════════════════════════════
45
-
46
- Tier: {calculated_tier}
47
- {tier capability description from tier-rules.md}
48
-
49
- Tools Detected:
50
- {for each tool that is available, show: tool name — version. ccc exposes no version string, so for ccc show its daemon health instead: ccc — daemon {ccc_daemon} (e.g. "ccc — daemon healthy")}
51
- {if no tools are available: (none yet — see "Climb to next tier" below)}
52
-
53
- {if calculated_tier is not Deep:}
54
- Climb to next tier:
55
- {if not tools.ast_grep: - Install ast-grep (https://ast-grep.github.io) — unlocks AST-backed code analysis (Forge tier)}
56
- {if tools.ast_grep and not tools.ccc: - Install cocoindex-code (https://github.com/cocoindex-io/cocoindex-code) — adds semantic-guided precision compilation (Forge+ tier)}
57
- {if tools.ast_grep and not tools.gh_cli: - Install GitHub CLI (https://cli.github.com) — required for Deep tier (cross-repository synthesis)}
58
- {if tools.ast_grep and not tools.qmd and qmd_status is "absent": - Install qmd (https://github.com/tobi/qmd) — required for Deep tier (knowledge search)}
59
- {if tools.ast_grep and not tools.qmd and qmd_status is "daemon_stopped": - Start the qmd daemon (already installed) — run `qmd start` (or your distribution's qmd service command) to unlock Deep tier (knowledge search)}
60
- {if tools.ccc and ccc_daemon is "error": - The ccc daemon is reporting errors — run `ccc doctor` to diagnose. CCC index will fail until resolved}
61
- {end if}
62
-
63
- {if hygiene_result is "completed":}
64
- QMD Registry:
65
- {hygiene_healthy} collection(s) healthy
66
- {if hygiene_orphaned_removed > 0: {hygiene_orphaned_removed} orphaned collection(s) removed}
67
- {if hygiene_orphaned_kept > 0: {hygiene_orphaned_kept} orphaned collection(s) kept}
68
- {if hygiene_stale_cleaned > 0: {hygiene_stale_cleaned} stale QMD registry entry/entries cleaned}
69
- {end if}
70
-
71
- {if ccc_registry_stale_cleaned > 0:}
72
- CCC Registry: {ccc_registry_stale_cleaned} stale entry/entries cleaned
73
- {end if}
74
-
75
- {if hygiene_result is "completed" and hygiene_healthy is 0:}
76
- QMD Registry: empty — collections are created automatically when you run /skf-create-skill.
77
- {end if}
78
-
79
- {if hygiene_result is "qmd_unavailable":}
80
- QMD Registry: skipped (qmd unavailable — if the daemon is stopped, `qmd start` restores it).
81
- {end if}
82
-
83
- {if tools.ccc is true:}
84
- CCC Index:
85
- {if ccc_index_result is "fresh": up to date — semantic discovery ready}
86
- {if ccc_index_result is "created": indexed this run — semantic discovery ready}
87
- {if ccc_index_result is "skipped": skipped (--ccc-skip-index) — run `/skf-setup` without --ccc-skip-index to build the index when you're ready}
88
- {if ccc_index_result is "failed": indexing failed — semantic discovery unavailable this session}
89
- {end if}
90
-
91
- Files written this run:
92
- - forge-tier.yaml — {project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml
93
- {if preferences_yaml_created is true:}
94
- - preferences.yaml — {project-root}/_bmad/_memory/forger-sidecar/preferences.yaml (first-run defaults)
95
- {end if}
96
- - {forge_data_folder}/ (directory ensured)
97
- {if settings_yml_written is true:}
98
- - .cocoindex_code/settings.yml — {project-root}/.cocoindex_code/settings.yml ({settings_yml_patterns_added} SKF exclusion pattern(s) merged)
99
- {end if}
100
- {if ccc_index_result is "created":}
101
- - .cocoindex_code/ ccc index — {ccc_file_count} files indexed
102
- {end if}
103
-
104
- {if tier_override is active:}
105
- Note: Tier override active (set in preferences.yaml)
106
-
107
- {if tier_override_invalid is true:}
108
- Note: tier_override value "{tier_override_invalid_value}" in preferences.yaml is not valid.
109
- {if tier_override_invalid_suggestion is non-null: Did you mean "{tier_override_invalid_suggestion}"?}
110
- Valid values are case-sensitive: Quick, Forge, Forge+, Deep. Using detected tier {calculated_tier}.
111
-
112
- {if tier_override_unsafe is true:}
113
- Warning: tier_override is forcing {calculated_tier} but the underlying tool prerequisites are not satisfied.
114
- Missing: {tier_override_unsafe_missing}. The override is honored, but downstream skills that
115
- rely on the missing tool(s) will fail at runtime. Install the missing tool(s) or remove
116
- the override from preferences.yaml.
117
-
118
- {if {previous_tier} is null:}
119
- Initial detection — {calculated_tier} tier established.
120
-
121
- {if {tier_changed} is true:}
122
- {appropriate upgrade/downgrade message from tier-rules.md}
123
-
124
- {if {tier_changed} is false and {tools_added} is empty and {tools_removed} is empty and {previous_tier} is non-null:}
125
- {same-tier message from tier-rules.md}
126
- {if preferences_yaml_created is false and (ccc_index_result is "fresh" or ccc_index_result is "none" or ccc_index_result is "skipped"): Nothing changed — your preferences were left untouched and the index was already current. You're good.}
127
-
128
- {if {tier_changed} is false and ({tools_added} or {tools_removed} is non-empty) and {previous_tier} is non-null:}
129
- Tier unchanged: {calculated_tier}.
130
- {if {tools_added} non-empty:} Newly detected: {comma-separated tool names from tools_added}{if ccc was added and tier is Deep: " — ccc enhances Deep tier transparently."}
131
- {if {tools_removed} non-empty:} No longer detected: {comma-separated tool names from tools_removed} — re-install to restore those capabilities.
132
-
133
- ═══════════════════════════════════════
134
- Forge ready. {calculated_tier} tier active.
135
- ═══════════════════════════════════════
136
-
137
- {if {headless_mode} is false:}
138
- Next: the fastest start is `@Ferris forge-auto <repo-or-doc-url>` — one command auto-scopes, briefs, compiles, tests at a 90% quality gate, and exports a verified skill with zero configuration. Prefer to scope by hand? `/skf-brief-skill` scopes your first compilation target, or `/skf-quick-skill` is a fast template-driven path. Already have a skill? `/skf-audit-skill` drift-checks an existing skill against current sources.
37
+ ```bash
38
+ cat > "{run_dir}/report-context.json" <<'SKF_JSON'
39
+ {
40
+ "orphan_auto_resolution": {orphan_auto_resolution_or_null},
41
+ "customization_resolver_unavailable": {customization_resolver_unavailable},
42
+ "error": null
43
+ }
44
+ SKF_JSON
139
45
  ```
140
46
 
141
- All re-run-delta context flags (`{tools_added}`, `{tools_removed}`, `{tier_changed}`) come from the detector's `deltas` block bound in stage 1 — no LLM-side recomputation, no set arithmetic in prose.
142
-
143
- ### 3. Display Required-Tier Failure Block (when applicable; skip when `{headless_mode}` or `{quiet_mode}` is true)
47
+ Write `{orphan_auto_resolution}` as the JSON object step 3 set (`{"action": "...", "source": "..."}`), or `null` when step 3 set none. `{customization_resolver_unavailable}` is JSON `null` unless SKILL.md On Activation bound it to the resolver's one-line failure reason; it is then that reason as a JSON string, its `"` and `\` escaped, and the envelope warns that the `{project-root}/_bmad/custom/` overrides were not applied. `error` stays `null`: a halt that names a phase never reaches this step, because it displays its own blocked envelope.
144
48
 
145
- If `{require_tier_satisfied}` is `false`, display this block immediately after the status report (the heading gate already handles the headless/quiet skip).
49
+ ### 2. Display Forge Status Report (skip when `{quiet_mode}` is true)
146
50
 
147
- When the block does fire (interactive run with require-tier failure):
51
+ Render the banner from the payload and the run folder:
148
52
 
53
+ ```bash
54
+ uv run {emitEnvelopeHelper} render-report --run-dir "{run_dir}" --project-root "{project-root}" \
55
+ --sidecar-path "{sidecar_path}" --forge-data-folder "{forge_data_folder}" \
56
+ --tier-rules "{skill-root}/references/tier-rules.md" < "{run_dir}/report-context.json"
149
57
  ```
150
- ═══════════════════════════════════════
151
- REQUIRED TIER NOT MET
152
- ═══════════════════════════════════════
153
58
 
154
- Required: {require_tier}
155
- Detected: {calculated_tier}
156
- Missing: {require_tier_failure_missing_tools}
59
+ Display its stdout as one code block, so its alignment holds, keeping every line in its order. When `{document_output_language}` is not English, translate the prose and keep paths, commands, flags, tool names and tier names as they are. If the script exits non-zero, or no path in `emitEnvelopeProbeOrder` exists, display one line instead, `FORGE STATUS could not be rendered: <message>`, where `<message>` is the `message` of its stderr JSON, or `skf-emit-result-envelope.py was not found`, and continue: the forge is configured either way.
157
60
 
158
- Install the missing tool(s) and re-run, or relax `--require-tier`.
159
- See "Climb to next tier" above for install URLs.
160
- ═══════════════════════════════════════
161
- ```
61
+ ### 3. Required-Tier Failure Block (skip when `{quiet_mode}` is true)
62
+
63
+ If section 2 displayed `FORGE STATUS could not be rendered` and `{require_tier_satisfied}` is `false`, display one line: `REQUIRED TIER NOT MET: --require-tier {require_tier}, detected {calculated_tier}, missing <tools>`, where `<tools>` is `{require_tier_failure_missing_tools}` joined with `, `, so the section 5 halt shows its cause. A banner that rendered already ends with the REQUIRED TIER NOT MET block: display nothing more.
162
64
 
163
65
  ### 4. Emit Headless JSON Envelope
164
66
 
165
- When `{headless_mode}` is `true` OR `{quiet_mode}` is `true`, build the context payload from this step's accumulated flags and forward it to `{emitEnvelopeHelper}` on stdin. Invoke via `uv run`. The script computes derived fields (`tools_added`, `tools_removed`, `tier_changed`, `warnings`), validates the assembled envelope against the JSON Schema at `src/shared/scripts/schemas/skf-setup-result-envelope.v1.json`, and emits the single prefixed line `SKF_SETUP_RESULT_JSON: {…}` on stdout.
67
+ When `{quiet_mode}` is `true`, run `{emitEnvelopeHelper}` on the payload section 1 staged; `--run-dir` makes it read the staged helper outputs too, and the three path options give it the run's paths. It emits the single prefixed line `SKF_SETUP_RESULT_JSON: {…}` on stdout. Bind `{setup_envelope_line}` ← that stdout line, and do not display it here. It is the only line a headless or quiet run displays, and in a standalone run it must be the run's final message: `claude -p` prints only the final message, and the health check still runs after this step. Section 5 displays it on a tier miss; otherwise the shared health check displays it when it stops (its §0). Either way it is displayed verbatim as its own line (no code fence, no preface, no commentary), with nothing of setup's after it. When `{pipeline_mode}` is true, control then returns to the forger, which keeps chaining.
166
68
 
167
69
  ```bash
168
- echo '{
169
- "tier": "{calculated_tier}",
170
- "previous_tier": {previous_tier_or_null},
171
- "tools": {tools_dict_from_step_01_or_skf_detect_tools_output},
172
- "previous_tools": {previous_tools_or_null},
173
- "config_path": "{project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml",
174
- "ccc_index": {
175
- "status": "{ccc_index_result}",
176
- "indexed_path": {ccc_indexed_path_or_null},
177
- "file_count": {ccc_file_count_or_null}
178
- },
179
- "files_written": {
180
- "forge-tier.yaml": true,
181
- "preferences.yaml": {preferences_yaml_created},
182
- "settings.yml": {settings_yml_written},
183
- "ccc_index": {ccc_index_result_was_created}
184
- },
185
- "tier_override_active": {tier_override_active},
186
- "tier_override_invalid": {tier_override_invalid},
187
- "tier_override_invalid_value": {tier_override_invalid_value_or_null},
188
- "tier_override_unsafe": {tier_override_unsafe},
189
- "tier_override_unsafe_missing": {tier_override_unsafe_missing_list},
190
- "require_tier_satisfied": {require_tier_satisfied_or_null},
191
- "require_tier_failure_missing": {require_tier_failure_missing_tools_list},
192
- "qmd_status": "{qmd_status}",
193
- "ccc_exclusion_warnings": {ccc_exclusion_warnings_list},
194
- "ccc_registry_stale_removed": {ccc_registry_stale_removed_paths_list},
195
- "ccc_indexing_failed_reason": {ccc_indexing_failed_reason_or_null},
196
- "orphan_auto_resolution": {orphan_auto_resolution_or_null},
197
- "error": {error_object_or_null}
198
- }' | uv run {emitEnvelopeHelper} emit
70
+ uv run {emitEnvelopeHelper} emit --run-dir "{run_dir}" --project-root "{project-root}" \
71
+ --sidecar-path "{sidecar_path}" --forge-data-folder "{forge_data_folder}" < "{run_dir}/report-context.json"
199
72
  ```
200
73
 
201
- The script's documented context-payload shape (see `src/shared/scripts/skf-emit-result-envelope.py` docstring) tolerates two `tools` shapes — bare booleans OR `skf-detect-tools.py`'s `{key: {available: bool, ...}}` output — so either step 1's normalized booleans OR the raw detect-tools output forwarded as-is will produce the correct envelope.
202
-
203
- **If the script exits non-zero:** the assembled envelope failed schema validation, which means a context flag from an earlier step is malformed. Surface the error to stderr and continue (missing JSON envelope on a headless run is a degraded but non-fatal state — the pipeline observer will see no envelope and treat that as "agent did not complete cleanly").
74
+ **If the script exits non-zero:** a value in the payload or in a staged helper output is malformed: set `{setup_envelope_line}` to the empty string. Display nothing and continue (a missing JSON envelope on a headless or quiet run is a degraded but non-fatal state: the pipeline observer sees no envelope and treats the run as not completed cleanly).
204
75
 
205
76
  ### 5. Chain to Health Check
206
77
 
207
- After the forge status report (and any failure block + JSON envelope) has been displayed:
78
+ After the forge status report and any failure block have been displayed (under headless or quiet, once `{setup_envelope_line}` is bound), delete the run folder:
79
+
80
+ ```bash
81
+ rm -f "{run_dir}/detect-tools.json" "{run_dir}/detect-tools.err" "{run_dir}/ccc-exclusions.json" "{run_dir}/write-tools.err" "{run_dir}/forge-data-dir.err" "{run_dir}/qmd-classify.json" "{run_dir}/qmd-remove.json" "{run_dir}/clean-stale.json" "{run_dir}/report-context.json" && rmdir "{run_dir}"
82
+ ```
83
+
84
+ Then:
208
85
 
209
- - If `{require_tier_satisfied}` is `false`, halt the workflow here without chaining to step 5. The tier miss is terminal; `{onCompleteCommand}` does not fire on a failed run.
210
- - Otherwise the forge is fully configured. If `{onCompleteCommand}` (resolved from `workflow.on_complete` at activation) is non-empty, execute it now — this is the workflow's terminal skill-specific action (e.g. trigger the first index build or notify an onboarding channel); in headless, log the action. Then load `{nextStepFile}`, read it fully, and execute it.
86
+ - If `{require_tier_satisfied}` is `false`, halt the workflow here without chaining to step 5. When `{quiet_mode}` is true, display `{setup_envelope_line}` verbatim as the run's final message in a standalone run (nothing when it is empty); when `{pipeline_mode}` is true, control then returns to the forger, which reads the envelope's `tier_failure` status. This halt emits no blocked envelope: the `tier_failure` envelope is its one line. The tier miss is terminal; `{onCompleteCommand}` does not fire on a failed run.
87
+ - Otherwise the forge is fully configured. If `{onCompleteCommand}` (resolved from `workflow.on_complete` at activation) is non-empty, carry out that instruction now: this is the workflow's terminal skill-specific action (for example, notify an onboarding channel); when `{quiet_mode}` is true, display nothing about it. Then load `{nextStepFile}`, read it fully, and execute it; under headless or quiet, the shared health check it chains to ends setup's output with `{setup_envelope_line}`.
211
88
 
212
89
  The health-check step is the true terminal step on success — do not stop after the report on a passing run even though it reads as final. Step 5 in turn delegates to `shared/health-check.md`; after that returns, the setup workflow is fully done.
@@ -1,10 +1,10 @@
1
1
  # Tier Report Copy
2
2
 
3
- The user-facing report strings the Step 4 report (`report.md`) consumes. Tool-detection probes and tier-calculation rules are owned by `skf-detect-tools.py` (see `references/detect-and-tier.md` §2) — this file holds only display copy, never detection or tier logic.
3
+ The strings the step 4 FORGE STATUS banner shows. `render-report` (`skf-emit-result-envelope.py`) reads the first line under each `###` heading below, without its surrounding double quotes, so keep each string on one line. Tool-detection probes and tier-calculation rules are owned by `skf-detect-tools.py`; this file holds only display copy, never detection or tier logic.
4
4
 
5
5
  ## Tier Capability Descriptions
6
6
 
7
- Use these for positive-framing in the report step. Describe what the tier GIVES, never what it lacks.
7
+ Describe what each tier gives, never what it lacks.
8
8
 
9
9
  ### Quick Tier
10
10
  "Quick tier active. You have fast, template-driven skill generation with package-name resolution. Perfect for getting started quickly."
@@ -13,15 +13,15 @@ Use these for positive-framing in the report step. Describe what the tier GIVES,
13
13
  "Forge tier active. You have AST-backed structural code analysis with line-level citations, plus template-driven generation. Every skill instruction traces to verified source code."
14
14
 
15
15
  ### Forge+ Tier
16
- "Forge+ tier active. Semantic-guided precision compilation — cocoindex-code maps the codebase semantically before AST extraction runs. Every skill begins with a ranked discovery pass that surfaces the most relevant source regions, then AST-backed verification gives each export its line-level citation."
16
+ "Forge+ tier active. Semantic-guided precision compilation: cocoindex-code maps the codebase semantically before AST extraction runs. Every skill begins with a ranked discovery pass that surfaces the most relevant source regions, then AST-backed verification gives each export its line-level citation."
17
17
 
18
18
  ### Deep Tier
19
- "Deep tier active. Full capability unlocked — AST-backed code analysis, GitHub repository exploration, and QMD knowledge search with cross-repository synthesis. Maximum provenance and intelligence."
19
+ "Deep tier active. Full capability unlocked: AST-backed code analysis, GitHub repository exploration, and QMD knowledge search with cross-repository synthesis. Maximum provenance and intelligence."
20
20
 
21
21
  ## Re-run Tier Change Messages
22
22
 
23
23
  ### Upgrade
24
- "Tier upgraded from {previous} to {current}. {newly available tool(s)} now detected — expanded capabilities unlocked."
24
+ "Tier upgraded from {previous} to {current}. {newly available tool(s)} now detected: expanded capabilities unlocked."
25
25
 
26
26
  ### Downgrade
27
27
  "Tier changed from {previous} to {current}. {tool} no longer detected. Run the tool's installation to restore capabilities."
@@ -1,17 +1,13 @@
1
1
  ---
2
2
  nextStepFile: 'auto-index.md'
3
3
  # `{forgeTierRwHelper}` = first existing path in `{forgeTierRwProbeOrder}`;
4
- # halt if neither exists. The script owns the canonical forge-tier.yaml format
5
- # and the array-preservation contract that protects qmd_collections /
6
- # ccc_index_registry / staleness_threshold_hours from being lost on rewrite.
7
- # Do not fall back to inline YAML emission — a prose-rendered template drifts
8
- # from the script and silently corrupts downstream skills.
4
+ # halt if neither exists. The script owns the canonical forge-tier.yaml
5
+ # format and keeps the registries a rewrite must not lose.
9
6
  forgeTierRwProbeOrder:
10
7
  - '{project-root}/_bmad/skf/shared/scripts/skf-forge-tier-rw.py'
11
8
  - '{project-root}/src/shared/scripts/skf-forge-tier-rw.py'
12
- # Resolve `{emitEnvelopeHelper}` for the headless/quiet blocked-envelope emit
13
- # on write failures (the regular envelope assembly happens in step 4, but
14
- # write halts never reach step 4 — see section 1's blocked-emit protocol).
9
+ # `{emitEnvelopeHelper}` = first existing path in `{emitEnvelopeProbeOrder}`,
10
+ # for the blocked envelope a halt in this step emits under headless or quiet.
15
11
  emitEnvelopeProbeOrder:
16
12
  - '{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py'
17
13
  - '{project-root}/src/shared/scripts/skf-emit-result-envelope.py'
@@ -23,74 +19,55 @@ emitEnvelopeProbeOrder:
23
19
 
24
20
  ## STEP GOAL:
25
21
 
26
- Write the detected tool availability and calculated tier to `forge-tier.yaml` (preserving registry arrays from any existing file), create `preferences.yaml` with first-run defaults if it does not exist, and ensure the `forge-data/` directory is present. All file mutations go through `{forgeTierRwHelper}` so the format is locked, atomic, and array-preservation is guaranteed.
22
+ Write the detected tools, the tier and the ccc index state to `{sidecar_path}/forge-tier.yaml` through `{forgeTierRwHelper}`, which reads them from the run folder and keeps the registries and the SKF exclusion record of an existing file, and make sure `{forge_data_folder}/` exists.
27
23
 
28
24
  ## Rules
29
25
 
30
- - Focus only on writing configuration files and creating directories
31
- - Do not re-detect tools — use results from step 1
32
- - Never inline a YAML template for forge-tier.yaml or preferences.yaml — the script owns the canonical format
33
- - File write failures are errors — report clearly and halt the workflow
26
+ - Never inline a YAML template for forge-tier.yaml: the script owns the canonical format
27
+ - Never create or edit `{sidecar_path}/preferences.yaml`: the installer writes it, and activation only reads it
28
+ - File write failures are errors: halt the workflow; under `{quiet_mode}` the blocked envelope is the only output, otherwise report the failure clearly
29
+ - Display messages only when `{quiet_mode}` is false; the one exception is the envelope line a halt displays
30
+ - When `{quiet_mode}` is true, write no assistant text at all between tool calls: no status, progress or step-transition notes, however brief
31
+ - If no path in `forgeTierRwProbeOrder` exists, halt with phase `step 2:helper-missing`, `path` set to its first entry, and reason `Setup cannot proceed: skf-forge-tier-rw.py was not found. Reinstall SKF, then re-run /skf-setup.`
32
+ - Every halt follows the SKILL.md halt contract: when `{quiet_mode}` is true, run `uv run {emitEnvelopeHelper} emit-blocked --phase '<phase>' --reason '<reason>' --path "<path>"`, which builds the payload itself (no `--path` for a halt without one, `--stderr-from` where the halt names it, and `--customization-resolver-unavailable "<reason>"` once SKILL.md On Activation item 6 bound `{customization_resolver_unavailable}` to a reason, escaped as the halt contract says), and display its stdout line verbatim and nothing else (the reason alone if `{emitEnvelopeHelper}` resolves to no path, or the helper exits non-zero or prints no line); otherwise display the reason
34
33
 
35
34
  ## MANDATORY SEQUENCE
36
35
 
37
36
  ### 1. Write forge-tier.yaml
38
37
 
39
- Build the JSON payload from context flags set by step 1 and step 1b. The payload must include `tools`, `tier`, and `ccc_index`; the script handles `tier_detected_at` defaulting to "now" if absent and preserves `qmd_collections`, `ccc_index_registry`, and a user-customized `ccc_index.staleness_threshold_hours` from any existing file.
40
-
41
- Invoke via `uv run`.
42
-
43
38
  ```bash
44
- echo '{
45
- "tools": {
46
- "ast_grep": {ast_grep},
47
- "gh_cli": {gh_cli},
48
- "qmd": {qmd},
49
- "ccc": {ccc},
50
- "ccc_daemon": {ccc_daemon},
51
- "security_scan": {security_scan}
52
- },
53
- "tier": "{calculated_tier}",
54
- "ccc_index": {
55
- "indexed_path": {ccc_indexed_path},
56
- "last_indexed": {ccc_last_indexed},
57
- "status": "{ccc_index_result}",
58
- "file_count": {ccc_file_count},
59
- "exclude_patterns": {ccc_exclude_patterns}
60
- }
61
- }' | uv run {forgeTierRwHelper} write-tools \
62
- --target "{project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml"
39
+ uv run {forgeTierRwHelper} write-tools \
40
+ --target "{sidecar_path}/forge-tier.yaml" \
41
+ --detect-from "{run_dir}/detect-tools.json" \
42
+ --ccc-from "{run_dir}/ccc-exclusions.json" 2> "{run_dir}/write-tools.err"
63
43
  ```
64
44
 
65
- The script atomically writes the file via temp + fsync + rename (crash-safe) and returns a JSON response with `wrote`, `preserved_arrays.qmd_collections` count, `preserved_arrays.ccc_index_registry` count, and the resolved `tier`.
66
-
67
- **Parse the response and set context flags for step 4:**
68
-
69
- - `{forge_tier_yaml_path}` ← `wrote`
70
- - `{forge_tier_qmd_collections_count}` ← `preserved_arrays.qmd_collections`
71
- - `{forge_tier_ccc_registry_count}` ← `preserved_arrays.ccc_index_registry`
72
-
73
- **If the script exits non-zero**: parse the stderr JSON `{"status":"error","message":...}`, set `{error: {phase: "step 2:write-tools", path: "{project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml", reason: <message>}}`, and halt the workflow before chaining to step 3. When `{headless_mode}` or `{quiet_mode}` is true, first pipe the same `{phase, reason, path}` payload to `python3 {emitEnvelopeHelper} emit-blocked` so the pipeline sees the blocked envelope before the halt (see `references/report.md` frontmatter for the helper probe order; the subcommand declares zero dependencies).
45
+ The script takes the tools and the tier from step 1's `detect-tools.json`, and the index state and the SKF exclusion record from step 1b's `ccc-exclusions.json`.
74
46
 
75
- ### 2. Initialize preferences.yaml
47
+ **If the script exits non-zero**: halt the workflow before chaining to step 3, with phase `step 2:write-tools`, path `{sidecar_path}/forge-tier.yaml` and as the reason the diagnostic in `{run_dir}/write-tools.err`. When `{quiet_mode}` is true, run the emitter, which reads that diagnostic itself, display its stdout line verbatim, and display nothing else: the envelope's `error` carries the path and reason. If the helper exits non-zero or prints no line, display the reason alone. Otherwise read that file and display the failure with its path and, as the reason, the `message` of its JSON error, else its first line.
76
48
 
77
49
  ```bash
78
- uv run {forgeTierRwHelper} init-prefs \
79
- --target "{project-root}/_bmad/_memory/forger-sidecar/preferences.yaml"
50
+ uv run {emitEnvelopeHelper} emit-blocked --phase "step 2:write-tools" --path "{sidecar_path}/forge-tier.yaml" \
51
+ --reason "<message>" --stderr-from "{run_dir}/write-tools.err" \
52
+ [--customization-resolver-unavailable "{customization_resolver_unavailable}"]
80
53
  ```
81
54
 
82
- The script creates the file with first-run defaults (`tier_override: ~`, `passive_context: true`, `headless_mode: false`, `compact_greeting: false`) if the file does not exist. When the file already exists, the script refuses to overwrite (preserves user customization) and reports `wrote: false`.
55
+ In each `emit-blocked` call of this step, keep the bracketed `--customization-resolver-unavailable` only when On Activation item 6 bound `{customization_resolver_unavailable}` to a reason, escaped as the halt contract says; otherwise leave it out.
83
56
 
84
- **Parse the response and set context flags for step 4:**
57
+ ### 2. Ensure the Forge Data Folder
85
58
 
86
- - `{preferences_yaml_created}` ← `wrote` (true on first run, false on re-run when the file pre-existed)
87
-
88
- **If the script exits non-zero**: same halt-and-blocked-envelope-emit pattern as section 1, with `phase: "step 2:init-prefs"` and the matching path.
59
+ ```bash
60
+ mkdir -p "{forge_data_folder}" 2> "{run_dir}/forge-data-dir.err"
61
+ ```
89
62
 
90
- ### 3. Ensure forge-data/ Directory
63
+ On non-zero exit, halt as section 1 does, with phase `step 2:forge-data-dir`, path `{forge_data_folder}` and the diagnostic in `{run_dir}/forge-data-dir.err` as the reason (an interactive run reads that file); under `{quiet_mode}`:
91
64
 
92
- Run `mkdir -p {forge_data_folder}`. The `-p` flag is idempotent (creates parents, exits 0 if the directory already exists), so the prompt does no existence-check reasoning. On non-zero exit, halt with the same blocked-envelope-emit pattern as section 1, using `phase: "step 2:forge-data-dir"` and the matching path.
65
+ ```bash
66
+ uv run {emitEnvelopeHelper} emit-blocked --phase "step 2:forge-data-dir" --path "{forge_data_folder}" \
67
+ --reason "<message>" --stderr-from "{run_dir}/forge-data-dir.err" \
68
+ [--customization-resolver-unavailable "{customization_resolver_unavailable}"]
69
+ ```
93
70
 
94
- ### 4. Auto-Proceed
71
+ ### 3. Auto-Proceed
95
72
 
96
- After forge-tier.yaml has been written successfully and preferences.yaml exists (created or pre-existing), display "**Proceeding to QMD collection hygiene...**", then load `{nextStepFile}`, read it fully, and execute it.
73
+ Once forge-tier.yaml is written, load `{nextStepFile}`, read it fully, and execute it.
@@ -12,7 +12,9 @@ Verifies that a skill is complete enough to be useful to an AI agent by checking
12
12
  ## Conventions
13
13
 
14
14
  - Bare paths (e.g. `references/<name>.md`) resolve from the skill root.
15
- - `references/` holds prompt content carved out of SKILL.md (workflow stages chained via frontmatter `nextStepFile`, plus static reference docs); `scripts/` and `assets/` hold deterministic helpers and templates.
15
+ - **Module-level path exception:** bare paths beginning with `knowledge/` or `shared/` resolve from the SKF module root (`{project-root}/_bmad/skf/` installed, `src/` in dev), not the skill root; e.g. `shared/references/output-contract-schema.md` and `shared/health-check.md`.
16
+ - **Sibling skills:** a path that names another SKF skill's folder (`skf-<name>/...`) resolves from the SKF module root, and that skill must be installed with this one. The coherence and migration rules cite `skf-create-skill/assets/skill-sections.md` and `skf-create-stack-skill/references/compose-mode-rules.md`.
17
+ - `references/` holds prompt content carved out of SKILL.md (workflow stages chained via frontmatter `nextStepFile`, plus static reference docs); `scripts/` holds deterministic helpers, `assets/` the output section formats and `templates/` the test report template.
16
18
  - `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives, if present).
17
19
  - `{project-root}`-prefixed paths resolve from the project working directory.
18
20
  - `{skill-name}` resolves to the skill directory's basename.
@@ -29,7 +31,11 @@ These rules apply to every step in this workflow:
29
31
  - Only load one step file at a time — never preload future steps
30
32
  - Update `stepsCompleted` in output file frontmatter before loading next step
31
33
  - Always communicate in `{communication_language}`
32
- - If `{headless_mode}` is true, auto-proceed through confirmation gates with their default action and log each auto-decision
34
+ - No stage waits for an answer in headless mode: the one question, the skill name, halts `input-missing` there
35
+ - Every HARD HALT names its `halt_reason` and phase and carries exit code 1 (`exit_code` in its envelope); in headless mode it prints its envelope through the shared emitter, as each stage's **Halt envelope** paragraph shows
36
+ - Once `references/init.md` §6a has taken the run lock, every HALT after it first releases the lock, whatever the release prints (it never removes another run's lock): from `{project-root}`, run `uv run {runLockHelper} release --lock "{forge_version}/.test-skill.lock" --owner "{run_owner}"`.
37
+ - The report is `{report_file}`: init.md §6c creates it as `.skf-test-report-{skill_name}-{run_id}.md`, and it takes its public name `test-report-{skill_name}-{run_id}.md` only once report.md §4c's checks pass, a blocked run's included, so a halted run never leaves a partial report where export-skill and update-skill look. The steps read the verdict inputs (`threshold`, `toolingStatus`, `workspaceDrift`, `testResult`) from its frontmatter, never from memory
38
+ - Run state (the scripts' files, the emitter's payloads) lives in `{run_dir}`: report.md §7 deletes it, a HALT keeps it
33
39
 
34
40
  ## Stages
35
41
 
@@ -42,49 +48,12 @@ These rules apply to every step in this workflow:
42
48
  | 4b | External Validators | references/external-validators.md | Yes |
43
49
  | 4c | Hard Gate | references/step-hard-gate.md | Yes |
44
50
  | 5 | Score | references/score.md | Yes |
45
- | 6 | Report | references/report.md | No (confirm) |
51
+ | 6 | Report | references/report.md | Yes |
46
52
  | 7 | Workflow Health Check | references/health-check.md | Yes |
47
53
 
48
54
  ## Invocation Contract
49
55
 
50
- | Aspect | Detail |
51
- |--------|--------|
52
- | **Inputs** | skill_name [required]; optional flags: `--allow-workspace-drift`, `--no-discovery` (skip the report step's Discovery Testing block), `--no-health-check` (skip §7 health-check dispatch), `--tier=<Quick\|Forge\|Forge+\|Deep>` (bypass forge-tier.yaml sidecar requirement), `--threshold=<N>` (override pass threshold; CLI wins over per-pipeline defaults and `workflow.default_threshold` scalar) |
53
- | **Gates** | step 6: Confirm Gate [C] |
54
- | **Outputs** | per-run `test-report-{skill_name}-{run_id}.md` with completeness score and result (PASS/FAIL); per-run `skf-test-skill-result-{run_id}.json` and `skf-test-skill-result-latest.json` written atomically under `{forge_version}/`; `evidence-report-fallback.md` written under `{forge_version}/` when threshold fallback occurs (score between 80% and target threshold) — downstream consumers (export-skill, update-skill `--from-test-report`) glob `test-report-{skill_name}-*.md` and pick newest by parsed ISO timestamp |
55
- | **Headless** | All gates auto-resolve with default action when `{headless_mode}` is true |
56
- | **Exit codes** | See "Exit Codes" below |
57
-
58
- ## Exit Codes
59
-
60
- Every terminal state in this workflow exits with a stable code so headless automators can branch on the verdict (and any HARD HALT) without grepping message text:
61
-
62
- | Code | Meaning | Raised by |
63
- | ---- | -------------------- | ------------------------------------------------------------------------------------------ |
64
- | 0 | success / PASS | step 6 §6b — `testResult: 'pass'` (after the result contract is written in §4c) |
65
- | 1 | error (HARD HALT) | infrastructure / precondition HALT in step 1 or step 6 before a verdict exists — see the "Result Contract" `halt_reason` set (the hard gate uses code 2) |
66
- | 2 | fail / FAIL | step 4c §3 — hard gate blocked (`halt_reason: "hard-gate-blocked"`); step 6 §6b — `testResult: 'fail'` (after the result contract is written in §4c) |
67
- | 3 | inconclusive | step 6 §6b — `testResult: 'inconclusive'` (distinct from fail so orchestrators can route to manual-review queues) |
68
- | 4 | pass-with-drift | step 6 §6b — `testResult: 'pass-with-drift'` (distinct from clean pass — `--allow-workspace-drift` was in effect; re-test against the pinned commit and refuse export — exit 0 would wrongly signal a clean pass) |
69
-
70
- ## Result Contract (Headless)
71
-
72
- When `{headless_mode}` is true, step 6 emits a single-line JSON envelope on **stdout** before chaining to step 7, and every HALT the Exit Codes table above marks with a non-zero code emits the same envelope shape on **stderr** with `status: "error"` and the `halt_reason` naming the failure, so a headless orchestrator branches on the reason without grepping prose:
73
-
74
- ```
75
- SKF_TEST_RESULT_JSON: {"status":"success|error","skill_name":"…","verdict":"PASS|FAIL|INCONCLUSIVE|pass-with-drift","score":N,"threshold":N,"report_path":"…|null","next_workflow":"export-skill|update-skill|null","exit_code":0,"halt_reason":null,"threshold_fallback":true,"original_threshold":90}
76
- ```
77
-
78
- `status` is `"success"` on the terminal happy path (PASS / FAIL / INCONCLUSIVE / pass-with-drift — the workflow completed), `"error"` on an emitted HARD HALT. `verdict` is the canonical result string (`null` on an infrastructure error halt). `next_workflow` is `"export-skill"` only when `verdict == "PASS"`; `"update-skill"` for `FAIL` or `pass-with-drift`; `null` for `INCONCLUSIVE` and error halts. `halt_reason` is `null` on the terminal path or one of the emitted strings: `"target-inaccessible"`, `"forge-tier-missing"`, `"workspace-drift"`, `"another-run-active"`, `"frontmatter-invalid"` (init HALTs), `"atomic-writer-missing"`, `"step-completeness-violation"`, `"report-anchor-missing"`, `"health-check-missing"` (report HALTs), or `"hard-gate-blocked"` (step 4c). `exit_code` is the code the Exit Codes table above assigns to the reached terminal state or HALT. Step 1 §3 frontmatter-validation now emits the `"frontmatter-invalid"` stderr envelope (see init.md §3c) and is branchable. Only the coverage/coherence analysis aborts print a diagnostic and exit non-zero **without** this envelope — they are the sole remaining outcomes outside the branchable set. When threshold fallback occurred, the envelope includes `"threshold_fallback":true` and `"original_threshold":N`; these fields are omitted when no fallback occurred.
79
-
80
- The same payload is persisted to disk by step 6 §4c (atomic write) at two locations under `{forge_version}/`:
81
-
82
- | Path | Purpose |
83
- | --------------------------------------------- | -------------------------------------------------------------------------- |
84
- | `skf-test-skill-result-{run_id}.json` | Per-run record. `{run_id}` carries UTC timestamp + PID + random suffix. |
85
- | `skf-test-skill-result-latest.json` | Latest copy — stable path for pipeline consumers (copy, not symlink). |
86
-
87
- The on-disk payload is the richer form: it adds `outputs[]` (report-path entries), `summary` (`score`, `threshold`, `result`, `testMode`, `activeCategories[]`, `inconclusiveReasons[]` when present, `threshold_fallback`, `original_threshold`, `evidence_report_path` when threshold fallback occurred), `runId`, and `healthCheckDispatched`. The stdout envelope is the compact subset documented above.
56
+ Headless callers: the full argument set (`Inputs`), the outputs, the exit codes and the `SKF_TEST_RESULT_JSON` result envelope live in `references/invocation-contract.md`. Interactive runs do not need it.
88
57
 
89
58
  ## On Activation
90
59
 
@@ -92,33 +61,24 @@ The on-disk payload is the richer form: it adds `outputs[]` (report-path entries
92
61
  - `project_name`, `user_name`, `communication_language`, `document_output_language`
93
62
  - `skills_output_folder`, `forge_data_folder`, `sidecar_path`
94
63
 
95
- 2. **Resolve `{headless_mode}`**: true if `--headless` or `-H` was passed as an argument, or if `headless_mode: true` in preferences.yaml. Default: false.
64
+ 2. **Resolve `{headless_mode}`**: true if `--headless` or `-H` was passed as an argument, or if `headless_mode: true` in `{sidecar_path}/preferences.yaml`. Default: false.
96
65
 
97
66
  3. **Resolve workflow customization.** Run:
98
67
 
99
68
  ```bash
100
- python3 {project-root}/_bmad/scripts/resolve_customization.py \
101
- --skill {skill-root} --key workflow
69
+ uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow
102
70
  ```
103
71
 
104
- The script merges the three customization layers per `bmad-customize`'s structural merge rules (scalars override, arrays append):
105
-
106
- - `{skill-root}/customize.toml` — bundled defaults
107
- - `_bmad/custom/<skill-name>.toml` under `{project-root}` — team overrides (committed)
108
- - `_bmad/custom/<skill-name>.user.toml` under `{project-root}` — personal overrides (gitignored)
109
-
110
- If the script fails or is missing, fall back to reading `{skill-root}/customize.toml` directly — the bundled defaults are an empty string for each path scalar.
72
+ It merges the bundled `{skill-root}/customize.toml` with `{project-root}/_bmad/custom/skf-test-skill.toml` (team overrides, committed) and `.user.toml` (personal overrides, gitignored). When it exits non-zero, prints no JSON or is missing, print one line, `[activation/warn] customization_resolver_unavailable: <reason>` (`<reason>`: its first stderr line, `not found` when the script is missing, `no JSON` when it printed none). If the resolver cannot run, read `{skill-root}/customize.toml` alone and use its bundled defaults: the `{project-root}/_bmad/custom/` overrides do not apply to this run. In that case keep the reason as `{customization_resolver_unavailable}`: report.md §4c hands it to the result as a warning.
111
73
 
112
- Apply the path-scalar fallback now so stage files don't have to repeat the conditional logic. For each of the three scalars, if the merged value is empty or absent, use the bundled default:
74
+ Apply the scalar fallbacks now so stage files don't have to repeat the conditional logic. For each scalar, if the merged value is empty or absent, use the bundled default:
113
75
 
114
76
  - `{testReportTemplatePath}` ← `workflow.test_report_template_path` if non-empty, else `templates/test-report-template.md`
115
- - `{outputFormatsPath}` ← `workflow.output_formats_path` if non-empty, else `assets/output-section-formats.md`
116
- - `{scoringRulesPath}` ← `workflow.scoring_rules_path` if non-empty, else `references/scoring-rules.md`
117
- - `{defaultThreshold}` ← `workflow.default_threshold` if non-empty/non-null, else `80`. CLI `--threshold=<N>` wins over per-pipeline defaults (from init.md §1b) which win over this scalar at the usage site in `references/score.md`.
77
+ - `{defaultThreshold}` ← `workflow.default_threshold` if non-empty/non-null, else `80`. init.md §1b resolves the precedence (CLI, then per-pipeline default, then this scalar) once and writes `threshold` and `thresholdSource` into the report frontmatter, which score.md §1 reads.
118
78
  - `{onCompleteCommand}` ← `workflow.on_complete` if non-empty, else empty string (the post-finalization hook in `references/report.md` is then a no-op).
119
79
 
120
- Stash all five as workflow-context variables that stage files reference directly — no conditional at the usage site.
80
+ Stash all three as workflow-context variables that stage files reference directly, with no conditional at the usage site. The scoring rules, the Gap Severity table and the output formats are not overridable: scripts own the scoring and the hard gate reads the table, so a house-style copy could change what blocks export.
121
81
 
122
- **Apply the array surfaces** (not silent no-ops): run `workflow.activation_steps_prepend` in order now; treat each `workflow.persistent_facts` entry as standing context for the run (`file:`-prefixed entries load their file/glob contents as facts — the bundled default globs any `project-context.md`); then run `workflow.activation_steps_append` after activation.
82
+ **Apply the array surfaces** (not silent no-ops): run `workflow.activation_steps_prepend` in order now; treat each `workflow.persistent_facts` entry as standing context for the run (`file:`-prefixed entries load their file/glob contents as facts: the bundled default loads every `project-context.md` under `{project-root}`; an entry prefixed `!` drops each earlier entry it names and loads nothing itself, so an override's `"!file:{project-root}/**/project-context.md"` turns that default off); then run `workflow.activation_steps_append` after activation.
123
83
 
124
84
  4. Load, read the full file, and then execute `references/init.md` to begin the workflow.