bmad-module-skill-forge 1.4.0 → 1.5.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 (231) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +0 -8
  3. package/docs/_data/pinned.yaml +1 -1
  4. package/docs/_internal/STABILITY.md +1 -1
  5. package/docs/architecture.md +2 -2
  6. package/docs/examples.md +1 -1
  7. package/docs/workflows.md +5 -5
  8. package/package.json +2 -2
  9. package/src/README.md +1 -1
  10. package/src/knowledge/ccc-bridge.md +12 -12
  11. package/src/knowledge/qmd-registry.md +5 -5
  12. package/src/shared/health-check.md +5 -5
  13. package/src/shared/references/description-guard-protocol.md +100 -0
  14. package/src/shared/references/output-contract-schema.md +1 -1
  15. package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +6 -6
  16. package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +9 -3
  17. package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +149 -0
  18. package/src/shared/scripts/schemas/skill-brief.v1.json +22 -2
  19. package/src/shared/scripts/skf-build-change-manifest.py +420 -0
  20. package/src/shared/scripts/skf-check-workspace-drift.py +321 -0
  21. package/src/shared/scripts/skf-compare-file-hashes.py +357 -0
  22. package/src/shared/scripts/skf-description-guard.py +359 -0
  23. package/src/shared/scripts/skf-detect-language.py +2 -2
  24. package/src/shared/scripts/skf-detect-scripts-assets.py +613 -0
  25. package/src/shared/scripts/skf-detect-tools.py +97 -8
  26. package/src/shared/scripts/skf-detect-workspaces.py +1 -1
  27. package/src/shared/scripts/skf-disqualify-candidates.py +576 -0
  28. package/src/shared/scripts/skf-emit-brief-result-envelope.py +3 -3
  29. package/src/shared/scripts/skf-emit-result-envelope.py +93 -9
  30. package/src/shared/scripts/skf-enumerate-stack-skills.py +514 -0
  31. package/src/shared/scripts/skf-forge-tier-rw.py +11 -11
  32. package/src/shared/scripts/skf-hash-content.py +284 -0
  33. package/src/shared/scripts/skf-load-provenance.py +295 -0
  34. package/src/shared/scripts/skf-merge-ccc-exclusions.py +45 -1
  35. package/src/shared/scripts/skf-pair-intersect.py +250 -0
  36. package/src/shared/scripts/skf-provenance-gap-dispatch.py +433 -0
  37. package/src/shared/scripts/skf-qmd-classify-collections.py +42 -8
  38. package/src/shared/scripts/skf-recommend-scope-type.py +2 -2
  39. package/src/shared/scripts/skf-render-quick-metadata.py +2 -2
  40. package/src/shared/scripts/skf-resolve-authoritative-files.py +504 -0
  41. package/src/shared/scripts/skf-scan-manifests.py +738 -0
  42. package/src/shared/scripts/skf-scan-skill-md-structure.py +375 -0
  43. package/src/shared/scripts/skf-update-active-symlink.py +315 -0
  44. package/src/shared/scripts/skf-validate-brief-inputs.py +5 -5
  45. package/src/shared/scripts/skf-validate-brief-schema.py +348 -0
  46. package/src/shared/scripts/skf-write-skill-brief.py +61 -5
  47. package/src/skf-analyze-source/SKILL.md +69 -16
  48. package/src/skf-analyze-source/assets/skill-brief-schema.md +1 -1
  49. package/src/skf-analyze-source/customize.toml +55 -0
  50. package/src/skf-analyze-source/{steps-c/step-01b-continue.md → references/continue.md} +12 -12
  51. package/src/skf-analyze-source/{steps-c/step-06-generate-briefs.md → references/generate-briefs.md} +29 -10
  52. package/src/skf-analyze-source/{steps-c/step-07-health-check.md → references/health-check.md} +5 -3
  53. package/src/skf-analyze-source/{steps-c/step-03-identify-units.md → references/identify-units.md} +44 -14
  54. package/src/skf-analyze-source/{steps-c/step-01-init.md → references/init.md} +27 -6
  55. package/src/skf-analyze-source/{steps-c/step-04-map-and-detect.md → references/map-and-detect.md} +52 -25
  56. package/src/skf-analyze-source/{steps-c/step-05-recommend.md → references/recommend.md} +15 -8
  57. package/src/skf-analyze-source/{steps-c/step-02-scan-project.md → references/scan-project.md} +12 -10
  58. package/src/skf-analyze-source/references/unit-detection-heuristics.md +2 -0
  59. package/src/skf-analyze-source/templates/analysis-report-template.md +6 -6
  60. package/src/skf-audit-skill/SKILL.md +66 -15
  61. package/src/skf-audit-skill/assets/drift-report-template.md +6 -5
  62. package/src/skf-audit-skill/customize.toml +49 -0
  63. package/src/skf-audit-skill/{steps-c/step-07-health-check.md → references/health-check.md} +5 -3
  64. package/src/skf-audit-skill/references/init.md +305 -0
  65. package/src/skf-audit-skill/{steps-c/step-02-re-index.md → references/re-index.md} +11 -11
  66. package/src/skf-audit-skill/{steps-c/step-06-report.md → references/report.md} +25 -7
  67. package/src/skf-audit-skill/{steps-c/step-04-semantic-diff.md → references/semantic-diff.md} +6 -6
  68. package/src/skf-audit-skill/{steps-c/step-05-severity-classify.md → references/severity-classify.md} +5 -5
  69. package/src/skf-audit-skill/references/severity-rules.md +2 -0
  70. package/src/skf-audit-skill/{steps-c/step-03-structural-diff.md → references/structural-diff.md} +29 -16
  71. package/src/skf-brief-skill/SKILL.md +48 -18
  72. package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
  73. package/src/skf-brief-skill/assets/skill-brief-schema.md +32 -2
  74. package/src/skf-brief-skill/customize.toml +44 -0
  75. package/src/skf-brief-skill/{steps-c/step-02-analyze-target.md → references/analyze-target.md} +5 -5
  76. package/src/skf-brief-skill/{steps-c/step-04-confirm-brief.md → references/confirm-brief.md} +13 -10
  77. package/src/skf-brief-skill/references/draft-checkpoint.md +4 -4
  78. package/src/skf-brief-skill/{steps-c/step-01-gather-intent.md → references/gather-intent.md} +24 -24
  79. package/src/skf-brief-skill/references/headless-args.md +9 -9
  80. package/src/skf-brief-skill/references/headless-source-authority-detection.md +1 -1
  81. package/src/skf-brief-skill/{steps-c/step-06-health-check.md → references/health-check.md} +4 -2
  82. package/src/skf-brief-skill/references/portfolio-similarity-check.md +2 -2
  83. package/src/skf-brief-skill/references/qmd-collection-registration.md +1 -1
  84. package/src/skf-brief-skill/{steps-c/step-03-scope-definition.md → references/scope-definition.md} +19 -16
  85. package/src/skf-brief-skill/references/version-resolution.md +2 -2
  86. package/src/skf-brief-skill/{steps-c/step-05-write-brief.md → references/write-brief.md} +11 -10
  87. package/src/skf-create-skill/SKILL.md +25 -19
  88. package/src/skf-create-skill/assets/compile-assembly-rules.md +3 -3
  89. package/src/skf-create-skill/assets/skill-sections.md +5 -5
  90. package/src/skf-create-skill/assets/tessl-dismissal-rules.md +11 -11
  91. package/src/skf-create-skill/customize.toml +35 -0
  92. package/src/skf-create-skill/references/authoritative-files-protocol.md +142 -0
  93. package/src/skf-create-skill/{steps-c/step-05-compile.md → references/compile.md} +16 -16
  94. package/src/skf-create-skill/{steps-c/step-03d-component-extraction.md → references/component-extraction.md} +16 -16
  95. package/src/skf-create-skill/{steps-c/step-02-ecosystem-check.md → references/ecosystem-check.md} +4 -4
  96. package/src/skf-create-skill/{steps-c/step-04-enrich.md → references/enrich.md} +3 -3
  97. package/src/skf-create-skill/{steps-c/step-03-extract.md → references/extract.md} +52 -120
  98. package/src/skf-create-skill/references/extraction-patterns.md +8 -8
  99. package/src/skf-create-skill/{steps-c/step-07-generate-artifacts.md → references/generate-artifacts.md} +17 -9
  100. package/src/skf-create-skill/{steps-c/step-09-health-check.md → references/health-check.md} +4 -2
  101. package/src/skf-create-skill/{steps-c/step-01-load-brief.md → references/load-brief.md} +40 -32
  102. package/src/skf-create-skill/{steps-c/step-08-report.md → references/report.md} +8 -8
  103. package/src/skf-create-skill/references/source-resolution-protocols.md +6 -6
  104. package/src/skf-create-skill/{steps-c/sub/step-02b-ccc-discover.md → references/sub/ccc-discover.md} +5 -5
  105. package/src/skf-create-skill/{steps-c/sub/step-03c-fetch-docs.md → references/sub/fetch-docs.md} +28 -12
  106. package/src/skf-create-skill/{steps-c/sub/step-03b-fetch-temporal.md → references/sub/fetch-temporal.md} +81 -50
  107. package/src/skf-create-skill/{steps-c/step-06-validate.md → references/validate.md} +46 -26
  108. package/src/skf-create-stack-skill/SKILL.md +76 -17
  109. package/src/skf-create-stack-skill/assets/provenance-map-schema.md +102 -0
  110. package/src/skf-create-stack-skill/assets/stack-skill-template.md +1 -1
  111. package/src/skf-create-stack-skill/customize.toml +46 -0
  112. package/src/skf-create-stack-skill/{steps-c/step-06-compile-stack.md → references/compile-stack.md} +6 -5
  113. package/src/skf-create-stack-skill/references/compose-mode-rules.md +3 -1
  114. package/src/skf-create-stack-skill/{steps-c/step-05-detect-integrations.md → references/detect-integrations.md} +32 -11
  115. package/src/skf-create-stack-skill/{steps-c/step-02-detect-manifests.md → references/detect-manifests.md} +28 -28
  116. package/src/skf-create-stack-skill/{steps-c/step-07-generate-output.md → references/generate-output.md} +11 -85
  117. package/src/skf-create-stack-skill/{steps-c/step-10-health-check.md → references/health-check.md} +4 -2
  118. package/src/skf-create-stack-skill/{steps-c/step-01-init.md → references/init.md} +70 -4
  119. package/src/skf-create-stack-skill/references/integration-patterns.md +2 -0
  120. package/src/skf-create-stack-skill/references/manifest-patterns.md +2 -0
  121. package/src/skf-create-stack-skill/{steps-c/step-04-parallel-extract.md → references/parallel-extract.md} +40 -17
  122. package/src/skf-create-stack-skill/{steps-c/step-03-rank-and-confirm.md → references/rank-and-confirm.md} +5 -4
  123. package/src/skf-create-stack-skill/{steps-c/step-09-report.md → references/report.md} +3 -3
  124. package/src/skf-create-stack-skill/{steps-c/step-08-validate.md → references/validate.md} +6 -6
  125. package/src/skf-drop-skill/SKILL.md +84 -12
  126. package/src/skf-drop-skill/customize.toml +57 -0
  127. package/src/skf-drop-skill/{steps-c/step-02-execute.md → references/execute.md} +49 -34
  128. package/src/skf-drop-skill/{steps-c/step-04-health-check.md → references/health-check.md} +6 -4
  129. package/src/skf-drop-skill/{steps-c/step-03-report.md → references/report.md} +13 -5
  130. package/src/skf-drop-skill/{steps-c/step-01-select.md → references/select.md} +63 -15
  131. package/src/skf-export-skill/SKILL.md +85 -16
  132. package/src/skf-export-skill/assets/managed-section-format.md +3 -3
  133. package/src/skf-export-skill/assets/snippet-format.md +2 -2
  134. package/src/skf-export-skill/customize.toml +49 -0
  135. package/src/skf-export-skill/{steps-c/step-03-generate-snippet.md → references/generate-snippet.md} +18 -12
  136. package/src/skf-export-skill/{steps-c/step-07-health-check.md → references/health-check.md} +6 -4
  137. package/src/skf-export-skill/{steps-c/step-01-load-skill.md → references/load-skill.md} +21 -51
  138. package/src/skf-export-skill/references/manifest-rebuild.md +68 -0
  139. package/src/skf-export-skill/references/multi-skill-mode.md +38 -0
  140. package/src/skf-export-skill/references/orphan-context-detection.md +75 -0
  141. package/src/skf-export-skill/references/orphan-row-detection.md +102 -0
  142. package/src/skf-export-skill/{steps-c/step-02-package.md → references/package.md} +7 -7
  143. package/src/skf-export-skill/references/preflight-snippet-root-probe.md +74 -0
  144. package/src/skf-export-skill/{steps-c/step-06-summary.md → references/summary.md} +30 -6
  145. package/src/skf-export-skill/{steps-c/step-05-token-report.md → references/token-report.md} +5 -5
  146. package/src/skf-export-skill/{steps-c/step-04-update-context.md → references/update-context.md} +116 -91
  147. package/src/skf-quick-skill/SKILL.md +63 -123
  148. package/src/skf-quick-skill/customize.toml +44 -0
  149. package/src/skf-quick-skill/references/batch-mode.md +102 -0
  150. package/src/skf-quick-skill/{steps-c/step-04-compile.md → references/compile.md} +10 -10
  151. package/src/skf-quick-skill/{steps-c/step-02-ecosystem-check.md → references/ecosystem-check.md} +5 -5
  152. package/src/skf-quick-skill/{steps-c/step-06-finalize.md → references/finalize.md} +7 -7
  153. package/src/skf-quick-skill/{steps-c/step-07-health-check.md → references/health-check.md} +3 -3
  154. package/src/skf-quick-skill/{steps-c/step-03-quick-extract.md → references/quick-extract.md} +5 -5
  155. package/src/skf-quick-skill/references/registry-resolution.md +2 -0
  156. package/src/skf-quick-skill/{steps-c/step-01-resolve-target.md → references/resolve-target.md} +14 -10
  157. package/src/skf-quick-skill/{steps-c/step-05-write-and-validate.md → references/write-and-validate.md} +4 -4
  158. package/src/skf-refine-architecture/SKILL.md +86 -16
  159. package/src/skf-refine-architecture/customize.toml +49 -0
  160. package/src/skf-refine-architecture/{steps-c/step-05-compile.md → references/compile.md} +4 -4
  161. package/src/skf-refine-architecture/{steps-c/step-02-gap-analysis.md → references/gap-analysis.md} +5 -5
  162. package/src/skf-refine-architecture/{steps-c/step-07-health-check.md → references/health-check.md} +6 -4
  163. package/src/skf-refine-architecture/{steps-c/step-04-improvements.md → references/improvements.md} +5 -5
  164. package/src/skf-refine-architecture/references/init.md +144 -0
  165. package/src/skf-refine-architecture/{steps-c/step-03-issue-detection.md → references/issue-detection.md} +5 -5
  166. package/src/skf-refine-architecture/references/refinement-rules.md +2 -0
  167. package/src/skf-refine-architecture/{steps-c/step-06-report.md → references/report.md} +14 -5
  168. package/src/skf-rename-skill/SKILL.md +82 -12
  169. package/src/skf-rename-skill/customize.toml +52 -0
  170. package/src/skf-rename-skill/{steps-c/step-02-execute.md → references/execute.md} +94 -99
  171. package/src/skf-rename-skill/references/health-check.md +30 -0
  172. package/src/skf-rename-skill/references/rebuild-context.md +110 -0
  173. package/src/skf-rename-skill/{steps-c/step-03-report.md → references/report.md} +13 -5
  174. package/src/skf-rename-skill/{steps-c/step-01-select.md → references/select.md} +59 -20
  175. package/src/skf-setup/SKILL.md +35 -35
  176. package/src/skf-setup/customize.toml +33 -0
  177. package/src/skf-setup/{steps-c/step-03-auto-index.md → references/auto-index.md} +10 -18
  178. package/src/skf-setup/{steps-c/step-01b-ccc-index.md → references/ccc-index.md} +14 -22
  179. package/src/skf-setup/{steps-c/step-01-detect-and-tier.md → references/detect-and-tier.md} +23 -10
  180. package/src/skf-setup/{steps-c/step-05-health-check.md → references/health-check.md} +1 -1
  181. package/src/skf-setup/{steps-c/step-04-report.md → references/report.md} +21 -19
  182. package/src/skf-setup/references/tier-rules.md +1 -1
  183. package/src/skf-setup/{steps-c/step-02-write-config.md → references/write-config.md} +14 -13
  184. package/src/skf-test-skill/SKILL.md +77 -15
  185. package/src/skf-test-skill/customize.toml +54 -0
  186. package/src/skf-test-skill/{steps-c/step-04-coherence-check.md → references/coherence-check.md} +28 -71
  187. package/src/skf-test-skill/{steps-c/step-03-coverage-check.md → references/coverage-check.md} +16 -39
  188. package/src/skf-test-skill/{steps-c/step-02-detect-mode.md → references/detect-mode.md} +4 -26
  189. package/src/skf-test-skill/{steps-c/step-04b-external-validators.md → references/external-validators.md} +6 -28
  190. package/src/skf-test-skill/references/health-check.md +14 -0
  191. package/src/skf-test-skill/{steps-c/step-01-init.md → references/init.md} +21 -37
  192. package/src/skf-test-skill/references/migration-section-rules.md +4 -2
  193. package/src/skf-test-skill/{steps-c/step-06-report.md → references/report.md} +41 -51
  194. package/src/skf-test-skill/{steps-c/step-05-score.md → references/score.md} +26 -43
  195. package/src/skf-test-skill/references/scoring-rules.md +8 -6
  196. package/src/skf-test-skill/references/source-access-protocol.md +7 -5
  197. package/src/skf-test-skill/scripts/compute-score.py +88 -17
  198. package/src/skf-test-skill/templates/test-report-template.md +13 -13
  199. package/src/skf-update-skill/SKILL.md +23 -14
  200. package/src/skf-update-skill/customize.toml +44 -0
  201. package/src/skf-update-skill/{steps-c/step-02-detect-changes.md → references/detect-changes.md} +176 -68
  202. package/src/skf-update-skill/references/health-check.md +32 -0
  203. package/src/skf-update-skill/{steps-c/step-01-init.md → references/init.md} +56 -8
  204. package/src/skf-update-skill/references/manual-section-rules.md +4 -0
  205. package/src/skf-update-skill/references/merge-conflict-rules.md +4 -0
  206. package/src/skf-update-skill/{steps-c/step-04-merge.md → references/merge.md} +8 -8
  207. package/src/skf-update-skill/{steps-c/step-03-re-extract.md → references/re-extract.md} +53 -44
  208. package/src/skf-update-skill/references/remote-source-resolution.md +5 -1
  209. package/src/skf-update-skill/references/report.md +214 -0
  210. package/src/skf-update-skill/{steps-c/step-05-validate.md → references/validate.md} +5 -5
  211. package/src/skf-update-skill/{steps-c/step-06-write.md → references/write.md} +73 -51
  212. package/src/skf-verify-stack/SKILL.md +89 -17
  213. package/src/skf-verify-stack/assets/feasibility-report-template.md +4 -4
  214. package/src/skf-verify-stack/customize.toml +50 -0
  215. package/src/skf-verify-stack/references/coverage-patterns.md +2 -2
  216. package/src/skf-verify-stack/{steps-c/step-02-coverage.md → references/coverage.md} +7 -7
  217. package/src/skf-verify-stack/{steps-c/step-07-health-check.md → references/health-check.md} +7 -5
  218. package/src/skf-verify-stack/references/init.md +166 -0
  219. package/src/skf-verify-stack/references/integration-verification-rules.md +1 -1
  220. package/src/skf-verify-stack/{steps-c/step-03-integrations.md → references/integrations.md} +12 -12
  221. package/src/skf-verify-stack/{steps-c/step-06-report.md → references/report.md} +22 -41
  222. package/src/skf-verify-stack/{steps-c/step-04-requirements.md → references/requirements.md} +7 -7
  223. package/src/skf-verify-stack/{steps-c/step-05-synthesize.md → references/synthesize.md} +8 -8
  224. package/tools/validate-docs-drift.js +1 -1
  225. package/src/skf-audit-skill/steps-c/step-01-init.md +0 -221
  226. package/src/skf-refine-architecture/steps-c/step-01-init.md +0 -136
  227. package/src/skf-rename-skill/steps-c/step-04-health-check.md +0 -22
  228. package/src/skf-test-skill/steps-c/step-07-health-check.md +0 -25
  229. package/src/skf-update-skill/steps-c/step-07-report.md +0 -148
  230. package/src/skf-update-skill/steps-c/step-08-health-check.md +0 -22
  231. package/src/skf-verify-stack/steps-c/step-01-init.md +0 -178
