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
@@ -28,7 +28,7 @@ Perform tier-aware extraction on only the changed files identified in step 02, p
28
28
  - Only extract files in the change manifest — do not touch unchanged files. **Exception (gap-driven mode):** §0a's Targeted Re-Extraction Branch also scans files listed in each manifest entry's `remediation_paths[]` to resolve citation-less Critical/High gaps.
29
29
  - For each changed file, launch a subprocess for deep AST analysis (Pattern 2); if unavailable, extract sequentially
30
30
 
31
- ## MANDATORY SEQUENCE
31
+ ## Steps
32
32
 
33
33
  ### 0. Check for Gap-Driven Mode
34
34
 
@@ -45,7 +45,7 @@ uv run {checkWorkspaceDriftHelper} <source-root> \
45
45
  [--allow-drift]
46
46
  ```
47
47
 
48
- Pass `--allow-drift` only when the user provided `--allow-workspace-drift` to update-skill. The helper accepts `""` and `"local"` as the "no pinned commit" sentinels; it also auto-skips when `source_root` is not a git working tree (bare checkout, tarball extract, etc.). **For per-repo pinned-commit maps (stack skills with no single commit):** the caller must skip the helper entirely — pass nothing and log `workspace_drift_check: skipped (no pinned commit)` directly.
48
+ Pass `--allow-drift` only when the user provided `--allow-workspace-drift` to update-skill. The helper accepts `""` and `"local"` as the "no pinned commit" sentinels; it also auto-skips when `source_root` is not a git working tree (bare checkout, tarball extract, etc.).
49
49
 
50
50
  The helper emits a result envelope:
51
51
 
@@ -63,7 +63,7 @@ The helper emits a result envelope:
63
63
 
64
64
  - **`ok` or `skipped`** (helper exit 0): log `log_message` and continue to bullet 1.
65
65
  - **`overridden`** (helper exit 0): log `log_message`, surface a visible warning in the final report ("**Workspace drift accepted via --allow-workspace-drift** — spot-checks read HEAD {head_short_sha}, not pinned {pinned_commit}"), and continue to bullet 1. The override does not automatically re-pin `metadata.source_commit`; re-pinning is explicit user work (run the normal-mode update-skill flow against the same HEAD, or re-create the skill).
66
- - **`mismatch`** (helper exit 2): HALT immediately with exit status `halted-for-workspace-drift`. Display the helper's `halt_message` verbatim — it already substitutes `{pinned_commit}`, `{source_ref or "unset"}`, `{source_root}`, `{head_sha}`, and the suggested `git checkout` command. Do not proceed to bullet 1. Step-04 merge has not run; no partial writes.
66
+ - **`mismatch`** (helper exit 2): HALT immediately with status `halted-for-workspace-drift`. Display the helper's `halt_message` verbatim — it already substitutes `{pinned_commit}`, `{source_ref or "unset"}`, `{source_root}`, `{head_sha}`, and the suggested `git checkout` command. Do not proceed to bullet 1. Step-04 merge has not run; no partial writes. In `{headless_mode}`, emit the halt envelope per SKILL.md §Headless (`error: {phase: "re-extract:workspace-drift", path: "{source_root}", reason: "..."}`).
67
67
 
68
68
  1. Use the provenance map already loaded in step 1 (at `{forge_version}/provenance-map.json`) — do not re-read
69
69
  2. **Partition by change category, then iterate the export-bearing entries.** Entries that do not name an export skip the per-export verification below — they have no symbol to resolve against source:
@@ -173,7 +173,7 @@ The helper emits a result envelope:
173
173
  c) Downgrade the gap(s) to Medium/Low/Info (accepts the degraded documentation outcome).
174
174
  ```
175
175
 
176
- Exit with status `halted-for-remediation-path`. Step-04 merge has not run; no partial writes.
176
+ Exit with status `halted-for-remediation-path`. Step-04 merge has not run; no partial writes. In `{headless_mode}`, emit the halt envelope per SKILL.md §Headless (`error: {phase: "re-extract:targeted-reextraction", reason: "..."}`).
177
177
 
178
178
  6. **Success summary** — record `targeted_reextraction: {resolved_count, files_scanned, exports_matched, tier}` in workflow context. The evidence report (step 6 §4) surfaces this alongside the verified / moved / missing tally.
179
179
 
@@ -223,7 +223,7 @@ The helper emits a result envelope:
223
223
 
224
224
  **Forge tier (AST structural extraction):**
225
225
 
226
- ⚠️ **CRITICAL:** Load and follow the **AST Extraction Protocol** from `{extractionPatternsData}`. Use the decision tree based on the number of changed files: prefer MCP `find_code()` for small sets, `find_code_by_rule()` with scoped YAML rules for medium sets, and CLI `--json=stream` with line-by-line streaming for large sets. Never use `ast-grep --json` (without `=stream`) — it loads the entire result set into memory and will fail on large codebases.
226
+ Load and follow the **AST Extraction Protocol** from `{extractionPatternsData}`. Use the decision tree based on the number of changed files: prefer MCP `find_code()` for small sets, `find_code_by_rule()` with scoped YAML rules for medium sets, and CLI `--json=stream` with line-by-line streaming for large sets. Never use `ast-grep --json` (without `=stream`) — it loads the entire result set into memory and will fail on large codebases.
227
227
 
228
228
  - Extract: function signatures, type definitions, class members, exported constants
229
229
  - Extract: parameter types, return types, JSDoc/docstring comments
@@ -243,18 +243,26 @@ The helper emits a result envelope:
243
243
 
244
244
  **Skip authoritative doc paths.** Before iterating the change manifest, build a skip set from `promoted_docs_new[]` (populated by step 2 §1b) and any existing `file_entries[]` entries with `file_type: "doc"` from the provenance map. These are documentation files tracked for drift detection only — they must not reach AST extraction, which would produce ghost entries on non-code content. If a change manifest entry matches the skip set, skip it silently and continue; doc-type drift is handled by step 2 Category D and step 4 Priority 6/7.
