bmad-module-skill-forge 1.9.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.nvmrc +1 -1
  3. package/README.md +10 -5
  4. package/docs/_data/pinned.yaml +2 -2
  5. package/docs/agents.md +11 -2
  6. package/docs/architecture.md +5 -4
  7. package/docs/bmad-synergy.md +30 -7
  8. package/docs/campaign.md +172 -0
  9. package/docs/examples.md +7 -3
  10. package/docs/forge-auto.md +90 -0
  11. package/docs/getting-started.md +9 -0
  12. package/docs/how-it-works.md +6 -4
  13. package/docs/index.md +4 -3
  14. package/docs/skill-model.md +1 -1
  15. package/docs/troubleshooting.md +17 -1
  16. package/docs/verifying-a-skill.md +2 -2
  17. package/docs/why-skf.md +1 -1
  18. package/docs/workflows.md +64 -24
  19. package/package.json +2 -2
  20. package/src/knowledge/skill-lifecycle.md +1 -1
  21. package/src/module-help.csv +4 -3
  22. package/src/shared/data/language-corpora.json +32 -0
  23. package/src/shared/references/pipeline-contracts.md +6 -3
  24. package/src/shared/scripts/schemas/skill-brief.v1.json +6 -1
  25. package/src/shared/scripts/skf-comention-pairs.py +350 -0
  26. package/src/shared/scripts/skf-count-tokens.py +222 -0
  27. package/src/shared/scripts/skf-derive-assembly-shape.py +107 -0
  28. package/src/shared/scripts/skf-detect-docs.py +240 -4
  29. package/src/shared/scripts/skf-detect-language.py +82 -3
  30. package/src/shared/scripts/skf-detect-tools.py +105 -2
  31. package/src/shared/scripts/skf-emit-result-envelope.py +17 -0
  32. package/src/shared/scripts/skf-enumerate-stack-skills.py +111 -2
  33. package/src/shared/scripts/skf-extract-public-api.py +53 -0
  34. package/src/shared/scripts/skf-find-cycles.py +246 -0
  35. package/src/shared/scripts/skf-hash-content.py +487 -2
  36. package/src/shared/scripts/skf-language-corpora.py +100 -0
  37. package/src/shared/scripts/skf-manifest-ops.py +67 -1
  38. package/src/shared/scripts/skf-merge-doc-urls.py +244 -0
  39. package/src/shared/scripts/skf-preapply.py +1 -1
  40. package/src/shared/scripts/skf-rebuild-managed-sections.py +180 -0
  41. package/src/shared/scripts/skf-recommend-scope-type.py +1 -2
  42. package/src/shared/scripts/skf-render-metadata-stats.py +499 -0
  43. package/src/shared/scripts/skf-rewrite-skill-name.py +308 -0
  44. package/src/shared/scripts/skf-shape-detect.py +576 -25
  45. package/src/shared/scripts/skf-shard-body.py +461 -0
  46. package/src/shared/scripts/skf-skill-inventory.py +139 -3
  47. package/src/shared/scripts/skf-structural-diff.py +307 -67
  48. package/src/shared/scripts/skf-validate-brief-schema.py +41 -6
  49. package/src/shared/scripts/skf-validate-feasibility-report.py +234 -0
  50. package/src/shared/scripts/skf-validate-frontmatter.py +17 -12
  51. package/src/shared/scripts/skf-validate-output.py +443 -10
  52. package/src/shared/scripts/skf-validate-pins.py +3 -3
  53. package/src/shared/scripts/skf-verify-no-trace.py +214 -0
  54. package/src/shared/scripts/skf-verify-provenance-completeness.py +439 -0
  55. package/src/shared/scripts/skf-write-skill-brief.py +21 -5
  56. package/src/skf-analyze-source/SKILL.md +17 -32
  57. package/src/skf-analyze-source/assets/skill-brief-schema.md +1 -1
  58. package/src/skf-analyze-source/customize.toml +2 -0
  59. package/src/skf-analyze-source/references/auto-docs-only.md +116 -0
  60. package/src/skf-analyze-source/references/continue.md +8 -13
  61. package/src/skf-analyze-source/references/generate-briefs.md +28 -12
  62. package/src/skf-analyze-source/references/headless-contract.md +33 -0
  63. package/src/skf-analyze-source/references/health-check.md +1 -2
  64. package/src/skf-analyze-source/references/identify-units.md +25 -36
  65. package/src/skf-analyze-source/references/init.md +12 -25
  66. package/src/skf-analyze-source/references/map-and-detect.md +8 -20
  67. package/src/skf-analyze-source/references/recommend.md +4 -14
  68. package/src/skf-analyze-source/references/scan-project.md +3 -11
  69. package/src/skf-analyze-source/references/step-auto-scope.md +211 -197
  70. package/src/skf-analyze-source/references/step-shape-detect.md +20 -13
  71. package/src/skf-analyze-source/references/unit-detection-heuristics.md +2 -2
  72. package/src/skf-audit-skill/SKILL.md +9 -6
  73. package/src/skf-audit-skill/customize.toml +2 -0
  74. package/src/skf-audit-skill/references/init.md +58 -32
  75. package/src/skf-audit-skill/references/re-index.md +15 -34
  76. package/src/skf-audit-skill/references/report.md +11 -58
  77. package/src/skf-audit-skill/references/semantic-diff.md +4 -22
  78. package/src/skf-audit-skill/references/severity-classify.md +53 -87
  79. package/src/skf-audit-skill/references/step-doc-drift.md +49 -19
  80. package/src/skf-audit-skill/references/structural-diff.md +43 -68
  81. package/src/skf-brief-skill/SKILL.md +7 -36
  82. package/src/skf-brief-skill/assets/scope-templates.md +1 -1
  83. package/src/skf-brief-skill/assets/skill-brief-schema.md +1 -1
  84. package/src/skf-brief-skill/customize.toml +14 -0
  85. package/src/skf-brief-skill/references/analyze-target.md +13 -18
  86. package/src/skf-brief-skill/references/confirm-brief.md +2 -15
  87. package/src/skf-brief-skill/references/draft-checkpoint.md +8 -8
  88. package/src/skf-brief-skill/references/gather-intent.md +27 -24
  89. package/src/skf-brief-skill/references/headless-args.md +1 -1
  90. package/src/skf-brief-skill/references/health-check.md +1 -22
  91. package/src/skf-brief-skill/references/invocation-contract.md +37 -0
  92. package/src/skf-brief-skill/references/scope-definition.md +6 -15
  93. package/src/skf-brief-skill/references/step-auto-brief.md +22 -9
  94. package/src/skf-brief-skill/references/step-auto-validate.md +3 -7
  95. package/src/skf-brief-skill/references/version-resolution.md +1 -1
  96. package/src/skf-brief-skill/references/write-brief.md +19 -13
  97. package/src/skf-campaign/SKILL.md +121 -0
  98. package/src/skf-campaign/assets/campaign-state-schema.json +191 -0
  99. package/src/skf-campaign/customize.toml +75 -0
  100. package/src/skf-campaign/manifest.yaml +15 -0
  101. package/src/skf-campaign/references/campaign-contracts.md +67 -0
  102. package/src/skf-campaign/references/campaign-directive-spec.md +32 -0
  103. package/src/skf-campaign/references/health-check.md +35 -0
  104. package/src/skf-campaign/references/step-01-setup.md +121 -0
  105. package/src/skf-campaign/references/step-02-strategy.md +102 -0
  106. package/src/skf-campaign/references/step-03-pins.md +56 -0
  107. package/src/skf-campaign/references/step-04-provenance.md +63 -0
  108. package/src/skf-campaign/references/step-05-skill-loop.md +103 -0
  109. package/src/skf-campaign/references/step-06-batch.md +88 -0
  110. package/src/skf-campaign/references/step-07-capstone.md +63 -0
  111. package/src/skf-campaign/references/step-08-verify.md +75 -0
  112. package/src/skf-campaign/references/step-09-refine.md +83 -0
  113. package/src/skf-campaign/references/step-10-export.md +106 -0
  114. package/src/skf-campaign/references/step-11-maintenance.md +84 -0
  115. package/src/skf-campaign/references/step-resume.md +115 -0
  116. package/src/skf-campaign/scripts/.gitkeep +0 -0
  117. package/src/skf-campaign/scripts/campaign-deps.py +244 -0
  118. package/src/skf-campaign/scripts/campaign-parse-manifest.py +119 -0
  119. package/src/skf-campaign/scripts/campaign-provenance.py +247 -0
  120. package/src/skf-campaign/scripts/campaign-render-batch.py +199 -0
  121. package/src/skf-campaign/scripts/campaign-render-kickoff.py +158 -0
  122. package/src/skf-campaign/scripts/campaign-report.py +249 -0
  123. package/src/skf-campaign/scripts/campaign-status.py +162 -0
  124. package/src/skf-campaign/scripts/campaign-validate-pins.py +174 -0
  125. package/src/skf-campaign/scripts/campaign-validate-state.py +207 -0
  126. package/src/skf-campaign/templates/campaign-brief-template.yaml +34 -0
  127. package/src/skf-campaign/templates/campaign-report-template.md +54 -0
  128. package/src/skf-campaign/templates/kickoff-template.md +48 -0
  129. package/src/skf-create-skill/SKILL.md +15 -4
  130. package/src/skf-create-skill/assets/compile-assembly-rules.md +35 -34
  131. package/src/skf-create-skill/assets/skill-sections.md +9 -100
  132. package/src/skf-create-skill/assets/tessl-dismissal-rules.md +4 -13
  133. package/src/skf-create-skill/customize.toml +13 -0
  134. package/src/skf-create-skill/references/authoritative-files-protocol.md +7 -7
  135. package/src/skf-create-skill/references/compile.md +37 -47
  136. package/src/skf-create-skill/references/component-extraction.md +8 -35
  137. package/src/skf-create-skill/references/ecosystem-check.md +9 -25
  138. package/src/skf-create-skill/references/enrich.md +4 -17
  139. package/src/skf-create-skill/references/extract.md +20 -27
  140. package/src/skf-create-skill/references/extraction-patterns-tracing.md +1 -1
  141. package/src/skf-create-skill/references/extraction-patterns.md +10 -8
  142. package/src/skf-create-skill/references/generate-artifacts.md +20 -25
  143. package/src/skf-create-skill/references/health-check.md +2 -2
  144. package/src/skf-create-skill/references/load-brief.md +16 -18
  145. package/src/skf-create-skill/references/report.md +27 -14
  146. package/src/skf-create-skill/references/source-resolution-protocols.md +4 -4
  147. package/src/skf-create-skill/references/step-auto-shard.md +52 -25
  148. package/src/skf-create-skill/references/step-doc-rot.md +33 -15
  149. package/src/skf-create-skill/references/step-doc-sources.md +13 -4
  150. package/src/skf-create-skill/references/sub/ccc-discover.md +2 -13
  151. package/src/skf-create-skill/references/sub/fetch-docs.md +33 -46
  152. package/src/skf-create-skill/references/sub/fetch-temporal.md +5 -20
  153. package/src/skf-create-skill/references/tier-degradation-rules.md +6 -8
  154. package/src/skf-create-skill/references/validate.md +69 -29
  155. package/src/skf-create-skill/scripts/scan-doc-rot.py +245 -0
  156. package/src/skf-create-stack-skill/SKILL.md +15 -9
  157. package/src/skf-create-stack-skill/assets/provenance-map-schema.md +1 -1
  158. package/src/skf-create-stack-skill/customize.toml +10 -0
  159. package/src/skf-create-stack-skill/references/compile-stack.md +7 -8
  160. package/src/skf-create-stack-skill/references/compose-mode-rules.md +2 -13
  161. package/src/skf-create-stack-skill/references/detect-integrations.md +49 -54
  162. package/src/skf-create-stack-skill/references/detect-manifests.md +37 -30
  163. package/src/skf-create-stack-skill/references/generate-output.md +24 -75
  164. package/src/skf-create-stack-skill/references/init.md +9 -81
  165. package/src/skf-create-stack-skill/references/manifest-patterns.md +5 -35
  166. package/src/skf-create-stack-skill/references/parallel-extract.md +12 -27
  167. package/src/skf-create-stack-skill/references/rank-and-confirm.md +6 -6
  168. package/src/skf-create-stack-skill/references/report.md +27 -62
  169. package/src/skf-create-stack-skill/references/validate.md +35 -31
  170. package/src/skf-drop-skill/SKILL.md +20 -23
  171. package/src/skf-drop-skill/customize.toml +10 -0
  172. package/src/skf-drop-skill/references/execute.md +67 -36
  173. package/src/skf-drop-skill/references/headless-contract.md +18 -0
  174. package/src/skf-drop-skill/references/health-check.md +1 -13
  175. package/src/skf-drop-skill/references/report.md +44 -10
  176. package/src/skf-drop-skill/references/select.md +93 -48
  177. package/src/skf-drop-skill/scripts/dir-sizes.py +116 -0
  178. package/src/skf-export-skill/SKILL.md +17 -14
  179. package/src/skf-export-skill/assets/managed-section-format.md +2 -5
  180. package/src/skf-export-skill/customize.toml +10 -6
  181. package/src/skf-export-skill/references/generate-snippet.md +21 -35
  182. package/src/skf-export-skill/references/load-skill.md +44 -42
  183. package/src/skf-export-skill/references/multi-skill-mode.md +1 -1
  184. package/src/skf-export-skill/references/orphan-context-detection.md +11 -3
  185. package/src/skf-export-skill/references/package.md +27 -33
  186. package/src/skf-export-skill/references/preflight-snippet-root-probe.md +24 -5
  187. package/src/skf-export-skill/references/result-envelope.md +28 -0
  188. package/src/skf-export-skill/references/summary.md +11 -5
  189. package/src/skf-export-skill/references/token-report.md +42 -24
  190. package/src/skf-export-skill/references/update-context.md +32 -33
  191. package/src/skf-forger/SKILL.md +32 -39
  192. package/src/skf-forger/references/pipeline-mode.md +34 -0
  193. package/src/skf-forger/scripts/parse-pipeline.py +270 -0
  194. package/src/skf-quick-skill/SKILL.md +10 -60
  195. package/src/skf-quick-skill/customize.toml +9 -0
  196. package/src/skf-quick-skill/references/batch-mode.md +6 -4
  197. package/src/skf-quick-skill/references/compile.md +15 -52
  198. package/src/skf-quick-skill/references/ecosystem-check.md +5 -20
  199. package/src/skf-quick-skill/references/finalize.md +12 -6
  200. package/src/skf-quick-skill/references/halt-contract.md +54 -0
  201. package/src/skf-quick-skill/references/health-check.md +3 -4
  202. package/src/skf-quick-skill/references/quick-extract.md +7 -18
  203. package/src/skf-quick-skill/references/registry-resolution.md +1 -23
  204. package/src/skf-quick-skill/references/resolve-target.md +27 -34
  205. package/src/skf-quick-skill/references/write-and-validate.md +10 -25
  206. package/src/skf-refine-architecture/SKILL.md +16 -8
  207. package/src/skf-refine-architecture/customize.toml +9 -0
  208. package/src/skf-refine-architecture/references/compile.md +10 -8
  209. package/src/skf-refine-architecture/references/gap-analysis.md +21 -50
  210. package/src/skf-refine-architecture/references/health-check.md +1 -1
  211. package/src/skf-refine-architecture/references/improvements.md +9 -25
  212. package/src/skf-refine-architecture/references/init.md +9 -16
  213. package/src/skf-refine-architecture/references/issue-detection.md +10 -25
  214. package/src/skf-refine-architecture/references/refinement-rules.md +4 -16
  215. package/src/skf-refine-architecture/references/report.md +14 -11
  216. package/src/skf-rename-skill/SKILL.md +11 -21
  217. package/src/skf-rename-skill/customize.toml +10 -0
  218. package/src/skf-rename-skill/references/execute.md +112 -82
  219. package/src/skf-rename-skill/references/exit-codes.md +12 -0
  220. package/src/skf-rename-skill/references/report.md +16 -8
  221. package/src/skf-rename-skill/references/select.md +69 -42
  222. package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -0
  223. package/src/skf-setup/SKILL.md +21 -13
  224. package/src/skf-setup/customize.toml +10 -0
  225. package/src/skf-setup/references/auto-index.md +11 -10
  226. package/src/skf-setup/references/ccc-index.md +14 -15
  227. package/src/skf-setup/references/detect-and-tier.md +10 -8
  228. package/src/skf-setup/references/report.md +26 -32
  229. package/src/skf-setup/references/tier-rules.md +2 -32
  230. package/src/skf-setup/references/write-config.md +9 -10
  231. package/src/skf-test-skill/SKILL.md +10 -8
  232. package/src/skf-test-skill/customize.toml +2 -0
  233. package/src/skf-test-skill/references/coherence-check.md +19 -31
  234. package/src/skf-test-skill/references/coverage-check.md +111 -67
  235. package/src/skf-test-skill/references/detect-mode.md +10 -41
  236. package/src/skf-test-skill/references/external-validators.md +11 -19
  237. package/src/skf-test-skill/references/init.md +39 -21
  238. package/src/skf-test-skill/references/migration-section-rules.md +4 -4
  239. package/src/skf-test-skill/references/report.md +60 -40
  240. package/src/skf-test-skill/references/score.md +32 -64
  241. package/src/skf-test-skill/references/scoring-rules.md +6 -62
  242. package/src/skf-test-skill/references/source-access-protocol.md +15 -5
  243. package/src/skf-test-skill/references/step-hard-gate.md +1 -3
  244. package/src/skf-test-skill/scripts/aggregate-coherence.py +276 -0
  245. package/src/skf-test-skill/scripts/check-metadata-coherence.py +359 -0
  246. package/src/skf-test-skill/scripts/combine-external-scores.py +190 -0
  247. package/src/skf-test-skill/scripts/compute-score.py +135 -4
  248. package/src/skf-test-skill/scripts/reconcile-coverage.py +327 -0
  249. package/src/skf-test-skill/scripts/validate-inventory.py +251 -0
  250. package/src/skf-test-skill/scripts/verify-declared-numerator.py +192 -0
  251. package/src/skf-update-skill/SKILL.md +17 -5
  252. package/src/skf-update-skill/customize.toml +11 -6
  253. package/src/skf-update-skill/references/detect-changes.md +48 -36
  254. package/src/skf-update-skill/references/health-check.md +5 -11
  255. package/src/skf-update-skill/references/init.md +40 -32
  256. package/src/skf-update-skill/references/manual-section-rules.md +1 -2
  257. package/src/skf-update-skill/references/merge-conflict-rules.md +1 -52
  258. package/src/skf-update-skill/references/merge.md +13 -57
  259. package/src/skf-update-skill/references/re-extract.md +27 -25
  260. package/src/skf-update-skill/references/report.md +14 -7
  261. package/src/skf-update-skill/references/validate.md +32 -30
  262. package/src/skf-update-skill/references/write.md +86 -51
  263. package/src/skf-update-skill/scripts/skf-new-file-diff.py +167 -0
  264. package/src/skf-verify-stack/SKILL.md +11 -21
  265. package/src/skf-verify-stack/customize.toml +12 -3
  266. package/src/skf-verify-stack/references/coverage-patterns.md +1 -29
  267. package/src/skf-verify-stack/references/coverage.md +21 -10
  268. package/src/skf-verify-stack/references/exit-codes.md +14 -0
  269. package/src/skf-verify-stack/references/health-check.md +1 -1
  270. package/src/skf-verify-stack/references/init.md +20 -25
  271. package/src/skf-verify-stack/references/integration-verification-rules.md +10 -19
  272. package/src/skf-verify-stack/references/integrations.md +44 -49
  273. package/src/skf-verify-stack/references/report.md +28 -34
  274. package/src/skf-verify-stack/references/requirements.md +3 -3
  275. package/src/skf-verify-stack/references/synthesize.md +36 -39
  276. package/src/skf-verify-stack/scripts/skf-coverage-tally.py +196 -0
  277. package/src/skf-verify-stack/scripts/skf-report-delta.py +256 -0
  278. package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +258 -0
  279. package/tools/cli/lib/ui.js +3 -2
  280. package/docs/deepwiki.md +0 -89
  281. package/src/skf-rename-skill/references/rebuild-context.md +0 -110
