bmad-module-skill-forge 1.9.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.nvmrc +1 -1
  3. package/README.md +10 -5
  4. package/docs/_data/pinned.yaml +2 -2
  5. package/docs/agents.md +11 -2
  6. package/docs/architecture.md +5 -4
  7. package/docs/bmad-synergy.md +30 -7
  8. package/docs/campaign.md +172 -0
  9. package/docs/examples.md +7 -3
  10. package/docs/forge-auto.md +90 -0
  11. package/docs/getting-started.md +9 -0
  12. package/docs/how-it-works.md +6 -4
  13. package/docs/index.md +4 -3
  14. package/docs/skill-model.md +1 -1
  15. package/docs/troubleshooting.md +17 -1
  16. package/docs/verifying-a-skill.md +2 -2
  17. package/docs/why-skf.md +1 -1
  18. package/docs/workflows.md +64 -24
  19. package/package.json +2 -2
  20. package/src/knowledge/skill-lifecycle.md +1 -1
  21. package/src/module-help.csv +4 -3
  22. package/src/shared/data/language-corpora.json +32 -0
  23. package/src/shared/references/pipeline-contracts.md +6 -3
  24. package/src/shared/scripts/schemas/skill-brief.v1.json +6 -1
  25. package/src/shared/scripts/skf-comention-pairs.py +350 -0
  26. package/src/shared/scripts/skf-count-tokens.py +222 -0
  27. package/src/shared/scripts/skf-derive-assembly-shape.py +107 -0
  28. package/src/shared/scripts/skf-detect-docs.py +240 -4
  29. package/src/shared/scripts/skf-detect-language.py +82 -3
  30. package/src/shared/scripts/skf-detect-tools.py +105 -2
  31. package/src/shared/scripts/skf-emit-result-envelope.py +17 -0
  32. package/src/shared/scripts/skf-enumerate-stack-skills.py +111 -2
  33. package/src/shared/scripts/skf-extract-public-api.py +53 -0
  34. package/src/shared/scripts/skf-find-cycles.py +246 -0
  35. package/src/shared/scripts/skf-hash-content.py +487 -2
  36. package/src/shared/scripts/skf-language-corpora.py +100 -0
  37. package/src/shared/scripts/skf-manifest-ops.py +67 -1
  38. package/src/shared/scripts/skf-merge-doc-urls.py +244 -0
  39. package/src/shared/scripts/skf-preapply.py +1 -1
  40. package/src/shared/scripts/skf-rebuild-managed-sections.py +180 -0
  41. package/src/shared/scripts/skf-recommend-scope-type.py +1 -2
  42. package/src/shared/scripts/skf-render-metadata-stats.py +499 -0
  43. package/src/shared/scripts/skf-rewrite-skill-name.py +308 -0
  44. package/src/shared/scripts/skf-shape-detect.py +576 -25
  45. package/src/shared/scripts/skf-shard-body.py +461 -0
  46. package/src/shared/scripts/skf-skill-inventory.py +139 -3
  47. package/src/shared/scripts/skf-structural-diff.py +307 -67
  48. package/src/shared/scripts/skf-validate-brief-schema.py +41 -6
  49. package/src/shared/scripts/skf-validate-feasibility-report.py +234 -0
  50. package/src/shared/scripts/skf-validate-frontmatter.py +17 -12
  51. package/src/shared/scripts/skf-validate-output.py +443 -10
  52. package/src/shared/scripts/skf-validate-pins.py +3 -3
  53. package/src/shared/scripts/skf-verify-no-trace.py +214 -0
  54. package/src/shared/scripts/skf-verify-provenance-completeness.py +439 -0
  55. package/src/shared/scripts/skf-write-skill-brief.py +21 -5
  56. package/src/skf-analyze-source/SKILL.md +17 -32
  57. package/src/skf-analyze-source/assets/skill-brief-schema.md +1 -1
  58. package/src/skf-analyze-source/customize.toml +2 -0
  59. package/src/skf-analyze-source/references/auto-docs-only.md +116 -0
  60. package/src/skf-analyze-source/references/continue.md +8 -13
  61. package/src/skf-analyze-source/references/generate-briefs.md +28 -12
  62. package/src/skf-analyze-source/references/headless-contract.md +33 -0
  63. package/src/skf-analyze-source/references/health-check.md +1 -2
  64. package/src/skf-analyze-source/references/identify-units.md +25 -36
  65. package/src/skf-analyze-source/references/init.md +12 -25
  66. package/src/skf-analyze-source/references/map-and-detect.md +8 -20
  67. package/src/skf-analyze-source/references/recommend.md +4 -14
  68. package/src/skf-analyze-source/references/scan-project.md +3 -11
  69. package/src/skf-analyze-source/references/step-auto-scope.md +211 -197
  70. package/src/skf-analyze-source/references/step-shape-detect.md +20 -13
  71. package/src/skf-analyze-source/references/unit-detection-heuristics.md +2 -2
  72. package/src/skf-audit-skill/SKILL.md +9 -6
  73. package/src/skf-audit-skill/customize.toml +2 -0
  74. package/src/skf-audit-skill/references/init.md +58 -32
  75. package/src/skf-audit-skill/references/re-index.md +15 -34
  76. package/src/skf-audit-skill/references/report.md +11 -58
  77. package/src/skf-audit-skill/references/semantic-diff.md +4 -22
  78. package/src/skf-audit-skill/references/severity-classify.md +53 -87
  79. package/src/skf-audit-skill/references/step-doc-drift.md +49 -19
  80. package/src/skf-audit-skill/references/structural-diff.md +43 -68
  81. package/src/skf-brief-skill/SKILL.md +7 -36
  82. package/src/skf-brief-skill/assets/scope-templates.md +1 -1
  83. package/src/skf-brief-skill/assets/skill-brief-schema.md +1 -1
  84. package/src/skf-brief-skill/customize.toml +14 -0
  85. package/src/skf-brief-skill/references/analyze-target.md +13 -18
  86. package/src/skf-brief-skill/references/confirm-brief.md +2 -15
  87. package/src/skf-brief-skill/references/draft-checkpoint.md +8 -8
  88. package/src/skf-brief-skill/references/gather-intent.md +27 -24
  89. package/src/skf-brief-skill/references/headless-args.md +1 -1
  90. package/src/skf-brief-skill/references/health-check.md +1 -22
  91. package/src/skf-brief-skill/references/invocation-contract.md +37 -0
  92. package/src/skf-brief-skill/references/scope-definition.md +6 -15
  93. package/src/skf-brief-skill/references/step-auto-brief.md +22 -9
  94. package/src/skf-brief-skill/references/step-auto-validate.md +3 -7
  95. package/src/skf-brief-skill/references/version-resolution.md +1 -1
  96. package/src/skf-brief-skill/references/write-brief.md +19 -13
  97. package/src/skf-campaign/SKILL.md +121 -0
  98. package/src/skf-campaign/assets/campaign-state-schema.json +191 -0
  99. package/src/skf-campaign/customize.toml +75 -0
  100. package/src/skf-campaign/manifest.yaml +15 -0
  101. package/src/skf-campaign/references/campaign-contracts.md +67 -0
  102. package/src/skf-campaign/references/campaign-directive-spec.md +32 -0
  103. package/src/skf-campaign/references/health-check.md +35 -0
  104. package/src/skf-campaign/references/step-01-setup.md +121 -0
  105. package/src/skf-campaign/references/step-02-strategy.md +102 -0
  106. package/src/skf-campaign/references/step-03-pins.md +56 -0
  107. package/src/skf-campaign/references/step-04-provenance.md +63 -0
  108. package/src/skf-campaign/references/step-05-skill-loop.md +103 -0
  109. package/src/skf-campaign/references/step-06-batch.md +88 -0
  110. package/src/skf-campaign/references/step-07-capstone.md +63 -0
  111. package/src/skf-campaign/references/step-08-verify.md +75 -0
  112. package/src/skf-campaign/references/step-09-refine.md +83 -0
  113. package/src/skf-campaign/references/step-10-export.md +106 -0
  114. package/src/skf-campaign/references/step-11-maintenance.md +84 -0
  115. package/src/skf-campaign/references/step-resume.md +115 -0
  116. package/src/skf-campaign/scripts/.gitkeep +0 -0
  117. package/src/skf-campaign/scripts/campaign-deps.py +244 -0
  118. package/src/skf-campaign/scripts/campaign-parse-manifest.py +119 -0
  119. package/src/skf-campaign/scripts/campaign-provenance.py +247 -0
  120. package/src/skf-campaign/scripts/campaign-render-batch.py +199 -0
  121. package/src/skf-campaign/scripts/campaign-render-kickoff.py +158 -0
  122. package/src/skf-campaign/scripts/campaign-report.py +249 -0
  123. package/src/skf-campaign/scripts/campaign-status.py +162 -0
  124. package/src/skf-campaign/scripts/campaign-validate-pins.py +174 -0
  125. package/src/skf-campaign/scripts/campaign-validate-state.py +207 -0
  126. package/src/skf-campaign/templates/campaign-brief-template.yaml +34 -0
  127. package/src/skf-campaign/templates/campaign-report-template.md +54 -0
  128. package/src/skf-campaign/templates/kickoff-template.md +48 -0
  129. package/src/skf-create-skill/SKILL.md +15 -4
  130. package/src/skf-create-skill/assets/compile-assembly-rules.md +35 -34
  131. package/src/skf-create-skill/assets/skill-sections.md +9 -100
  132. package/src/skf-create-skill/assets/tessl-dismissal-rules.md +4 -13
  133. package/src/skf-create-skill/customize.toml +13 -0
  134. package/src/skf-create-skill/references/authoritative-files-protocol.md +7 -7
  135. package/src/skf-create-skill/references/compile.md +37 -47
  136. package/src/skf-create-skill/references/component-extraction.md +8 -35
  137. package/src/skf-create-skill/references/ecosystem-check.md +9 -25
  138. package/src/skf-create-skill/references/enrich.md +4 -17
  139. package/src/skf-create-skill/references/extract.md +20 -27
  140. package/src/skf-create-skill/references/extraction-patterns-tracing.md +1 -1
  141. package/src/skf-create-skill/references/extraction-patterns.md +10 -8
  142. package/src/skf-create-skill/references/generate-artifacts.md +20 -25
  143. package/src/skf-create-skill/references/health-check.md +2 -2
  144. package/src/skf-create-skill/references/load-brief.md +16 -18
  145. package/src/skf-create-skill/references/report.md +27 -14
  146. package/src/skf-create-skill/references/source-resolution-protocols.md +4 -4
  147. package/src/skf-create-skill/references/step-auto-shard.md +52 -25
  148. package/src/skf-create-skill/references/step-doc-rot.md +33 -15
  149. package/src/skf-create-skill/references/step-doc-sources.md +13 -4
  150. package/src/skf-create-skill/references/sub/ccc-discover.md +2 -13
  151. package/src/skf-create-skill/references/sub/fetch-docs.md +33 -46
  152. package/src/skf-create-skill/references/sub/fetch-temporal.md +5 -20
  153. package/src/skf-create-skill/references/tier-degradation-rules.md +6 -8
  154. package/src/skf-create-skill/references/validate.md +69 -29
  155. package/src/skf-create-skill/scripts/scan-doc-rot.py +245 -0
  156. package/src/skf-create-stack-skill/SKILL.md +15 -9
  157. package/src/skf-create-stack-skill/assets/provenance-map-schema.md +1 -1
  158. package/src/skf-create-stack-skill/customize.toml +10 -0
  159. package/src/skf-create-stack-skill/references/compile-stack.md +7 -8
  160. package/src/skf-create-stack-skill/references/compose-mode-rules.md +2 -13
  161. package/src/skf-create-stack-skill/references/detect-integrations.md +49 -54
  162. package/src/skf-create-stack-skill/references/detect-manifests.md +37 -30
  163. package/src/skf-create-stack-skill/references/generate-output.md +24 -75
  164. package/src/skf-create-stack-skill/references/init.md +9 -81
  165. package/src/skf-create-stack-skill/references/manifest-patterns.md +5 -35
  166. package/src/skf-create-stack-skill/references/parallel-extract.md +12 -27
  167. package/src/skf-create-stack-skill/references/rank-and-confirm.md +6 -6
  168. package/src/skf-create-stack-skill/references/report.md +27 -62
  169. package/src/skf-create-stack-skill/references/validate.md +35 -31
  170. package/src/skf-drop-skill/SKILL.md +20 -23
  171. package/src/skf-drop-skill/customize.toml +10 -0
  172. package/src/skf-drop-skill/references/execute.md +67 -36
  173. package/src/skf-drop-skill/references/headless-contract.md +18 -0
  174. package/src/skf-drop-skill/references/health-check.md +1 -13
  175. package/src/skf-drop-skill/references/report.md +44 -10
  176. package/src/skf-drop-skill/references/select.md +93 -48
  177. package/src/skf-drop-skill/scripts/dir-sizes.py +116 -0
  178. package/src/skf-export-skill/SKILL.md +17 -14
  179. package/src/skf-export-skill/assets/managed-section-format.md +2 -5
  180. package/src/skf-export-skill/customize.toml +10 -6
  181. package/src/skf-export-skill/references/generate-snippet.md +21 -35
  182. package/src/skf-export-skill/references/load-skill.md +44 -42
  183. package/src/skf-export-skill/references/multi-skill-mode.md +1 -1
  184. package/src/skf-export-skill/references/orphan-context-detection.md +11 -3
  185. package/src/skf-export-skill/references/package.md +27 -33
  186. package/src/skf-export-skill/references/preflight-snippet-root-probe.md +24 -5
  187. package/src/skf-export-skill/references/result-envelope.md +28 -0
  188. package/src/skf-export-skill/references/summary.md +11 -5
  189. package/src/skf-export-skill/references/token-report.md +42 -24
  190. package/src/skf-export-skill/references/update-context.md +32 -33
  191. package/src/skf-forger/SKILL.md +32 -39
  192. package/src/skf-forger/references/pipeline-mode.md +34 -0
  193. package/src/skf-forger/scripts/parse-pipeline.py +270 -0
  194. package/src/skf-quick-skill/SKILL.md +10 -60
  195. package/src/skf-quick-skill/customize.toml +9 -0
  196. package/src/skf-quick-skill/references/batch-mode.md +6 -4
  197. package/src/skf-quick-skill/references/compile.md +15 -52
  198. package/src/skf-quick-skill/references/ecosystem-check.md +5 -20
  199. package/src/skf-quick-skill/references/finalize.md +12 -6
  200. package/src/skf-quick-skill/references/halt-contract.md +54 -0
  201. package/src/skf-quick-skill/references/health-check.md +3 -4
  202. package/src/skf-quick-skill/references/quick-extract.md +7 -18
  203. package/src/skf-quick-skill/references/registry-resolution.md +1 -23
  204. package/src/skf-quick-skill/references/resolve-target.md +27 -34
  205. package/src/skf-quick-skill/references/write-and-validate.md +10 -25
  206. package/src/skf-refine-architecture/SKILL.md +16 -8
  207. package/src/skf-refine-architecture/customize.toml +9 -0
  208. package/src/skf-refine-architecture/references/compile.md +10 -8
  209. package/src/skf-refine-architecture/references/gap-analysis.md +21 -50
  210. package/src/skf-refine-architecture/references/health-check.md +1 -1
  211. package/src/skf-refine-architecture/references/improvements.md +9 -25
  212. package/src/skf-refine-architecture/references/init.md +9 -16
  213. package/src/skf-refine-architecture/references/issue-detection.md +10 -25
  214. package/src/skf-refine-architecture/references/refinement-rules.md +4 -16
  215. package/src/skf-refine-architecture/references/report.md +14 -11
  216. package/src/skf-rename-skill/SKILL.md +11 -21
  217. package/src/skf-rename-skill/customize.toml +10 -0
  218. package/src/skf-rename-skill/references/execute.md +112 -82
  219. package/src/skf-rename-skill/references/exit-codes.md +12 -0
  220. package/src/skf-rename-skill/references/report.md +16 -8
  221. package/src/skf-rename-skill/references/select.md +69 -42
  222. package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -0
  223. package/src/skf-setup/SKILL.md +21 -13
  224. package/src/skf-setup/customize.toml +10 -0
  225. package/src/skf-setup/references/auto-index.md +11 -10
  226. package/src/skf-setup/references/ccc-index.md +14 -15
  227. package/src/skf-setup/references/detect-and-tier.md +10 -8
  228. package/src/skf-setup/references/report.md +26 -32
  229. package/src/skf-setup/references/tier-rules.md +2 -32
  230. package/src/skf-setup/references/write-config.md +9 -10
  231. package/src/skf-test-skill/SKILL.md +10 -8
  232. package/src/skf-test-skill/customize.toml +2 -0
  233. package/src/skf-test-skill/references/coherence-check.md +19 -31
  234. package/src/skf-test-skill/references/coverage-check.md +111 -67
  235. package/src/skf-test-skill/references/detect-mode.md +10 -41
  236. package/src/skf-test-skill/references/external-validators.md +11 -19
  237. package/src/skf-test-skill/references/init.md +39 -21
  238. package/src/skf-test-skill/references/migration-section-rules.md +4 -4
  239. package/src/skf-test-skill/references/report.md +60 -40
  240. package/src/skf-test-skill/references/score.md +32 -64
  241. package/src/skf-test-skill/references/scoring-rules.md +6 -62
  242. package/src/skf-test-skill/references/source-access-protocol.md +15 -5
  243. package/src/skf-test-skill/references/step-hard-gate.md +1 -3
  244. package/src/skf-test-skill/scripts/aggregate-coherence.py +276 -0
  245. package/src/skf-test-skill/scripts/check-metadata-coherence.py +359 -0
  246. package/src/skf-test-skill/scripts/combine-external-scores.py +190 -0
  247. package/src/skf-test-skill/scripts/compute-score.py +135 -4
  248. package/src/skf-test-skill/scripts/reconcile-coverage.py +327 -0
  249. package/src/skf-test-skill/scripts/validate-inventory.py +251 -0
  250. package/src/skf-test-skill/scripts/verify-declared-numerator.py +192 -0
  251. package/src/skf-update-skill/SKILL.md +17 -5
  252. package/src/skf-update-skill/customize.toml +11 -6
  253. package/src/skf-update-skill/references/detect-changes.md +48 -36
  254. package/src/skf-update-skill/references/health-check.md +5 -11
  255. package/src/skf-update-skill/references/init.md +40 -32
  256. package/src/skf-update-skill/references/manual-section-rules.md +1 -2
  257. package/src/skf-update-skill/references/merge-conflict-rules.md +1 -52
  258. package/src/skf-update-skill/references/merge.md +13 -57
  259. package/src/skf-update-skill/references/re-extract.md +27 -25
  260. package/src/skf-update-skill/references/report.md +14 -7
  261. package/src/skf-update-skill/references/validate.md +32 -30
  262. package/src/skf-update-skill/references/write.md +86 -51
  263. package/src/skf-update-skill/scripts/skf-new-file-diff.py +167 -0
  264. package/src/skf-verify-stack/SKILL.md +11 -21
  265. package/src/skf-verify-stack/customize.toml +12 -3
  266. package/src/skf-verify-stack/references/coverage-patterns.md +1 -29
  267. package/src/skf-verify-stack/references/coverage.md +21 -10
  268. package/src/skf-verify-stack/references/exit-codes.md +14 -0
  269. package/src/skf-verify-stack/references/health-check.md +1 -1
  270. package/src/skf-verify-stack/references/init.md +20 -25
  271. package/src/skf-verify-stack/references/integration-verification-rules.md +10 -19
  272. package/src/skf-verify-stack/references/integrations.md +44 -49
  273. package/src/skf-verify-stack/references/report.md +28 -34
  274. package/src/skf-verify-stack/references/requirements.md +3 -3
  275. package/src/skf-verify-stack/references/synthesize.md +36 -39
  276. package/src/skf-verify-stack/scripts/skf-coverage-tally.py +196 -0
  277. package/src/skf-verify-stack/scripts/skf-report-delta.py +256 -0
  278. package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +258 -0
  279. package/tools/cli/lib/ui.js +3 -2
  280. package/docs/deepwiki.md +0 -89
  281. package/src/skf-rename-skill/references/rebuild-context.md +0 -110