245
245
 
246
- DO NOT BE LAZY — For EACH remaining file in the change manifest with status MODIFIED, ADDED, or RENAMED, launch a subprocess that:
246
+ For each remaining file in the change manifest with status MODIFIED, ADDED, or RENAMED, launch a subprocess that:
247
247
 
248
248
  1. Loads the source file
249
249
  2. Performs tier-appropriate extraction (Quick/Forge/Forge+/Deep)
250
- 3. For each export found:
251
- - Record: export name, type (function/class/type/constant), signature
252
- - Record: file path, start line, end line
253
- - Record: parameters with types (if function/method)
254
- - Record: return type (if function/method)
255
- - Record: JSDoc/docstring summary (if present)
256
- - Label: confidence tier (T1/T1-low/T2)
257
- 4. Returns structured extraction findings to parent
250
+ 3. Extract each export into the per-file return contract shown in bullet 4.
251
+ 4. **Return contract.** Each extraction worker returns ONLY this per-file block no prose, no commentary, no markdown fences (the parent strips wrapping fences before parsing). The shape is exactly the per-file record §4 aggregates (the `Per-file extractions` block, lines below), so the parent appends it verbatim rather than re-parsing free text:
252
+
253
+ ```json
254
+ {
255
+ "file_path": "...",
256
+ "exports": [
257
+ {"name": "...", "type": "function|class|type|constant",
258
+ "signature": "...", "location": "{file}:{start_line}-{end_line}",
259
+ "confidence": "T1|T1-low|T2",
260
+ "parameters": [{"name": "...", "type": "..."}],
261
+ "return_type": "...", "docstring": "...",
262
+ "qmd_evidence": "<if Deep tier, else omit>"}
263
+ ]
264
+ }
265
+ ```
258
266
 
259
267
  **For DELETED files:** No extraction needed — deletions handled in merge step.
260
268
 
@@ -277,7 +285,7 @@ This helps the merge step (section 4) prioritize which changes are most likely t
277
285
 
278
286
  CCC failures: skip ranking silently, all changes treated equally.
279
287
 
280
- **Note on remote sources:** If `source_root` is a workspace clone, the CCC index may already exist from a prior forge and can be reused via `ccc search --refresh`. If the source is an ephemeral fallback clone, the clone path is not indexed by CCC — the search will return empty results and semantic ranking will be skipped. Deferred CCC indexing is implemented in create-skill step 3 but not in update-skill. All changes are treated equally for ephemeral remote sources.
288
+ **Note on remote sources:** If `source_root` is a workspace clone, the CCC index may already exist from a prior forge and can be reused via `ccc search --refresh`. If the source is an ephemeral fallback clone, the clone path is not indexed by CCC — the search returns empty results, so semantic ranking is skipped and all changes are treated equally.
281
289
 
282
290
  **IF `tools.ccc` is false:** Skip this section silently.
283
291
 
@@ -342,16 +350,10 @@ Extraction Results:
342
350
 
343
351
  **Proceeding to merge with existing skill...**"
344
352
 
345
- ### 6. Present MENU OPTIONS
346
-
347
- - **If `dry_run_mode` is true:** display "**Dry-run mode — skipping merge/validate/write.** Loading report..." and load `report.md` (NOT `{nextStepFile}`). The report emits the dry-run envelope describing what merge+write WOULD have done.
348
- - Else, display "**Proceeding to merge...**" and after extraction results are compiled, immediately load, read entire file, then execute `{nextStepFile}`.
349
- - This is an auto-proceed step with no user choices.
350
-
351
- ## CRITICAL STEP COMPLETION NOTE
353
+ ### 6. Route to Next Step
352
354
 
353
- ONLY WHEN all changed files have been extracted and results compiled will you load the next file:
355
+ This step auto-proceeds — no user choices. Once all changed files are extracted and results compiled, load and fully read the next file, then execute it, per the branch that applies:
354
356
 
355
- - `dry_run_mode == true` → load `report.md`. Report emits status `dry-run`. No artifact is modified on disk by this run.
356
- - Otherwise → load `{nextStepFile}` (merge.md) to begin the merge operation.
357
+ - **`dry_run_mode == true`**display "**Dry-run mode — skipping merge/validate/write.** Loading report..." and load `report.md` (NOT `{nextStepFile}`); it emits status `dry-run` describing what merge+write would have done. No artifact is modified on disk by this run.
358
+ - **Otherwise**display "**Proceeding to merge...**" and load `{nextStepFile}` (merge.md) to begin the merge operation.
357
359
 
@@ -16,7 +16,7 @@ Present a comprehensive change summary showing what was updated, [MANUAL] sectio
16
16
  - Present clear, actionable summary with next step recommendations
17
17
  - Chains to the local health-check step via `{nextStepFile}` after completion — the user-facing summary is NOT the terminal step
18
18
 
19
- ## MANDATORY SEQUENCE
19
+ ## Steps
20
20
 
21
21
  ### 1. Handle No-Change Shortcut
22
22
 
