bmad-module-skill-forge 2.2.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (435) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +49 -49
  3. package/docs/404.md +10 -8
  4. package/docs/_data/pinned.yaml +22 -13
  5. package/docs/_internal/STABILITY.md +58 -35
  6. package/docs/agents.md +39 -53
  7. package/docs/architecture.md +65 -51
  8. package/docs/bmad-synergy.md +53 -51
  9. package/docs/campaign.md +127 -75
  10. package/docs/concepts.md +34 -28
  11. package/docs/examples.md +70 -68
  12. package/docs/forge-auto.md +34 -31
  13. package/docs/getting-started.md +118 -57
  14. package/docs/how-it-works.md +25 -21
  15. package/docs/index.md +15 -15
  16. package/docs/skill-model.md +70 -59
  17. package/docs/troubleshooting.md +135 -18
  18. package/docs/verifying-a-skill.md +83 -57
  19. package/docs/why-skf.md +24 -22
  20. package/docs/workflows.md +274 -110
  21. package/package.json +18 -10
  22. package/src/forger/preferences.yaml +8 -1
  23. package/src/knowledge/agentskills-spec.md +2 -0
  24. package/src/knowledge/ccc-bridge.md +40 -24
  25. package/src/knowledge/confidence-tiers.md +9 -5
  26. package/src/knowledge/overview.md +3 -3
  27. package/src/knowledge/progressive-capability.md +8 -8
  28. package/src/knowledge/provenance-tracking.md +9 -5
  29. package/src/knowledge/qmd-registry.md +2 -2
  30. package/src/knowledge/skf-knowledge-index.csv +2 -2
  31. package/src/knowledge/skill-lifecycle.md +18 -11
  32. package/src/knowledge/split-body-strategy.md +0 -3
  33. package/src/knowledge/tool-resolution.md +4 -2
  34. package/src/knowledge/version-paths.md +101 -15
  35. package/src/module-help.csv +3 -3
  36. package/src/module.yaml +10 -0
  37. package/src/shared/data/ast-grep-recipes.yaml +608 -0
  38. package/src/shared/data/ide-context-files.json +30 -0
  39. package/src/shared/health-check.md +32 -12
  40. package/src/shared/references/description-guard-protocol.md +12 -9
  41. package/src/shared/references/feasibility-report-schema.md +19 -13
  42. package/src/shared/references/headless-gate-convention.md +55 -3
  43. package/src/shared/references/output-contract-schema.md +19 -8
  44. package/src/shared/references/pipeline-contracts.md +94 -29
  45. package/src/shared/references/tessl-review.md +77 -0
  46. package/src/shared/scripts/schemas/skf-analyze-result-envelope.v1.json +194 -0
  47. package/src/shared/scripts/schemas/skf-audit-result-envelope.v1.json +192 -0
  48. package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +32 -4
  49. package/src/shared/scripts/schemas/skf-campaign-result-envelope.v1.json +174 -0
  50. package/src/shared/scripts/schemas/skf-create-skill-result-envelope.v1.json +284 -0
  51. package/src/shared/scripts/schemas/skf-drop-skill-result-envelope.v1.json +164 -0
  52. package/src/shared/scripts/schemas/skf-export-result-envelope.v1.json +160 -0
  53. package/src/shared/scripts/schemas/skf-quick-skill-result-envelope.v1.json +261 -0
  54. package/src/shared/scripts/schemas/skf-refine-architecture-result-envelope.v1.json +192 -0
  55. package/src/shared/scripts/schemas/skf-rename-skill-result-envelope.v1.json +179 -0
  56. package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +27 -11
  57. package/src/shared/scripts/schemas/skf-stack-result-envelope.v1.json +176 -0
  58. package/src/shared/scripts/schemas/skf-test-result-envelope.v1.json +173 -0
  59. package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +19 -5
  60. package/src/shared/scripts/schemas/skf-verify-stack-result-envelope.v1.json +180 -0
  61. package/src/shared/scripts/schemas/skill-brief.v1.json +34 -0
  62. package/src/shared/scripts/schemas/workspace-detection.v1.json +1 -1
  63. package/src/shared/scripts/skf-atomic-write.py +30 -14
  64. package/src/shared/scripts/skf-build-change-manifest.py +2203 -24
  65. package/src/shared/scripts/skf-ccc-git-hygiene.py +532 -0
  66. package/src/shared/scripts/skf-check-unit-records.py +184 -0
  67. package/src/shared/scripts/skf-check-workspace-drift.py +538 -9
  68. package/src/shared/scripts/skf-classify-changed-files.py +694 -0
  69. package/src/shared/scripts/skf-comention-pairs.py +1333 -123
  70. package/src/shared/scripts/skf-compare-file-hashes.py +1 -1
  71. package/src/shared/scripts/skf-count-imports.py +1867 -0
  72. package/src/shared/scripts/skf-count-tokens.py +1 -1
  73. package/src/shared/scripts/skf-derive-assembly-shape.py +3 -2
  74. package/src/shared/scripts/skf-description-guard.py +99 -11
  75. package/src/shared/scripts/skf-detect-docs.py +694 -2
  76. package/src/shared/scripts/skf-detect-language.py +486 -107
  77. package/src/shared/scripts/skf-detect-registry.py +887 -0
  78. package/src/shared/scripts/skf-detect-scripts-assets.py +1 -1
  79. package/src/shared/scripts/skf-detect-tools.py +209 -27
  80. package/src/shared/scripts/skf-detect-workspaces.py +506 -30
  81. package/src/shared/scripts/skf-disqualify-candidates.py +821 -182
  82. package/src/shared/scripts/skf-emit-brief-result-envelope.py +69 -191
  83. package/src/shared/scripts/skf-emit-result-envelope.py +1604 -106
  84. package/src/shared/scripts/skf-enumerate-stack-skills.py +986 -117
  85. package/src/shared/scripts/skf-extract-public-api.py +4084 -85
  86. package/src/shared/scripts/skf-extraction-inventory.py +746 -0
  87. package/src/shared/scripts/skf-extraction-snapshot.py +539 -0
  88. package/src/shared/scripts/skf-fetch-temporal.py +674 -0
  89. package/src/shared/scripts/skf-find-cycles.py +97 -29
  90. package/src/shared/scripts/skf-find-test-report.py +476 -0
  91. package/src/shared/scripts/skf-forge-tier-rw.py +444 -203
  92. package/src/shared/scripts/skf-github-fetch.py +365 -0
  93. package/src/shared/scripts/skf-github-probe.py +661 -0
  94. package/src/shared/scripts/skf-hash-content.py +166 -12
  95. package/src/shared/scripts/skf-language-corpora.py +1 -1
  96. package/src/shared/scripts/skf-load-provenance.py +159 -27
  97. package/src/shared/scripts/skf-manifest-ops.py +1 -1
  98. package/src/shared/scripts/skf-merge-ccc-exclusions.py +2307 -223
  99. package/src/shared/scripts/skf-merge-doc-urls.py +1 -1
  100. package/src/shared/scripts/skf-names-present.py +221 -0
  101. package/src/shared/scripts/skf-pair-intersect.py +119 -28
  102. package/src/shared/scripts/skf-parse-gaps.py +1384 -0
  103. package/src/shared/scripts/skf-preapply.py +1 -1
  104. package/src/shared/scripts/skf-preflight.py +161 -27
  105. package/src/shared/scripts/skf-promote-staged.py +430 -0
  106. package/src/shared/scripts/skf-provenance-gap-dispatch.py +39 -7
  107. package/src/shared/scripts/skf-qmd-classify-collections.py +229 -45
  108. package/src/shared/scripts/skf-quick-batch.py +774 -0
  109. package/src/shared/scripts/skf-rebuild-managed-sections.py +972 -88
  110. package/src/shared/scripts/skf-recommend-scope-type.py +323 -156
  111. package/src/shared/scripts/skf-render-metadata-stats.py +156 -12
  112. package/src/shared/scripts/skf-render-quick-metadata.py +132 -28
  113. package/src/shared/scripts/skf-render-stack-metadata.py +976 -0
  114. package/src/shared/scripts/skf-resolve-authoritative-files.py +128 -13
  115. package/src/shared/scripts/skf-resolve-package.py +523 -106
  116. package/src/shared/scripts/skf-rewrite-skill-name.py +433 -47
  117. package/src/shared/scripts/skf-run-lock.py +577 -0
  118. package/src/shared/scripts/skf-scan-manifests.py +998 -57
  119. package/src/shared/scripts/skf-scan-skill-md-structure.py +1341 -37
  120. package/src/shared/scripts/skf-severity-classify.py +712 -108
  121. package/src/shared/scripts/skf-shape-detect.py +298 -204
  122. package/src/shared/scripts/skf-shard-body.py +9 -8
  123. package/src/shared/scripts/skf-skill-inventory.py +2412 -89
  124. package/src/shared/scripts/skf-skills-module.py +472 -0
  125. package/src/shared/scripts/skf-source-tree.py +1796 -0
  126. package/src/shared/scripts/skf-structural-diff.py +670 -119
  127. package/src/shared/scripts/skf-tessl-review.py +706 -0
  128. package/src/shared/scripts/skf-update-active-symlink.py +5 -5
  129. package/src/shared/scripts/skf-update-run-state.py +624 -0
  130. package/src/shared/scripts/skf-validate-brief-inputs.py +92 -29
  131. package/src/shared/scripts/skf-validate-brief-schema.py +4 -1
  132. package/src/shared/scripts/skf-validate-feasibility-report.py +577 -66
  133. package/src/shared/scripts/skf-validate-frontmatter.py +103 -26
  134. package/src/shared/scripts/skf-validate-output.py +712 -64
  135. package/src/shared/scripts/skf-validate-pins.py +1 -1
  136. package/src/shared/scripts/skf-verify-no-trace.py +116 -10
  137. package/src/shared/scripts/skf-verify-provenance-completeness.py +2919 -54
  138. package/src/shared/scripts/skf-write-skill-brief.py +367 -19
  139. package/src/shared/tool-requirements.yaml +201 -0
  140. package/src/skf-analyze-source/SKILL.md +41 -36
  141. package/src/skf-analyze-source/assets/skill-brief-schema.md +7 -8
  142. package/src/skf-analyze-source/customize.toml +36 -24
  143. package/src/skf-analyze-source/references/auto-docs-only.md +58 -20
  144. package/src/skf-analyze-source/references/continue.md +2 -13
  145. package/src/skf-analyze-source/references/discover-additional-source.md +147 -0
  146. package/src/skf-analyze-source/references/generate-briefs.md +121 -55
  147. package/src/skf-analyze-source/references/headless-contract.md +42 -15
  148. package/src/skf-analyze-source/references/identify-units.md +96 -110
  149. package/src/skf-analyze-source/references/init.md +73 -71
  150. package/src/skf-analyze-source/references/map-and-detect.md +123 -105
  151. package/src/skf-analyze-source/references/map-unit-exports.md +68 -0
  152. package/src/skf-analyze-source/references/recommend.md +51 -70
  153. package/src/skf-analyze-source/references/scan-project.md +60 -84
  154. package/src/skf-analyze-source/references/scan-root.md +39 -0
  155. package/src/skf-analyze-source/references/step-auto-scope-coexistence.md +47 -0
  156. package/src/skf-analyze-source/references/step-auto-scope-corpora.md +53 -0
  157. package/src/skf-analyze-source/references/step-auto-scope-split.md +91 -0
  158. package/src/skf-analyze-source/references/step-auto-scope.md +208 -293
  159. package/src/skf-analyze-source/references/step-shape-detect.md +14 -12
  160. package/src/skf-analyze-source/references/unit-detection-heuristics.md +37 -42
  161. package/src/skf-audit-skill/SKILL.md +43 -51
  162. package/src/skf-audit-skill/assets/drift-report-template.md +27 -3
  163. package/src/skf-audit-skill/customize.toml +41 -20
  164. package/src/skf-audit-skill/references/constituent-freshness.md +91 -0
  165. package/src/skf-audit-skill/references/doc-drift.md +141 -0
  166. package/src/skf-audit-skill/references/headless-contract.md +29 -0
  167. package/src/skf-audit-skill/references/init.md +148 -210
  168. package/src/skf-audit-skill/references/re-index.md +96 -108
  169. package/src/skf-audit-skill/references/report.md +96 -33
  170. package/src/skf-audit-skill/references/semantic-diff.md +27 -18
  171. package/src/skf-audit-skill/references/severity-classify.md +79 -65
  172. package/src/skf-audit-skill/references/severity-rules.md +15 -6
  173. package/src/skf-audit-skill/references/structural-diff.md +75 -90
  174. package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
  175. package/src/skf-audit-skill/scripts/render-drift-tables.py +685 -0
  176. package/src/skf-brief-skill/SKILL.md +36 -25
  177. package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
  178. package/src/skf-brief-skill/assets/scope-templates.md +17 -24
  179. package/src/skf-brief-skill/assets/skill-brief-schema.md +29 -15
  180. package/src/skf-brief-skill/customize.toml +48 -20
  181. package/src/skf-brief-skill/references/analyze-target.md +142 -125
  182. package/src/skf-brief-skill/references/confirm-brief.md +10 -8
  183. package/src/skf-brief-skill/references/draft-checkpoint.md +36 -17
  184. package/src/skf-brief-skill/references/gather-intent-ratify.md +68 -0
  185. package/src/skf-brief-skill/references/gather-intent.md +87 -182
  186. package/src/skf-brief-skill/references/headless-args.md +84 -16
  187. package/src/skf-brief-skill/references/health-check.md +1 -1
  188. package/src/skf-brief-skill/references/invocation-contract.md +18 -13
  189. package/src/skf-brief-skill/references/portfolio-similarity-check.md +1 -1
  190. package/src/skf-brief-skill/references/qmd-collection-registration.md +7 -10
  191. package/src/skf-brief-skill/references/scope-definition.md +123 -47
  192. package/src/skf-brief-skill/references/step-auto-brief.md +24 -80
  193. package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
  194. package/src/skf-brief-skill/references/version-resolution.md +3 -2
  195. package/src/skf-brief-skill/references/write-brief.md +66 -57
  196. package/src/skf-campaign/SKILL.md +31 -34
  197. package/src/skf-campaign/assets/campaign-state-schema.json +25 -4
  198. package/src/skf-campaign/customize.toml +47 -16
  199. package/src/skf-campaign/references/campaign-contracts.md +39 -29
  200. package/src/skf-campaign/references/campaign-directive-spec.md +4 -2
  201. package/src/skf-campaign/references/health-check.md +7 -16
  202. package/src/skf-campaign/references/step-01-setup.md +46 -84
  203. package/src/skf-campaign/references/step-02-strategy.md +31 -30
  204. package/src/skf-campaign/references/step-03-pins.md +26 -18
  205. package/src/skf-campaign/references/step-04-provenance.md +24 -23
  206. package/src/skf-campaign/references/step-05-skill-loop.md +67 -48
  207. package/src/skf-campaign/references/step-06-batch.md +41 -34
  208. package/src/skf-campaign/references/step-07-capstone.md +40 -25
  209. package/src/skf-campaign/references/step-08-verify.md +28 -29
  210. package/src/skf-campaign/references/step-09-refine.md +29 -30
  211. package/src/skf-campaign/references/step-10-export.md +48 -36
  212. package/src/skf-campaign/references/step-11-maintenance.md +31 -34
  213. package/src/skf-campaign/references/step-resume.md +37 -68
  214. package/src/skf-campaign/scripts/campaign-deps.py +57 -18
  215. package/src/skf-campaign/scripts/campaign-parse-manifest.py +361 -54
  216. package/src/skf-campaign/scripts/campaign-provenance.py +96 -53
  217. package/src/skf-campaign/scripts/campaign-quality-gate.py +592 -0
  218. package/src/skf-campaign/scripts/campaign-render-batch.py +257 -49
  219. package/src/skf-campaign/scripts/campaign-render-kickoff.py +343 -50
  220. package/src/skf-campaign/scripts/campaign-report.py +204 -37
  221. package/src/skf-campaign/scripts/campaign-state.py +1128 -0
  222. package/src/skf-campaign/scripts/campaign-status.py +10 -74
  223. package/src/skf-campaign/scripts/campaign-validate-pins.py +30 -3
  224. package/src/skf-campaign/scripts/campaign-validate-state.py +34 -4
  225. package/src/skf-campaign/templates/campaign-brief-template.yaml +4 -5
  226. package/src/skf-campaign/templates/campaign-report-template.md +5 -1
  227. package/src/skf-campaign/templates/kickoff-template.md +0 -14
  228. package/src/skf-create-skill/SKILL.md +27 -20
  229. package/src/skf-create-skill/assets/compile-assembly-rules.md +6 -5
  230. package/src/skf-create-skill/assets/skill-sections.md +15 -5
  231. package/src/skf-create-skill/customize.toml +20 -8
  232. package/src/skf-create-skill/references/authoritative-files-protocol.md +41 -42
  233. package/src/skf-create-skill/references/batch-mode.md +81 -0
  234. package/src/skf-create-skill/references/ccc-index-check.md +27 -0
  235. package/src/skf-create-skill/references/compile.md +107 -29
  236. package/src/skf-create-skill/references/component-extraction.md +113 -91
  237. package/src/skf-create-skill/references/enrich.md +41 -23
  238. package/src/skf-create-skill/references/entry-points-by-hand.md +20 -0
  239. package/src/skf-create-skill/references/extract.md +200 -161
  240. package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
  241. package/src/skf-create-skill/references/extraction-patterns-tracing.md +2 -2
  242. package/src/skf-create-skill/references/extraction-patterns.md +584 -196
  243. package/src/skf-create-skill/references/generate-artifacts.md +145 -93
  244. package/src/skf-create-skill/references/health-check.md +1 -1
  245. package/src/skf-create-skill/references/load-brief.md +53 -36
  246. package/src/skf-create-skill/references/relabel-rule.md +12 -0
  247. package/src/skf-create-skill/references/report.md +28 -59
  248. package/src/skf-create-skill/references/source-resolution-protocols.md +49 -155
  249. package/src/skf-create-skill/references/step-auto-shard.md +20 -93
  250. package/src/skf-create-skill/references/step-doc-rot.md +44 -60
  251. package/src/skf-create-skill/references/step-doc-sources.md +28 -19
  252. package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
  253. package/src/skf-create-skill/references/sub/fetch-docs.md +106 -59
  254. package/src/skf-create-skill/references/sub/fetch-temporal.md +53 -166
  255. package/src/skf-create-skill/references/tier-degradation-rules.md +18 -9
  256. package/src/skf-create-skill/references/validate.md +173 -99
  257. package/src/skf-create-skill/scripts/scan-doc-rot.py +232 -99
  258. package/src/skf-create-stack-skill/SKILL.md +29 -56
  259. package/src/skf-create-stack-skill/assets/metadata-contract.md +51 -0
  260. package/src/skf-create-stack-skill/assets/provenance-map-schema.md +15 -15
  261. package/src/skf-create-stack-skill/assets/stack-skill-template.md +23 -57
  262. package/src/skf-create-stack-skill/customize.toml +23 -12
  263. package/src/skf-create-stack-skill/references/compile-stack.md +57 -66
  264. package/src/skf-create-stack-skill/references/compose-mode-rules.md +24 -44
  265. package/src/skf-create-stack-skill/references/detect-integrations.md +92 -95
  266. package/src/skf-create-stack-skill/references/detect-manifests.md +46 -71
  267. package/src/skf-create-stack-skill/references/generate-output.md +138 -128
  268. package/src/skf-create-stack-skill/references/init.md +90 -32
  269. package/src/skf-create-stack-skill/references/integration-patterns.md +1 -17
  270. package/src/skf-create-stack-skill/references/invocation-contract.md +34 -0
  271. package/src/skf-create-stack-skill/references/manifest-patterns.md +32 -20
  272. package/src/skf-create-stack-skill/references/parallel-extract.md +112 -38
  273. package/src/skf-create-stack-skill/references/rank-and-confirm.md +57 -75
  274. package/src/skf-create-stack-skill/references/report.md +39 -33
  275. package/src/skf-create-stack-skill/references/validate.md +20 -39
  276. package/src/skf-drop-skill/SKILL.md +28 -51
  277. package/src/skf-drop-skill/customize.toml +44 -30
  278. package/src/skf-drop-skill/references/execute.md +79 -146
  279. package/src/skf-drop-skill/references/invocation-contract.md +64 -0
  280. package/src/skf-drop-skill/references/report.md +46 -30
  281. package/src/skf-drop-skill/references/select.md +118 -124
  282. package/src/skf-drop-skill/scripts/dir-sizes.py +54 -26
  283. package/src/skf-drop-skill/scripts/drop-roster.py +322 -0
  284. package/src/skf-export-skill/SKILL.md +40 -62
  285. package/src/skf-export-skill/assets/managed-section-format.md +14 -50
  286. package/src/skf-export-skill/assets/snippet-format.md +3 -1
  287. package/src/skf-export-skill/customize.toml +42 -13
  288. package/src/skf-export-skill/references/generate-snippet.md +54 -46
  289. package/src/skf-export-skill/references/health-check.md +2 -0
  290. package/src/skf-export-skill/references/invocation-contract.md +15 -0
  291. package/src/skf-export-skill/references/load-skill.md +88 -62
  292. package/src/skf-export-skill/references/manifest-rebuild.md +9 -10
  293. package/src/skf-export-skill/references/multi-skill-mode.md +4 -4
  294. package/src/skf-export-skill/references/orphan-context-detection.md +13 -5
  295. package/src/skf-export-skill/references/orphan-row-detection.md +31 -22
  296. package/src/skf-export-skill/references/package.md +15 -73
  297. package/src/skf-export-skill/references/preflight-snippet-root-probe.md +51 -70
  298. package/src/skf-export-skill/references/result-envelope.md +31 -16
  299. package/src/skf-export-skill/references/summary.md +41 -17
  300. package/src/skf-export-skill/references/token-report.md +4 -12
  301. package/src/skf-export-skill/references/update-context.md +118 -237
  302. package/src/skf-forger/SKILL.md +61 -37
  303. package/src/skf-forger/bmad-skill-manifest.yaml +4 -1
  304. package/src/skf-forger/customize.toml +43 -0
  305. package/src/skf-forger/references/pipeline-mode.md +73 -18
  306. package/src/skf-forger/scripts/forge-status.py +299 -0
  307. package/src/skf-forger/scripts/parse-pipeline.py +322 -54
  308. package/src/skf-forger/scripts/pipeline-gate.py +428 -0
  309. package/src/skf-forger/scripts/pipeline-journal.py +1052 -0
  310. package/src/skf-quick-skill/SKILL.md +54 -53
  311. package/src/skf-quick-skill/assets/skill-template.md +4 -2
  312. package/src/skf-quick-skill/customize.toml +51 -20
  313. package/src/skf-quick-skill/references/batch-mode.md +74 -21
  314. package/src/skf-quick-skill/references/compile.md +30 -31
  315. package/src/skf-quick-skill/references/ecosystem-check.md +7 -57
  316. package/src/skf-quick-skill/references/finalize.md +69 -18
  317. package/src/skf-quick-skill/references/halt-contract.md +41 -29
  318. package/src/skf-quick-skill/references/health-check.md +5 -3
  319. package/src/skf-quick-skill/references/quick-extract.md +114 -45
  320. package/src/skf-quick-skill/references/registry-resolution.md +9 -64
  321. package/src/skf-quick-skill/references/resolve-target.md +116 -66
  322. package/src/skf-quick-skill/references/write-and-validate.md +79 -40
  323. package/src/skf-refine-architecture/SKILL.md +43 -53
  324. package/src/skf-refine-architecture/customize.toml +49 -20
  325. package/src/skf-refine-architecture/references/compile.md +97 -54
  326. package/src/skf-refine-architecture/references/exit-codes.md +30 -0
  327. package/src/skf-refine-architecture/references/finding-storage.md +21 -0
  328. package/src/skf-refine-architecture/references/gap-analysis.md +101 -38
  329. package/src/skf-refine-architecture/references/improvements.md +14 -20
  330. package/src/skf-refine-architecture/references/init.md +98 -57
  331. package/src/skf-refine-architecture/references/issue-detection.md +32 -39
  332. package/src/skf-refine-architecture/references/refinement-rules.md +37 -48
  333. package/src/skf-refine-architecture/references/report.md +65 -54
  334. package/src/skf-refine-architecture/scripts/skf-check-preservation.py +1619 -0
  335. package/src/skf-rename-skill/SKILL.md +19 -54
  336. package/src/skf-rename-skill/customize.toml +32 -26
  337. package/src/skf-rename-skill/references/execute.md +230 -184
  338. package/src/skf-rename-skill/references/exit-codes.md +7 -7
  339. package/src/skf-rename-skill/references/health-check.md +1 -7
  340. package/src/skf-rename-skill/references/invocation-contract.md +25 -0
  341. package/src/skf-rename-skill/references/report.md +63 -52
  342. package/src/skf-rename-skill/references/select.md +197 -115
  343. package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -21
  344. package/src/skf-setup/SKILL.md +26 -26
  345. package/src/skf-setup/customize.toml +14 -10
  346. package/src/skf-setup/references/auto-index.md +50 -63
  347. package/src/skf-setup/references/ccc-index.md +29 -90
  348. package/src/skf-setup/references/detect-and-tier.md +58 -67
  349. package/src/skf-setup/references/health-check.md +2 -0
  350. package/src/skf-setup/references/invocation-contract.md +14 -0
  351. package/src/skf-setup/references/report.md +43 -166
  352. package/src/skf-setup/references/tier-rules.md +5 -5
  353. package/src/skf-setup/references/write-config.md +34 -57
  354. package/src/skf-test-skill/SKILL.md +17 -57
  355. package/src/skf-test-skill/assets/output-section-formats.md +33 -34
  356. package/src/skf-test-skill/customize.toml +27 -13
  357. package/src/skf-test-skill/references/coherence-check.md +134 -62
  358. package/src/skf-test-skill/references/coverage-check-tiers.md +35 -0
  359. package/src/skf-test-skill/references/coverage-check.md +217 -254
  360. package/src/skf-test-skill/references/detect-mode.md +5 -5
  361. package/src/skf-test-skill/references/external-validators.md +94 -82
  362. package/src/skf-test-skill/references/health-check.md +6 -7
  363. package/src/skf-test-skill/references/init.md +163 -88
  364. package/src/skf-test-skill/references/invocation-contract.md +66 -0
  365. package/src/skf-test-skill/references/migration-section-rules.md +5 -2
  366. package/src/skf-test-skill/references/report.md +162 -142
  367. package/src/skf-test-skill/references/score.md +80 -107
  368. package/src/skf-test-skill/references/scoring-rules.md +41 -155
  369. package/src/skf-test-skill/references/source-access-protocol.md +19 -92
  370. package/src/skf-test-skill/references/step-hard-gate.md +51 -33
  371. package/src/skf-test-skill/scripts/aggregate-coherence.py +218 -30
  372. package/src/skf-test-skill/scripts/build-result-context.py +287 -0
  373. package/src/skf-test-skill/scripts/check-metadata-coherence.py +37 -4
  374. package/src/skf-test-skill/scripts/combine-external-scores.py +23 -6
  375. package/src/skf-test-skill/scripts/compute-score.py +223 -45
  376. package/src/skf-test-skill/scripts/gap-ledger.py +1381 -0
  377. package/src/skf-test-skill/scripts/hard-gate.py +203 -0
  378. package/src/skf-test-skill/scripts/load-coverage-inputs.py +760 -0
  379. package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
  380. package/src/skf-test-skill/scripts/reconcile-coverage.py +273 -79
  381. package/src/skf-test-skill/scripts/score-signatures.py +459 -0
  382. package/src/skf-test-skill/scripts/stage-helper-payload.py +148 -0
  383. package/src/skf-test-skill/scripts/validate-inventory.py +311 -16
  384. package/src/skf-test-skill/scripts/verify-declared-numerator.py +127 -52
  385. package/src/skf-test-skill/templates/test-report-template.md +21 -15
  386. package/src/skf-update-skill/SKILL.md +38 -25
  387. package/src/skf-update-skill/customize.toml +27 -12
  388. package/src/skf-update-skill/references/detect-changes.md +233 -222
  389. package/src/skf-update-skill/references/gap-driven.md +336 -0
  390. package/src/skf-update-skill/references/health-check.md +31 -5
  391. package/src/skf-update-skill/references/init.md +250 -84
  392. package/src/skf-update-skill/references/invocation-contract.md +12 -0
  393. package/src/skf-update-skill/references/manual-section-rules.md +6 -23
  394. package/src/skf-update-skill/references/merge.md +180 -47
  395. package/src/skf-update-skill/references/re-extract.md +53 -262
  396. package/src/skf-update-skill/references/report.md +100 -35
  397. package/src/skf-update-skill/references/write.md +331 -149
  398. package/src/skf-update-skill/scripts/skf-new-file-diff.py +29 -7
  399. package/src/skf-verify-stack/SKILL.md +23 -42
  400. package/src/skf-verify-stack/assets/feasibility-report-template.md +11 -5
  401. package/src/skf-verify-stack/customize.toml +55 -22
  402. package/src/skf-verify-stack/references/coverage-patterns.md +17 -8
  403. package/src/skf-verify-stack/references/coverage.md +67 -64
  404. package/src/skf-verify-stack/references/exit-codes.md +21 -8
  405. package/src/skf-verify-stack/references/init.md +107 -62
  406. package/src/skf-verify-stack/references/integration-verification-rules.md +12 -13
  407. package/src/skf-verify-stack/references/integrations.md +106 -65
  408. package/src/skf-verify-stack/references/report.md +59 -42
  409. package/src/skf-verify-stack/references/requirements.md +32 -9
  410. package/src/skf-verify-stack/references/synthesize.md +53 -39
  411. package/src/skf-verify-stack/scripts/skf-coverage-tally.py +398 -52
  412. package/src/skf-verify-stack/scripts/skf-previous-report.py +330 -0
  413. package/src/skf-verify-stack/scripts/skf-report-delta.py +453 -49
  414. package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +240 -27
  415. package/tools/cli/commands/install.js +11 -4
  416. package/tools/cli/commands/status.js +15 -3
  417. package/tools/cli/commands/update.js +11 -4
  418. package/tools/cli/lib/tool-check.js +320 -0
  419. package/tools/cli/lib/version-check.js +22 -9
  420. package/tools/cli/skf-cli.js +4 -1
  421. package/.gitattributes +0 -16
  422. package/.nvmrc +0 -1
  423. package/docs/_internal/RELEASING.md +0 -679
  424. package/release-audits/v1.0.0-launch-audit.md +0 -728
  425. package/src/skf-audit-skill/references/step-doc-drift.md +0 -177
  426. package/src/skf-brief-skill/references/headless-source-authority-detection.md +0 -26
  427. package/src/skf-campaign/manifest.yaml +0 -15
  428. package/src/skf-create-skill/assets/tessl-dismissal-rules.md +0 -106
  429. package/src/skf-create-skill/references/ecosystem-check.md +0 -74
  430. package/src/skf-drop-skill/references/headless-contract.md +0 -18
  431. package/src/skf-update-skill/references/merge-conflict-rules.md +0 -15
  432. package/src/skf-update-skill/references/remote-source-resolution.md +0 -98
  433. package/src/skf-update-skill/references/validate.md +0 -124
  434. package/tools/validate-docs-drift.js +0 -233
  435. package/tools/validate-docs-links.js +0 -665