@@ -6,6 +6,12 @@ nextStepFile: '../enrich.md'
6
6
  atomicWriteProbeOrder:
7
7
  - '{project-root}/_bmad/skf/shared/scripts/skf-atomic-write.py'
8
8
  - '{project-root}/src/shared/scripts/skf-atomic-write.py'
9
+ # Resolve `{deriveAssemblyShapeHelper}` the same way — used in §1 to decide
10
+ # whether this is a whole-language reference (registry-corpora prose retained
11
+ # as a Language Guide) or a standard skill (unchanged behaviour).
12
+ deriveAssemblyShapeProbeOrder:
13
+ - '{project-root}/_bmad/skf/shared/scripts/skf-derive-assembly-shape.py'
14
+ - '{project-root}/src/shared/scripts/skf-derive-assembly-shape.py'
9
15
  ---
10
16
 
11
17
  <!-- Config: communicate in {communication_language}. -->
@@ -33,6 +39,14 @@ Evaluate the following conditions. **If the condition fails, skip silently to se
33
39
 
34
40
  No tier gate — if `doc_urls` are present, this step runs at Quick, Forge, and Deep tiers alike.
35
41
 
42
+ **Determine assembly shape (whole-language gate).** Resolve `{deriveAssemblyShapeHelper}` from `{deriveAssemblyShapeProbeOrder}` (first existing path wins) and run it on the brief:
43
+
44
+ ```bash
45
+ uv run {deriveAssemblyShapeHelper} {brief_path}
46
+ ```
47
+
48
+ If the result's `assembly_shape` is `whole-language-reference` (the brief carries ≥1 `doc_urls` entry with `source: language-registry` — a compiler/interpreter repo enriched with the language's canonical prose), set the in-context flag `whole_language_reference: true`. This changes ONLY how the registry-sourced corpora are handled below (§4a): their prose is retained as a **Language Guide** rather than shredded into per-export items. For every other brief the flag is false and this step behaves exactly as before — no change to ordinary skills.
49
+
36
50
  ### 2. Security Notice