@@ -0,0 +1,245 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # requires-python = ">=3.10"
4
+ # ///
5
+ """Deterministic doc-rot correction-indicator scan (step-doc-rot.md §2).
6
+
7
+ step 5c self-declares its correction scan "grep-based and deterministic — no AI
8
+ judgment is used for detection." This helper *is* that grep: it walks the
9
+ resolved feeder artifacts, matches every line against the fixed 13-row
10
+ correction-pattern table with case-insensitive substring containment (no regex,
11
+ no semantics), and emits the matches as JSON. It applies the one positional
12
+ filter the step documents — dropping matches that land inside the compiled
13
+ SKILL.md's own `## Migration & Deprecation Warnings` section (compile §4b
14
+ already authored those, so re-emitting them would be circular) — before it
15
+ returns. Running the scan here (instead of in-prompt) makes the "deterministic,
16
+ identical input → identical output" promise actually hold: the model no longer
17
+ hand-greps multi-KB artifacts.
18
+
19
+ The genuine judgment the step keeps in-prompt is untouched by this script:
20
+ enriching each match's `affected` symbol from surrounding context (§2) and
21
+ choosing where the `## CORRECTION` block goes (§3). The script emits every
22
+ deterministic field (`source`, `pattern`, `category`, `context_line`,
23
+ `line_number`); the prompt adds `affected`.
24
+
25
+ The pattern table and category labels are the contract in step-doc-rot.md §2 —
26
+ keep the two in lockstep.
27
+
28
+ CLI usage:
29
+ uv run scan-doc-rot.py --skill-md <staged SKILL.md> [FEEDER ...]
30
+ uv run scan-doc-rot.py --feeder evidence-report.md --feeder provenance-map.json
31
+
32
+ --skill-md the compiled/staged SKILL.md feeder (feeder #4); matches inside its
33
+ `## Migration & Deprecation Warnings` section are excluded. It is
34
+ also scanned like any other feeder.
35
+ FEEDER any other feeder artifact (evidence-report.md, provenance-map.json,
36
+ temporal-context files). Repeatable positionally or via --feeder.
37
+
38
+ Missing or empty files are skipped silently (not an error), matching §1's
39
+ "attempt to load; if it does not exist or is empty, skip it."
40
+
41
+ Output (stdout, one object):
42
+ {
43
+ "scanned": ["<path>", ...], # feeders that existed and were non-empty
44
+ "matches": [ # correction_matches[] (affected added in-prompt)
45
+ {"source": "<path>", "pattern": "deprecated", "category": "Deprecation",
46
+ "context_line": "<line text>", "line_number": <1-indexed int>},
47
+ ...
48
+ ],
49
+ "match_count": <int>,
50
+ "excluded_count": <int> # SKILL.md matches dropped by the §4b filter
51
+ }
52
+
53
+ Exit codes:
54
+ 0 — scan emitted successfully (including the zero-match case)
55
+ 1 — invalid arguments (no feeders supplied)
56
+ """
57
+
58
+ from __future__ import annotations
59
+
60
+ import argparse
61
+ import json
62
+ import re
63
+ import sys
64
+ from pathlib import Path
65
+
66
+ # Fixed correction-pattern table — mirrors step-doc-rot.md §2. (pattern, category)
67
+ # Order is the table order; scanning is per-pattern so overlapping patterns
68
+ # (e.g. "deprecated" ⊂ "@deprecated") each record their own hit, exactly as the
69
+ # 13-row table enumerates them.
70
+ PATTERN_TABLE: list[tuple[str, str]] = [
71
+ ("deprecated", "Deprecation"),
72
+ ("@deprecated", "Deprecation"),
73
+ ("breaking change", "Breaking change"),
74
+ ("BREAKING", "Breaking change"),
75
+ ("removed in", "Removal"),
76
+ ("was removed", "Removal"),
77
+ ("renamed to", "Rename"),
78
+ ("renamed from", "Rename"),
79
+ ("superseded by", "Supersession"),
80
+ ("replaced by", "Supersession"),
81
+ ("no longer supported", "End of life"),
82
+ ("migration required", "Migration"),
83
+ ("signature changed", "Signature change"),
84
+ ]
85
+
86
+ _MIGRATION_HEADING = re.compile(r"^\s*##\s+Migration\s*&\s*Deprecation Warnings", re.IGNORECASE)
87
+
88
+
89
+ def scan_text(text: str, source: str) -> list[dict]:
90
+ """Case-insensitive substring scan of `text` against PATTERN_TABLE.
91
+
92
+ Returns one record per (line, pattern) hit, in file order then table order.
93
+ line_number is 1-indexed. Pure — no I/O.
94
+ """
95
+ matches: list[dict] = []
96
+ for idx, line in enumerate(text.splitlines(), start=1):
97
+ lowered = line.lower()
98
+ for pattern, category in PATTERN_TABLE:
99
+ if pattern.lower() in lowered:
100
+ matches.append(
101
+ {
102
+ "source": source,
103
+ "pattern": pattern,
104
+ "category": category,
105
+ "context_line": line.strip(),
106
+ "line_number": idx,
107
+ }
108
+ )
109
+ return matches
110
+
111
+
112
+ def migration_section_range(skill_md_text: str) -> tuple[int, int] | None:
113
+ """1-indexed [start, end) line window of the `## Migration & Deprecation
114
+ Warnings` section, or None if the section is absent.
115
+
116
+ start = the heading line; end = the next level-2 (`## `) heading, or EOF.
117
+ A `### ` subsection inside the section does NOT close it (only a sibling
118
+ `## ` heading does), matching §2's "before the next `##` heading".
119
+ """
120
+ lines = skill_md_text.splitlines()
121
+ start = None
122
+ for idx, line in enumerate(lines, start=1):
123
+ if _MIGRATION_HEADING.match(line):
124
+ start = idx
125
+ break
126
+ if start is None:
127
+ return None
128
+ end = len(lines) + 1
129
+ for idx in range(start + 1, len(lines) + 1):
130
+ if lines[idx - 1].lstrip().startswith("## "):
131
+ end = idx
132
+ break
133
+ return (start, end)
134
+
135
+
136
+ def apply_migration_exclusion(
137
+ matches: list[dict], skill_md_source: str | None, skill_md_text: str | None
138
+ ) -> tuple[list[dict], int]:
139
+ """Drop matches whose source is the compiled SKILL.md and whose line sits
140
+ inside its Migration & Deprecation Warnings section. Returns (kept, dropped)."""
141
+ if skill_md_source is None or skill_md_text is None:
142
+ return matches, 0
143
+ window = migration_section_range(skill_md_text)
144
+ if window is None:
145
+ return matches, 0
146
+ start, end = window
147
+ kept, dropped = [], 0
148
+ for m in matches:
149
+ if m["source"] == skill_md_source and start <= m["line_number"] < end:
150
+ dropped += 1
151
+ continue
152
+ kept.append(m)
153
+ return kept, dropped
154
+
155
+
156
+ def _load(path: str) -> str | None:
157
+ """Read a feeder file as UTF-8. Returns None for missing/empty (skip, not
158
+ an error). UTF-8 avoids cp1252 mojibake on Windows."""
159
+ p = Path(path)
160
+ if not p.is_file():
161
+ return None
162
+ text = p.read_text(encoding="utf-8")
163
+ if not text.strip():
164
+ return None
165
+ return text
166
+
167
+
168
+ def scan_files(feeders: list[str], skill_md: str | None) -> dict:
169
+ """Scan every feeder + the skill-md feeder, apply the §4b exclusion, return
170
+ the result object. Deterministic: feeders scanned in the given order."""
171
+ scanned: list[str] = []
172
+ matches: list[dict] = []
173
+ skill_md_text = None
174
+
175
+ ordered = list(feeders)
176
+ if skill_md is not None:
177
+ ordered.append(skill_md)
178
+
179
+ for path in ordered:
180
+ text = _load(path)
181
+ if text is None:
182
+ continue
183
+ scanned.append(path)
184
+ if path == skill_md:
185
+ skill_md_text = text
186
+ matches.extend(scan_text(text, path))
187
+
188
+ matches, excluded = apply_migration_exclusion(matches, skill_md, skill_md_text)
189
+ return {
190
+ "scanned": scanned,
191
+ "matches": matches,
192
+ "match_count": len(matches),
193
+ "excluded_count": excluded,
194
+ }
195
+
196
+
197
+ def _build_parser() -> argparse.ArgumentParser:
198
+ parser = argparse.ArgumentParser(
199
+ prog="scan-doc-rot",
200
+ description=(
201
+ "Deterministic doc-rot correction-indicator scan (step-doc-rot.md §2): "
202
+ "case-insensitive substring match of feeder artifacts against the fixed "
203
+ "correction-pattern table, with the compiled SKILL.md's Migration & "
204
+ "Deprecation Warnings section excluded."
205
+ ),
206
+ formatter_class=argparse.RawDescriptionHelpFormatter,
207
+ )
208
+ parser.add_argument(
209
+ "positional_feeders",
210
+ nargs="*",
211
+ metavar="FEEDER",
212
+ help="Feeder artifact paths (evidence-report.md, provenance-map.json, temporal files).",
213
+ )
214
+ parser.add_argument(
215
+ "--feeder",
216
+ action="append",
217
+ default=[],
218
+ dest="feeders",
219
+ help="Feeder artifact path (repeatable). Equivalent to a positional FEEDER.",
220
+ )
221
+ parser.add_argument(
222
+ "--skill-md",
223
+ dest="skill_md",
224
+ default=None,
225
+ help="Compiled/staged SKILL.md feeder; its Migration & Deprecation Warnings "
226
+ "section is excluded from matches.",
227
+ )
228
+ return parser
229
+
230
+
231
+ def main(argv=None) -> int:
232
+ parser = _build_parser()
233
+ args = parser.parse_args(argv)
234
+ feeders = list(args.positional_feeders) + list(args.feeders)
235
+ if not feeders and args.skill_md is None:
236
+ parser.print_usage(file=sys.stderr)
237
+ print("error: supply at least one feeder path or --skill-md", file=sys.stderr)
238
+ return 1
239
+ result = scan_files(feeders, args.skill_md)
240
+ print(json.dumps(result, indent=2))
241
+ return 0
242
+
243
+
244
+ if __name__ == "__main__":
245
+ raise SystemExit(main())
@@ -12,6 +12,7 @@ Produces a consolidated stack skill documenting how libraries connect. **Code-mo
12
12
  ## Conventions