@@ -6,21 +6,21 @@ When `source_repo` is a remote URL (GitHub URL or owner/repo format) and the tie
6
6
 
7
7
  - **ast-grep requires local files** — it cannot operate on remote URLs
8
8
 
9
- **Workspace-first clone strategy (preferred):**
9
+ **Private tree at the resolved commit (preferred):**
10
10
 
11
- 1. Check `git` availability (`git --version`). `git` is effectively guaranteed at Deep tier (via `gh` dependency) but not guaranteed at Forge tier.
12
- 2. If `git` is available: check for an existing workspace checkout at `{workspace_root}/repos/{host}/{owner}/{repo}/`. If found, `git fetch` to update. If not found, clone into the workspace path with `--depth 1 --single-branch`. See `source-resolution-protocols.md` for the full workspace resolution algorithm.
11
+ 1. `skf-source-tree.py resolve` reads the resolved commit into a private tree of the run's own, from the workspace checkout at `{workspace_root}/repos/{host}/{owner}/{repo}/` when it holds the commit and from the remote otherwise. It then moves that workspace checkout to the same commit, cloning it first when it is missing, after the git hygiene check (it undoes the `.gitignore` edit `ccc init` made there and keeps ccc's index folder and SKF's lock file out of `git status`). See `source-resolution-protocols.md` for the full resolution algorithm.
12
+ 2. When `git` is missing, resolve reports `git-unavailable` and reads no tree, and the run falls back to source reading (below). `git` is effectively guaranteed at Deep tier (via the `gh` dependency) but not at Forge tier.
13
13
  3. The workspace uses a full checkout (no sparse-checkout). Brief `include_patterns` and `exclude_patterns` are applied as file-level filters at extraction time, not at the git level. This allows a single workspace checkout to serve multiple briefs with different scope filters.