37
51
 
38
52
  Display an informational notice (not a gate — the user already approved these URLs in the brief):
@@ -72,7 +86,7 @@ Subpage discovery is triggered if **either** of the following independent trigge
72
86
 
73
87
  The URL matches the path criteria above (ends in `/`, bare domain, or 1 segment) AND the fetched content is under **2000 words**. Short content on root-like URLs almost certainly indicates a navigation hub or landing page, even if it contains introductory code examples that would prevent Trigger 1 from firing. This handles modern doc sites (Mintlify, Docusaurus, GitBook) that include hero sections with code snippets on their root pages.
74
88
 
75
- If neither trigger fires, keep the page content as-is and do NOT trigger subpage discovery.
89
+ If neither trigger fires, keep the page content as-is and do not trigger subpage discovery.
76
90
 
77
91
  **If a root URL with minimal content is detected:**
78
92
 
@@ -122,6 +136,19 @@ Parse the successfully fetched markdown for:
122
136
 
123
137
  **No hallucination:** If information cannot be found in the fetched content, exclude it. Do not infer or fabricate API details.
124
138
 
139
+ **Whole-language references — retain prose, do not shred (`whole_language_reference: true`):** For a whole-language reference the registry-sourced corpora (the guide/Book, the standard/library docs) ARE the product, not the compiler's internal exports. Reducing that prose to per-export signature items and then discarding it under the §5 "T3 never overrides T1" rule (the compiler's AST already owns names like `Vec`, `Option`, `HashMap`) would gut exactly the content the skill exists to teach. So for these briefs, skip §4a below for the registry corpora.
140
+
141
+ ### 4a. Retain the Language Guide (whole-language references only)
142
+
143
+ **Skip this section entirely unless `whole_language_reference: true`.** When it is true, for each `doc_urls` entry whose `source` is `language-registry`:
144
+
145
+ - Do not reduce its fetched markdown to per-export items. Instead retain the cleaned prose as a Language-Guide entry `{url, label, prose}`, where `prose` is the substantive body (narrative, idioms, usage examples, conceptual reference) lightly trimmed of navigation/boilerplate, each block cited `[EXT:{url}]`.
146
+ - Collect these into a `language_guide[]` context artifact, in `doc_urls` order.
147
+
148
+ This artifact is a **distinct** carrier — it is not merged into the extraction inventory and is not subject to the §5 conflict rule, so the canonical prose survives intact into step 5 (compile), which foregrounds it as the skill's Language Guide. Non-registry docs (README-detected, homepage, Pages, docs-folder) still flow through §4's normal per-export extraction and the §5 merge unchanged.
149
+
150
+ **If a registry corpus could not be fetched** (network failure), record it in `language_guide[]` as `{url, label, prose: null}` and warn — step 5 surfaces the gap rather than emitting a thin guide silently.
151
+
125
152
  ### 5. Build Doc-Fetch Inventory