13
13
 
14
14
  - Bare paths (e.g. `references/<name>.md`) resolve from the skill root.
15
+ - The `knowledge/` and `shared/` prefixes are the exception: they resolve from the **SKF module root** (`{project-root}/_bmad/skf/` when installed, `src/` during development), not the skill root — they point at module-shared reference docs (`knowledge/tool-resolution.md`, `knowledge/version-paths.md`) and scripts/schemas (`shared/references/…`) that live once at the module root, mirroring the resolution note `references/health-check.md` carries for `shared/health-check.md`.
15
16
  - `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.
16
17
  - `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives, if present).
17
18
  - `{project-root}`-prefixed paths resolve from the project working directory.
@@ -34,7 +35,9 @@ These rules apply to every step in this workflow:
34
35
 
35
36
  ## Workflow state contract
36
37
 
37
- Every step that emits a warning ("log a warning", "record in workflow state for the evidence report", "Warning: ...", etc.) appends a structured entry to a single in-memory list named `workflow_warnings[]`. Each entry has the shape `{step: "step-NN", severity: "info|warn|error", code: "<short-slug>", message: "<human text>", context: {<optional fields>}}`. Step 7 surfaces these in `evidence-report.md`; step 8 may add validation findings; step 9 §5 reads the accumulated list and renders the user-facing "Warnings" section. There is exactly one accumulator for the whole workflow — do not invent per-step channels.
38
+ Every step that emits a warning appends a structured entry to a single in-memory list named `workflow_warnings[]` (the one accumulator for the whole workflow). Each entry has the shape `{step: "step-NN", severity: "info|warn|error", code: "<short-slug>", message: "<human text>", context: {<optional fields>}}`. Step 7 surfaces these in `evidence-report.md`; step 8 may add validation findings; step 9 §5 reads the accumulated list and renders the user-facing "Warnings" section.
39
+
40
+ **Single-pass — no mid-run checkpoint.** State lives in memory until step 7 commits `provenance-map.json`/`evidence-report.md`; the workflow keeps no resumable checkpoint and On Activation does not probe for a prior run — the analysis is deterministic and cheap to redo, and the two gates are trivially re-confirmed. If interrupted before that commit, restart from step 1.
38
41
 