14
- 4. For update-skill: `changed_files_from_manifest` scoping is applied as file-level filters at extraction time on the full workspace checkout.
15
- 5. If workspace clone/fetch succeeds: use the workspace path for AST extraction. All results are T1 with `[AST:...]` citations.
16
- 6. If workspace fails: fall back to ephemeral clone (`{system_temp}/skf-ephemeral-{skill-name}-{timestamp}/`). If ephemeral succeeds, use it. Ephemeral clone is deleted after extraction.
14
+ 4. For update-skill: a skill forged from a remote repository is read from a checkout of the skill's commit that update-skill prepares for each run (from the workspace clone's objects or the remote), never from the workspace clone as it stands, and `changed_files_from_manifest` scoping is applied as file-level filters at extraction time; a gap-driven repair reads the workspace clone after checking that it holds the skill's pinned commit.
15
+ 5. If `resolve` reads the tree: use the tree for AST extraction. Each export an ast-grep rule matches is T1 with an `[AST:...]` citation; an export read by eye stays T1-low (see Source Read by Choice below).
16
+ 6. If the remote cannot be reached, or the fetch or checkout fails, no tree is read: fall back to source reading (below). A tree that was read is removed at the end of the run.
17
17
  7. Workspace checkouts persist across forges — CCC indexes, tool outputs, and the checkout itself are reused.