126
153
 
127
154
  **Mode determines merge behavior:**
@@ -129,7 +156,9 @@ Parse the successfully fetched markdown for:
129
156
  - **`source_type: "docs-only"`** — The doc-fetch inventory IS the extraction inventory. It replaces the empty inventory from step 3, since there was no source code to extract from.
130
157
  - **`source_type: "source"` (supplemental mode)** — Merge T3 items into the existing extraction inventory from step 3.
131
158
 
132
- **Conflict rule:** T3 items NEVER override existing T1, T1-low, or T2 items for the same export. When an export already has a higher-confidence entry, the T3 item is discarded. T3 has the lowest priority.
159
+ **Conflict rule:** T3 items never override existing T1, T1-low, or T2 items for the same export. When an export already has a higher-confidence entry, the T3 item is discarded T3 has the lowest priority.
160
+
161
+ **Language-Guide carve-out:** the `language_guide[]` artifact from §4a (whole-language references) is not part of the export inventory and is therefore not subject to this conflict rule — it carries no export key, so it cannot collide with a T1 compiler export and can never be pruned. It is passed separately into step 5, which renders it as the foregrounded Language Guide section. Only the per-export T3 items participate in the T1/T2/T3 merge.
133
162
 
134
163
  **Edge case — T1-zero supplemental mode:** If T1 extraction produced zero results and `doc_urls` are present in supplemental mode, T3 items should be used as the primary inventory since no T1 data exists to conflict with.