39
42
  ## Stages
40
43
 
@@ -65,14 +68,13 @@ Every step that emits a warning ("log a warning", "record in workflow state for
65
68
 
66
69
  Every HARD HALT in this workflow exits with a stable code so headless automators can branch on the failure class without grepping message text:
67
70
 
68
- | Code | Meaning | Raised by |
71
+ | Code | Meaning | Raised by (halt_reason) |
69
72
  | ---- | -------------------- | ------------------------------------------------------------------------------------------ |
70
73
  | 0 | success | step 10 (terminal handoff to shared health-check) |
71
- | 2 | input-missing / input-invalid | step 1 §0 (`config.yaml` missing or malformed); step 2 §2 headless cannot proceed without manifests (S2); step 4 §3 all extractions failed (B7); step 5 §2 feasibility-report `schemaVersion` mismatch; compose-mode-rules `schemaVersion` mismatch |
72
- | 3 | resolution-failure | step 1 §1 (`forge-tier.yaml` missing); step 2 §0 compose-mode skill resolution corruption (manifest + symlink both fail); step 2 §0 compose-mode zero qualifying skills (S1/S3) |
73
- | 4 | write-failure | step 7 §1 stage-dir / commit-dir failure; step 7 §1 group-dir collision when an existing non-stack skill occupies the target path |
74
- | 5 | overwrite-cancelled | step 7 collision when the user declines to replace an existing stack package |
75
- | 6 | user-cancelled | any interactive menu in step 3 / step 6 (user selected `[X]` Cancel and exit) |
74
+ | 2 | input / precondition invalid | step 1 §0 `config.yaml` missing/malformed (`config-missing`); step 2 §2 headless with no manifests (`no-manifests`, S2); step 4 §3 all extractions failed (`all-extractions-failed`, B7); step 5 §2 feasibility-report `schemaVersion` mismatch (`schema-version-mismatch`) |
75
+ | 3 | resolution-failure | step 1 §1 `forge-tier.yaml` missing (`forge-tier-missing`); step 2 §0 compose-mode skill-resolution corruption (manifest + symlink both fail); step 2 §0 compose-mode zero qualifying skills (S1/B4); step 4 §0 compose-cycle — all `resolution-failure` |
76
+ | 4 | write-failure | step 7 §1 stage-dir / commit-dir failure; step 7 §1 group-dir collision when an existing non-stack skill occupies the target path — both `write-failure` |
77
+ | 6 | user-cancelled | any interactive menu in step 3 / step 6 when the user selects `[X]` Cancel and exit (`user-cancelled`) |
76
78
 
77
79
  ## Result Contract (Headless)
78
80
 
@@ -82,7 +84,7 @@ When `{headless_mode}` is true, step 9 emits a single-line JSON envelope on **st
82
84
  SKF_STACK_RESULT_JSON: {"status":"success|error","skill_package":"…|null","skill_name":"…","stack_libraries":["…"],"mode":"code|compose","exit_code":0,"halt_reason":null}
83
85
  ```
84
86
 
85
- `status` is `"success"` on the terminal happy path, `"error"` on any HALT. `skill_package` is the absolute path to the committed stack-skill directory (or `null` on error before commit). `skill_name` is the stack skill's published name (e.g. `{project_name}-stack`). `stack_libraries` is the array of library names included in the stack (constituent skill names in compose-mode, dependency names in code-mode). `mode` is `"code"` or `"compose"` per the run's resolved mode. `halt_reason` is one of: `null` (success), `"input-missing"`, `"input-invalid"`, `"forge-tier-missing"`, `"config-missing"`, `"no-manifests"`, `"all-extractions-failed"`, `"schema-version-mismatch"`, `"resolution-failure"`, `"write-failure"`, `"overwrite-cancelled"`, `"user-cancelled"`. `exit_code` matches the table above.
87
+ `status` is `"success"` on the terminal happy path, `"error"` on any HALT. `skill_package` is the absolute path to the committed stack-skill directory (or `null` on error before commit). `skill_name` is the stack skill's published name (e.g. `{project_name}-stack`). `stack_libraries` is the array of library names included in the stack (constituent skill names in compose-mode, dependency names in code-mode). `mode` is `"code"` or `"compose"` per the run's resolved mode (`null` if the run halts before mode resolution). `halt_reason` is one of: `null` (success), `"config-missing"`, `"forge-tier-missing"`, `"no-manifests"`, `"all-extractions-failed"`, `"schema-version-mismatch"`, `"resolution-failure"`, `"write-failure"`, `"user-cancelled"`. `exit_code` matches the table above. Fields unknown at the halt point are `null` (`skill_name`) or `[]` (`stack_libraries`) — e.g. a `config-missing` halt precedes `project_name` resolution.
86
88
 
87
89
  ## On Activation
88
90
 
@@ -118,6 +120,10 @@ SKF_STACK_RESULT_JSON: {"status":"success|error","skill_package":"…|null","ski
118
120
  - `{composeModeRulesPath}` ← `workflow.compose_mode_rules_path` if non-empty, else `references/compose-mode-rules.md`
119
121
  - `{provenanceMapSchemaPath}` ← `workflow.provenance_map_schema_path` if non-empty, else `assets/provenance-map-schema.md`
120
122
 
121
- Stash all five as workflow-context variables. Stage files reference `{stackSkillTemplatePath}` / `{integrationPatternsPath}` / `{manifestPatternsPath}` / `{composeModeRulesPath}` / `{provenanceMapSchemaPath}` directly no conditional at the usage site. Empty-string overrides cleanly fall through to the bundled default; non-empty values let orgs swap in house-style copies without forking the skill.
123
+ Also resolve `{onCompleteCommand}` `workflow.on_complete` if non-empty, else empty string (no-op`references/report.md` §6c skips the hook invocation entirely).
124
+
125
+ Stash all five paths plus `{onCompleteCommand}` as workflow-context variables. Stage files reference `{stackSkillTemplatePath}` / `{integrationPatternsPath}` / `{manifestPatternsPath}` / `{composeModeRulesPath}` / `{provenanceMapSchemaPath}` directly; empty-string overrides fall through to the bundled default.
126
+
127
+ Also apply the array surfaces: run `workflow.activation_steps_prepend` now, keep `workflow.persistent_facts` as standing context (`file:` entries load their contents), then run `workflow.activation_steps_append` after.
122
128
 
123
129
  4. Load, read the full file, and then execute `references/init.md` to begin the workflow.
@@ -53,7 +53,7 @@ Used when the workflow ran in code-mode against an actual codebase. `source_repo
53
53
 
54
54
  ## Compose-mode variant
55
55
 
56
- Used when the workflow ran in compose-mode against pre-generated constituent skills. Source-anchor fields (`source_repo`, `source_commit`, `source_ref`) are `null` because there is no codebase to anchor against — provenance traces back to the constituent skills instead, captured in the `constituents[]` array. Each entry's `extraction_method` is `"compose-from-skill"`; integrations have `detection_method` of `"architecture_co_mention"` (named in the architecture doc), `"constituent_documented_contract"` (a cross-library contract documented in a constituent skill's integration docs but not co-mentioned in the architecture document — e.g. a grep-verified upstream seam cited from a source skill), or `"inferred_from_shared_domain"` (synthesized inference from shared language/domain, no cited contract). `detection_method` records *how* an edge was discovered; it is orthogonal to `confidence`, which is inherited from the constituent skills per the Confidence Tier Inheritance matrix in `references/compose-mode-rules.md` (the integration tier is the weaker of the pair — never forced to a fixed band by detection method).
56
+ Used when the workflow ran in compose-mode against pre-generated constituent skills. Source-anchor fields (`source_repo`, `source_commit`, `source_ref`) are `null` because there is no codebase to anchor against — provenance traces back to the constituent skills instead, captured in the `constituents[]` array. Each entry's `extraction_method` is `"compose-from-skill"`; integrations have `detection_method` of `"architecture_co_mention"` (named in the architecture doc), `"constituent_documented_contract"` (a cross-library contract documented in a constituent skill's integration docs but not co-mentioned in the architecture document — e.g. a grep-verified upstream seam cited from a source skill), or `"inferred_from_shared_domain"` (synthesized inference from shared language/domain, no cited contract). `detection_method` records *how* an edge was discovered; it is orthogonal to `confidence`, which is inherited from the constituent skills per the Confidence Tier Inheritance matrix in `{composeModeRulesPath}` (the integration tier is the weaker of the pair — never forced to a fixed band by detection method).
57
57
 