@@ -89,7 +89,7 @@ The headless envelope carries `status: "dry-run"`, `files_written: []`, the `hea
89
89
 
90
90
  | Metric | Value |
91
91
  |--------|-------|
92
- | **Skill** | {skill_name} ({single/stack}) |
92
+ | **Skill** | {skill_name} |
93
93
  | **Forge Tier** | {tier} |
94
94
  | **Mode** | {update_mode}{mode_fallback_note} |
95
95
  | **Duration** | {step count} steps |
@@ -169,7 +169,6 @@ These signals also appear in `warnings[]` on the headless envelope; the Mode row
169
169
  | `{resolved_skill_package}/metadata.json` | Updated |
170
170
  | `{forge_version}/provenance-map.json` | Updated |
171
171
  | `{forge_version}/evidence-report.md` | Appended |
172
- | {stack reference files if applicable} | Updated |
173
172
 
174
173
  Where `{resolved_skill_package}` = `{skills_output_folder}/{skill_name}/{version}/{skill_name}/` and `{forge_version}` = `{forge_data_folder}/{skill_name}/{version}/` — see `knowledge/version-paths.md`."
175
174
 
@@ -199,16 +198,24 @@ Write the result contract per `shared/references/output-contract-schema.md`: the
199
198
  **Headless envelope (`SKF_UPDATE_RESULT_JSON`):** when `{headless_mode}` is true, ALSO emit a single-line JSON envelope to stdout prefixed with the literal `SKF_UPDATE_RESULT_JSON: `. Schema: `src/shared/scripts/schemas/skf-update-result-envelope.v1.json`. Construct the envelope from in-context state:
200
199
 
201
200
  ```json