135
164
 
@@ -173,48 +202,6 @@ Display:
173
202
 
174
203
  Proceeding to enrichment..."
175
204
 
176
- ### 7. Menu Handling Logic
177
-
178
- **Auto-proceed step — no user interaction.**
179
-
180
- After documentation fetch is complete (or skipped for any reason), immediately load, read entire file, then execute `{nextStepFile}`.
181
-
182
- #### EXECUTION RULES:
183
-
184
- - This is an auto-proceed step with no user choices
185
- - No `doc_urls` in brief: skip directly to next step with no output
186
- - No web fetching available: skip with warning then auto-proceed
187
- - All URLs failed: skip with warning then auto-proceed
188
- - Successful fetch: display report then auto-proceed
189
- - All failures degrade gracefully — skip and auto-proceed
190
-
191
- ## CRITICAL STEP COMPLETION NOTE
192
-
193
- ONLY WHEN documentation is fetched and T3 items are merged into the extraction inventory (or the step is skipped due to no `doc_urls`, no web tools, or fetch failures) will you proceed to load `{nextStepFile}` for enrichment.
194
-
195
- ---
196
-
197
- ## SYSTEM SUCCESS/FAILURE METRICS
198
-
199
- ### SUCCESS:
200
-
201
- - No `doc_urls` in brief: skipped silently, auto-proceeded
202
- - `doc_urls` present: each URL fetched using whatever web tool is available
203
- - Root URLs with minimal content: subpage discovery attempted, relevant subpages fetched
204
- - Individual fetch failures handled gracefully (skip and continue)
205
- - All extracted content cited as T3 with `[EXT:{url}]` provenance
206
- - Existing T1/T1-low/T2 items never overridden by T3 data
207
- - Docs-only mode: doc-fetch inventory correctly replaces empty extraction inventory
208
- - Supplemental mode: T3 items merged into existing inventory respecting conflict rule
209
- - Auto-proceeded to step 4
210
-
211
- ### SYSTEM FAILURE:
212
-
213
- - Halting the workflow because web fetching is unavailable or a URL fails
214
- - Including fetched content without `[EXT:{url}]` citations
215
- - Overriding existing higher-confidence extractions (T1, T1-low, T2) with T3 data
216
- - Hardcoding a specific fetching tool instead of being tool-agnostic
217
- - Hallucinating API details not found in the fetched content
218
- - Beginning compilation in this step (that is step 5)
205
+ ### 7. Auto-Proceed
219
206
 