@@ -20,39 +20,39 @@ nextWorkflow: ''
20
20
  # Test Report: {{skillName}}
21
21
 
22
22
  <!--
23
- Section order is LOAD-BEARING: step-05 §5 enforces it, step-06 §5 verifies
23
+ Section order is LOAD-BEARING: step 5 §5 enforces it, step 6 §5 verifies
24
24
  stepsCompleted against the canonical chain. Do not reorder or delete anchors.
25
25
 
26
26
  Anchor / Step mapping:
27
- Test Summary → step-02-detect-mode
28
- Coverage Analysis → step-03-coverage-check
29
- Coherence Analysis → step-04-coherence-check
30
- External Validation→ step-04b-external-validators
31
- Completeness Score → step-05-score
32
- Gap Report → step-06-report (includes Discovery Quality subsection)
27
+ Test Summary → detect-mode
28
+ Coverage Analysis → coverage-check
29
+ Coherence Analysis → coherence-check
30
+ External Validation→ external-validators
31
+ Completeness Score → score
32
+ Gap Report → report (includes Discovery Quality subsection)
33
33
  -->
34
34
 
35
35
  ## Test Summary
36
36
 
37
- <!-- Populated by step-02-detect-mode §3 -->
37
+ <!-- Populated by detect-mode §3 -->
38
38
 