202
- SKF_UPDATE_RESULT_JSON: {"skf_update":{"status":"success|no-changes|halted-for-*|blocked","skill_name":"<name>","version":"<v>","previous_version":"<v>","update_mode":"normal|gap-driven|degraded","files_written":[...],"headless_decisions":[...],"warnings":[...],"error":null|{...}}}
201
+ SKF_UPDATE_RESULT_JSON: {"skf_update":{"status":"success|no-changes|detect-only|dry-run|halted-for-*|blocked","skill_name":"<name>","version":"<v>","previous_version":"<v>","update_mode":"normal|gap-driven|degraded","files_written":[...],"headless_decisions":[...],"warnings":[...],"error":null|{...}}}
203
202
  ```
204
203
 
205
- - `headless_decisions[]` — verbatim from the in-context array populated by gates (init.md §confirmation, detect-changes.md §1b/§1c/§2.2, merge.md §gate). Each entry `{gate, default_action, taken_action, reason, evidence?}`. Empty when no gates auto-resolved (e.g. no-changes path skipped detect-changes' gates).
206
- - `status` — single-field outcome for pipeline branching. `"success"` when the run wrote artifacts and produced no halts; `"no-changes"` when §1 short-circuited; one of the documented `halted-for-*` codes when a halt fired; `"blocked"` as the catch-all.
204
+ - `headless_decisions[]` — verbatim from the in-context array populated by gates (init.md §confirmation and §4 degraded-rebuild, detect-changes.md §1b/§1c/§2.2, merge.md §gate). Each entry `{gate, default_action, taken_action, reason, evidence?}`. Empty when no gates auto-resolved (e.g. no-changes path skipped detect-changes' gates).
205
+ - `status` — single-field outcome for pipeline branching. `"success"` when the run wrote artifacts and produced no halts; `"no-changes"` when §1 short-circuited; `"detect-only"` / `"dry-run"` for the §1a/§1b read-only exits; one of the documented `halted-for-*` codes when a halt fired; `"blocked"` as the catch-all. The full enum lives in the schema (this step emits the value already resolved in context).
207
206
  - `error` — null on success or no-changes. Object `{phase, path?, reason}` describing the failure when a halt or write error fired. Pipelines branch on `error !== null` for non-zero exit semantics.
208
207
 
209
208
  The headless envelope is the structured channel; the per-run JSON written above is the audit trail. Both coexist — the envelope is one line on stdout for grep-friendly consumption, the per-run JSON is the full record on disk.
210
209
 
210
+ **Post-finalization hook.** If `{onCompleteCommand}` (resolved in SKILL.md On Activation §3 from `workflow.on_complete`) is non-empty, invoke it after both result-JSON writes complete:
211
+
212
+ ```bash
213
+ {onCompleteCommand} --result-path={forge_version}/update-skill-result-latest.json
214
+ ```
215
+
216
+ Run it with a bounded timeout (default 60s). On success, log an Info note and continue; on non-zero exit, timeout, or any failure, append the reason to `warnings[]` (surfaced on the headless envelope) and continue. The hook must never fail the workflow — it is integration glue (notify a CI router, chain audit/export/test) orthogonal to the update outcome. Empty `{onCompleteCommand}` = no-op, no log entry.
217
+
211
218
  ### 6. Chain to Health Check
212
219
 
213
- ONLY WHEN the change summary has been presented, files-written list displayed, and result contract saved will you then load, read the full file, and execute `{nextStepFile}`. The health-check step is the true terminal step — do not stop here even though the report reads as final.
220
+ Once the change summary has been presented, the files-written list displayed, and the result contract saved, load, read the full file, and execute `{nextStepFile}`. The health-check step is the true terminal step — do not stop at the report even though it reads as final.
214
221
 
@@ -1,5 +1,13 @@
1
1
  ---
2
2
  nextStepFile: 'write.md'
3
+ # Resolve `{hashContentHelper}` to the first existing path; HALT if neither
4
+ # candidate exists. Check B uses its `manual-verify` subcommand to verify the
5
+ # merged (on-disk) SKILL.md against the byte-exact [MANUAL] inventory captured
6
+ # in step 1 §5 — the deterministic replacement for the LLM byte-identity
7
+ # eyeball, which could silently pass a subtly truncated block.
8
+ hashContentProbeOrder:
9
+ - '{project-root}/_bmad/skf/shared/scripts/skf-hash-content.py'
10
+ - '{project-root}/src/shared/scripts/skf-hash-content.py'
3
11
  ---
4
12
 
5
13
  <!-- Config: communicate in {communication_language}. -->
@@ -14,9 +22,9 @@ Validate the merged skill content against the agentskills.io specification, veri
14
22
 
15
23
  - Focus only on validation — do not fix issues (that's the user's choice)
16
24
  - Validation is read-only — do not modify merged content
17
- - Use parallel validation checks (Pattern 4) when available; if unavailable, check sequentially
25
+ - Run the two live structural checks (B, then C) in order; Checks A, D, E, F are deferred to step 6
18
26
 
19
- ## MANDATORY SEQUENCE
27
+ ## Steps
20
28
 
21
29
  ### 1. Check Tool Availability and Validation Timing
22
30
 
@@ -27,30 +35,40 @@ Run: `npx skill-check -h`
27
35
 
28
36
  **Important:** Do not assume availability — empirical check required.
29
37
 
30
- **Validation timing note:** Step-04 section 6b has already written SKILL.md (and stack reference files) to disk. External-tool checks against written files (skill-check Checks A, E, F) still run in **step 6 section 7** to co-locate external-tool validation with post-write verification. Structural checks (B, C, D) run here against the merged content — content on disk is byte-identical to the in-context copy.
38
+ **Validation timing note:** Step-04 section 6b has already written SKILL.md to disk. External-tool checks against written files (skill-check Checks A, E, F) still run in **step 6 section 7** to co-locate external-tool validation with post-write verification. Check D (Provenance Completeness) is deterministic but needs both `metadata.json` and `provenance-map.json` on disk — neither exists yet at this step — so it is deferred to **step 6 section 6a**, which runs it via the completeness helper against the freshly-written artifacts. Structural checks (B, C) run here against the merged content — content on disk is byte-identical to the in-context copy.
31
39
 
32
- ### 2. Launch Parallel Validation Checks
40
+ ### 2. Run Validation Checks
33
41
 
34
- Launch subprocesses in parallel for each validation category, aggregating results when complete:
42
+ Per the §1 timing note, only Check B (a single deterministic `manual-verify` script) and Check C (an in-prompt tier-label consistency check) run live at this step; Checks A, D, E, F are deferred to step 6. Run B then C in order — one script plus one in-prompt comparison have nothing to fan out.
35
43
 
36
44
  **Check A — Spec Compliance (deferred to post-write):**
37
45
 
38
46
  Skill-check requires written files on disk. This check is deferred to step 6 section 7. Perform manual structural check only: verify merged SKILL.md has required sections (exports, usage patterns, conventions), verify export entries have name/type/signature/file:line reference, flag missing sections.
39
47
 
40
48
  **Check B — [MANUAL] Section Integrity:**
41
- - Compare [MANUAL] inventory from step 01 against merged content
42
- - Verify every [MANUAL] block exists in merged result, byte-identical (zero modification)
43
- - Flag any [MANUAL] blocks moved, truncated, or missing
49
+
50
+ Run the deterministic [MANUAL]-integrity verifier against the step-1 §5 inventory — do not eyeball byte-identity (a subtly truncated block reads as intact to the eye):
51
+
52
+ ```bash
53
+ uv run {hashContentHelper} manual-verify {skill_package}/SKILL.md \
54
+ --inventory {manual_inventory}
55
+ ```
56
+
57
+ Read the verdict JSON `{"preserved":[...], "modified":[...], "missing":[...], "moved":[...], "ok":bool}` (the on-disk SKILL.md is byte-identical to the merged in-context copy per the timing note above):
58
+ - `ok == true` → status PASS. `preserved` blocks are byte-identical in place; any `moved` blocks are byte-identical but relocated with their logical parent section (report as informational, not a finding).
59
+ - `modified` non-empty → FAIL: these blocks' byte-exact interiors changed (the truncation a marker-count/eyeball check would miss). List each by name.
60
+ - `missing` non-empty → FAIL: these blocks lost their markers entirely. List each by name.
61
+
62
+ Populate the §3 `manual_integrity` record from this verdict (`sections_verified` = inventory count, `sections_intact` = `len(preserved) + len(moved)`). This check is advisory here (findings inform, do not block); write.md §1 enforces the same `ok` verdict as a HALT gate before any derived artifact is written.
44
63
 
45
64
  **Check C — Confidence Tier Consistency:**
46
65
  - Verify all re-extracted exports have confidence labels (T1/T1-low/T2)
47
66
  - Verify tier labels match forge tier: Quick=T1-low only, Forge=T1 (T1-low for degraded), Forge+=T1 (same as Forge, CCC improves coverage not confidence), Deep=T1+T2
48
67
  - Flag mismatched or missing tier labels
49
68
 
50
- **Check D — Provenance Completeness:**
51
- - Verify every export has a provenance map entry with valid file:line references
52
- - Verify no stale references to old file paths or line numbers
53
- - Flag orphaned provenance entries (export removed but provenance remains)
69
+ **Check D — Provenance Completeness (deferred to post-write):**
70
+
71
+ The provenance map does not exist on disk until step 6 §3 writes it, and completeness is a deterministic set-diff (metadata `exports[]` vs provenance `entries[].export_name`) plus file:line citation resolution — not something to eyeball. This check is deferred to **step 6 section 6a**, which runs `skf-verify-provenance-completeness.py` against the just-written `metadata.json` and `provenance-map.json` and reads back `missing[]` / `orphaned[]` / `stale[]` findings. Do not attempt the set comparison here — there is no provenance map to compare against yet. The `Provenance` row in §5's summary is populated from §6a's result.
54
72
 
55
73
  **Check E — Diff Comparison (via skill-check):**
56
74
 
@@ -83,16 +101,6 @@ Validation Results:
83
101
  quality_score: [0-100] # from skill-check, if available
84
102
  ```
85
103
 
86
- ### 4. For Stack Skills — Validate Reference Files
87
-
88
- **ONLY if skill_type == "stack":**
89
-
90
- Repeat checks A-D for each reference file:
91
- - `references/{library}.md` — spec compliance and [MANUAL] integrity
92
- - `references/integrations/{pair}.md` — spec compliance and [MANUAL] integrity
93
-
94
- **If skill_type != "stack":** Skip with notice.
95
-
96
104
  ### 5. Display Validation Summary
97
105
 
98
106
  "**Validation Results:**