220
- **Master Rule:** Documentation fetching is best-effort T3 enrichment. Fetch what you can, cite everything as `[EXT:{url}]`, never override higher-confidence data, and move on. Failures degrade gracefully — they never block the skill compilation pipeline.
207
+ No user interaction. After the fetch completes or is skipped for any reason, load `{nextStepFile}`, read it fully, then execute it.
@@ -123,7 +123,7 @@ Per-call rationale:
123
123
  rm -f "$ERR_FILE"
124
124
  ```
125
125
 
126
- Failed individual fetches get a one-line placeholder; the loop continues with remaining tags. If a rate limit (HTTP 429) is hit, stop the release loop, keep the partial `releases.md` file in place (do NOT delete it), and log: "Release fetch stopped at tag {N}/{total} due to rate limiting — partial releases.md retained."
126
+ Failed individual fetches get a one-line placeholder; the loop continues with remaining tags. If a rate limit (HTTP 429) is hit, stop the release loop, keep the partial `releases.md` file in place (do not delete it), and log: "Release fetch stopped at tag {N}/{total} due to rate limiting — partial releases.md retained."
127
127
 
128
128
  **Why sequential here when the rest is parallel:** the append-per-release pattern guarantees that a mid-loop abort (rate limit, network drop, user interrupt) leaves a partial but well-formed `releases.md` with every release fetched so far. Parallel writers appending to the same file would need file locking and per-writer ordering — the simpler sequential loop is robust for free, and 10 release fetches contribute only ~5-10s of the total wall-clock.
129
129
 
@@ -197,7 +197,7 @@ else
197
197
  fi
198
198
  ```
199
199
 
200
- **Rollback rule:** if the `qmd collection add` step fails (non-zero exit, network error, parse error) AND the prior `remove` succeeded, the canonical registry entry in `forge-tier.yaml` MUST be removed to match QMD's actual state. A dangling registry entry that points at a non-existent QMD collection poisons subsequent cache-hit checks in §2. Emit a warning in evidence-report and skip the embed — enrichment degrades to no-QMD for this run.
200
+ **Rollback rule:** if the `qmd collection add` step fails (non-zero exit, network error, parse error) after the prior `remove` succeeded, remove the canonical registry entry in `forge-tier.yaml` to match QMD's actual state. A dangling registry entry that points at a non-existent QMD collection poisons subsequent cache-hit checks in §2. Emit a warning in evidence-report and skip the embed — enrichment degrades to no-QMD for this run.
201
201
 
202
202
  **Scope the embed:** Always pass `--collection {skill-name}-temporal` to `qmd embed`. An unscoped `qmd embed` re-embeds every collection in the QMD store, which can take minutes per run in batch mode and generates wasteful GPU/API cost. If the installed `qmd` CLI does not accept `--collection` (older upstream versions), gate the embed behind a per-skill check: if a previous `{skill-name}-temporal` entry already exists in `qmd_collections` and its `created_at` is within 24 hours, skip the embed entirely and warn "qmd embed skipped — upstream qmd lacks --collection scope; re-embedding all collections would be wasteful in batch mode". Log the skip in the evidence report.
203
203
 
@@ -231,7 +231,7 @@ rm -rf {project-root}/_bmad-output/{skill-name}-temporal/
231
231
 
232
232
  **Error handling:**
233
233
 
234
- - If QMD indexing fails: log the error, note that temporal enrichment will be unavailable. Do NOT fail the workflow.
234
+ - If QMD indexing fails: log the error, note that temporal enrichment will be unavailable. Do not fail the workflow.
235
235
  - If registry update fails: log the error, continue. The collection may exist in QMD even if the registry entry failed.
236
236
  - If cleanup fails: log a warning and continue.
237
237
 
@@ -239,22 +239,7 @@ Display brief confirmation:
239
239
 
240
240
  "**Temporal context indexed.** Collection `{skill-name}-temporal` created ({file_count} files: {list files}). Proceeding to enrichment..."
241
241
 
242
- ### 5. Menu Handling Logic
242
+ ### 5. Auto-Proceed
243
243
 
244
- **Auto-proceed stepno user interaction.**
245
-
246
- After temporal context is fetched and indexed (or skipped for any reason), immediately load, read entire file, then execute `{nextStepFile}`.
247
-
248
- #### EXECUTION RULES:
249
-
250
- - This is an auto-proceed step with no user choices
251
- - Quick/Forge/Forge+ tiers skip directly to next step with no output
252
- - Non-GitHub sources skip directly to next step with no output
253
- - Cached collections (< 7 days old) skip with brief cache-hit message
254
- - Deep tier with fresh fetch displays brief confirmation then auto-proceeds
255
- - All failures degrade gracefully — skip and auto-proceed
256
-
257
- ## CRITICAL STEP COMPLETION NOTE
258
-
259
- ONLY WHEN temporal context is indexed into QMD (or the step is skipped due to eligibility, cache, or failure) will you proceed to load `{nextStepFile}` for documentation fetch.
244
+ No user interaction. After temporal context is fetched and indexed (or skipped for any reason non-Deep tier, non-GitHub source, cache hit, or any failure), load `{nextStepFile}`, read it fully, then execute it.
260
245
 