39
39
  ## Coverage Analysis
40
40
 
41
- <!-- Populated by step-03-coverage-check §5 -->
41
+ <!-- Populated by coverage-check §5 -->
42
42
 
43
43
  ## Coherence Analysis
44
44
 
45
- <!-- Populated by step-04-coherence-check §6 (naive or contextual variant) -->
45
+ <!-- Populated by coherence-check §6 (naive or contextual variant) -->
46
46
 
47
47
  ## External Validation
48
48
 
49
- <!-- Populated by step-04b-external-validators §5 -->
49
+ <!-- Populated by external-validators §5 -->
50
50
 
51
51
  ## Completeness Score
52
52
 
53
- <!-- Populated by step-05-score §6 -->
53
+ <!-- Populated by score §6 -->
54
54
 
55
55
  ## Gap Report
56
56
 
57
- <!-- Populated by step-06-report §3-§4b (includes Discovery Quality subsection) -->
57
+ <!-- Populated by report §3-§4b (includes Discovery Quality subsection) -->
58
58
 
@@ -9,6 +9,15 @@ description: Smart regeneration preserving [MANUAL] sections after source change
9
9
 
10
10
  Surgically updates existing skills when source code changes, preserving all [MANUAL] developer content while re-extracting only affected exports with full provenance tracking. Only changed exports are re-extracted — unchanged content is never touched. Every regenerated instruction must trace to code with file:line citations. Stack skills (`skill_type: "stack"` in metadata.json) are not supported by surgical update — use `skf-create-stack-skill` to re-compose from updated constituents. If a stack skill is provided, this workflow exits with a redirect message.