@@ -110,13 +118,7 @@ Repeat checks A-D for each reference file:
110
118
 
111
119
  **If findings exist:** List each with severity, description, and location. Add: "Validation is advisory. Findings do not block the update."
112
120
 
113
- ### 6. Present MENU OPTIONS
114
-
115
- Display: "**Proceeding to write updated files...**"
116
-
117
- After validation summary is displayed, immediately load, read entire file, then execute {nextStepFile}. This is an auto-proceed step — validation is advisory, not blocking.
118
-
119
- ## CRITICAL STEP COMPLETION NOTE
121
+ ### 6. Route to Next Step
120
122
 
121
- ONLY WHEN all validation checks have completed and findings are displayed will you load {nextStepFile} to write the updated files. Validation does NOT block — it informs.
123
+ This step auto-proceeds — no user choices; validation is advisory and does not block, it only informs. Once all validation checks have completed and findings are displayed, display "**Proceeding to write updated files...**", then load, fully read, and execute `{nextStepFile}` to write the updated files.
122
124
 
@@ -17,6 +17,31 @@ descriptionGuardProbeOrder:
17
17
  updateActiveSymlinkProbeOrder:
18
18
  - '{project-root}/_bmad/skf/shared/scripts/skf-update-active-symlink.py'
19
19
  - '{project-root}/src/shared/scripts/skf-update-active-symlink.py'
20
+ # Resolve `{verifyProvenanceCompletenessHelper}` to the first existing path.
21
+ # §6a runs Check D (Provenance Completeness), deferred from step 5 because it
22
+ # needs both metadata.json + provenance-map.json on disk: the export/provenance
23
+ # set-diff (missing + orphaned entries) and file:line citation resolution.
24
+ # Advisory — do not HALT if neither path resolves; fall back to the in-prose
25
+ # set comparison §6a documents (graceful degradation).
26
+ verifyProvenanceCompletenessProbeOrder:
27
+ - '{project-root}/_bmad/skf/shared/scripts/skf-verify-provenance-completeness.py'
28
+ - '{project-root}/src/shared/scripts/skf-verify-provenance-completeness.py'
29
+ # Resolve `{hashContentHelper}` to the first existing path; HALT if neither
30
+ # candidate exists. §1 uses its `manual-verify` subcommand to verify the
31
+ # post-merge file against the byte-exact [MANUAL] inventory captured in step 1
32
+ # §5; a marker-count comparison would pass a block whose interior was truncated
33
+ # without changing the marker count.
34
+ hashContentProbeOrder:
35
+ - '{project-root}/_bmad/skf/shared/scripts/skf-hash-content.py'
36
+ - '{project-root}/src/shared/scripts/skf-hash-content.py'
37
+ # Resolve `{renderMetadataStatsHelper}` by probing `{renderMetadataStatsProbeOrder}`
38
+ # in order (installed SKF module path first, src/ dev-checkout fallback); first
39
+ # existing path wins. HALT if neither resolves — §2's `stats` block and
40
+ # `confidence_distribution` are computed values that must not be hand-binned,
41
+ # and this is the same helper sibling create-skill compiles them with.
42
+ renderMetadataStatsProbeOrder:
43
+ - '{project-root}/_bmad/skf/shared/scripts/skf-render-metadata-stats.py'
44
+ - '{project-root}/src/shared/scripts/skf-render-metadata-stats.py'
20
45
  ---
21
46
 
22
47
  <!-- Config: communicate in {communication_language}. -->
@@ -25,7 +50,7 @@ updateActiveSymlinkProbeOrder:
25
50
 
26
51
  ## STEP GOAL:
27
52
 
28
- Verify the merged SKILL.md and stack reference files that step 4 section 6b wrote to disk, then write the derived artifacts (metadata.json, provenance-map.json, evidence-report.md, context-snippet.md, and the active symlink).
53
+ Verify the merged SKILL.md that step 4 section 6b wrote to disk, then write the derived artifacts (metadata.json, provenance-map.json, evidence-report.md, context-snippet.md, and the active symlink).
29
54
 
30
55
  ## Rules
31
56
 
@@ -34,7 +59,7 @@ Verify the merged SKILL.md and stack reference files that step 4 section 6b wrot
34
59
  - Do not skip provenance map update — critical for future audits
35
60
  - HALT immediately on verification failure before writing any derived artifact — a partial-write skill package is worse than an unchanged one
36
61
 
37
- ## MANDATORY SEQUENCE
62
+ ## Steps
38
63
 
39
64
  ### 0. Description Guard Protocol
40
65
 
@@ -48,13 +73,19 @@ Update-skill does not run the optional post-restore frontmatter re-validation to
48
73
 
49
74
  SKILL.md was written in step 4 section 6b. Verify the write landed intact before proceeding to any derived-artifact writes.
50
75
 
51
- - Read `{skill_package}/SKILL.md` from disk
52
- - Count `<!-- [MANUAL:*] -->` opening markers and compare against the [MANUAL] inventory captured in step 1
53
76
  - Verify the resolved `{skill_package}` path matches the version directory step 4 wrote to (if the version changed, step 4 updated `{skill_package}` in context to point at the new path)
54
- - If [MANUAL] count matches and path resolves: proceed to section 2
55
- - **If [MANUAL] count does not match: HALT immediately.** Do not write `metadata.json`, `provenance-map.json`, or any other artifact — further writes would compound the inconsistency. Alert the user:
77
+ - Run the deterministic [MANUAL]-integrity verifier against the byte-exact inventory captured in step 1 §5:
56
78
 