58
58
  ```json
59
59
  {
@@ -1,6 +1,8 @@
1
1
  # DO NOT EDIT -- overwritten on every update.
2
2
  #
3
3
  # Workflow customization surface for skf-create-stack-skill.
4
+ # Team overrides: _bmad/custom/skf-create-stack-skill.toml (under {project-root})
5
+ # Personal overrides: _bmad/custom/skf-create-stack-skill.user.toml (under {project-root})
4
6
 
5
7
  [workflow]
6
8
 
@@ -34,6 +36,14 @@ persistent_facts = [
34
36
  "file:{project-root}/**/project-context.md",
35
37
  ]
36
38
 
39
+ # Command invoked once the workflow reaches its terminal stage — after the
40
+ # stack package is committed and the result contract is written (step 9,
41
+ # report.md §6c), before the health-check chain. Override wins. Use for a
42
+ # terminal action such as catalog registration or notifying a downstream
43
+ # pipeline. Empty string = no terminal action. The hook never fails the run.
44
+
45
+ on_complete = ""
46
+
37
47
  # --- Optional asset overrides ---
38
48
  #
39
49
  # Lift the canonical asset paths so orgs can substitute house-style copies
@@ -1,6 +1,5 @@
1
1
  ---
2
2
  nextStepFile: 'generate-output.md'
3
- stackSkillTemplate: 'assets/stack-skill-template.md'
4
3
  ---
5
4
 
6
5
  <!-- Config: communicate in {communication_language}. Artifact text in {document_output_language}. -->
@@ -13,7 +12,7 @@ Assemble the main SKILL.md by combining per-library extractions with the integra
13
12
 
14
13
  ## Rules
15
14
 
16
- - Compile SKILL.md following the stack-skill-template structure — integration patterns go first (primary value)
15
+ - Compile SKILL.md following the stack-skill-template structure — integration patterns go first
17
16
  - Do not write output files (Step 07)
18
17
  - Present compiled content for user review
19
18
 
@@ -21,7 +20,7 @@ Assemble the main SKILL.md by combining per-library extractions with the integra
21
20
 
22
21
  ### 1. Load Template Structure
23
22
 
24
- Load `{stackSkillTemplate}` and prepare SKILL.md section structure.
23
+ Load `{stackSkillTemplatePath}` and prepare SKILL.md section structure.
25
24
 
26
25
  ### 2. Generate Frontmatter
27
26
 
@@ -41,12 +40,12 @@ description: >
41
40
  **Frontmatter rules:**
42
41
 
43
42
  - `name`: lowercase alphanumeric + hyphens only, must match skill output directory name. **Stack skills MUST end in `-stack`** (e.g., `{project_name}-stack`) — this is how consumers (skf-verify-stack, skf-test-skill) detect stack vs individual skills.
44
- - `description`: non-empty, max 1024 chars, trigger-optimized for agent discovery. MUST use third-person voice ("Processes..." not "I can..." or "You can..."). **Do NOT enumerate every library by name** — a 12+ library stack overruns 1024 chars. Keep the generic "{lib_count} libraries with {integration_count} integration patterns" form; if a per-library parenthetical is used, cap it to the top libraries by import/export count with a `+{N} more` suffix (full list lives in `metadata.json` `libraries[]`). See "Sizing Guidance for Large Stacks" in `{stackSkillTemplate}`.
43
+ - `description`: non-empty, max 1024 chars, trigger-optimized for agent discovery. MUST use third-person voice ("Processes..." not "I can..." or "You can..."). **Do NOT enumerate every library by name** — a 12+ library stack overruns 1024 chars. Keep the generic "{lib_count} libraries with {integration_count} integration patterns" form; if a per-library parenthetical is used, cap it to the top libraries by import/export count with a `+{N} more` suffix (full list lives in `metadata.json` `libraries[]`). See "Sizing Guidance for Large Stacks" in `{stackSkillTemplatePath}`.
45
44
  - No other frontmatter fields — only `name`, `description`, `license`, `compatibility`, `metadata`, `allowed-tools` are permitted by spec
46
45
 
47
46
  ### 3. Compile Integration Layer
48
47
 
49
- **This is the core value of the stack skill.** Compile in order:
48
+ Compile in order:
50
49
 
51
50
  **Zero-integration guard:** If the integration graph from step 05 has zero edges (no detected integration pairs), skip the integration layer compilation and note: "No integration patterns detected — stack skill will contain library summaries without an integration layer." Proceed directly to section 4 (Per-Library Sections).
52
51
 
@@ -72,7 +71,7 @@ description: >
72
71
  `Per-Library Summaries` and `Library Reference Index` are the largest sections
73
72
  and grow with the stack. For a **large stack** (heuristic: **> 6 libraries OR
74
73
  > 6 integration patterns**), author both into `references/stack-catalog.md`
75
- (structure in `{stackSkillTemplate}`) and place only the inline pointer from the
74
+ (structure in `{stackSkillTemplatePath}`) and place only the inline pointer from the
76
75
  template's "Sizing Guidance" in SKILL.md — this keeps the body under the 500-line
77
76
  `body.max_lines` budget that step 08 enforces. For a **small stack**, keep both
78
77
  inline (inline passive context yields higher task accuracy). Either way, step 08's
@@ -132,9 +131,9 @@ Display: **Select:** [C] Continue to Output Generation | [X] Cancel and exit
132
131
 
133
132
  #### EXECUTION RULES:
134
133
 
135
- - ALWAYS halt and wait for user input after presenting compilation
134
+ - This is a review gate — advancing without the user's `C` would write output files from a compilation they never reviewed. Halt and wait for input after presenting the compiled SKILL.md.
136
135
  - **GATE [default: C]** — If `{headless_mode}`: auto-proceed with [C] Continue, log: "headless: auto-approve stack compilation"
137
- - ONLY proceed to next step when user approves and selects 'C'
136
+ - Proceed to the next step only once the user approves by selecting `C`.
138
137
 
139
138
  #### Menu Handling Logic:
140
139
 
@@ -6,18 +6,7 @@ Rules for synthesizing a stack skill from pre-generated individual skills and an
6
6
 
7
7
  ## Skill Loading
8
8
 
9
- Skills use version-nested directories see `knowledge/version-paths.md` for the full path templates and resolution rules.
10
-
11
- **Version-aware skill enumeration:**
12
-
13
- 1. **Primary: Export manifest** — Read `{skills_output_folder}/.export-manifest.json`. For each entry in `exports`, resolve the active version path: `{skills_output_folder}/{skill-name}/{active_version}/{skill-name}/` — this directory must contain both `SKILL.md` and `metadata.json`.
14
- 2. **Fallback: `active` symlinks** — If the manifest does not exist, is empty, or a manifest entry lacks an `active_version`, scan for `{skills_output_folder}/*/active/*/SKILL.md`. Each match resolves to a skill package at `{skills_output_folder}/{skill-name}/active/{skill-name}/` (the `{active_skill}` template).
15
- 3. **Filter:** Skip any skill named `{project_name}-stack` or any skill where `metadata.json` has `"skill_type": "stack"` — stack skills must not be loaded as source dependencies to avoid self-referencing loops
16
- 4. Skip any resolved skill package missing either `SKILL.md` or `metadata.json` — log a warning and skip
17
- 5. Load each `metadata.json` from the resolved version-aware path and extract: `name`, `language`, `confidence_tier`, `source_repo`, `exports` (count), `version`
18
- 6. Store the skill group directory name as `skill_dir` (the top-level name under `{skills_output_folder}`, distinct from `name` — the directory may differ from the metadata name)
19
- 7. Store the resolved package path as `skill_package_path` for use in later steps (extraction, integration detection)
20
- 8. Store loaded skills as `raw_dependencies` with `source: "existing_skill"`
9
+ The version-aware skill-enumeration protocol (export-manifest primary → active-symlink fallback → stack-skill filter → load metadata fields → store as `raw_dependencies`) is specified operationally in `detect-manifests.md` §0. That step runs at step 2 and has already enumerated and loaded every constituent skill into workflow state before this file is consulted at step 5, so the loading is not re-performed here — this file covers only the compose-mode composition rules below.
21
10
 
22
11
  ## Compose-mode Co-mention Precision
23
12
 
@@ -86,4 +75,4 @@ When no architecture document is available:
86
75
  - Mark all inferred integrations: `[inferred from shared domain]`
87
76
  - Inferred integrations default to lowest confidence of the pair with `[inferred from shared domain]` suffix (use this instead of `[composed]` for inferred integrations)
88
77
 
89
- **Constituent-documented contracts (distinct from shared-domain inference):** When a constituent skill's own integration docs cite a verifiable cross-library contract (e.g. a grep-verified upstream seam) that the architecture document does not co-mention, record it with `detection_method: constituent_documented_contract` (see `assets/provenance-map-schema.md`) — NOT `inferred_from_shared_domain`. It is a cited contract, not a synthesized guess. Its confidence still inherits the weaker tier of the pair per the matrix above — detection method is orthogonal to tier and never forces a fixed band.
78
+ **Constituent-documented contracts (distinct from shared-domain inference):** When a constituent skill's own integration docs cite a verifiable cross-library contract (e.g. a grep-verified upstream seam) that the architecture document does not co-mention, record it with `detection_method: constituent_documented_contract` (see `{provenanceMapSchemaPath}`) — NOT `inferred_from_shared_domain`. It is a cited contract, not a synthesized guess. Its confidence still inherits the weaker tier of the pair per the matrix above — detection method is orthogonal to tier and never forces a fixed band.
@@ -1,10 +1,14 @@
1
1
  ---
2
2
  nextStepFile: 'compile-stack.md'
3
- integrationPatterns: 'references/integration-patterns.md'
4
- composeModeRules: 'references/compose-mode-rules.md'
5
3
  pairIntersectProbeOrder:
6
4
  - '{project-root}/_bmad/skf/shared/scripts/skf-pair-intersect.py'
7
5
  - '{project-root}/src/shared/scripts/skf-pair-intersect.py'
6
+ comentionProbeOrder:
7
+ - '{project-root}/_bmad/skf/shared/scripts/skf-comention-pairs.py'
8
+ - '{project-root}/src/shared/scripts/skf-comention-pairs.py'
9
+ validateFeasibilityReportProbeOrder:
10
+ - '{project-root}/_bmad/skf/shared/scripts/skf-validate-feasibility-report.py'
11
+ - '{project-root}/src/shared/scripts/skf-validate-feasibility-report.py'
8
12
  ---
9
13
 
10
14
  <!-- Config: communicate in {communication_language}. -->
@@ -19,7 +23,6 @@ Analyze co-import patterns between confirmed libraries to identify integration p
19
23
 
20
24
  - Focus on detecting cross-library patterns using subprocess Pattern 1 (grep/search)
21
25
  - Do not compile SKILL.md (Step 06)
22
- - Integration detection is the core differentiator of stack skills vs individual skills
23
26
 
24
27
  ## MANDATORY SEQUENCE
25
28
 
@@ -54,7 +57,7 @@ From `confirmed_dependencies`, conceptually you have N*(N-1)/2 unordered pairs.
54
57
  `pairs[]` is sorted by `intersection_count` DESC, then `(a, b)` ASC for stable ordering. Default Top-K cap is **20** (matches S7 below); pass `--top-k N` to override.
55
58
  3. **Parse the JSON result** and use `pairs[]` as the qualifying-pair set for §2 onward. The `intersection_count` is the candidate file count for the §2 2-file threshold pre-grep; `files[]` is the grep-scope for that pair.
56
59
 
57
- **Top-K cap (S7, 20):** If the script's response has `truncated: true`, more pairs than the cap had non-empty intersections. Surface a user-visible warning composed as: `"non-empty-intersection pair count {total_pairs} exceeds cap — analyzing top 20 by intersection size; {total_pairs - 20} pairs skipped"`. Record this cap in the evidence report. (Tie-break by intersection size is what the script sorts on; if you need to override the cap intentionally, pass `--top-k N` and document the rationale.) The legacy 50-dependency threshold that formerly gated a separate Top-K pass is retired — the file-intersection prune does the bulk of the work and the cap is now a second-order safety limit, not a primary strategy.
60
+ **Top-K cap (S7, 20):** If the script's response has `truncated: true`, more pairs than the cap had non-empty intersections. Surface a user-visible warning composed as: `"non-empty-intersection pair count {total_pairs} exceeds cap — analyzing top 20 by intersection size; {total_pairs - 20} pairs skipped"`. Record this cap in the evidence report. (Tie-break by intersection size is what the script sorts on; if you need to override the cap intentionally, pass `--top-k N` and document the rationale.) The cap is a second-order safety limit, not a primary strategy — the file-intersection prune does the bulk of the work.
58
61
 
59
62
  Report: "**Analyzing {pair_count} library pairs for integration patterns** (pruned from {N*(N-1)/2} via file-list intersection; {capped_count} after Top-K if applicable)**...**"
60
63
 
@@ -64,29 +67,54 @@ Report: "**Analyzing {pair_count} library pairs for integration patterns** (prun
64
67
 
65
68
  Instead of co-import grep, detect integrations from architecture document:
66
69
 
67
- 1. Load `{composeModeRules}` for integration evidence format rules
70
+ 1. Load `{composeModeRulesPath}` for integration evidence format rules
68
71
  2. **If `{architecture_doc_path}` is null or not available:** Skip directly to the "If no architecture document available" fallback below
69
- 3. Load the architecture document from `{architecture_doc_path}`
70
- 4. **Prose-based co-mention analysis with precision guards (H2):**
71
- - Use **word-boundary matching** when searching for skill names in the architecture document: `\b{skill_name}\b` (case-insensitive). This prevents substring false positives (e.g., `react` matching inside `reactive`).
72
- - **Exclude non-body sections.** Detect H1 and H2 markdown headers (`^# ` and `^## `) and skip any paragraphs under headers that normalise to `introduction`, `overview`, `glossary`, `table of contents`, `references`, `appendix`, or `index`. Co-mentions inside headings themselves also do not qualify.
73
- - **Require ≥2 qualifying paragraphs.** A pair `(A, B)` qualifies only when at least two distinct body paragraphs each contain word-boundary matches for both `A` and `B`. A single co-mention paragraph is insufficient evidence.
74
- - Risks and rationale are documented in `{composeModeRules}` under "Compose-mode co-mention precision".
75
- 5. For each detected integration pair:
72
+ 3. **Compute qualifying co-mention pairs deterministically via the shared script.** The precision guards (word-boundary matching `\b{skill_name}\b` case-insensitive to reject substrings like `react` inside `reactive`; H1/H2 section exclusion for headers that normalise to `introduction`, `overview`, `glossary`, `table of contents`, `references`, `appendix`, or `index`, with heading text itself never a co-mention source; and the ≥2-distinct-body-paragraph gate) are a scan-and-count with one correct answer per `(architecture_doc, skill-name-set)` — do not perform them in-prompt. Risks and rationale stay documented in `{composeModeRulesPath}` under "Compose-mode co-mention precision".
73
+
74
+ **Resolve `{comentionHelper}`** from `{comentionProbeOrder}`; first existing path wins.
75
+
76
+ ```bash
77
+ uv run {comentionHelper} comention --doc {architecture_doc_path} --skills -
78
+ ```
79
+ piping the loaded skill names — the `confirmed_dependencies` names — as a JSON array on stdin (e.g. `["react", "express"]`; use a temp file under `{forge_data_folder}/` if stdin piping is unavailable). The script emits:
80
+ ```json
81
+ {
82
+ "pairs": [
83
+ {"a": "<skill>", "b": "<skill>", "paragraph_count": N,
84
+ "evidence": [{"header": "<governing-header-or-null>", "excerpt": "<text>"}, ...]},
85
+ ...
86
+ ],
87
+ "excluded_section_count": M
88
+ }
89
+ ```
90
+ `pairs[]` contains only qualifying pairs (≥2 distinct body paragraphs), sorted by `paragraph_count` DESC then `(a, b)` ASC. Use `pairs[]` as the detected-integration-pair set for step 4 onward; each pair's `evidence[]` supplies the governing header and paragraph excerpts to quote as architecture-reference evidence.
91
+
92
+ **Graceful degradation:** if no `{comentionProbeOrder}` candidate exists (e.g. `uv` unavailable on claude.ai web), perform the equivalent scan directly per the guards above and the script's `--help` contract, then proceed with the same qualifying-pair set.
93
+ 4. For each detected integration pair (from `pairs[]`):
76
94
  - Load both skills' export lists and API signatures