11
11
 
12
+ ## Conventions
13
+
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.
16
+ - `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives, if present).
17
+ - `{project-root}`-prefixed paths resolve from the project working directory.
18
+ - `{skill-name}` resolves to the skill directory's basename.
19
+ - **Cross-skill data coupling:** stages in this workflow load four shared assets from `skf-create-skill` to keep extraction semantics aligned between create and update — `re-extract.md` pulls `extraction-patterns.md`, `extraction-patterns-tracing.md`, and `tier-degradation-rules.md` from `skf-create-skill/references/`; `remote-source-resolution.md` references `source-resolution-protocols.md`; `write.md` reads `skill-sections.md` from `skf-create-skill/assets/`. Update-skill assumes these files are present at install time and that their semantics are stable across the two skills' versions.
20
+
12
21
  ## Role
13
22
 
14
23
  You are a precision code analyst operating in Ferris Surgeon mode. This is a surgical operation, not an exploratory session. You bring AST-backed structural analysis and provenance-driven change detection expertise, while the source code provides the ground truth.
@@ -19,8 +28,6 @@ These rules apply to every step in this workflow:
19
28
 
20
29
  - Never hallucinate — every statement must have AST provenance
21
30
  - [MANUAL] sections survive regeneration with zero content loss
22
- - Read each step file completely before taking any action
23
- - Follow the mandatory sequence in each step exactly — do not skip, reorder, or optimize
24
31
  - Only load one step file at a time — never preload future steps
25
32
  - Always communicate in `{communication_language}`
26
33
  - If `{headless_mode}` is true, auto-proceed through confirmation gates with their default action and log each auto-decision
@@ -29,23 +36,25 @@ These rules apply to every step in this workflow:
29
36
 
30
37
  | # | Step | File | Auto-proceed |
31
38
  |---|------|------|--------------|
32
- | 1 | Initialize & Load | steps-c/step-01-init.md | No (confirm) |
33
- | 2 | Detect Changes | steps-c/step-02-detect-changes.md | Yes |
34
- | 3 | Re-Extract | steps-c/step-03-re-extract.md | Yes |
35
- | 4 | Merge | steps-c/step-04-merge.md | Yes |
36
- | 5 | Validate | steps-c/step-05-validate.md | Yes |
37
- | 6 | Write | steps-c/step-06-write.md | Yes |
38
- | 7 | Report | steps-c/step-07-report.md | Yes |
39
- | 8 | Workflow Health Check | steps-c/step-08-health-check.md | Yes |
39
+ | 1 | Initialize & Load | references/init.md | No (confirm) |
40
+ | 2 | Detect Changes | references/detect-changes.md | Yes |
41
+ | 3 | Re-Extract | references/re-extract.md | Yes |
42
+ | 4 | Merge | references/merge.md | Yes |
43
+ | 5 | Validate | references/validate.md | Yes |
44
+ | 6 | Write | references/write.md | Yes |
45
+ | 7 | Report | references/report.md | Yes |
46
+ | 8 | Workflow Health Check | references/health-check.md | Yes |
40
47
 
41
48
  ## Invocation Contract
42
49
 
43
50
  | Aspect | Detail |
44
51
  |--------|--------|
45
52
  | **Inputs** | skill_name [required] |
46
- | **Gates** | step-01: Confirm Gate [C] | step-04: Confirm Gate [C if clean merge, HALT if conflicts] |
47
- | **Outputs** | Updated SKILL.md, updated provenance-map.json, evidence-report.md |
48
- | **Headless** | All gates auto-resolve with default action when `{headless_mode}` is true |
53
+ | **Flags** | `--headless` / `-H` (auto-resolve all gates); `--from-test-report` (gap-driven mode); `--allow-workspace-drift` (gap-driven only bypass §0.a pinning guard); `--detect-only` (run detect-changes only, exit before re-extract; envelope `status="detect-only"`); `--dry-run` (run detect-changes + re-extract, exit before merge/write; envelope `status="dry-run"` describes what would change). If both `--detect-only` and `--dry-run` are passed, `--detect-only` wins. |
54
+ | **Gates** | step 1: Confirm Gate [C] | step 4: Confirm Gate [C if clean merge, HALT if conflicts] |
55
+ | **Outputs** | Updated SKILL.md, updated provenance-map.json, evidence-report.md (none when `--detect-only` or `--dry-run` is set — those modes are read-only inspection paths) |
56
+ | **Concurrency** | Two simultaneous real-update runs against the same skill would corrupt provenance. init.md §1b acquires a PID-file lock at `{forge_data_folder}/{skill_name}/.skf-update.lock` before any artifact read; live-PID collisions halt with `status: "halted-for-concurrent-run"`. Stale locks (dead PID) are cleared silently with a warning. The lock is released by the terminal health-check step (step 8) and by every documented halt path. Read-only modes (`--detect-only`, `--dry-run`) skip the lock entirely — they're safe alongside a concurrent real update. |
57
+ | **Headless** | All gates auto-resolve with default action when `{headless_mode}` is true. Each auto-resolved gate appends a `{gate, default_action, taken_action, reason, evidence?}` entry to `headless_decisions[]`, surfaced in step 7's `SKF_UPDATE_RESULT_JSON` envelope so non-interactive runs can be audited post-hoc. Pipeline branches on the envelope's top-level `status` field (`success`, `no-changes`, `detect-only`, `dry-run`, or one of the documented `halted-for-*` codes). The first four are successful exits — pipelines treating non-success as failure must include them in the success set. Schema: `src/shared/scripts/schemas/skf-update-result-envelope.v1.json`. |
49
58
 
50
59
  ## On Activation
51
60
 
@@ -55,4 +64,4 @@ These rules apply to every step in this workflow:
55
64
 
56
65
  2. **Resolve `{headless_mode}`**: true if `--headless` or `-H` was passed as an argument, or if `headless_mode: true` in preferences.yaml. Default: false.
57
66
 
58
- 3. Load, read the full file, and then execute `./steps-c/step-01-init.md` to begin the workflow.
67
+ 3. Load, read the full file, and then execute `references/init.md` to begin the workflow.
@@ -0,0 +1,44 @@
1
+ # DO NOT EDIT -- overwritten on every update.
2
+ #
3
+ # Workflow customization surface for skf-update-skill.
4
+
5
+ [workflow]
6
+
7
+ # --- Configurable below. Overrides merge per BMad structural rules: ---
8
+ # scalars: override wins • arrays (persistent_facts, activation_steps_*): append
9
+ # arrays-of-tables with `code`/`id`: replace matching items, append new ones.
10
+
11
+ # Steps to run before the standard activation (uv probe, config load).
12
+ # Overrides append. Use for org-wide pre-flight checks (auth, network,
13
+ # compliance) that must precede any skill update work.
14
+
15
+ activation_steps_prepend = []
16
+
17
+ # Steps to run after activation but before the first stage executes.
18
+ # Overrides append. Use for context loads or banner customization that
19
+ # should run once activation completes successfully.
20
+
21
+ activation_steps_append = []
22
+
23
+ # Persistent facts the workflow keeps in mind for the whole run
24
+ # (drift policies, manual-section preservation rules, compliance
25
+ # guardrails). Overrides append.
26
+ #
27
+ # Each entry is either:
28
+ # - a literal sentence, e.g. "Updates must preserve [MANUAL] sections verbatim."
29
+ # - a file reference prefixed with `file:`, e.g.
30
+ # "file:{project-root}/docs/update-policy.md" (globs supported; file
31
+ # contents are loaded and treated as facts).
32
+
33
+ persistent_facts = [
34
+ "file:{project-root}/**/project-context.md",
35
+ ]
36
+
37
+ # --- Optional gate thresholds ---
38
+ #
39
+ # Override the default thresholds used by detect-changes and merge. Empty
40
+ # string or commented = use the bundled default (50% deletion ratio,
41
+ # 80% rename similarity).
42
+
43
+ deletion_ratio_threshold = ""
44
+ rename_similarity_threshold = ""
@@ -1,8 +1,34 @@
1
1
  ---
2
- nextStepFile: './step-03-re-extract.md'
3
- noChangeReportFile: './step-07-report.md'
2
+ nextStepFile: 're-extract.md'
3
+ noChangeReportFile: 'report.md'
4
+ # Resolve `{hashContentHelper}` to the first existing path; HALT if neither
5
+ # candidate exists — §1b and §Category D rely on the helper for deterministic
6
+ # SHA-256 hashing (file-read + size + line-count) and provenance comparison
7
+ # (UNCHANGED / MODIFIED_FILE / DELETED_FILE classification). Falling back to
8
+ # prose-driven hashing would lose hash stability across runs.
9
+ hashContentProbeOrder:
10
+ - '{project-root}/_bmad/skf/shared/scripts/skf-hash-content.py'
11
+ - '{project-root}/src/shared/scripts/skf-hash-content.py'
12
+ # Resolve `{buildChangeManifestHelper}` to the first existing path; HALT if
13
+ # neither candidate exists. §3 uses `build` to aggregate Category A/B/C/D
14
+ # results into the unified manifest; §2.2 uses `deletion-ratio` to compute
15
+ # the major-version trigger. Falling back to prose-driven count rollups
16
+ # would let the LLM drift on manifest shape across runs.
17
+ buildChangeManifestProbeOrder:
18
+ - '{project-root}/_bmad/skf/shared/scripts/skf-build-change-manifest.py'
19
+ - '{project-root}/src/shared/scripts/skf-build-change-manifest.py'
20
+ # Resolve `{provenanceGapDispatchHelper}` to the first existing path; HALT
21
+ # if neither exists. §1c uses it to discover the latest drift report, parse
22
+ # Out-of-Scope candidates, and classify them against brief.scope.amendments[]
23
+ # in one call. Falling back to prose-driven markdown parsing would let
24
+ # report-format drift produce silent skips of out-of-scope candidates.
25
+ provenanceGapDispatchProbeOrder:
26
+ - '{project-root}/_bmad/skf/shared/scripts/skf-provenance-gap-dispatch.py'
27
+ - '{project-root}/src/shared/scripts/skf-provenance-gap-dispatch.py'
4
28
  ---
5
29
 
30
+ <!-- Config: communicate in {communication_language}. -->
31
+
6
32
  # Step 2: Detect Changes
7
33
 
8
34
  ## STEP GOAL:
@@ -16,11 +42,9 @@ Compare current source code state against the provenance map to produce a comple
16
42
 
17
43
  ## MANDATORY SEQUENCE
18
44
 
19
- **CRITICAL:** Follow this sequence exactly. Do not skip, reorder, or improvise unless user explicitly requests a change.
20
-
21
45
  ### 0. Check for Test Report Input (Gap-Driven Mode)
22
46
 
23
- **If `update_mode == "gap-driven"` (set in step-01 via `--from-test-report`):**
47
+ **If `update_mode == "gap-driven"` (set in step 1 via `--from-test-report`):**
24
48
 
25
49
  Load the test report at `{test_report_path}` and extract findings:
26
50
 
@@ -36,9 +60,9 @@ Load the test report at `{test_report_path}` and extract findings:
36
60
  | Medium | Stale documentation | MODIFIED_EXPORT (docs reference removed export) |
37
61
  | Low | Missing metadata/examples | metadata update |
38
62
 
39
- 4. Build the change manifest from translated gaps — no file-level timestamp comparison needed since source hasn't changed. For each manifest entry, propagate these fields from the test report finding so step-03 can resolve the export against live source:
63
+ 4. Build the change manifest from translated gaps — no file-level timestamp comparison needed since source hasn't changed. For each manifest entry, propagate these fields from the test report finding so step 3 can resolve the export against live source:
40
64
 
41
- - **`severity`** — the Gap Report severity (`Critical`, `High`, `Medium`, `Low`, `Info`). Step-03 §0 and step-06 §3 gate the null-citation fallback on severity: Critical/High gaps must produce AST provenance, Medium/Low/Info gaps may degrade to `unknown`.
65
+ - **`severity`** — the Gap Report severity (`Critical`, `High`, `Medium`, `Low`, `Info`). Step-03 §0 and step 6 §3 gate the null-citation fallback on severity: Critical/High gaps must produce AST provenance, Medium/Low/Info gaps may degrade to `unknown`.
42
66
  - **`source_citation: {file, line}`** — populated only when the finding's `Source:` field is a `file:line` pair (e.g., a Gap Report row that cites `packages/utils/src/builder-utils.ts:33`). Step-03 §0 uses this field to perform a live spot-check against source rather than flagging the export as `unknown`. Omit when the `Source:` field is a region reference (e.g., `@storybook/addon-docs control primitives`) or missing.
43
67
  - **`remediation_paths: [path, ...]`** — path-like tokens extracted from the finding's `Remediation:` text: any substring matching a recognized source file extension (`.ts`, `.tsx`, `.js`, `.jsx`, `.mjs`, `.cjs`, `.py`, `.rs`, `.go`, `.java`, `.rb`, `.c`, `.h`, `.cpp`), or a directory/glob fragment under the project's source root. Include every matching path verbatim. Step-03 §0a uses this list as the source set for its Targeted Re-Extraction Branch when `source_citation` is absent and severity is Critical/High. Omit the field when the Remediation text names no paths — the entry then falls through to `unknown` or to §0a's halt, depending on severity.
44
68
  5. Set `gap_count` from the total number of translated entries
@@ -100,7 +124,7 @@ Read the source directory at `{source_root}` and build a current file inventory:
100
124
  [U] Update — halt this run and return to skf-brief-skill to refine scope
101
125
  ```