57
- "**[MANUAL] section count mismatch after write.** Expected {N} from step 1 inventory, found {M} on disk at `{skill_package}/SKILL.md`. The skill package is in an inconsistent state. Manual recovery required — restore the previous version from `{skill_group}/{previous_version}/` or fix the file in place, then re-run update-skill."
79
+ ```bash
80
+ uv run {hashContentHelper} manual-verify {skill_package}/SKILL.md \
81
+ --inventory {manual_inventory}
82
+ ```
83
+
84
+ The verdict JSON is `{"preserved":[...], "modified":[...], "missing":[...], "moved":[...], "ok":bool}`. A `modified` block is one whose byte-exact interior changed (an interior truncation); a `missing` block lost its markers entirely; a `moved` block is byte-identical but relocated with its logical parent section (clean — does not fail the gate). `ok == (modified empty AND missing empty)`.
85
+ - If `ok == true` and the path resolves: proceed to section 2
86
+ - **If `ok == false`: HALT immediately** with status `halted-for-manual-mismatch`. Do not write `metadata.json`, `provenance-map.json`, or any other artifact — further writes would compound the inconsistency. In `{headless_mode}`, emit the halt envelope per SKILL.md §Headless (`error: {phase: "write:verify-manual-integrity", path: "{skill_package}/SKILL.md", reason: "..."}`). Alert the user:
87
+
88
+ "**[MANUAL] section integrity failure after write.** Blocks modified (interior changed): {modified}. Blocks missing (markers lost): {missing}. Relocated-but-intact (advisory only): {moved}. Verified against the step-1 inventory `{manual_inventory}`, on disk at `{skill_package}/SKILL.md`. The skill package is in an inconsistent state. Manual recovery required — restore the previous version from `{skill_group}/{previous_version}/` or fix the file in place, then re-run update-skill."
58
89
 
59
90
  ### 2. Write Updated metadata.json
60
91
 
@@ -64,22 +95,28 @@ Update `{skill_package}/metadata.json`:
64
95
  - Update `version`: **if `update_mode == "gap-driven"`, do not bump — the skill is being repaired against the same source commit, so leave `version` unchanged and update only `generation_date` / `last_update` below.** This keeps metadata `version` consistent with the on-disk `{skill_package}` path, which step 4 §6b also leaves unchanged in gap-driven mode (see step 4 §6b's "If the source version detected during step 3 differs..." carve-out — in gap-driven mode no source version is detected, so step 4 writes into the existing version directory). Otherwise, if a source version was detected during re-extraction and differs from the current metadata version, use the source version; otherwise increment patch version
65
96
  - Update `generation_date` timestamp to current ISO-8601 date
66
97
  - Update `exports` array to reflect current export list
67
- - Update `stats` from re-extraction results:
68
- - `exports_documented`: count of exports with documentation in the merged skill
98
+ - **Compute the `stats` block and `confidence_distribution` deterministically** with `{renderMetadataStatsHelper}` (resolve from `{renderMetadataStatsProbeOrder}`; first existing path wins) — the same helper sibling create-skill compiles them with, so create and update emit byte-identical stats for identical inputs. The helper owns all the arithmetic: it bins each provenance `entries[]` row once by its `signature_source` tier into `confidence_distribution.{t1,t1_low,t2,t3}`, sets `exports_documented` = the entry count, and derives `exports_total` = `exports_public_api` + `exports_internal`, `public_api_coverage` = documented / public_api (`null` if public_api is 0), `total_coverage` = documented / total (`null` if total is 0), plus `scripts_count` / `assets_count` from the inventory arrays. Run `uv run {renderMetadataStatsHelper} --help` for the full contract. Do not hand-bin the distribution — binning T2 annotations + T3 doc items on top of the per-export tiers double-counts, which per-entry binning by `signature_source` makes structurally impossible. You supply only the judgment payload:
99
+
100
+ **Judgment payload (what you decide — passed as JSON on stdin):**
69
101
  - `exports_public_api`: count of exports from public entry points (`__init__.py`, `index.ts`, `lib.rs`, or equivalent)
70
102
  - `exports_internal`: count of all other non-underscore-prefixed exports
71
- - `exports_total`: `exports_public_api` + `exports_internal`
72
- - `public_api_coverage`: `exports_documented / exports_public_api` (`null` if `exports_public_api` is 0)
73
- - `total_coverage`: `exports_documented / exports_total` (`null` if `exports_total` is 0)
74
- - Update `confidence_distribution` from re-extraction results:
75
- - `confidence_distribution.t1`, `confidence_distribution.t1_low`, `confidence_distribution.t2`, `confidence_distribution.t3`: update counts from re-extraction results
76
- - `scripts_count`, `assets_count`: update from re-extraction results if scripts/assets changed
77
- - For stack skills: update `library_count`, `integration_count` if changed
103
+ - `scripts` / `assets`: the scripts / assets inventory arrays (or `[]` when empty) — the helper sets `scripts_count` / `assets_count` from their lengths
104
+
105
+ **Invoke** since the helper reads `entries[]`, stage §3's `provenance-map.json` write first (§3 does not depend on these stats):
106
+
107
+ ```bash
108
+ echo '{"exports_public_api": {N}, "exports_internal": {M}, "scripts": {scripts-inventory-or-[]}, "assets": {assets-inventory-or-[]}}' \
109
+ | uv run {renderMetadataStatsHelper} {forge_version}/provenance-map.json
110
+ ```
111
+
112
+ Write the returned `stats` and `confidence_distribution` objects into `metadata.json` **verbatim**. If the helper reports `coherence.ok: false`, some provenance entries carry a missing/unrecognized `signature_source` (§3 must write it on every entry) — fix the provenance map, do not hand-edit the stats.
78
113
 
79
114
  ### 3. Write Updated provenance-map.json
80
115
 
81
116
  Write to `{forge_version}/provenance-map.json`:
82
117
 
118
+ **Every entry this step writes or rewrites carries a `signature_source` (`T1` / `T1-low` / `T2` / `T3`)** — the tier that contributed the structural signature, matching create-skill's entry contract. §2's stats helper bins each entry on this field, so a missing value trips its `coherence.ok: false` check. Preserve it byte-identical on untouched entries; set it from the contributing extraction tier on every re-extracted or new entry.
119
+
83
120
  **If `no_reextraction == true` (gap-driven mode from step 3 section 0):**
84
121
  Dispatch per-entry on the verification outcome recorded by step 3 — gap-driven runs produce a mix of `verified`, `moved`, `re-extracted`, and `unknown` outcomes, and each requires a different provenance-map write strategy:
85
122
 
@@ -122,6 +159,8 @@ Dispatch per-entry on the verification outcome recorded by step 3 — gap-driven
122
159
  }