@@ -8,7 +8,7 @@ When `source_repo` is a remote URL (GitHub URL or owner/repo format) and the tie
8
8
 
9
9
  **Workspace-first clone strategy (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.
11
+ 1. Check `git` availability (`git --version`). `git` is effectively guaranteed at Deep tier (via `gh` dependency) but not guaranteed at Forge tier.
12
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.
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
14
  4. For update-skill: `changed_files_from_manifest` scoping is applied as file-level filters at extraction time on the full workspace checkout.
@@ -18,21 +18,19 @@ When `source_repo` is a remote URL (GitHub URL or owner/repo format) and the tie
18
18
 
19
19
  **Fallback (clone fails or `git` unavailable):**
20
20
 
21
- - The extraction step MUST warn the user explicitly before degrading
22
- - **create-skill:** Warning must include actionable guidance — clone locally and update `source_repo` in the brief to the local path
23
- - **update-skill:** Warning must include actionable guidance — clone locally, re-run [CS] Create Skill with the local path to regenerate provenance data, then re-run the update
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
+ - **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
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
27
27
 
28
- Silent degradation is **forbidden**. The user must always know when AST extraction was skipped and why.
29
-
30
28
  ## AST Tool Unavailable at Forge/Deep Tier
31
29
 
32
30
  When the tier is Forge or Deep but ast-grep is not functional:
33
31
 
34
- - The extraction step MUST warn the user explicitly before degrading
35
- - Warning must include actionable guidance: run [SF] Setup Forge to detect tools
32
+ - The extraction step warns the user explicitly before degrading
33
+ - The warning includes actionable guidance: run [SF] Setup Forge to detect tools
36
34
  - Extraction proceeds using Quick tier strategy
37
35
  - All results labeled T1-low
38
36
  - The degradation reason is recorded in the evidence report
@@ -17,6 +17,27 @@ atomicWriteProbeOrder:
17
17
  descriptionGuardProbeOrder:
18
18
  - '{project-root}/_bmad/skf/shared/scripts/skf-description-guard.py'
19
19
  - '{project-root}/src/shared/scripts/skf-description-guard.py'
20
+ # Resolve `{frontmatterValidator}` by probing `{frontmatterValidatorProbeOrder}`
21
+ # 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.
24
+ frontmatterValidatorProbeOrder:
25
+ - '{project-root}/_bmad/skf/shared/scripts/skf-validate-frontmatter.py'
26
+ - '{project-root}/src/shared/scripts/skf-validate-frontmatter.py'
27
+ # Resolve `{shardBodyHelper}` by probing `{shardBodyProbeOrder}` in order
28
+ # (installed SKF module path first, src/ dev-checkout fallback); first existing
29
+ # path wins. §4 uses it as the deterministic selective splitter and reads its
30
+ # `tier1_preserved` field instead of counting Tier-1 headings pre/post by hand.
31
+ shardBodyProbeOrder:
32
+ - '{project-root}/_bmad/skf/shared/scripts/skf-shard-body.py'
33
+ - '{project-root}/src/shared/scripts/skf-shard-body.py'
34
+ # Resolve `{renderMetadataStatsHelper}` by probing `{renderMetadataStatsProbeOrder}`
35
+ # in order (installed SKF module path first, src/ dev-checkout fallback); first
36
+ # existing path wins. §7 uses it in --check mode to re-derive the metadata
37
+ # `stats` / `confidence_distribution` instead of re-doing the arithmetic by hand.
38
+ renderMetadataStatsProbeOrder:
39
+ - '{project-root}/_bmad/skf/shared/scripts/skf-render-metadata-stats.py'
40
+ - '{project-root}/src/shared/scripts/skf-render-metadata-stats.py'
20
41
  ---
21
42
 
22
43
  <!-- Config: communicate in {communication_language}. -->
@@ -43,7 +64,7 @@ To validate the compiled SKILL.md content against the agentskills.io specificati
43
64
 
44
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.
45
66
 
46
- **This skill's post-restore re-validation hook:** after `{descriptionGuardHelper}` reports `restored: true`, run `uv run {project-root}/src/shared/scripts/skf-validate-frontmatter.py <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).
67
+ **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).
47
68
 
48
69
  ### 1. Check Tool Availability
49
70
 
@@ -104,14 +125,14 @@ If `restored: true` in the verify-restore output, apply §0's post-restore re-va
104
125
 
105
126
  **If skill-check was available:** Skip — already validated in step 2.
106
127
 
107
- **If skill-check NOT available (fallback):** Perform manual frontmatter compliance check:
128
+ **If skill-check not available (fallback):** Perform manual frontmatter compliance check:
108
129
 
109
130
  - [ ] Frontmatter present — file starts with `---` and has closing `---`
110
131
  - [ ] `name` field — present, non-empty, lowercase alphanumeric + hyphens only, 1-64 chars
111
132
  - [ ] `name` matches skill output directory name
112
133
  - [ ] `description` field — present, non-empty, 1-1024 characters
113
134
  - [ ] No unknown fields — only `name`, `description`, `license`, `compatibility`, `metadata`, `allowed-tools` permitted
114
- - [ ] `version` and `author` are NOT in frontmatter (they belong in metadata.json)
135
+ - [ ] `version` and `author` are not in frontmatter (they belong in metadata.json)
115
136
 
116
137
  If fails: auto-fix (deterministic), re-validate once, record result. If passes: record "Frontmatter: PASS".
117
138
 
@@ -137,13 +158,21 @@ If `restored: true` in the verify-restore output, apply §0's post-restore re-va
137
158
 