102
126
 
103
- 5. **Headless mode (`{headless_mode}` is true):** auto-select `[S] Skip` for every candidate — record `action: "skipped"`, `reason: "headless: no user to prompt"`, `workflow: "skf-update-skill"`. A non-interactive update run must never silently add files to scope.
127
+ 5. **Headless mode (`{headless_mode}` is true):** auto-select `[S] Skip` for every candidate — record `action: "skipped"`, `reason: "headless: no user to prompt"`, `workflow: "skf-update-skill"`. A non-interactive update run must never silently add files to scope. **Also append one entry per candidate to in-context `headless_decisions[]`** (surfaced via `SKF_UPDATE_RESULT_JSON` by step 7): `{gate: "detect-changes.promoted-doc-prompt", default_action: "S", taken_action: "S", reason: "headless: no user to prompt", evidence: {path: "<candidate.path>"}}`.
104
128
 
105
129
  6. **Apply decision:**
106
130
 
@@ -108,7 +132,7 @@ Read the source directory at `{source_root}` and build a current file inventory:
108
132
  1. Append `candidate.path` to `brief.scope.include` as a literal glob.
109
133
  2. Append a `brief.scope.amendments[]` entry: `action: "promoted"`, `path: candidate.path`, `reason: {user-provided or auto: "discovered post-creation — matched heuristic {basename}"}`, `heuristic: {basename}`, `date: {today ISO}`, `workflow: "skf-update-skill"`.