77
- - Compose an integration section following the format from `{composeModeRules}`
95
+ - Compose an integration section following the format from `{composeModeRulesPath}`
78
96
  - Include VS feasibility verdict if a feasibility report matching the filename pattern defined in `src/shared/references/feasibility-report-schema.md` exists under `{forge_data_folder}/` (timestamped `feasibility-report-{project_slug}-{YYYYMMDD-HHmmss}.md` or the stable `feasibility-report-{project_slug}-latest.md` copy). Schema version `"1.0"` is required; see the schema for the full contract.
79
97
  - Cite evidence from both skills: `[from skill: {skill_name}]`
80
98
 
81
- All integration evidence inherits confidence tiers from the source skills. Load and apply the full **Confidence Tier Inheritance** matrix from `{composeModeRules}` to compute the correct tier for each pair (covers T1+T1, T1+T1-low, T1-low+T1-low, T1+T2, T1-low+T2, T2+T2 cases). Apply the `[composed]` suffix to all confidence labels — e.g., `T1 [composed]`, `T1-low [composed, +T2 annotations]`.
99
+ All integration evidence inherits confidence tiers from the source skills. Load and apply the full **Confidence Tier Inheritance** matrix from `{composeModeRulesPath}` to compute the correct tier for each pair (covers T1+T1, T1+T1-low, T1-low+T1-low, T1+T2, T1-low+T2, T2+T2 cases). Apply the `[composed]` suffix to all confidence labels — e.g., `T1 [composed]`, `T1-low [composed, +T2 annotations]`.
82
100
 