18
18
 
19
- **Fallback (clone fails or `git` unavailable):**
19
+ **Fallback (no tree can be read, or `git` is unavailable):**
20
20
 
21
21
  - The extraction step warns the user explicitly before degrading — a silent drop from AST (T1) to source reading (T1-low) would leave them trusting a lower-confidence result without knowing it changed
22
22
  - **create-skill:** the warning includes actionable guidance — clone locally and update `source_repo` in the brief to the local path
23
- - **update-skill:** the warning includes actionable guidance — clone locally, re-run [CS] Create Skill with the local path to regenerate provenance data, then re-run the update
23
+ - **update-skill:** does not degrade to source reading for a remote skill: when it cannot get the commit to read, it stops before change detection (`init:source-tree`), since reading any other tree would compare the skill with the wrong code; when only the network is down, it reads the pinned commit from the workspace clone.
24
24
  - Extraction proceeds using Quick tier strategy (source reading via gh_bridge — resolved as `gh api` commands or direct file I/O; see `knowledge/tool-resolution.md`)
25
25
  - All results labeled T1-low with `[SRC:...]` citations
26
26
  - The degradation reason is recorded in the evidence report
@@ -41,5 +41,14 @@ When ast-grep fails on an individual file (parse error, unsupported syntax):
41
41
 
42
42
  - Fall back to source reading for **that file only**
43
43
  - Other files continue with AST extraction
44
- - The affected file's results are labeled T1-low; unaffected files retain T1
44
+ - The affected file's results are labeled T1-low with `[SRC:...]` citations, `extraction_method: source-read` and `ast_node_type: null`; exports ast-grep matched in other files stay T1
45
45
  - Log a warning noting which file degraded and why
46
+
47
+ ## Source Read by Choice
48
+
49
+ When ast-grep works but an export is read by eye anyway (a file read to confirm a signature, a re-export the rules did not match, a symbol found while reading a neighbouring file):
50
+
51
+ - Label the export by the tool that produced it, not by the tier: T1-low with a `[SRC:{file}:L{line}]` citation
52
+ - Record `extraction_method: source-read`, `ast_node_type: null` and a `signature_source` other than T1
53
+ - Only an export an ast-grep rule matched is T1, with an `[AST:...]` citation, `extraction_method: ast-grep` and, as `ast_node_type`, the `kind` its recipe declares in `extraction-patterns.md`, or the kind the ast-grep Patterns table in `extraction-patterns-by-hand.md` gives a `find_code` pattern
54
+ - This is not a degradation: no warning is needed, and other exports keep their own labels
@@ -1,26 +1,27 @@
1
1
  ---
2
2
  nextStepFile: 'generate-artifacts.md'
3
- tesslDismissalData: 'assets/tessl-dismissal-rules.md'
4
- descriptionGuardProtocol: '{project-root}/src/shared/references/description-guard-protocol.md'
5
3
  # Resolve `{atomicWriteHelper}` by probing `{atomicWriteProbeOrder}` in order
6
4
  # (installed SKF module path first, src/ dev-checkout fallback); first existing
7
- # path wins. HALT if neither resolves — losing atomic-write guarantees is not
8
- # an option for the staging-directory artifacts this step produces.
5
+ # path wins. HALT (exit code 3, helper-missing) if neither resolves: the
6
+ # staging-directory artifacts this step writes need atomic writes.
9
7
  atomicWriteProbeOrder:
10
8
  - '{project-root}/_bmad/skf/shared/scripts/skf-atomic-write.py'
11
9
  - '{project-root}/src/shared/scripts/skf-atomic-write.py'
12
10
  # Resolve `{descriptionGuardHelper}` by probing `{descriptionGuardProbeOrder}`
13
11
  # in order (installed SKF module path first, src/ dev-checkout fallback);
14
- # first existing path wins. HALT if neither resolves — letting an external
15
- # tool's rewrite of the description field stand would silently regress
16
- # discovery quality.
12
+ # first existing path wins. HALT (exit code 3, helper-missing) if neither
13
+ # resolves: letting an external tool's rewrite of the description field
14
+ # stand would silently regress discovery quality.
17
15
  descriptionGuardProbeOrder:
18
16
  - '{project-root}/_bmad/skf/shared/scripts/skf-description-guard.py'
19
17
  - '{project-root}/src/shared/scripts/skf-description-guard.py'
20
18
  # Resolve `{frontmatterValidator}` by probing `{frontmatterValidatorProbeOrder}`
21
19
  # in order (installed SKF module path first, src/ dev-checkout fallback); first
22
- # existing path wins. §0's post-restore re-validation hook uses it; an installed
23
- # module has no src/ tree, so a bare src/ path would silently fail the hook.
20
+ # existing path wins.
21
+ # HALT (exit code 3, helper-missing) if neither resolves: §6's description
22
+ # check has no fallback, and §0's post-restore re-validation hook uses it
23
+ # too; an installed module has no src/ tree, so a bare src/ path would
24
+ # silently skip both.
24
25
  frontmatterValidatorProbeOrder:
25
26
  - '{project-root}/_bmad/skf/shared/scripts/skf-validate-frontmatter.py'
26
27
  - '{project-root}/src/shared/scripts/skf-validate-frontmatter.py'
@@ -38,6 +39,41 @@ shardBodyProbeOrder:
38
39
  renderMetadataStatsProbeOrder:
39
40
  - '{project-root}/_bmad/skf/shared/scripts/skf-render-metadata-stats.py'
40
41
  - '{project-root}/src/shared/scripts/skf-render-metadata-stats.py'
42
+ # Resolve `{verifyProvenanceCompletenessHelper}` to the first existing path.
43
+ # §7's relabel runs its `kind-at`, and §7a its `verify` and `fix`. Advisory:
44
+ # if neither path resolves, §7a records that its check did not run, and a
45
+ # node kind that needs `kind-at` stays a WARN.
46
+ verifyProvenanceCompletenessProbeOrder:
47
+ - '{project-root}/_bmad/skf/shared/scripts/skf-verify-provenance-completeness.py'
48
+ - '{project-root}/src/shared/scripts/skf-verify-provenance-completeness.py'
49
+ # Resolve `{tesslReviewHelper}` by probing `{tesslReviewProbeOrder}` in order
50
+ # (installed SKF module path first, src/ dev-checkout fallback); first existing
51
+ # path wins. If neither path exists, §6b records that Tessl Review did not run
52
+ # and continues: the review is optional and never gates the workflow.
53
+ tesslReviewProbeOrder:
54
+ - '{project-root}/_bmad/skf/shared/scripts/skf-tessl-review.py'
55
+ - '{project-root}/src/shared/scripts/skf-tessl-review.py'
56
+ # Resolve `{tesslReviewRules}` the same way. §6b loads it after a completed
57
+ # review to mark the suggestions SKF does not follow; without it the
58
+ # suggestions are listed unmarked.
59
+ tesslReviewRulesProbeOrder:
60
+ - '{project-root}/_bmad/skf/shared/references/tessl-review.md'
61
+ - '{project-root}/src/shared/references/tessl-review.md'
62
+ preferencesFile: '{sidecar_path}/preferences.yaml'
63
+ # Loaded only when §7 or §7a meets a provenance label or node-kind finding.
64
+ relabelRuleData: 'references/relabel-rule.md'
65
+ # Resolve `{extractionPatternsData}` to the first existing path, as step 3
66
+ # did: the Relabel Rule's `kind-at` reads the recipes there.
67
+ extractionPatternsDataProbeOrder:
68
+ - '{project-root}/_bmad/skf/skf-create-skill/references/extraction-patterns.md'
69
+ - '{project-root}/src/skf-create-skill/references/extraction-patterns.md'
70
+ # HARD HALT helpers (Rules).
71
+ sourceTreeProbeOrder:
72
+ - '{project-root}/_bmad/skf/shared/scripts/skf-source-tree.py'
73
+ - '{project-root}/src/shared/scripts/skf-source-tree.py'
74
+ emitEnvelopeProbeOrder:
75
+ - '{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py'
76
+ - '{project-root}/src/shared/scripts/skf-emit-result-envelope.py'
41
77
  ---
42
78
 
43
79
  <!-- Config: communicate in {communication_language}. -->
@@ -46,23 +82,31 @@ renderMetadataStatsProbeOrder:
46
82
 
47
83
  ## STEP GOAL:
48
84
 
49
- To validate the compiled SKILL.md content against the agentskills.io specification using skill-check, auto-fix any validation failures, and confirm spec compliance before artifact generation.
85
+ To validate the compiled SKILL.md content against the agentskills.io specification using skill-check, auto-fix any validation failures, confirm that the frontmatter description holds no angle brackets, and confirm spec compliance before artifact generation. When the user has opted in to Tessl Review, also record Tessl's review of the skill as advice; it never gates the step.
50
86
 
51
87
  ## Rules
52
88
 
53
89
  - Focus only on validating compiled content against spec — only fix spec compliance issues
54
90
  - Validation and auto-fix modify files in the staging directory
55
- - `<staging-skill-dir>` resolves to `_bmad-output/{skill-name}/` as created by step 5. The directory name must match the skill's frontmatter `name` field exactly — `skill-check`'s `frontmatter.name_matches_directory` rule rejects any suffix.
91
+ - `<staging-skill-dir>` resolves to `_bmad-output/.skf-stage/{skill-name}/` as created by step 5. Its last folder name must match the skill's frontmatter `name` field exactly — `skill-check`'s `frontmatter.name_matches_directory` rule rejects any suffix.
56
92
  - If skill-check unavailable: skip validation, add warning to evidence report
57
93
  - Ignore non-zero exit codes from skill-check if JSON output shows 0 errors
94
+ - Tessl Review (§6b) is optional and advisory: it never halts, never asks the user anything and never changes the staged files, and SKF applies none of its suggestions
95
+ - A HARD HALT, once step 3 §2b has bound `{source_tree}`, first runs `uv run {sourceTreeHelper} close --tree "{source_tree}"` from `{project-root}` (resolved from `{sourceTreeProbeOrder}`) and goes on whatever it prints, and emits through `{emitEnvelopeHelper}`, resolved from `{emitEnvelopeProbeOrder}` when it is not bound. After its envelope, under `--batch` it ends only this brief: return to `references/batch-mode.md` §3, even when the halt reads as the end of the run.
58
96
 
59
97
  ## MANDATORY SEQUENCE
60
98
 