110
134
  3. **Write the amended brief back to disk immediately** at `{forge_data_folder}/{skill_name}/skill-brief.yaml`. Preserve all other fields.
111
- 4. **Compute SHA-256 content hash** of `candidate.path` and add an entry to the in-context `promoted_docs_new[]` list: `{path, heuristic, size_bytes, line_count, content_hash}`. This list is consumed by §4 merge Priority 7 to write new `file_entries[]` rows — promoted docs do NOT go through §3 code re-extraction, which would produce ghost entries on non-code files.
135
+ 4. **Hash the candidate** via `uv run {hashContentHelper} hash {candidate.path}` emits `{content_hash, size_bytes, line_count}` as JSON. Combine with the existing context fields and append to the in-context `promoted_docs_new[]` list: `{path, heuristic, size_bytes, line_count, content_hash}`. This list is consumed by §4 merge Priority 7 to write new `file_entries[]` rows — promoted docs do NOT go through §3 code re-extraction, which would produce ghost entries on non-code files.
112
136
  5. Display: `"Promoted {path} — brief amended, scheduled as new file_entries row for file_type doc."`
113
137
 
114
138
  - **[S] Skip:**
@@ -143,23 +167,51 @@ Read the source directory at `{source_root}` and build a current file inventory:
143
167
 
144
168
  **Procedure:**
145
169
 
146
- 1. **Locate the most recent audit drift report.** Search `{forge_data_folder}/{skill_name}/{baseline_version}/drift-report-*.md`, sorted by timestamp descending. Pick the latest. If none found, **skip §1c entirely** the post-detection deletion-ratio trigger in §2.2 still catches major restructures even without an audit pass.
170
+ 1. **Discover, parse, and reconcile in one call.** The helper handles drift-report discovery (glob, timestamp-DESC sort, latest wins), Out-of-Scope section extraction (both `## Out-of-Scope Observations` and `### Out-of-Scope New Public API` under `## Remediation Suggestions` heading shapes), candidate parsing (bullet and table markdown formats), and amendment reconciliation against `brief.scope.amendments[]`:
147
171
 
148
- 2. **Parse the report for an "Out-of-Scope Observations" section.** Look for either a top-level `## Out-of-Scope Observations` heading or a `### Out-of-Scope New Public API` subsection under `## Remediation Suggestions`. Each entry must expose:
172
+ ```bash
173
+ uv run {provenanceGapDispatchHelper} dispatch \
174
+ --skill-name {skill_name} \
175
+ --baseline-version {baseline_version} \
176
+ --forge-data-folder {forge_data_folder} \
177
+ --brief {forge_data_folder}/{skill_name}/skill-brief.yaml
178
+ ```
149
179
 
150
- - `path` — literal file path or directory glob (e.g., `python/cocoindex/_internal/api.py` or `python/cocoindex/resources/**`)
151
- - `evidence` — short one-liner from the report (export count, rationale)
180
+ Output envelope:
181
+
182
+ ```json
183
+ {
184
+ "status": "no-report" | "no-candidates" | "candidates-found",
185
+ "report_path": "<abs path>" | null,
186
+ "candidates_total": N,
187
+ "classified": [
188
+ {
189
+ "path": "<glob or file path>",
190
+ "evidence": "<one-liner>",
191
+ "status": "already-in-scope" | "pre-decided-skipped"
192
+ | "pre-decided-demoted" | "unresolved",
193
+ "prior_action": "promoted" | "skipped"
194
+ | "demoted-include" | "demoted-exclude"
195
+ | null
196
+ }, ...
197
+ ],
198
+ "summary": {"pre_decided_count": N, "unresolved_count": N}
199
+ }
200
+ ```
152
201
 
153
- **Note:** This section is an optional audit-skill output. `skf-audit-skill` does not currently discover new files (per `src/skf-audit-skill/steps-c/step-02-re-index.md` — new-file detection is the responsibility of update-skill). The section is a forward-looking integration point: manual additions to the drift report or a future audit-skill enhancement populate it. If absent, no candidates from this trigger — proceed to step 6.
202
+ 2. **Dispatch on `status`:**
154
203
 
155
- 3. **Reconcile against existing amendments.** For each candidate, consult `brief.scope.amendments[]`:
204
+ - **`no-report`** — no drift report under `{forge_data_folder}/{skill_name}/{baseline_version}/`. **Skip §1c entirely** proceed to step 6's summary line (omit). §2.2's post-detection deletion-ratio trigger still catches major restructures.
205
+ - **`no-candidates`** — report exists but the Out-of-Scope section is absent or empty. Proceed to step 6's summary line with `"no out-of-scope observations in drift report."`
206
+ - **`candidates-found`** — iterate `classified[]`:
207
+ - `status: "already-in-scope"` → skip silently (`prior_action: "promoted"`).
208
+ - `status: "pre-decided-skipped"` → honor silently (`prior_action: "skipped"`).
209
+ - `status: "pre-decided-demoted"` → record as `pre_decided`; do not re-prompt (`prior_action` ∈ `demoted-include`, `demoted-exclude`).
210
+ - `status: "unresolved"` → continue to step 4 (user prompt).
156
211
 
157
- - `action: "promoted"` AND `path` matches already in scope, skip silently.
158
- - `action: "skipped"` AND `path` matches → user previously declined, honor silently.
159
- - `action: "demoted-include"` or `action: "demoted-exclude"` AND `path` matches → user previously narrowed scope on this path, do not re-prompt; record as `pre_decided`.
160
- - No matching amendment → continue to user prompt.
212
+ **Note:** the Out-of-Scope section is an optional audit-skill output. `skf-audit-skill` does not currently discover new files (per `src/skf-audit-skill/references/re-index.md` new-file detection is the responsibility of update-skill). The section is a forward-looking integration point: manual additions or a future audit-skill enhancement populate it.
161
213
 
162
- 4. **Prompt for each unresolved candidate.** Present the same menu shape as §1b:
214
+ 3. **Prompt for each unresolved candidate.** Present the same menu shape as §1b:
163
215
 
164
216
  ```
165
217
  **Out-of-scope new public API discovered**
@@ -175,9 +227,9 @@ Read the source directory at `{source_root}` and build a current file inventory:
175
227
  [U] Update — halt this run and return to skf-brief-skill to refine scope
176
228
  ```
177
229
 
178
- 5. **Headless mode (`{headless_mode}` is true):** auto-select `[S] Skip` for every candidate — record `action: "skipped"`, `category: "scope-expansion"`, `reason: "headless: no user to prompt"`, `workflow: "skf-update-skill"`. A non-interactive update run must never silently expand scope.
230
+ 4. **Headless mode (`{headless_mode}` is true):** auto-select `[S] Skip` for every candidate — record `action: "skipped"`, `category: "scope-expansion"`, `reason: "headless: no user to prompt"`, `workflow: "skf-update-skill"`. A non-interactive update run must never silently expand scope. **Also append one entry per candidate to in-context `headless_decisions[]`** (surfaced via `SKF_UPDATE_RESULT_JSON` by step 7): `{gate: "detect-changes.scope-expansion", default_action: "S", taken_action: "S", reason: "headless: no user to prompt", evidence: {path: "<candidate.path>"}}`.
179
231
 
180
- 6. **Apply decision:**
232
+ 5. **Apply decision:**
181
233
 
182
234
  - **[P] Promote:**
183
235
  1. Append `candidate.path` to `brief.scope.include` as a literal glob (preserve any wildcards from the drift report).
@@ -197,7 +249,7 @@ Read the source directory at `{source_root}` and build a current file inventory:
197
249
  2. Display: `"Halting update-skill. Re-run skf-brief-skill to refine scope for {skill_name}, then re-run skf-update-skill."`