83
101
  **VS verdict parsing (if feasibility report exists):** The feasibility report format is defined by the shared schema at `src/shared/references/feasibility-report-schema.md` (single source of truth; skf-verify-stack is the producer, this skill is the consumer). Follow the schema strictly:
84
102
 
85
103
  - Locate the report via the filename pattern in the schema: `{forge_data_folder}/feasibility-report-{project_slug}-{YYYYMMDD-HHmmss}.md` (or the stable `feasibility-report-{project_slug}-latest.md` copy next to it).
86
- - **Schema version guard:** Parse the report's YAML frontmatter and verify `schemaVersion == "1.0"`. If the field is missing or mismatched, HALT with an explicit error: `"feasibility-report schemaVersion mismatch: expected '1.0', got '{value}' refusing to proceed"`. Do NOT attempt to interpret unknown versions.
104
+ - **Schema version guard (deterministic gate):** Resolve `{validateFeasibilityReportHelper}` from `{validateFeasibilityReportProbeOrder}` (first existing path wins) and run it against the located report:
105
+
106
+ ```bash
107
+ python3 {validateFeasibilityReportHelper} <located-report-path>
108
+ ```
109
+
110
+ Consume `schemaVersionOk` / `schemaVersionFound` from its JSON. If `schemaVersionOk` is false, HALT with `"feasibility-report schemaVersion mismatch: expected '1.0', got '{schemaVersionFound}' — refusing to proceed"`, then emit the result envelope on stderr per the Result Contract in SKILL.md and exit `2`. The script's structural findings (`headingsOk` / `orderViolations`) are advisory for this consumer — it gates only on schemaVersion. **If the helper does not resolve or cannot run,** parse the report's YAML frontmatter directly and compare `schemaVersion` to the literal `1.0`, applying the same HALT (a missing or mismatched version halts identically). Unknown versions are never interpreted.
111
+
112
+ ```
113
+ SKF_STACK_RESULT_JSON: {"status":"error","skill_package":null,"skill_name":"{project_name}-stack","stack_libraries":[],"mode":"compose","exit_code":2,"halt_reason":"schema-version-mismatch"}
114
+ ```
87
115
  - Read `overallVerdict` from frontmatter (exactly one of `FEASIBLE|CONDITIONALLY_FEASIBLE|NOT_FEASIBLE`).