138
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).
139
160
 
140
- **FORBIDDEN:** Running `npx skill-check split-body --write` without prior selective extraction. The `split-body --write` command extracts ALL `##` sections top-to-bottom, destroying Tier 1 inline content that the two-tier design depends on. This command is a LAST RESORT only after selective split has been attempted and proven insufficient.
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.
162
+
163
+ ```bash
164
+ uv run {shardBodyHelper} <staging-skill-dir>/SKILL.md --budget 400
165
+ ```
166
+
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.
141
170
 
142
- **If selective split alone does not bring body under the limit** (rare — typically only occurs 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.
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.
143
172
 
144
- **Tier 1 preservation check:** After ANY split operation, verify that ALL of the following 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 Tier 1 section was moved to references/, restore it immediately and re-split targeting only Tier 2 sections.
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.
145
174
 
146
- **Post-split Tier-1 count check (mandatory):** before invoking the splitter, count the Tier-1 `##`-level section headings present in SKILL.md (any heading whose title matches one of the Tier-1 names listed above) and store as `tier1_count_pre`. After the split completes, recount as `tier1_count_post`. **HALT** if `tier1_count_post < tier1_count_pre` with: "Split reduced Tier-1 section count from {pre} to {post}. 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 count drop indicates 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).
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).
147
176
 
148
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.
149
178
 
@@ -182,8 +211,8 @@ Parse output for: `description_score`, `content_score`, `review_score`, `validat
182
211
  **Apply dismissal rules** in this order:
183
212
 
184
213
  1. **Check score thresholds** against the "Score Thresholds" table in `{tesslDismissalData}`. Most importantly:
185
- - 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[]`.
186
- - 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.
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.
187
216
  - If `review_score < 60` or `content_score < 60`: record warnings in the evidence report, continue.
188
217
  2. **Iterate `judge_suggestions[]`.** For each suggestion:
189
218
  - Cross-reference against the rules in `{tesslDismissalData}` in order.
@@ -199,7 +228,9 @@ tessl installs automatically via `npx`. A missing tool is not an error — grace
199
228
 
200
229
  **If §6 produced no novel suggestions (all dismissed via `{tesslDismissalData}`) OR tessl was unavailable:** Skip this gate — auto-proceed.
201
230
 
202
- **If §6 produced novel suggestions** (ones not matched by any dismissal rule), present them to the user:
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.
232
+
233
+ **If §6 produced novel suggestions** (ones not matched by any dismissal rule) AND `{headless_mode}` is false, present them to the user:
203
234
 
204
235
  "**Content quality review: {score}%**
205
236
 
@@ -225,14 +256,21 @@ tessl suggestions (novel — not matched by `{tesslDismissalData}`):
225
256
 
226
257
  ### 7. Validate metadata.json
227
258
 
228
- Cross-check metadata.json against extraction inventory:
229
- - `stats.exports_documented` / `stats.exports_public_api` / `stats.exports_internal` / `stats.exports_total` are accurate
230
- - `stats.public_api_coverage` and `stats.total_coverage` are correctly computed (null when denominator is 0)
231
- - `confidence_distribution.t1`, `confidence_distribution.t1_low`, `confidence_distribution.t2`, `confidence_distribution.t3` match actual counts
232
- - `spec_version` is "1.3"
233
- - If `scripts[]` or `assets[]` arrays present: verify `stats.scripts_count`/`stats.assets_count` match array lengths; verify `file_entries` count in provenance-map.json matches
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:
260
+
261
+ ```bash
262
+ uv run {renderMetadataStatsHelper} <staging-skill-dir>/provenance-map.json \
263
+ --check <staging-skill-dir>/metadata.json
264
+ ```
265
+
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):
234
267
 
235
- Auto-fix any discrepancies (these are computed values).
268
+ - **`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.
270
+
271
+ Then verify the two fields the helper does not own (genuine constants/contract):
272
+ - `spec_version` is `"1.3"`.
273
+ - `scope_type` is present and equals the brief's `scope.type` verbatim.
236
274
 
237
275
  ### 8. Update Evidence Report
238
276
 
@@ -263,6 +301,18 @@ Add validation results to evidence-report content in context:
263
301
  - {warnings, security results, tessl scores and suggestions — or "skipped"}
264
302
  ```
265
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:
305
+
306
+ ```
307
+ ## Auto-Decisions
308
+
309
+ | Step | Gate | Decision | Rationale | Timestamp |
310
+ |------|------|----------|-----------|-----------|
311
+ | {step} | {gate} | {decision}{value?} | {rationale} | {timestamp} |
312
+ ```
313
+
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`.
315
+
266
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:
267
317
 
268
318
  - `Restored: true` when `description_guard_restored == true`, otherwise `false`.
@@ -272,17 +322,7 @@ Add validation results to evidence-report content in context:
272
322
 
273
323
  When `Restored: false`, the three follow-up fields are all `—` — this is the clean-run expected state.
274
324
 
275
- ### 9. Menu Handling Logic
276
-
277
- **Conditional interaction step.** If tessl produced suggestions, section 6b halts for user input. Otherwise, auto-proceed.
278
-
279
- After validation completes (including any user decisions from section 6b), immediately load, read entire file, then execute `{nextStepFile}`.
280
-
281
- - Tool unavailability is a skip, not a halt
282
- - Validation failures are warnings — proceed to artifact generation
283
- - tessl gate only triggers when suggestions exist — no gate for clean reviews or unavailable tools
284
-
285
- ## CRITICAL STEP COMPLETION NOTE
325
+ ### 9. Auto-Proceed
286
326
 
287
- ONLY WHEN validation is complete (or skipped) and evidence-report content is updated will you proceed to load `{nextStepFile}` for artifact generation.
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.
288
328