123
160
  ```
124
161
 
162
+ `manual_sections_preserved` = `len(preserved) + len(moved)` from the §1 `manual-verify` verdict (blocks that survived byte-identical, whether in place or relocated). Do not re-count markers by hand — the §1 verdict is the deterministic source.
163
+
125
164
  ### 4. Write Updated evidence-report.md
126
165
 
127
166
  Append update operation section to `{forge_version}/evidence-report.md` (create the file with a standard header if it does not yet exist):
@@ -168,18 +207,9 @@ Append update operation section to `{forge_version}/evidence-report.md` (create
168
207
 
169
208
  **Context Snippet population** (used by §5 after the staleness check runs): §4 writes the sub-block with placeholders; §5 updates the on-disk evidence report in place after deciding whether to regenerate. Set `Regenerated: true` and populate `Triggers fired` with any combination of `headline-exports`, `version`, `gotchas` when at least one trigger fired. Set `Regenerated: false` and `Triggers fired: —` when none fired (the gap-driven / internals-only outcome). Always fill `Notes` with a one-sentence reason (e.g., `"Gap-driven repair — no snippet surface changed"`, `"Version bumped 0.1.0 → 0.2.0; headline exports re-ranked"`).
170
209
 
171
- ### 5. Verify Stack Skill Reference File Writes (Conditional) and Regenerate context-snippet.md
210
+ ### 5. Regenerate context-snippet.md
172
211
 
173
- **ONLY if skill_type == "stack":**
174
-
175
- Stack reference files were written in step 4 section 6b. Verify each affected reference file that the merge produced:
176
-
177
- - Read each `references/{library}.md` back from disk
178
- - Read each `references/integrations/{pair}.md` back from disk
179
- - Verify per-file [MANUAL] section counts match the per-file inventory captured in step 1
180
- - **If any verification fails: HALT** using the same recovery protocol as section 1 — do not regenerate `context-snippet.md` or write any further derived artifact
181
-
182
- **For all skills (both single and stack) — regenerate `context-snippet.md` if stale:**
212
+ **Regenerate `context-snippet.md` if stale:**
183
213
 
184
214
  `context-snippet.md` is a `{skill_package}` deliverable that goes stale whenever **headline exports**, **version**, or **gotchas** change in this run. Regenerate it only when at least one of these triggers fired; otherwise skip — a skip is the correct outcome for gap-driven repairs and other runs that touch internals below the snippet's surface, where regenerating would produce byte-identical content.
185
215
 
@@ -193,10 +223,7 @@ Stack reference files were written in step 4 section 6b. Verify each affected re
193
223
 
194
224
  **If no trigger fired:** skip regeneration — do not touch `context-snippet.md` on disk. The snippet remains valid against the prior run's surface. Continue to §5b.
195
225
 
196
- **If at least one trigger fired:** regenerate the snippet using the format from the matching template file:
197
-
198
- - For single skills: `skf-create-skill/assets/skill-sections.md` (pipe-delimited indexed format)
199
- - For stack skills: `skf-create-stack-skill/assets/stack-skill-template.md`
226
+ **If at least one trigger fired:** regenerate the snippet using the format from `skf-create-skill/assets/skill-sections.md` (pipe-delimited indexed format).
200
227
 
201
228
  Use the **flat draft form** for the `root:` path in the draft snippet: `root: skills/{skill-name}/`. The per-IDE skill root (e.g., `.claude/skills/`, `.windsurf/skills/`, `.github/skills/` — see `skf-export-skill/assets/managed-section-format.md`) is applied later by `export-skill` step 3 when the skill is exported. Do not choose an IDE-specific prefix in update-skill — that is an export-time decision that depends on config.yaml.
202
229
 
@@ -204,8 +231,6 @@ Pull values for the regenerated snippet from the updated metadata.json (version,
204
231
 
205
232
  Write the regenerated snippet to `{skill_package}/context-snippet.md`, preserving file permissions.
206
233
 
207
- **If skill_type == "stack"**, also verify that the reference file updates from the first half of this section have been applied before writing the snippet so the stack snippet reflects the newest integration list.
208
-
209
234
  ### 5b. Update Active Symlink
210
235
 
211
236
  Flip `{skill_group}/active` to point at the current `{version}` via the helper. The call is **always** run — atomic, idempotent, and verified in one shot. The helper's no-op path handles the "version did not change" case (gap-driven mode, or no source drift) without writing to disk:
@@ -225,9 +250,11 @@ The helper emits a result envelope with `status` ∈ `{ok, flipped, mismatch, mi
225
250
  - **`missing-target`** (exit 2): `{skill_group}/{version}/` directory does not exist on disk. HALT — display `halt_message` verbatim. This indicates §4 §6b did not write the version directory before §5b ran (a workflow bug, not a user error).
226
251
  - **`mismatch`** (exit 2): re-read after flip showed the symlink still points elsewhere. HALT — display `halt_message`. Should be impossible because the helper uses `os.replace` (atomic rename); a mismatch here indicates filesystem-level interference (concurrent writer, broken FUSE mount).
227
252
 
253
+ Both exit-2 halts carry status `halted-for-write-failure`; in `{headless_mode}`, emit the halt envelope per SKILL.md §Headless (`error: {phase: "write:active-symlink", reason: "..."}`).
254
+
228
255
  ### 6. Verify Derived Artifact Writes
229
256
 
230
- SKILL.md was verified in section 1 and stack reference files in section 5 (both written by step 4 section 6b). This section verifies the artifacts this step wrote: `metadata.json`, `provenance-map.json`, `evidence-report.md`, `context-snippet.md`, and the `active` symlink from §5b.
257
+ SKILL.md was verified in section 1 (written by step 4 section 6b). This section verifies the artifacts this step wrote: `metadata.json`, `provenance-map.json`, `evidence-report.md`, `context-snippet.md`, and the `active` symlink from §5b.
231
258
 
232
259
  For each derived artifact:
233
260
  - Read back the file
@@ -246,12 +273,33 @@ For each derived artifact:
246
273
  | evidence-report.md | {VERIFIED/FAILED} |
247
274
  | context-snippet.md | {VERIFIED/FAILED} |
248
275
  | {skill_group}/active symlink | {VERIFIED/FAILED} (readlink → {resolved_version}, expected {version}) |
249
- | {stack reference files...} | {VERIFIED in section 5} |
250
276
 
251
- **On symlink `mismatch` (helper exit 2):** HALT. Do not proceed to §7 post-write validation or §8 menu. Display the helper's `halt_message` verbatim — it already includes the diverged target, the expected version, and the recovery command. This matches the severity of the other four artifact checks — silent divergence here mis-routes any downstream consumer that uses the symlink fallback.
277
+ **On symlink `mismatch` (helper exit 2):** HALT with status `halted-for-write-failure`. Do not proceed to §7 post-write validation or §8 menu. Display the helper's `halt_message` verbatim — it already includes the diverged target, the expected version, and the recovery command; in `{headless_mode}`, emit the halt envelope per SKILL.md §Headless (`error: {phase: "write:verify-active-symlink", reason: "..."}`). This matches the severity of the other four artifact checks — silent divergence here mis-routes any downstream consumer that uses the symlink fallback.
252
278
 
253
279
  **All files written and verified.**"
254
280
 
281
+ ### 6a. Provenance Completeness (Check D — Deferred from Step 05)
282
+
283
+ `validate.md` Check D (Provenance Completeness) is a deterministic set-diff plus citation resolution, and it needs both `metadata.json` (written in §2) and `provenance-map.json` (written in §3) on disk — neither exists at validate time, so the check is deferred here. Run it against the just-written artifacts via `{verifyProvenanceCompletenessHelper}`:
284
+
285
+ ```bash
286
+ uv run {verifyProvenanceCompletenessHelper} verify \
287
+ --metadata {skill_package}/metadata.json \
288
+ --provenance {forge_version}/provenance-map.json \
289
+ --source-root {source_root}
290
+ ```
291
+
292
+ The helper reads its `--source-root` (falling back to the provenance map's own `source_root` field when the flag is omitted); pass the resolved `{source_root}` so citation resolution runs against the same tree re-extraction read. **Read the emitted JSON — do NOT recompute the set operations by eye; an LLM set-diff can silently pass a dropped or orphaned entry:**
293
+
294
+ - `missing[]` — documented exports (metadata `exports[]`) with no provenance entry: a coverage gap.
295
+ - `orphaned[]` — provenance `entries[].export_name` whose export was removed but the entry remains.
296
+ - `stale[]` — entries whose `source_file:source_line` no longer resolves; each carries a `reason` of `file-missing`, `line-out-of-bounds`, or `line-invalid`. Internal names are canonicalized through `reexport_map` before the diff, so a barrel-renamed export does not read as missing or orphaned.
297
+ - `summary.stale_check` — `"checked"` when citations were resolved against the source tree, or `"skipped-no-source-root"` when no source root resolved on disk (the completeness + orphan diffs still ran; `stale` is empty by construction, not clean-by-verification).
298
+
299
+ Map `status` to the `Provenance:` line of the §4 evidence report's Validation Summary: `PASS` when `status == "pass"`, `WARN` when `status == "findings"` (this is the persistent record — step 5 §5's table was rendered before the provenance map existed, so it necessarily showed this row as deferred). Provenance findings are **advisory** — they do not block the update. Surface each `missing` / `orphaned` / `stale` entry in the evidence report's Validation Summary so the user can decide, and note when `stale_check` was `skipped-no-source-root`.
300
+
301
+ **Graceful degradation:** if neither probe path resolves (no `uv` / script available), fall back to the manual set comparison the script encapsulates — enumerate metadata `exports[]` and provenance `entries[].export_name` (canonicalizing internal names through `reexport_map`), diff the two sets for missing/orphaned entries, and spot-check that each `source_file:source_line` still points at a real line in the source tree. Prefer the script — it does this deterministically.
302
+
255
303
  ### 7. Run Post-Write Validation (Deferred from Step 05)
256
304
 
257
305
  External tool checks deferred from step 5 now run against the written files.
@@ -284,20 +332,7 @@ Record findings in the evidence report (section 4), including any `description_g
284
332
 
285
333
  **If skill-check unavailable:** Skip with note — structural checks from step 5 are sufficient.
286
334
 
287
- ### 8. Present MENU OPTIONS
288
-
289
- Display: "**Proceeding to report...**"
290
-
291
- #### Menu Handling Logic:
292
-
293
- - After all writes verified and post-write validation complete, immediately load, read entire file, then execute {nextStepFile}
294
-
295
- #### EXECUTION RULES:
296
-
297
- - This is an auto-proceed step with no user choices
298
- - Proceed directly to report after verification
299
-
300
- ## CRITICAL STEP COMPLETION NOTE
335
+ ### 8. Route to Next Step
301
336
 
302
- ONLY WHEN all files have been written and verified will you load {nextStepFile} to display the change report.
337
+ This step auto-proceeds — no user choices. Once all files have been written and verified and post-write validation is complete, display "**Proceeding to report...**", then load, fully read, and execute `{nextStepFile}` to display the change report.
303
338