198
250
  3. Exit with status `halted-for-brief-refinement`. Change manifest is not yet built — no partial writes to provenance.
199
251
 
200
- 7. **Summary:** After all candidates are resolved (or none were found):
252
+ 6. **Summary:** After all candidates are resolved (or none were found):
201
253
 
202
254
  - `"Scope reconciliation: {N} candidates, {P} promoted, {S} skipped, {A} pre-decided from amendments."`
203
255
  - If N = 0 (section absent or empty): `"Scope reconciliation: no out-of-scope observations in drift report."`
@@ -215,7 +267,7 @@ Before launching parallel subprocesses, build a `change_detection_excludes` set
215
267
 
216
268
  The exclusion set includes:
217
269
 
218
- - Every path in `promoted_docs_new[]` (populated by §1b). These files are tracked as `file_entries[]` via step-04 Priority 7, not through Category A code extraction. Without this exclusion, Category A would classify them as ADDED (because they're in source but not yet in the provenance map) and §3 re-extract would send them to AST extraction, producing ghost entries.
270
+ - Every path in `promoted_docs_new[]` (populated by §1b). These files are tracked as `file_entries[]` via step 4 Priority 7, not through Category A code extraction. Without this exclusion, Category A would classify them as ADDED (because they're in source but not yet in the provenance map) and §3 re-extract would send them to AST extraction, producing ghost entries.
219
271
  - Every source path in `file_entries[].source_file` where `file_type == "doc"` in the existing provenance map. These are already-tracked authoritative docs; any drift in them is handled by Category D (script/asset file changes), not Category A.
220
272
 
221
273
  Record the set size: "**Change-detection excludes:** {count} paths ({promoted_docs_new count} new promotions + {existing doc file_entries count} already tracked)."
@@ -227,7 +279,7 @@ Launch subprocesses in parallel that compare source state against provenance map
227
279
  **Category A — File-level changes:**
228
280
  - Files in provenance map but missing from source → DELETED
229
281
  - Files in source but not in provenance map AND not in `change_detection_excludes` → ADDED
230
- - Files in `change_detection_excludes`: skip entirely (routed to file_entries via §1b → step-04 Priority 7, never through Category A)
282
+ - Files in `change_detection_excludes`: skip entirely (routed to file_entries via §1b → step 4 Priority 7, never through Category A)
231
283
  - Files in both but with different timestamps/sizes → MODIFIED
232
284
  - Files with same content at different paths → MOVED
233
285
 
@@ -243,12 +295,35 @@ Launch subprocesses in parallel that compare source state against provenance map
243
295
  - If content similarity > 80%: classify as RENAMED instead of deleted+added. **Similarity mechanism by tier:** Quick: compare file size ratio (within 20%) and export name overlap (>70% of exports match by name). Forge and above: use ast-grep to compare export signatures between the deleted and added files. Forge+/Deep: use CCC semantic similarity when available
244
296
 
245
297
  **Category D — Script/asset file changes:**
246
- - Compare `file_entries` from provenance-map.json against current source files
247
- - For each file_entry: compute current SHA-256 content hash, compare against stored hash
248
- - Files with changed hashes → MODIFIED_FILE
249
- - Files in provenance but missing from source → DELETED_FILE
250
- - Files in source matching detection patterns (scripts/, bin/, assets/, templates/) but not in provenance → NEW_FILE
251
- - Files in `scripts/[MANUAL]/` or `assets/[MANUAL]/` → SKIP (user-authored, preserved)
298
+
299
+ Run the bulk comparison once via:
300
+
301
+ ```bash
302
+ uv run {hashContentHelper} compare <source-root> \
303
+ --provenance-map <provenance-map-path>
304
+ ```
305
+
306
+ The helper emits:
307
+
308
+ ```json
309
+ {
310
+ "comparisons": [
311
+ {"source_file": "...", "classification": "UNCHANGED|MODIFIED_FILE|DELETED_FILE",
312
+ "stored_hash": "sha256:...", "current_hash": "sha256:..."|null,
313
+ "current_size_bytes": N|null}, ...
314
+ ],
315
+ "stats": {"total": N, "unchanged": U, "modified": M, "deleted": D}
316
+ }
317
+ ```
318
+
319
+ Translate the helper's output into the change manifest:
320
+ - `MODIFIED_FILE` rows → add to manifest as MODIFIED_FILE
321
+ - `DELETED_FILE` rows → add to manifest as DELETED_FILE
322
+ - `UNCHANGED` rows → omit from the manifest (no action needed)
323
+
324
+ The helper does NOT detect NEW_FILE — its job is provenance comparison only. Detect new files via `skf-detect-scripts-assets.py` from create-skill step 3 §4c against the current source tree, then subtract the paths already present in `provenance.file_entries[].source_file`. Remaining files matching detection patterns (`scripts/`, `bin/`, `assets/`, `templates/`) and NOT under `scripts/[MANUAL]/` or `assets/[MANUAL]/` are NEW_FILE.
325
+
326
+ Files in `scripts/[MANUAL]/` or `assets/[MANUAL]/` → SKIP (user-authored, preserved).
252
327
 
253
328
  Aggregate all subprocess results into a unified change manifest.
254
329
 
@@ -261,22 +336,29 @@ Aggregate all subprocess results into a unified change manifest.
261
336
 
262
337
  **Purpose:** §1c catches the major-version case when an audit drift report supplies explicit candidates. §2.2 is the safety net that fires when no audit was run (or audit emitted no out-of-scope section): it inspects the just-built Category A/B results for the deletion-ratio signature of a major-version restructure and gives the user an off-ramp before §3 commits the change manifest.
263
338
 
264
- **Skip this section entirely if:**
265
-
266
- - `update_mode == "gap-driven"` (test-report mode), OR
267
- - `degraded_mode == true` (no provenance baseline to compare against — every export looks "modified", deletion ratio is meaningless), OR
268
- - Provenance map's tracked export count is zero.
269
-
270
- **Trigger:** Compute
339
+ **Trigger computation:** invoke the helper with the same Category A/B/C/D JSON used for §3, plus the provenance map:
271
340
 
341
+ ```bash
342
+ echo "{category JSON}" | uv run {buildChangeManifestHelper} deletion-ratio \
343
+ --provenance-map {forge_version}/provenance-map.json
272
344
  ```
273
- deleted_export_count = (sum of exports across Category A DELETED files)
274
- + (DELETED_EXPORT count from Category B)
275
- total_provenance_exports = provenance_map.entries.length
276
- deletion_ratio = deleted_export_count / total_provenance_exports
345
+
346
+ The helper handles the three skip conditions internally — when the input has `update_mode: "gap-driven"`, `degraded_mode: true`, or the provenance has zero entries, it returns `skip_reason` set and `should_trigger: false`. The output envelope:
347
+
348
+ ```json
349
+ {
350
+ "skip_reason": "gap-driven" | "degraded-mode" | "zero-provenance-exports" | null,
351
+ "deleted_export_count": N,
352
+ "total_provenance_exports": N,
353
+ "deletion_ratio": 0.X,
354
+ "deleted_file_count": N,
355
+ "added_in_scope_count": N,
356
+ "renamed_or_moved_count": N,
357
+ "should_trigger": <bool>
358
+ }
277
359
  ```
278
360
 
279
- If `deletion_ratio >= 0.50`, present the prompt below. Otherwise skip §2.2 silently and continue to §3.
361
+ If `skip_reason` is non-null OR `should_trigger` is false, skip the prompt and continue to §3. If `should_trigger` is true, present the prompt below.
280
362
 
281
363
  **Prompt:**
282
364
 
@@ -296,7 +378,7 @@ The upstream surface appears to have been substantially replaced. The brief's
296
378
  [A] Audit — halt and run skf-audit-skill to map the new surface, then re-run update-skill
297
379
  ```
298
380
 
299
- **Headless mode (`{headless_mode}` is true):** auto-select `[C] Continue`, log a WARN-level entry to the evidence report (`scope_reconciliation_post: {trigger: "deletion-ratio", ratio: X, decision: "headless-continue"}`), and surface the warning in step-07's report. A non-interactive run must not silently halt, but the user must be able to see the signal post-hoc.
381
+ **Headless mode (`{headless_mode}` is true):** auto-select `[C] Continue`, log a WARN-level entry to the evidence report (`scope_reconciliation_post: {trigger: "deletion-ratio", ratio: X, decision: "headless-continue"}`), and surface the warning in step 7's report. A non-interactive run must not silently halt, but the user must be able to see the signal post-hoc. **Also append to in-context `headless_decisions[]`** (surfaced via `SKF_UPDATE_RESULT_JSON` by step 7): `{gate: "detect-changes.deletion-ratio", default_action: "C", taken_action: "C", reason: "headless: deletion-ratio threshold exceeded but no user to halt", evidence: {deletion_ratio: <ratio>, deleted_export_count: <N>, total_provenance_exports: <T>}}`.
300
382
 
301
383
  **Apply decision:**
302
384
 
@@ -308,30 +390,51 @@ The upstream surface appears to have been substantially replaced. The brief's
308
390
 
309
391
  ### 3. Build Change Manifest
310
392
 
311
- Compile the change manifest with structured entries:
393
+ Hand the assembled Category A/B/C/D JSON to the helper:
312
394
 
395
+ ```bash
396
+ echo "{category JSON}" | uv run {buildChangeManifestHelper} build
313
397
  ```
314
- Change Manifest:
315
- files_changed: [count]
316
- files_added: [count]
317
- files_deleted: [count]
318
- files_moved: [count]
319
-
320
- exports_modified: [count]
321
- exports_new: [count]
322
- exports_deleted: [count]
323
- exports_renamed: [count]
324
- exports_moved: [count]
325
-
326
- scripts_modified, scripts_added, scripts_deleted: {counts}
327
- assets_modified, assets_added, assets_deleted: {counts}
328
-
329
- Per-file detail:
330
- {file_path}:
331
- status: MODIFIED|ADDED|DELETED|MOVED
332
- exports_affected: [{export_name, change_type, old_line, new_line}]
398
+
399
+ The category JSON shape is:
400
+
401
+ ```json
402
+ {
403
+ "category_a": {"modified": [...], "added": [...], "deleted": [...]},
404
+ "category_b": {"modified_exports": [...], "new_exports": [...],
405
+ "deleted_exports": [...], "moved_exports": [...]},
406
+ "category_c": {"renamed_files": [...], "renamed_exports": [...]},
407
+ "category_d": {"scripts_modified": [...], "scripts_added": [...],
408
+ "scripts_deleted": [...], "assets_modified": [...],
409
+ "assets_added": [...], "assets_deleted": [...]},
410
+ "degraded_mode": <bool>,
411
+ "update_mode": "normal" | "gap-driven"
412
+ }
413
+ ```
414
+
415
+ The helper emits the unified manifest envelope:
416
+
417
+ ```json
418
+ {
419
+ "no_changes": <bool>,
420
+ "degraded_mode": <bool>,
421
+ "counts": {
422
+ "files_changed": N, "files_added": N, "files_deleted": N, "files_moved": N,
423
+ "exports_modified": N, "exports_new": N, "exports_deleted": N,
424
+ "exports_renamed": N, "exports_moved": N,
425
+ "scripts_modified": N, "scripts_added": N, "scripts_deleted": N,
426
+ "assets_modified": N, "assets_added": N, "assets_deleted": N
427
+ },
428
+ "total_export_changes": N,
429
+ "per_file": [
430
+ {"file_path": "...", "status": "MODIFIED|ADDED|DELETED|MOVED",
431
+ "exports_affected": [{name, change_type, old_line, new_line}, ...]}
432
+ ]
433
+ }
333
434
  ```
334
435
 
436
+ `per_file` entries are sorted MODIFIED → ADDED → DELETED → MOVED, then alphabetically within each status group, so downstream stages can rely on stable ordering. MOVED entries include an extra `old_path` field. Stash the envelope as the change manifest in workflow context.
437
+
335
438
  ### 4. Check for No-Change Shortcut
336
439
 
337
440
  **If zero changes detected across all categories:**
@@ -364,15 +467,20 @@ Display: "**Proceeding to re-extraction...**"
364
467
 
365
468
  #### Menu Handling Logic:
366
469
 
367
- - After change manifest is built, immediately load, read entire file, then execute {nextStepFile}
368
- - **EXCEPTION:** If no changes detected (section 4), load {noChangeReportFile} instead
470
+ - **If `detect_only_mode` is true:** display "**Detect-only mode — skipping re-extract/merge/validate/write.** Loading report..." and load `{noChangeReportFile}` (report.md). The report handles the detect-only envelope. Do NOT load `{nextStepFile}`.
471
+ - Else, after change manifest is built, immediately load, read entire file, then execute `{nextStepFile}`.
472
+ - **EXCEPTION:** If no changes detected (section 4), load `{noChangeReportFile}` instead.
369
473
 
370
474
  #### EXECUTION RULES:
371
475
 
372
476
  - This is an auto-proceed step with no user choices
373
- - Proceed directly to next step after change detection completes
477
+ - Proceed directly to next step after change detection completes (or to report when `detect_only_mode` is true)
374
478
 
375
479
  ## CRITICAL STEP COMPLETION NOTE
376
480
 
377
- ONLY WHEN the change manifest is fully built will you load {nextStepFile} to begin re-extraction. If no changes detected, skip to {noChangeReportFile}.
481
+ ONLY WHEN the change manifest is fully built will you load the next file:
482
+
483
+ - `detect_only_mode == true` → load `{noChangeReportFile}` (report.md). Report emits status `detect-only`.
484
+ - No changes detected → load `{noChangeReportFile}` (report.md). Report emits status `no-changes`.
485
+ - Otherwise → load `{nextStepFile}` (re-extract.md) to begin re-extraction.
378
486
 
@@ -0,0 +1,32 @@
1
+ ---
2
+ # `shared/health-check.md` resolves relative to the SKF module root
3
+ # (`_bmad/skf/` when installed, `src/` during development), NOT relative
4
+ # to this step file.
5
+ nextStepFile: 'shared/health-check.md'
6
+ ---
7
+
8
+ <!-- Config: communicate in {communication_language}. -->
9
+
10
+ # Step 8: Workflow Health Check
11
+
12
+ ## STEP GOAL:
13
+
14
+ Chain to the shared workflow self-improvement health check at `{nextStepFile}`. This is the terminal step of update-skill — after the shared health check completes, the workflow is fully done.
15
+
16
+ ## Rules
17
+
18
+ - No user-facing reports, file writes, or result contracts in this step — those belong in step 7
19
+ - Delegate directly to `{nextStepFile}` with no additional commentary
20
+ - Do not attempt any other action between loading this step and executing `{nextStepFile}` (other than the lock release below)
21
+
22
+ ## MANDATORY SEQUENCE
23
+
24
+ 1. **Release the concurrency lock** acquired by init.md §1b (skip when `detect_only_mode` or `dry_run_mode` is true — those modes never acquired one):
25
+
26
+ ```bash
27
+ rm -f "{forge_data_folder}/{skill_name}/.skf-update.lock"
28
+ ```
29
+
30
+ The lock release MUST run before delegating to the shared health-check, since the health-check is the terminal step — once it returns, the workflow is done and any held lock becomes orphaned for the next run to clean up. Releasing here keeps the lock lifecycle tight against the workflow's actual span.
31
+
32
+ 2. Load `{nextStepFile}`, read it fully, then execute it.