99
+ **Helpers.** Resolve `{atomicWriteHelper}`, `{descriptionGuardHelper}` and `{frontmatterValidator}` now, each ← the first existing path of its probe order. If one has no path, **HARD HALT** (exit code 3, `helper-missing`, phase `validate`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "Cannot validate the staged skill: {the missing script} is missing. Re-install SKF, then re-run create-skill."
100
+
61
101
  ### 0. Description Guard Protocol
62
102
 
63
- **Used by:** §2 (`skill-check check --fix`), §4 (`split-body`), and any future tool invocation that may modify SKILL.md.
103
+ **Used by:** §2 (`skill-check check --fix`) and §4 (the body split).
104
+
105
+ The deterministic phases are executed via `{descriptionGuardHelper}`: the calling sections (§2 and §4) invoke the helper at the capture and verify-restore points.
64
106
 
65
- Load `{descriptionGuardProtocol}` for the full prose explanation of the four-phase guard (why it exists, what counts as divergence, why token-stream comparison is the right shape). The deterministic phases are executed via `{descriptionGuardHelper}` — the calling sections (§2 and §4) invoke the helper at the capture and verify-restore points. `verify-restore` refuses an empty `--captured-description` (exit 1, file untouched); when that happens, follow the protocol's empty-snapshot rule instead of re-running with the empty value.
107
+ **Guard outputs.** Bind `{guarded_description}` ← `description` from each `capture`, which reads the staged `<staging-skill-dir>/SKILL.md` just before the tool that may rewrite it. Bind `{guard_restored}` ← `restored` and `{guard_diff_kind}` ← `diff_kind` from each `verify-restore`. When `{guard_restored}` is true, set the in-context `description` to `{guarded_description}` so later sections do not work from the tool-mutated value, and record `description_guard_restored: true` with the tool name and `description_guard_diff_kind: {guard_diff_kind}` in workflow context for the evidence report (§8). A later `verify-restore` that exits 0 with `{guard_restored}` false leaves those records in place.
108
+
109
+ **Empty-snapshot rule.** `verify-restore` refuses an empty or whitespace-only `--captured-description` (exit 1, file untouched). Never re-run it with the empty value: writing it back would blank the field the guard protects. If the description compile §2a sanitized is still in context (an in-context copy of the description, not of the file), re-run `verify-restore` with that value. Otherwise record `description_guard_restored: false` and `description_guard_refused: empty-capture` with the tool name; the evidence report (§8) renders that as a fired guard, not as a clean run.
66
110
 
67
111
  **This skill's post-restore re-validation hook:** after `{descriptionGuardHelper}` reports `restored: true`, resolve `{frontmatterValidator}` from `{frontmatterValidatorProbeOrder}` (first existing path wins), run `uv run {frontmatterValidator} <staging-skill-dir>/SKILL.md` and capture `schema_revalidation_result` in context. If the validator exits non-zero OR reports failure for the `description` field, flip the Schema result back to `FAIL` in the evidence report (overriding any prior PASS/WARN from §2), record `description_guard_revalidation: FAIL` with the validator's diagnostic message, and continue — do not halt (step 9 health-check and result contract still need to run so the failure is surfaced through the normal artifact path).
68
112
 
@@ -71,7 +115,7 @@ Load `{descriptionGuardProtocol}` for the full prose explanation of the four-pha
71
115
  Run: `timeout 30s npx skill-check -h` — the short timeout protects against a cold `npx` download blocking the workflow indefinitely on a slow network.
72
116
 
73
117
  - If succeeds: Continue to automated validation (section 2)
74
- - If fails or times out: Perform manual fallback (section 3); add note to evidence-report: "Spec validation performed manually — skill-check tool unavailable". Also set `metadata.validation_status: 'manual-only'` in `metadata.json` (write via `python3 {atomicWriteHelper} write --target <staging-skill-dir>/metadata.json`), and in the evidence-report's `Validation Results` section mark Security, Body, and Content Quality (tessl) rows explicitly as `skipped — skill-check unavailable`. Downstream consumers (pipeline, forger, test-skill) check `validation_status` to decide how much weight to put on the artifact; leaving it unset would make a manual-only run look equivalent to a fully automated PASS.
118
+ - If fails or times out: Perform manual fallback (section 3); add note to evidence-report: "Spec validation performed manually — skill-check tool unavailable". Also set `metadata.validation_status: 'manual-only'` in `metadata.json` (write via `python3 {atomicWriteHelper} write --target <staging-skill-dir>/metadata.json`), and in the evidence-report's `Validation Results` section mark the Security and Body rows explicitly as `skipped — skill-check unavailable` (§6 and §6b do not depend on skill-check). Downstream consumers (pipeline, forger, test-skill) check `validation_status` to decide how much weight to put on the artifact; leaving it unset would make a manual-only run look equivalent to a fully automated PASS.
75
119
 
76
120
  **Important:** Do not assume availability — empirical check required.
77
121
 
@@ -113,7 +157,7 @@ uv run {descriptionGuardHelper} verify-restore <staging-skill-dir>/SKILL.md \
113
157
  --captured-description "{guarded_description}"
114
158
  ```
115
159
 
116
- If `restored: true` in the verify-restore output, apply §0's post-restore re-validation hook. If `fixed[]` was non-empty in the skill-check output, also re-read the modified SKILL.md to sync the in-context copy before proceeding — this prevents silent divergence between the in-context and on-disk versions that step 7 will use for artifact generation.
160
+ If `restored: true` in the verify-restore output, apply §0's post-restore re-validation hook. Step 7 promotes the staged files as they are on disk, `--fix` changes included.
117
161
 
118
162
  **Note:** `skill-check` may return non-zero exit code even when `summary.errorCount` is 0. Always rely on parsed JSON, not the shell exit code.
119
163
 
@@ -138,45 +182,30 @@ If fails: auto-fix (deterministic), re-validate once, record result. If passes:
138
182
 
139
183
  ### 4. Split Oversized Body (if needed)
140
184
 
141
- **If step 2 reported `body.max_lines` failure:**
142
-
143
- **Description Guard Protocol:** Split operations may rewrite the frontmatter. Wrap the split invocation in the four-phase guard defined in §0:
185
+ **If step 2 reported `body.max_lines` failure:** split the body with `{shardBodyHelper}`, the splitter step 5b auto-shard runs (resolve it from `{shardBodyProbeOrder}`; first existing path wins), inside the §0 guard, since a split may rewrite the frontmatter. Never run `npx skill-check split-body --write`: it moves every `##` section to `references/`, Tier 1 included.
144
186
 
145
187
  ```bash
146
- # Phase 1 — capture before the split
188
+ # Phase 1: capture before the split
147
189
  uv run {descriptionGuardHelper} capture <staging-skill-dir>/SKILL.md
148
190
  # stash returned `description` as `guarded_description`
149
191
 
150
- # Phase 2 — run the split (selective extraction or, last-resort, split-body --write)
192
+ # Phase 2: the split
193
+ uv run {shardBodyHelper} <staging-skill-dir>/SKILL.md --budget 400
151
194
 
152
- # Phases 3+4 — verify and restore after the split
195
+ # Phases 3 and 4: verify and restore after the split
153
196
  uv run {descriptionGuardHelper} verify-restore <staging-skill-dir>/SKILL.md \
154
197
  --captured-description "{guarded_description}"
155
198
  ```
156
199
 
157
200
  If `restored: true` in the verify-restore output, apply §0's post-restore re-validation hook.
158
201
 
159
- **Mandatory approach — selective split:** Identify Tier 2 sections by their `## Full` heading prefix (e.g., `## Full API Reference`, `## Full Type Definitions`, `## Full Integration Patterns`). Extract ONLY those sections to `references/`, starting with the largest. Keep ALL Tier 1 content and any smaller sections inline. Inline passive context achieves 100% task accuracy vs 79% for on-demand retrieval (per Vercel research).
160
-
161
- This selective split is deterministic — run `{shardBodyHelper}` (the same splitter step 5b auto-shard uses) rather than counting and extracting by hand. **Resolve `{shardBodyHelper}`** from `{shardBodyProbeOrder}`; first existing path wins.
202
+ The splitter extracts the Tier 2 sections, those whose heading starts `## Full`, largest first, to `references/` until the body fits, puts a cross-reference blockquote in each one's place, and reports `sections_extracted`, `body_lines_after`, `tier1_preserved` (with any pulled heading in `tier1_missing`), `xref_ok` and `under_budget`. Act on them:
162
203
 
163
- ```bash
164
- uv run {shardBodyHelper} <staging-skill-dir>/SKILL.md --budget 400
165
- ```
204
+ - **`tier1_preserved` is false:** **HARD HALT** (exit code 5, `tier1-not-preserved`, phase `validate`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "Split reduced Tier-1 section count (missing {tier1_missing}). Tier-1 sections must remain inline. Aborting the body split: manual review required." Every Tier 1 section must remain inline, and the context snippet's `#quick-start` and `#key-types` anchors name two of them, so this one check keeps the anchors resolving too.
205
+ - **`xref_ok` is false:** **HARD HALT** (exit code 5, `shard-xref-broken`, phase `validate`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "The body split left a cross-reference that does not resolve. Aborting."
206
+ - **`under_budget` is false** (rare: Tier 1 alone runs past about 300 lines): trim `## Key API Summary` and `## Architecture at a Glance` until the body fits, never moving a Tier 1 section to `references/`, then run the split again, guard included, and take `body_lines_after` from it.
166
207
 
167
- It extracts the largest `## Full` sections to `references/` until the body fits, rewrites each as a cross-reference blockquote through the atomic-write helper, and reports `sections_extracted`, `body_lines_after`, `tier1_preserved`, `xref_ok`, and `under_budget`.
168
-
169
- **Do not run `npx skill-check split-body --write` before selective extraction.** It extracts every `##` section top-to-bottom, destroying the Tier 1 inline content the two-tier design depends on — a last resort used only after selective split has been attempted and proven insufficient.
170
-
171
- **If selective split alone does not bring body under the limit** (the splitter reports `under_budget: false` — rare, typically only when Tier 1 itself exceeds 300 lines): reduce Tier 1 Key API Summary and Architecture at a Glance sections to fit within limits. Do not fall back to automated `split-body --write` to solve a Tier 1 sizing problem.
172
-
173
- **Tier 1 preservation check:** After any split operation, verify that all of the following Tier 1 sections remain inline in SKILL.md (not moved to references/): Overview, Quick Start, Common Workflows, Key API Summary, Migration & Deprecation Warnings (if present), Key Types, Architecture at a Glance, CLI (if present), Scripts & Assets (if present), Manual Sections. If any was moved to references/, restore it immediately and re-split targeting only Tier 2 sections.
174
-
175
- **Post-split Tier-1 count check (mandatory):** do not recount Tier-1 headings by hand — consume the splitter's `tier1_preserved` field. `{shardBodyHelper}` compares the Tier-1 headings inline before extraction against those inline afterward and reports `tier1_preserved` (with any pulled headings in `tier1_missing`). Read it from the invocation above, or re-check any split's result with `uv run {shardBodyHelper} <staging-skill-dir>/SKILL.md --dry-run`. **HALT** if `tier1_preserved` is false with: "Split reduced Tier-1 section count (missing {tier1_missing}). Tier-1 sections must remain inline. Restoring from staging backup and aborting body split — manual review required." Do not proceed past §4 — Tier-1 preservation is a hard invariant and a `tier1_preserved: false` result means the splitter pulled an inline section into references/ regardless of the section-list check above (e.g., heading-text variation, capitalization, or the splitter's own heuristics).
176
-
177
- **Anchor validation and remediation:** After any split, verify that context-snippet section anchors (`#quick-start`, `#key-types`) still resolve to headings in SKILL.md. If an anchor no longer resolves (section was split out), restore that section to SKILL.md inline content — the context-snippet must always reference sections that exist in the main file.
178
-
179
- Then re-validate: `npx skill-check check <staging-skill-dir> --format json {security_scan_flag}` — use the flag cached from §2's probe. If `{skill_check_flag_fallback}` is true, skip re-validation and rely on the §3 manual check.
208
+ Then re-validate: `npx skill-check check <staging-skill-dir> --format json {security_scan_flag}`, with the flag cached from §2's probe. If `{skill_check_flag_fallback}` is true, skip re-validation and rely on the §3 manual check.
180
209
 
181
210
  **If skill-check unavailable or no body size issue:** Skip.
182
211
 
@@ -200,90 +229,136 @@ Record: "Security scan skipped — SNYK_TOKEN not configured"
200
229
 
201
230
  **If skill-check unavailable:** Skip with note: "Security scan skipped — skill-check tool unavailable"
202
231
 
203
- ### 6. Content Quality Review (tessl)
232
+ ### 6. Description Angle-Bracket Check
204
233
 
205
- **If tessl available**, run: `timeout 120s npx -y tessl skill review <staging-skill-dir>` — the 120s cap matches skf-test-skill's tessl invocation guard and prevents a stalled LLM call in tessl from blocking compilation. On timeout, treat the step as unavailable and record `tessl: timeout — content quality review skipped` in the evidence report.
234
+ The Claude platform does not accept a skill whose frontmatter `description` contains XML tags, and none of the validators this step runs checks for them: skill-check has no such rule and Tessl Review accepts them. Step 5 §2a replaces every `<` with `{` and every `>` with `}` before SKILL.md is written, and the §0 guard puts that description back whenever a tool rewrites it; this section checks the staged result after every tool in this step has run, whether or not skill-check was available.
206
235
 
207
- Parse output for: `description_score`, `content_score`, `review_score`, `validation_result`, `judge_suggestions[]`.
236
+ Resolve `{frontmatterValidator}` from `{frontmatterValidatorProbeOrder}`; first existing path wins. If neither path resolves, or the command below prints no JSON object, **HARD HALT** (exit code 3, `helper-missing`, phase `validate`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "Cannot check the staged description: skf-validate-frontmatter.py is missing or did not run. Re-install SKF, then re-run create-skill." Run:
208
237
 
209
- **Load dismissal rules:** Before interpreting any findings, load `{tesslDismissalData}` completely. This file is the single source of truth for tessl findings that SKF expects and must dismiss. It defines score thresholds, suggestion dismissal patterns, and the action to take when each rule matches.
238
+ ```bash
239
+ uv run {frontmatterValidator} "<staging-skill-dir>/SKILL.md" --forbid-angle-brackets
240
+ ```
210
241
 
211
- **Apply dismissal rules** in this order:
242
+ Rely on the parsed JSON, not the exit code: the validator also exits 1 for the frontmatter issues §2 and §3 already recorded. Bind `{description_angle_brackets}` ← `description_angle_brackets`.
212
243
 
213
- 1. **Check score thresholds** against the "Score Thresholds" table in `{tesslDismissalData}`. Most importantly:
214
- - If tessl's output contains a `findings[]` entry with rule ID `description_field` (the deterministic angle-bracket / XML-tag validator): follow the **recover-then-halt** path defined by the `description-xml-tags-guarded-upstream` rule in `{tesslDismissalData}`. Re-apply step 5 §2a's `<`/`>` → `{`/`}` substitution in place on the staging SKILL.md frontmatter `description`, re-sync the in-context copy, and re-run `npx -y tessl skill review <staging-skill-dir>` once. **Re-run gate:** treat the `description_field` finding being **absent** from the re-run as the only successful recovery outcome. If the finding persists on the re-run — whether the re-substitution improved the description or not — that counts as recovery failure: halt with the original `description-xml-tags-guarded-upstream` failure message from `{tesslDismissalData}`, do not proceed to §6b, and do not downgrade the recovery to a warning. On successful recovery (finding cleared), log `description-recovery: applied ({count} substitutions)` in the evidence report under "Dismissed tessl suggestions" and continue suggestion iteration against the rerun's `judge_suggestions[]`.
215
- - If the LLM-judge `description_score` is below 100 **but no `description_field` finding is present** (the deterministic validator PASSED): this is a soft discoverability signal (jargon density, trigger-term phrasing) from the judge's sub-scores, not a sanitizer bypass. Record `description_judge_score: {n}% (deterministic description_field validator PASSED)` as a warning in the evidence report and continue — do not trigger the recover-then-halt path and do not halt.
216
- - If `review_score < 60` or `content_score < 60`: record warnings in the evidence report, continue.
217
- 2. **Iterate `judge_suggestions[]`.** For each suggestion:
218
- - Cross-reference against the rules in `{tesslDismissalData}` in order.
219
- - If a rule matches: record `{rule_id, rationale, suggestion_text}` under "Dismissed tessl suggestions" in the evidence report. Do not apply.
220
- - If no rule matches: add to the "Novel tessl suggestions" list for §6b to surface to the user.
221
- 3. **Short-circuit when empty.** If every suggestion was dismissed (no novel suggestions), §6b has nothing to show — auto-proceed to §7.
244
+ - **`{description_angle_brackets}` is `0`:** record `Description angle brackets: none` and continue to §6b.
245
+ - **`{description_angle_brackets}` is null** (the description is missing, blank or not a string, which §2 or §3 already recorded): record `Description angle brackets: not checked — no description` and continue to §6b.
246
+ - **`{description_angle_brackets}` is above `0`:** apply step 5 §2a's substitution again, in place. The guard helper rewrites only the `description` field and takes no description on the command line, so backticks and `$` in it are safe:
222
247
 
223
- - **Unavailable:** Skip with note: "Content quality review skipped — tessl tool unavailable"
248
+ ```bash
249
+ uv run {descriptionGuardHelper} sanitize "<staging-skill-dir>/SKILL.md"
250
+ ```
224
251
 
225
- tessl installs automatically via `npx`. A missing tool is not an error — graceful skip.
252
+ Bind `{angle_bracket_substitutions}` ← `substitutions`, `{angle_brackets_sanitized}` ← `sanitized` and `{sanitized_description}` ← `description`. Then run the validator command above once more and bind `{description_angle_brackets}` ← `description_angle_brackets` again.
253
+ - **Recovered** (the guard helper exited 0, `{angle_brackets_sanitized}` is true and `{description_angle_brackets}` is now `0`): record `Description angle brackets: re-sanitized ({angle_bracket_substitutions} substitutions)` and continue to §6b.
254
+ - **Otherwise** **HARD HALT** (exit code 5, `description-angle-brackets`, phase `validate`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "Description sanitization failed: the staged SKILL.md description still holds angle brackets after step 5 §2a's substitution was applied again. The Claude platform does not accept XML tags in a skill description. Check that `<staging-skill-dir>/SKILL.md` can be written, then re-run create-skill." Nothing has been promoted yet, so the halt writes no result file.
226
255
 
227
- #### 6b. User Decision Gate (conditional)
256
+ ### 6b. Tessl Review (optional)
228
257
 
229
- **If §6 produced no novel suggestions (all dismissed via `{tesslDismissalData}`) OR tessl was unavailable:** Skip this gate — auto-proceed.
258
+ Tessl Review (`tessl review run`, which the helper below runs on a copy of `<staging-skill-dir>`) scores the skill on Tessl's servers with validation checks and two AI judges, one for the description and one for the content. It runs only when the user opted in by setting `tessl_review_workspace` in `{preferencesFile}` to a Tessl workspace name, because it needs a Tessl account, uploads the skill's files to that workspace's review history and spends Tessl credits. The helper applies that setting and every other condition, so run it on every pass and let it decide; `{tesslReviewRules}` explains what is uploaded and what each result means. Nothing in this section halts, asks the user anything, changes the staged files or adds an auto-decision, in interactive and headless runs alike.
230
259
 
231
- **GATE [default: S]** — If `{headless_mode}` is true AND §6 produced novel suggestions: auto-select [S] Skip (a headless run has no human to triage novel suggestions), record `"tessl suggestions: {N} novel suggestion(s) auto-skipped (headless)"` in the evidence report under "Dismissed tessl suggestions", log `"headless: auto-skip {N} novel tessl suggestion(s)"`, and append `{step: "validate", gate: "tessl-suggestions", decision: "S", value: "{N} novel auto-skipped", rationale: "headless mode — no human to triage novel tessl suggestions", timestamp: {ISO}}` to the in-context `headless_decisions[]` list and, the moment it lands, append the same object as a JSON line to the durable audit sink `{sidecar_path}/auto-decisions.jsonl` (the on-landing append established at step 1 §3). §8 below reconciles the sink into the evidence-report `## Auto-Decisions` table — this is the last gate to fire; the earlier gates' rows are already in the sink and were rendered into the staged report at step 5 §7. This is the one consequential auto-decision that drops human-relevant feedback, so it must leave an audit row rather than vanishing. Then auto-proceed to §7 — do not present the menu below.
260
+ Resolve `{tesslReviewHelper}` ← first existing path in `{tesslReviewProbeOrder}`. If neither path exists, set `{tessl_summary}` to `not run — skf-tessl-review.py is missing` and `{tessl_warnings}` to the one line `Tessl Review: {tessl_summary}`, add that line to the evidence report's Remaining Warnings and continue to §7. Otherwise submit the review:
232
261
 
233
- **If §6 produced novel suggestions** (ones not matched by any dismissal rule) AND `{headless_mode}` is false, present them to the user:
262
+ ```bash
263
+ uv run {tesslReviewHelper} submit "<staging-skill-dir>" --preferences "{preferencesFile}"
264
+ ```
234
265
 
235
- "**Content quality review: {score}%**
266
+ A review takes Tessl about two minutes, so no call waits for all of it. When the review is on, `submit` sends a copy of the skill to Tessl and returns `pending` with Tessl's run id as soon as Tessl accepts it; when it is off or cannot run, `submit` returns that result instead. While `{tessl_status}` is `pending`, collect the review, at most six times, and add `--final` to the sixth call, which turns a review still running into `timeout`:
236
267
 
237
- tessl suggestions (novel — not matched by `{tesslDismissalData}`):
238
- {numbered list of novel suggestions}
268
+ ```bash
269
+ uv run {tesslReviewHelper} collect "{tessl_run_id}" --workspace "{tessl_workspace}" --tessl-version "{tessl_version}"
270
+ ```
239
271
 
240
- **Select an option:**
241
- - **[S] Skip** — proceed with current content as-is (default)
242
- - **[A] Apply structural fixes** — apply only structural suggestions (split sections, consolidate duplicates). No new content generated.
243
- - **[R] Review all** — show each suggestion with proposed changes before applying"
272
+ Each call ends within two minutes (a `collect` checks the review for up to 90 seconds, then returns `pending` again or the result), so run each one with your shell tool's default time limit. If the shell tool stops a call before it prints its JSON, or it prints none, make that the last call: set `{tessl_status}` to `failed`, `{tessl_summary}` to `failed — stopped before skf-tessl-review.py reported a result` and `{tessl_warnings}` to the one line `Tessl Review: {tessl_summary}`, keep `{tessl_run_id}` and the other values the calls before it bound, add that line to the Remaining Warnings and continue to §7. Otherwise rely on the JSON, not the exit code, and bind these from the `submit` JSON and again from each `collect` JSON, whose values replace the earlier ones:
244
273
 
245
- #### Gate Rules:
274
+ - `{tessl_status}` ← `status`
275
+ - `{tessl_summary}` ← `summary`
276
+ - `{tessl_warnings}` ← `warnings`
277
+ - `{tessl_workspace}` ← `workspace`
278
+ - `{tessl_version}` ← `tessl_version`
279
+ - `{tessl_run_id}` ← `run_id`
280
+ - `{tessl_review_score}` ← `review_score`
281
+ - `{tessl_description_score}` ← `description_score`
282
+ - `{tessl_content_score}` ← `content_score`
283
+ - `{tessl_validation}` ← `validation`
284
+ - `{tessl_description_suggestions}` ← `description_suggestions`
285
+ - `{tessl_content_suggestions}` ← `content_suggestions`
246
286
 
247
- - **Structural suggestions** (split reference section, consolidate duplicates, reorder sections) can be applied without zero-hallucination risk — they restructure existing content
248
- - **Semantic suggestions** (add examples, add error handling, add validation checkpoints) introduce content not verified from source code. If the user chooses to apply these:
249
- - Warn: "This adds content not verified from source code."
250
- - Mark applied content with `<!-- [TESSL:auto-fix] -->` markers
251
- - Cite as `[TESSL:suggestion]` in the provenance map with `confidence: "TESSL"` (below T3)
252
- - Record in evidence report: "TESSL-suggested content applied: {count} items (unverified)"
253
- - **If user selects [S]:** Record "tessl suggestions: skipped by user" in evidence report. Proceed to section 7.
254
- - **If user selects [A]:** Apply structural fixes only, re-run tessl to capture updated score, record results. Proceed to section 7.
255
- - **If user selects [R]:** Show each suggestion with the proposed change. For each, user confirms or skips. Apply confirmed changes, record results. Proceed to section 7.
287
+ Every key is always present: the scores and `{tessl_validation}` are null and the suggestion lists are empty unless `{tessl_status}` is `reviewed`, and `{tessl_run_id}` is null until Tessl has accepted the review. After the last call, add each entry of `{tessl_warnings}` to the evidence report's Remaining Warnings: a score below 60%, validation errors or, for any status other than `reviewed` and `off`, why the review produced no score. When `{tessl_status}` is `reviewed`, resolve `{tesslReviewRules}` ← first existing path in `{tesslReviewRulesProbeOrder}`, load it, and mark each entry of `{tessl_content_suggestions}` that one of its rules matches with `(not applicable: <rule-id>)`; if neither path exists, list the suggestions unmarked. Apply no suggestion: content suggestions would add text SKF cannot cite to source, and the description comes from the brief. The staged skill holds no `scripts/` or `assets/` until step 7 copies them, so for a brief with scripts or assets, validation findings about missing `scripts/` or `assets/` paths are expected here; test-skill reviews the finished package. §8 records the result.
256
288
 
257
289
  ### 7. Validate metadata.json
258
290
 
259
- **Re-derive the computed fields with `{renderMetadataStatsHelper}` in check mode** rather than re-doing the arithmetic by hand. Resolve `{renderMetadataStatsHelper}` from `{renderMetadataStatsProbeOrder}` (first existing path wins; HALT if neither resolves), then run it against the staged provenance-map and metadata.json:
291
+ **Re-derive the computed fields with `{renderMetadataStatsHelper}` in check mode** rather than re-doing the arithmetic by hand. Resolve `{renderMetadataStatsHelper}` from `{renderMetadataStatsProbeOrder}` (first existing path wins; if neither resolves, **HARD HALT** (exit code 3, `helper-missing`, phase `validate`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "Cannot check metadata.json: skf-render-metadata-stats.py is missing. Re-install SKF, then re-run create-skill."), then run it against the staged provenance-map and metadata.json:
260
292
 
261
293
  ```bash
262
294
  uv run {renderMetadataStatsHelper} <staging-skill-dir>/provenance-map.json \
263
295
  --check <staging-skill-dir>/metadata.json
264
296
  ```
265
297
 
266
- The helper re-bins `entries[]` by `signature_source`, recomputes `exports_documented`, `exports_total`, and `public_api_coverage` / `total_coverage` (null when the denominator is 0), and cross-checks `stats.scripts_count` / `stats.assets_count` against the `scripts[]` / `assets[]` array lengths and the provenance-map `file_entries` counts. It takes the judgment values (`exports_public_api`, `exports_internal`, `effective_denominator`) from `metadata.json` itself and infers the shape from `scope_type` / `skill_type` (pass `--shape` to override). Parse the emitted JSON (rely on the JSON, not the exit code):
298
+ The helper re-bins `entries[]` by `signature_source`, recomputes `exports_documented`, `exports_total`, and `public_api_coverage` / `total_coverage` (null when the denominator is 0), and cross-checks `stats.scripts_count` / `stats.assets_count` against the `scripts[]` / `assets[]` array lengths and the provenance-map `file_entries` counts. It also checks that each T1 or T1-low provenance entry's `confidence`, `signature_source` and `ast_node_type` match its `extraction_method`, and that no entry read by eye (`source-read`) carries `signature_source: "T1"` at any confidence. It takes the judgment values (`exports_public_api`, `exports_internal`, `effective_denominator`) from `metadata.json` itself and infers the shape from `scope_type` / `skill_type` (pass `--shape` to override). Parse the emitted JSON (rely on the JSON, not the exit code):
267
299
 
268
300
  - **`coherence.ok: true`** — the computed fields are internally consistent; record "Metadata: PASS".
269
- - **`coherence.ok: false`** — each `violations[]` entry is `{field, expected, actual}` where `expected` is the correct value. **Auto-fix each computed-value violation** (`field` starting `stats.` or `confidence_distribution.`) by setting that field in `metadata.json` to `expected` (write via `python3 {atomicWriteHelper} write --target <staging-skill-dir>/metadata.json`), leaving every other stats field — e.g. `stats.notes` on a reference app — untouched. Record "Metadata: auto-fixed {N} computed-value discrepanc(y|ies)" listing the fields. These are computed values, so the helper is authoritative — a `confidence_distribution` violation is the per-entry mis-binning compile.md §4 describes (T2 annotations + T3 doc items counted on top of the per-export tiers); the helper's per-entry counts replace them. Carve-outs are handled by `--shape`: a **stack** distribution sums to the constituent count and a **reference-app** distribution to the per-citation count, so those are consistent states, not violations. A `provenance.file_entries.*` violation is not a computed metadata field — it means the provenance-map `file_entries` and metadata counts disagree; record it as a warning for manual reconciliation rather than auto-editing the count.
301
+ - **A `provenance.entries[<i>].*` violation** (handle these before any other): entry `<i>` of the staged provenance map (its `export_name` is in the violation) carries a label its `extraction_method` does not allow (one compile §4 did not settle): relabel it by the Relabel Rule in `{relabelRuleData}`, resolving `{verifyProvenanceCompletenessHelper}` ← first existing path in `{verifyProvenanceCompletenessProbeOrder}` for its `kind-at` lookup. Write the relabeled map with `python3 {atomicWriteHelper} write --target <staging-skill-dir>/provenance-map.json`, then re-run the check above and act on its new result: a relabeled `signature_source` moves the distribution, so the computed-value fixes below come from the re-run, and a violation left as a WARN does not block them. Record the relabeled export names, and each WARN left, on the evidence report's `Provenance labels` line (§8).
302
+ - **`coherence.ok: false`**: each `violations[]` entry is `{field, expected, actual}` where `expected` is the correct value. **Auto-fix each computed-value violation** (`field` starting `stats.` or `confidence_distribution.`) by setting that field in `metadata.json` to `expected` (write via `python3 {atomicWriteHelper} write --target <staging-skill-dir>/metadata.json`), leaving every other stats field (e.g. `stats.notes` on a reference app) untouched. Record "Metadata: auto-fixed {N} computed-value discrepanc(y|ies)" listing the fields. These are computed values, so the helper is authoritative: a `confidence_distribution` violation is the per-entry mis-binning compile.md §4 describes (T2 annotations + T3 doc items counted on top of the per-export tiers); the helper's per-entry counts replace them. The carve-out is handled by `--shape`: a **reference-app** distribution sums to the per-citation count, a consistent state, not a violation. A `provenance.file_entries.*` violation is not a computed metadata field: it means the provenance-map `file_entries` and metadata counts disagree; record it as a warning for manual reconciliation rather than auto-editing the count.
270
303
 
271
304
  Then verify the two fields the helper does not own (genuine constants/contract):
272
305
  - `spec_version` is `"1.3"`.
273
306
  - `scope_type` is present and equals the brief's `scope.type` verbatim.
274
307
 
308
+ ### 7a. Verify Provenance Lines and Citation Prefixes
309
+
310
+ Check that each staged provenance entry's `source_line` is the line that defines its export (the `def` or declaration line itself, not a decorator or blank line above it), and that each `[AST:]` / `[SRC:]` citation in SKILL.md and `references/` carries the prefix its entry's `extraction_method` implies: `ast-grep` gives `[AST:]`, `source-read` gives `[SRC:]`. Also check that each ast-grep entry's `ast_node_type` is a node kind ast-grep knows for its file's language. Resolve `{verifyProvenanceCompletenessHelper}` ← first existing path in `{verifyProvenanceCompletenessProbeOrder}`. If neither path exists, record `Provenance lines: not run: verifier missing` and continue to §8. Otherwise bind `{verify_json}` ← `{project-root}/_bmad-output/.skf-stage/{skill-name}.verify.json` (beside the staging folder, never inside the skill) and, from `{project-root}`, remove the JSON an earlier run left there and run the verifier against the staged package:
311
+
312
+ ```bash
313
+ rm -f "{verify_json}"
314
+ uv run {verifyProvenanceCompletenessHelper} verify \
315
+ --metadata <staging-skill-dir>/metadata.json \
316
+ --provenance <staging-skill-dir>/provenance-map.json \
317
+ --source-root {source_root} \
318
+ --skill-dir <staging-skill-dir> \
319
+ --check-node-kinds \
320
+ -o "{verify_json}"
321
+ ```
322
+
323
+ `{source_root}` is the local tree step 3 extracted from. When it is null, empty or a URL, leave out the `--source-root` line (an empty flag value fails the helper's arguments). When there is no local tree (no flag), the helper checks no source line and reports `summary.stale_check: skipped-no-source-root`, and the citation check still runs. A JSON at `{verify_json}` after the call is this run's: read it, not the exit code (exit 1 means findings). When no JSON is there after the call (an input error, exit 2, `uv` failing, or a shell timeout that stopped it), record `Provenance lines: not run: verifier error`, add the helper's stderr to the evidence report's Remaining Warnings and continue to §8. When `summary.skill_citations_scanned` is above 0 and `summary.skill_citations_matched` is 0, no citation names a path and line the map records (the citations use another root), so the prefix check compared nothing: list that as a WARN. `--check-node-kinds` reports in `node_kinds[]` each `ast-grep` entry whose `ast_node_type` is `ERROR` or not shaped like a kind (judged without ast-grep), or that the ast-grep CLI does not know as a kind of its file's language; each item gives the entry's `entry_index`, `export_name`, `source_file`, `source_line` and `language`. `summary.node_kind_check` is `skipped-no-ast-grep` when no ast-grep CLI is on PATH, or `skipped-unrecognized-ast-grep` when the ast-grep found does not reject a kind no grammar has, so its answers cannot be read: either way ast-grep judged no kind. `node_kinds_unchecked[]` lists, with a `reason`, the entries whose kind ast-grep could not judge, and `summary.node_kind_check_skipped` counts the ast-grep entries in files ast-grep has no language for. Record both on the `Provenance lines` line.
324
+
325
+ Fix the findings that have one answer, in this order, then run the command above once more:
326
+
327
+ 1. **Citation prefixes and source lines.** Never apply them by hand: from `{project-root}`, run the verifier's `fix` on the JSON the run above wrote:
328
+
329
+ ```bash
330
+ uv run {verifyProvenanceCompletenessHelper} fix \
331
+ --verify "{verify_json}" \
332
+ --provenance <staging-skill-dir>/provenance-map.json \
333
+ --skill-dir <staging-skill-dir>
334
+ ```
335
+
336
+ It gives each mismatched citation its `expected_prefix`, moves each `source_line` that has exactly one value in `definition_lines` there, with the citations of the old line in SKILL.md and `references/` (a range by both ends, each citation at most once), writes each changed file through the atomic writer, and prints `applied[]`, `left_as_warn[]` (each finding it left, with its `why`), `files_written[]` and `summary`, on exit 0 and on exit 1 (it left a WARN) alike. Exit 2 prints no JSON (its stderr line names any file it already wrote): list a WARN, `not fixed: verifier error` with that line, and go on to item 2.
337
+ 2. **Node kinds.** For each `node_kinds[]` item (`reason` is `invalid-kind` or `error-kind`), take the entry at its `entry_index` in the staged provenance map (its `export_name` and `source_file` confirm it; item 1's `fix` may have moved its `source_line`) and set its `ast_node_type` to the node kind the Relabel Rule in `{relabelRuleData}` gives: the kind of the recipe the export's `ast_recipe` names in the extraction inventory step 3 §5 wrote, `{project-root}/_bmad-output/.skf-stage/{skill-name}.inventory.json`, else its `kind-at` lookup at the entry's current `source_line`. When the rule gives no kind, list a WARN with its reason. Never invent a kind, and never change `extraction_method` to clear the finding. Write the map with `python3 {atomicWriteHelper} write --target <staging-skill-dir>/provenance-map.json`.
338
+
339
+ If that second run leaves no JSON at `{verify_json}`, record the fixes already applied and `second run: verifier error`, and continue to §8. Fix nothing else, and triage what is left:
340
+
341
+ - A `left_as_warn[]` item whose `why` is `no-definition-line` is unverified, not gone: the rules found no definition line, which may be a shape they do not cover. List its export as unverified.
342
+ - Every other `left_as_warn[]` item needs a person to decide, so list each as a WARN: several definition lines (`several-definition-lines`), a `file-missing`, `line-out-of-bounds` or `line-invalid` item (`needs-decision`), a citation of a line another entry also records, which may cite that export (`shared-line`), a citation or entry `fix` could not find (`citation-not-found`, `entry-not-found`), and a citation inside a `[MANUAL]` block (`inside-manual-block`).
343
+ - The helper's `missing` and `orphaned` exports are not line, citation or node-kind findings: add each to the evidence report's Remaining Warnings.
344
+
345
+ Record the result on the evidence report's `Provenance lines` line (§8): `pass` when the first run found nothing, `findings` when it found something and this section fixed nothing, or what it fixed (`fix`'s `summary.source_lines_moved` and `summary.citation_prefixes_fixed`, and the node kinds item 2 set); then the unverified exports, a WARN for each `left_as_warn[]` item and each other line, citation or node-kind finding the second run still reports, `source lines not checked: no local source tree` when `stale_check` is `skipped-no-source-root`, `node kinds not checked: no ast-grep CLI` or `node kinds not checked: unrecognized ast-grep` when `node_kind_check` is `skipped-no-ast-grep` or `skipped-unrecognized-ast-grep`, each `node_kinds_unchecked[]` entry with its `reason`, and `summary.node_kind_check_skipped` when it is above 0. This section never halts.
346
+
275
347
  ### 8. Update Evidence Report
276
348
 
277
- Add validation results to evidence-report content in context:
349
+ Write the validation results into the staged `<staging-skill-dir>/evidence-report.md`, in place of the `[PENDING: populated by step 6]` placeholders compile left, with `python3 {atomicWriteHelper} write --target <staging-skill-dir>/evidence-report.md`: step 7 promotes that file as it is. In the same write, add under `## Remaining Warnings` the notes steps 5a to 5c kept for the evidence report (the doc-sources note, `{temporal_feeder_notice}` when step 5c set it, because the Deep-tier temporal feeder held no files) and, once each, the skipped authoritative-files scan when the inventory's `authoritative_files_scan` records `not_scanned` (a remote source that was never cloned; the `skipped` count of candidates the user skipped is not a warning). When no split ran and the staged `references/` holds no file, the Body line says `Tier-2 kept inline (references/ empty)`, so an audit can tell inline by design from a split that failed.
278
350
 
279
351
  ```markdown
280
352
  ## Validation Results
281
353
  - Schema: {pass/fail} (quality score: {score}/100)
282
354
  - Frontmatter: {pass/fail}
283
- - Body: {pass/fail} {split-body applied if applicable}
355
+ - Body: {pass/fail} {body split applied if applicable}
284
356
  - Security: {pass/warn/skipped}
285
- - Content Quality (tessl): {pass/warn/skipped} (score: {score}%)
357
+ - Description angle brackets: {none | re-sanitized ({count} substitutions) | not checked — no description}
358
+ - Tessl Review: {tessl_summary}
286
359
  - Metadata: {pass/fail}
360
+ - Provenance labels: {pass | relabeled {N} to match extraction_method: {export names}}{; WARN, no node kind found: {export names}}
361
+ - Provenance lines: {pass | findings | fixed {N} source lines, {M} citation prefixes and {K} node kinds | not run: verifier missing | not run: verifier error}{; second run: verifier error}{; unverified, no definition line found: {export names}}{; WARN: {each line, citation or node-kind warning §7a lists}}{; source lines not checked: no local source tree}{; node kinds not checked: no ast-grep CLI | unrecognized ast-grep}{; node kinds unchecked: {export name (reason) for each node_kinds_unchecked item}}{; node kinds skipped: {N} in files ast-grep has no language for}
287
362
 
288
363
  ## Quality Score Breakdown
289
364
  - Frontmatter (30%): {score} | Description (30%): {score} | Body (20%): {score} | Links (10%): {score} | File (10%): {score}
@@ -297,32 +372,31 @@ Add validation results to evidence-report content in context:
297
372
  ## Auto-Fixed Issues
298
373
  - {list of issues automatically corrected by --fix}
299
374
 
300
- ## Remaining Warnings / Security Findings / Content Quality (tessl)
301
- - {warnings, security results, tessl scores and suggestions — or "skipped"}
302
- ```
303
-
304
- **Auto-Decisions table (reconcile from the durable sink — idempotent):** all gates have now fired — every one appended its row to the on-disk sink `{sidecar_path}/auto-decisions.jsonl` as it landed (including §6b's tessl-suggestions row), step 5 §7 rendered the step 1–3d rows into the staged `<staging-skill-dir>/evidence-report.md`, and steps 7–9 add none. Reconcile: read the sink's JSON lines (the authoritative durable record — it survives any compaction of the in-context buffer), union them with both the `## Auto-Decisions` rows already in `<staging-skill-dir>/evidence-report.md` and the in-context `headless_decisions[]` buffer, keyed on `step`+`gate` so no decision is duplicated or dropped, and re-render the section from that union. Because the rows are recovered from the sink rather than from the possibly-compacted buffer, the audit table stays complete on a long headless run. Emit one row per entry:
375
+ ## Remaining Warnings
376
+ - {warnings and security results, then each entry of {tessl_warnings} — or "none"}
305
377
 
378
+ ## Tessl Review
379
+ - Result: {tessl_summary}
380
+ - Workspace: {tessl_workspace or —} · tessl {tessl_version or —} · Run: {tessl_run_id or —}
381
+ - Validation findings: {each {tessl_validation} finding as `name (status): message`, or "none"}
382
+ - Description suggestions (to act on one, edit the description in the brief and re-run create-skill): {each of {tessl_description_suggestions}, or "none"}
383
+ - Content suggestions (advisory, not applied): {each of {tessl_content_suggestions} with its `(not applicable: <rule-id>)` mark, or "none"}
306
384
  ```
307
- ## Auto-Decisions
308
385
 
309
- | Step | Gate | Decision | Rationale | Timestamp |
310
- |------|------|----------|-----------|-----------|
311
- | {step} | {gate} | {decision}{value?} | {rationale} | {timestamp} |
312
- ```
386
+ When `{tessl_status}` is not `reviewed`, the `## Tessl Review` section holds only its Result line and, when `{tessl_run_id}` is set, its Workspace line, so the report names the run of a review that may still finish.
313
387
 
314
- If the sink, the on-disk rows, and `headless_decisions[]` are all empty, keep the single line step 5 §7 emitted: `No auto-decisions — workflow ran interactively (or all gates had no match to auto-resolve).` This keeps the section always present so reviewers can tell "zero auto-decisions" apart from "section missing", and keeps the row count equal to `summary.auto_decision_count`.
388
+ **Auto-Decisions:** keep the `## Auto-Decisions` section step 5 §7 rendered from the run sink as it is: every gate decided before step 5, and no step records a decision after it, so its rows already match `summary.auto_decision_count`.
315
389
 
316
- **Description Guard population:** if the §0 protocol fired during §2 (`skill-check --fix`) or §4 (`split-body`), fill the four Description Guard fields from context:
390
+ **Description Guard population:** if the §0 protocol fired during §2 (`skill-check --fix`) or §4 (the body split), fill the four Description Guard fields from context:
317
391
 
318
392
  - `Restored: true` when `description_guard_restored == true`, otherwise `false`.
319
- - `Triggering tool`: the tool name recorded by §0 (`skill-check --fix`, `skill-check split-body`, etc.), or `—` if the guard did not fire.
393
+ - `Triggering tool`: the tool name recorded by §0 (`skill-check --fix` in §2, `skf-shard-body.py` in §4), or the template's no-fire dash if the guard did not fire.
320
394
  - `Original description preserved`: `true` if the restore succeeded (on-disk now matches the pre-tool snapshot), `false` if restoration itself failed (rare — treat as a halt condition in a future version).
321
- - `Notes`: a one-sentence description of what the tool had changed. Typical values: `"replaced with generic summary"`, `"truncated at N chars"`, `"angle-bracket tokens re-introduced"`, `"field deleted entirely"`. If `Restored: false`, use `—`.
395
+ - `Notes`: a one-sentence description of what the tool had changed, based on the recorded `description_guard_diff_kind` (`replaced`, `truncated` or `deleted`). Typical values: `"replaced with generic summary"`, `"truncated at N chars"`, `"angle-bracket tokens re-introduced"`, `"field deleted entirely"`. If `Restored: false`, use `—`.
322
396
 
323
- When `Restored: false`, the three follow-up fields are all `—` — this is the clean-run expected state — with one exception: when `description_guard_refused == "empty-capture"` (the protocol's empty-snapshot rule — `verify-restore` exited 1 and no in-context copy allowed a re-run), the guard did fire and must not render as a clean run. Set `Restored: false`, `Triggering tool` to the recorded tool name, `Original description preserved: false`, and `Notes: guard refused — empty captured snapshot (empty-capture)`.
397
+ When `Restored: false`, the three follow-up fields are all `—` — this is the clean-run expected state — with one exception: when `description_guard_refused == "empty-capture"` (§0's empty-snapshot rule — `verify-restore` exited 1 and no in-context copy allowed a re-run), the guard did fire and must not render as a clean run. Set `Restored: false`, `Triggering tool` to the recorded tool name, `Original description preserved: false`, and `Notes: guard refused — empty captured snapshot (empty-capture)`.
324
398
 
325
399
  ### 9. Auto-Proceed
326
400
 
327
- Conditional interaction: §6b halts for user input only when tessl produced novel suggestions; otherwise the step auto-proceeds. After validation completes (including any §6b decisions), load `{nextStepFile}`, read it fully, then execute it. Tool unavailability and validation failures are skips and warnings, never halts.
401
+ No user interaction: this step has no gate. After validation completes, load `{nextStepFile}`, read it fully, then execute it. Tool unavailability, validation failures and every Tessl Review result are recorded as skips and warnings; the step halts only where a section above says HALT: a helper whose probe order says HALT and that no path resolves, the §4 Tier-1 preservation and cross-reference checks, and the §6 description check.
328
402