88
116
  - Parse the `## Integration Verdicts` markdown table for per-pair verdicts (exactly one of `Verified|Plausible|Risky|Blocked`). Any unknown verdict token is a hard error per the schema — do not silently drop or map.
89
- - For each architecture-detected pair, include `VS overall: {overallVerdict}` and `VS pair: {verdict}` in the integration evidence per the format in `{composeModeRules}`. VS verdicts do not apply to inferred integrations since the VS report operates on architecture-described interactions only. Additionally, flag any pairs where VS reported `Risky` or `Blocked` by appending a `[VS: Risky]` or `[VS: Blocked]` warning annotation to the integration entry.
117
+ - For each architecture-detected pair, include `VS overall: {overallVerdict}` and `VS pair: {verdict}` in the integration evidence per the format in `{composeModeRulesPath}`. VS verdicts do not apply to inferred integrations since the VS report operates on architecture-described interactions only. Additionally, flag any pairs where VS reported `Risky` or `Blocked` by appending a `[VS: Risky]` or `[VS: Blocked]` warning annotation to the integration entry.
90
118
 
91
119
  If no architecture document available:
92
120
  - Infer potential integrations from skills sharing the same `language` field or sharing domain keywords in their SKILL.md descriptions (use the `usage_patterns` and `exports` fields from `per_library_extractions[]` built in step 4, or reload SKILL.md from the version-aware path: use `skill_package_path` from step 2, or resolve via `{skills_output_folder}/{skill_dir}/active/{skill_dir}/SKILL.md` — see `knowledge/version-paths.md`)
@@ -115,7 +143,7 @@ If `tools.ccc` is true AND `ccc_index.status` is `"fresh"` or `"stale"` in forge
115
143
 
116
144
  For each library pair with **0 or 1 co-import files** (below the 2-file threshold — S9, symmetric to give the 0-hit case the same chance as the 1-hit case), run `ccc_bridge.search("{libA} {libB}", source_root, top_k=10)` to find files where the two libraries interact semantically — even without explicit import co-location. If CCC returns additional files where both libraries appear, add them to the pair's co-import candidate list and re-evaluate against the 2-file threshold.
117
145
 
118
- **CCC precision guard for 1-file pairs (H3):** When a CCC hit would elevate a 1-file pair to qualifying status, run a post-hoc verification on that file: re-grep the file and confirm it contains explicit import statements for **both** libraries (per the ecosystem import patterns from `references/manifest-patterns.md`). If either import is missing (e.g., one library is only name-dropped in a comment or string), drop the CCC-added file from the candidate list. Only pairs with ≥2 files that each contain explicit imports for both libraries qualify. Log rejected CCC candidates in workflow state for the evidence report.
146
+ **CCC precision guard for 1-file pairs (H3):** When a CCC hit would elevate a 1-file pair to qualifying status, run a post-hoc verification on that file: re-grep the file and confirm it contains explicit import statements for **both** libraries (per the ecosystem import patterns from `{manifestPatternsPath}`). If either import is missing (e.g., one library is only name-dropped in a comment or string), drop the CCC-added file from the candidate list. Only pairs with ≥2 files that each contain explicit imports for both libraries qualify. Log rejected CCC candidates in workflow state for the evidence report.
119
147
 
120
148
  **Tool resolution for ccc_bridge.search:** Use `/ccc` skill search (Claude Code), ccc MCP server (Cursor), or `ccc search "{libA} {libB}" --path {source_root} --top 10` (CLI). See `knowledge/tool-resolution.md`.
121
149
 
@@ -125,16 +153,9 @@ CCC failures: skip augmentation silently, proceed with grep-only results.
125
153
 
126
154
  ### 3. Classify Integration Types
127
155
 
128
- Load `{integrationPatterns}` for classification rules.
156
+ Load `{integrationPatternsPath}` for classification rules.
129
157
 
130
- For each qualifying pair, analyze to classify the integration type (**in compose-mode**: all architecture-document-detected pairs qualify automatically — the 2+ co-import file threshold applies only in code-mode; **in code-mode**: pair must have 2+ co-import files):
131
-
132
- - **Type 1: Middleware Chain** — Sequential function calls piping output between libraries
133
- - **Type 2: Shared Types** — Type definitions exchanged between libraries
134
- - **Type 3: Configuration Bridge** — One library configuring or initializing another
135
- - **Type 4: Event Handler** — Event patterns crossing library boundaries
136
- - **Type 5: Adapter/Wrapper** — Thin wrapper connecting library interfaces
137
- - **Type 6: State Sharing** — Shared state stores or context providers
158
+ For each qualifying pair, analyze to classify the integration type against those pattern types (**in compose-mode**: all architecture-document-detected pairs qualify automatically — the 2+ co-import file threshold applies only in code-mode; **in code-mode**: pair must have 2+ co-import files):
138
159
 
139
160
  For each detected integration:
140
161
  - Identify the top 3 files demonstrating the pattern
@@ -145,7 +166,7 @@ For each detected integration:
145
166
  - `architecture-co-mention` — compose-mode pair qualified via word-boundary co-mention in the architecture document (per §2 H2 guards). Maps to `detection_method: architecture_co_mention` in `provenance-map.json`.
146
167
  - `constituent-documented-contract` — compose-mode pair whose cross-library contract is documented in a constituent skill's integration docs (cited, e.g. a grep-verified upstream seam) but not co-mentioned in the architecture document. Maps to `detection_method: constituent_documented_contract` in `provenance-map.json`.
147
168
  - `inferred-shared-domain` — compose-mode pair without an architecture document, inferred from shared `language` or domain keywords (no cited contract). Maps to `detection_method: inferred_from_shared_domain` in `provenance-map.json`.
148
- - Render as `{tier} ({qualifier})` — e.g., `T1-low (grep-co-import)`, `T1 (ccc-augmented)`, `T1-low (architecture-co-mention) [composed]`. The `[composed]`/`[inferred from shared domain]` suffix from `compose-mode-rules.md` is appended after the qualifier in compose-mode.
169
+ - Render as `{tier} ({qualifier})` — e.g., `T1-low (grep-co-import)`, `T1 (ccc-augmented)`, `T1-low (architecture-co-mention) [composed]`. The `[composed]`/`[inferred from shared domain]` suffix from `{composeModeRulesPath}` is appended after the qualifier in compose-mode.
149
170
 
150
171
  **Provenance ↔ SKILL.md tier parity:** The tier derived above is the single value for this edge — write the *same* tier to both the SKILL.md integration label and `provenance-map.json` `integrations[].confidence`. The detection-method qualifier (and the `provenance-map.json` `detection_method` it maps to) records *how* the edge was found and is orthogonal to confidence; it never forces the tier into a fixed band.
151
172
 
@@ -159,33 +180,7 @@ Assemble the integration graph:
159
180
 
160
181
  ### 5. Display Integration Summary
161
182
 
162
- **If integrations detected:**
163
-
164
- "**Integration detection complete.**
165
-
166
- **Integration graph:** {lib_count} libraries, {pair_count} integration pairs
167
-
168
- **Hub libraries** (connected to 3+ others):
169
- {For each hub:} - **{library}** — integrates with {partner_list}
170
-
171
- **Detected integrations:**
172
- | Library A | Library B | Type | Co-import Files | Confidence |
173
- |-----------|-----------|------|-----------------|------------|
174
- | {name} | {name} | {type} | {count} | {tier} |
175
-
176
- {If cross-cutting patterns:}
177
- **Cross-cutting patterns:**
178
- - {description spanning 3+ libraries}
179
-
180
- **Proceeding to stack compilation...**"
181
-
182
- **If no integrations detected:**
183
-
184
- "**No co-import integration patterns detected** between confirmed libraries.
185
-
186
- The libraries in this project appear to operate independently. The stack skill will contain library summaries without an integration layer.
187
-
188
- **Proceeding to stack compilation...**"
183
+ If integrations were detected, report the integration graph (`{lib_count}` libraries, `{pair_count}` pairs): the hub libraries (connected to 3+ others) with their partners, each detected pair (library A, library B, type, co-import file count, confidence tier), and any cross-cutting patterns spanning 3+ libraries. If none were detected, report that no co-import integration patterns were found — the libraries appear to operate independently, so the stack skill will carry library summaries without an integration layer.
189
184
 
190
185
  ### 6. Auto-Proceed to Next Step
191
186