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
@@ -1,6 +1,20 @@
1
1
  ---
2
2
  returnToStep: 'extract.md'
3
3
  extractionPatternsData: 'references/extraction-patterns.md'
4
+ # If neither path exists, Phase 1 goes on without demo exclusion or
5
+ # registry detection.
6
+ detectRegistryProbeOrder:
7
+ - '{project-root}/_bmad/skf/shared/scripts/skf-detect-registry.py'
8
+ - '{project-root}/src/shared/scripts/skf-detect-registry.py'
9
+ # If neither path exists, Phase 4 runs the AST Extraction Protocol instead.
10
+ extractPublicApiProbeOrder:
11
+ - '{project-root}/_bmad/skf/shared/scripts/skf-extract-public-api.py'
12
+ - '{project-root}/src/shared/scripts/skf-extract-public-api.py'
13
+ # If neither path exists, Phase 2b saves no answer and the next run asks
14
+ # again.
15
+ writeSkillBriefProbeOrder:
16
+ - '{project-root}/_bmad/skf/shared/scripts/skf-write-skill-brief.py'
17
+ - '{project-root}/src/shared/scripts/skf-write-skill-brief.py'
4
18
  ---
5
19
 
6
20
  <!-- Config: communicate in {communication_language}. -->
@@ -14,105 +28,119 @@ When `scope.type: "component-library"`, perform specialized extraction that trea
14
28
  ## Rules
15
29
 
16
30
  - Focus only on extracting component catalog, props interfaces, and shared types
17
- - Do not compile SKILL.md content (Step 05) or write output files
31
+ - Do not compile SKILL.md content (Step 05). Write only the scratch files under `{component_scan}`, Phase 4's runner JSON at `{extraction_json}` and, in Phase 2b, the brief
18
32
  - Every extracted item must have a provenance citation: `[AST:{file}:L{line}]` or `[SRC:{file}:L{line}]`
19
33
 
20
34
  ## MANDATORY SEQUENCE
21
35
 
22
- **Prerequisite — §2a already ran.** Step-03 executes `§2a Discovered Authoritative Files Protocol` before delegating to this file. Any promoted authoritative files (`llms.txt`, `AGENTS.md`, etc.) are tracked in the `promoted_docs[]` context list and will be written to `file_entries[]` with `file_type: "doc"` by step 5 §6 — they do not appear in the filtered file list that was passed into this step, so Phase 1 demo exclusion below only operates on code files. No special handling is required in this file for promoted docs. See step 3 §2a for the full flow.
36
+ **Prerequisite: §2a already ran.** Step-03 executes `§2a Discovered Authoritative Files Protocol` before delegating to this file. Any promoted authoritative files (`llms.txt`, `AGENTS.md`, etc.) are tracked in the `promoted_docs[]` context list and will be written to `file_entries[]` with `file_type: "doc"` by step 5 §6. Phase 1 lists them with the brief's other files (a promotion adds each to `scope.include`), and no Phase 4 recipe reads a doc, so this file needs no special handling for them. See step 3 §2a for the full flow.
23
37
 
24
38
  ### Phase 1: Demo/Example Exclusion
25
39
 
26
40
  Before extraction, identify and exclude demo/example files to avoid inflating export counts.
27
41
 
28
- **Note:** For remote sources, the file list from step 3 section 2 was built from the API tree. When scanning for demo directories, scan the local workspace/clone path (`remote_clone_path`) instead of the API-derived file list.
42
+ Bind `{brief_file}` ← the brief file step 1 loaded: `{brief_path}`, `{forge_data_folder}/{skill-name}/skill-brief.yaml` for a skill name, or the current brief of a `--batch` run. Make a scratch folder for this step's files, from `{project-root}`, and bind `{component_scan}` ← the path it prints:
29
43
 
30
- **If `scope.demo_patterns` is specified in the brief:** Use those patterns directly.
44
+ ```bash
45
+ mkdir -p "{project-root}/_bmad-output/.skf-run" && mktemp -d "{project-root}/_bmad-output/.skf-run/skf-create-skill-3d-XXXXXXXX"
46
+ ```
31
47
 
32
- **Otherwise, auto-detect:**
48
+ Resolve `{detectRegistryHelper}` from `{detectRegistryProbeOrder}`. It lists the files of the brief's scope under `{source_root}`, the tree extraction reads, and counts the demo files among them. From `{project-root}`, run it with one `--pattern` for each glob of the brief's `scope.demo_patterns` when it sets them:
33
49
 
34
- 1. Scan the filtered file list for directories matching: `demo/`, `demos/`, `stories/`, `examples/`, `__stories__/`, `storybook/`
35
- 2. Scan for file patterns matching: `*.stories.*`, `*.story.*`, `*.example.*`, `*.demo.*`
36
- 3. Count matches per pattern category
50
+ ```bash
51
+ uv run {detectRegistryHelper} demo --source-root "{source_root}" --brief "{brief_file}" [--pattern "{glob}"] --files-to "{component_scan}/files.txt" --kept-to "{component_scan}/kept.txt"
52
+ ```
37
53
 
38
- **User confirmation required:**
54
+ With no local tree (`{source_root}` is not a folder: a Quick-tier remote source, or one step 3 §2b could not read into a tree), pipe it the repository's file list, `gh api "repos/{owner}/{repo}/git/trees/{source_ref}?recursive=1" --jq '.tree[] | select(.type == "blob") | .path'`, with `--files-from -` in place of `--source-root`.
39
55
 
40
- "**Auto-detected {N} demo/example files** in {M} directories matching these patterns:
41
- {list detected patterns with counts}
56
+ It writes the brief's files to `files.txt` and those no demo pattern matches to `kept.txt`, and prints `patterns[]` (each glob, its `files` count and a `sample`), `excluded`, `directories` and `also_matched[]`: `uv run {detectRegistryHelper} --help` describes them.
42
57
 
43
- Confirm exclusion? [Y/n] Or adjust patterns:"
58
+ **If `scope.demo_patterns` is specified in the brief:** exclude what those patterns match, with no prompt. When `also_matched[]` is not empty, log: "Files the default demo patterns match are left in, since the brief's `scope.demo_patterns` names none of them: {each `also_matched[]` glob, its file count and its sample}. Add a glob to the brief's `scope.demo_patterns` to leave them out."
44
59
 
45
- **GATE [default: Y]** — if `{headless_mode}` is true: auto-confirm the auto-detected exclusion patterns, log "headless: auto-confirm demo/example exclusion ({N} files, {M} directories)", and append `{step: "component-extraction", gate: "demo-exclusion", decision: "Y", value: "{N} files / {M} dirs", rationale: "headless mode — auto-detected demo patterns accepted", timestamp: {ISO}}` to `headless_decisions[]` 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) — the sink feeds the evidence-report `## Auto-Decisions` table at step 5 §7 and step 6 §8. Then proceed without waiting.
60
+ **Otherwise, when `excluded` is not 0, ask for confirmation**, since some `examples/` directories hold API-level code (`{N}` is `excluded`, `{M}` is `directories`):
46
61
 
47
- Wait for user response (interactive only). Apply confirmed patterns to the exclude list. Record `demo_files_excluded: {count}` in context.
62
+ "**Auto-detected {N} demo/example files** in {M} directories matching these patterns:
63
+ {for each patterns[] entry: its glob, its file count and its sample files}
48
64
 
49
- Update the filtered file list by removing excluded demo files before proceeding.
65
+ Confirm exclusion? [Y/n] Or adjust patterns:"
50
66
 
51
- ### Phase 2: Registry Detection
67
+ **GATE [default: Y]**: if `{headless_mode}` is true, auto-confirm the auto-detected exclusion patterns, log "headless: auto-confirm demo/example exclusion ({N} files, {M} directories)", and record it per the Workflow Rules: stage `{"step": "component-extraction", "gate": "demo-exclusion", "decision": "Y", "value": "{N} files / {M} dirs", "rationale": "headless mode: auto-detected demo patterns accepted", "timestamp": "{ISO}"}` as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-create-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"` (step 5 §7 renders it in the evidence report's `## Auto-Decisions` table). Then proceed without waiting.
52
68
 
53
- The component registry is the primary API surface for component libraries.
69
+ Wait for user response (interactive only). When the user adjusts the patterns, run the command again with one `--pattern` for each pattern given and use that result. On `n`, exclude nothing. Record `demo_files_excluded: {count}` in context (0 on `n`), and `demo_answer` ← the `patterns[]` globs the user confirmed or gave (none on `n`, in headless mode, or when the brief set them).
54
70
 
55
- **If `scope.registry_path` is specified in the brief:**
71
+ Bind `{scan_list}`, the filtered file list for the rest of this step: `{component_scan}/kept.txt` when files were excluded, else `{component_scan}/files.txt`.
56
72
 
57
- Read the specified file directly. Parse it as described below.
73
+ **If the command exits non-zero, or no `{detectRegistryHelper}` candidate resolves:** warn "Demo exclusion and registry detection are skipped: {its stderr, or 'skf-detect-registry.py is missing, so re-install SKF'}.", exclude nothing and bind `{scan_list}` to null. Phase 2 then takes a brief's `scope.registry_path` as the registry unscored, or goes on with no registry.
58
74
 
59
- **Otherwise, auto-detect:**
75
+ ### Phase 2: Registry Detection
76
+
77
+ The component registry is the primary API surface for component libraries. Score it with the helper, from `{project-root}`:
60
78
 
61
- 1. Search the filtered file list for files matching these patterns (in priority order):
62
- - Files named `registry.ts`, `registry.tsx`, `registry.js` in any directory
63
- - Files named `components.ts`, `components.tsx` in `registry/`, `catalog/`, or `components/` directories
64
- - Files named `index.ts`, `index.tsx` in `registry/` or `catalog/` directories
79
+ - **If the brief sets `scope.registry_path`:** `uv run {detectRegistryHelper} registry --source-root "{source_root}" --path "{scope.registry_path}"`. Its `selected` file is the registry whatever its score: continue to Phase 3 with no prompt. When `selected` is null (`candidates[0].error` says why), warn "The brief's scope.registry_path `{scope.registry_path}` could not be read ({error}): detecting the registry instead.", set `registry_path_unreadable` ← true, and run the next command.
80
+ - **Otherwise:** `uv run {detectRegistryHelper} registry --files-from "{scan_list}" --source-root "{source_root}"`.
65
81
 
66
- 2. For each candidate, read the file and look for:
67
- - Arrays of objects with fields like `id`, `name`, `component`, `category`
68
- - Type annotations containing `Component[]` or similar array types
69
- - 10+ entries to qualify as a registry (reject small arrays)
82
+ With no local tree, first fetch the files the command reads into `{component_scan}/registry/`, each at its own relative path (`gh api "repos/{owner}/{repo}/contents/{path}?ref={source_ref}" -H "Accept: application/vnd.github.raw"`): the brief's `scope.registry_path` or a path the user gives below, else the paths `uv run {detectRegistryHelper} registry --files-from "{scan_list}" --candidates-only` prints, one per line. Then pass `--source-root "{component_scan}/registry"`.
70
83
 
71
- 3. **Confidence scoring** for each candidate:
72
- - +3 points: Contains `id` field per entry
73
- - +2 points: Contains `name` or `component` field per entry
74
- - +2 points: Contains `category` or `tags` field per entry
75
- - +1 point: Located in a `registry/` or `catalog/` directory
76
- - +1 point: Has 20+ entries
77
- - Minimum threshold: 5 points to qualify
84
+ It prints `selected` (the best qualifying candidate, or null), `headless_accept` and `candidates[]`, each with its `path`, `score` out of 9, `entry_count` and `sample` (its first entries): `uv run {detectRegistryHelper} --help` gives the candidate rules and the score rubric. When it exits non-zero, go on as when no registry was found.
78
85
 
79
- 4. **User confirmation required:**
86
+ **If `selected` is not null, ask for confirmation:**
80
87
 
81
88
  "**Registry candidate detected** at `{path}` (confidence: {score}/9, {count} entries).
82
89
 
83
90
  Sample entries:
84
- {show 3-5 sample entries with id, name, category}
91
+ {show the selected candidate's sample entries with id, name, category}
92
+ {if another candidate qualifies: 'Other candidates: {path} ({score}/9, {count} entries)'}
85
93
 
86
94
  Is this the component registry? [Y/n] Or provide the correct path:"
87
95
 
88
- **GATE [default: Y]** — if `{headless_mode}` is true AND `score >= 7` (high-confidence candidate): auto-confirm the registry candidate, log "headless: auto-confirm registry candidate `{path}` (score {score}/9)", and append `{step: "component-extraction", gate: "registry-confirm", decision: "Y", value: "{path} score={score}/9", rationale: "headless mode — high-confidence registry candidate auto-accepted", timestamp: {ISO}}` to `headless_decisions[]` 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). If `score < 7` in headless mode, auto-reject the candidate (treat as "no registry found"), log "headless: auto-reject low-confidence registry candidate (score {score}/9) — below auto-accept threshold 7", record the decision the same way (buffer + sink, `decision: "reject-low-score"`), and fall through to the "no registry found" branch below. Confidence threshold 7 matches the minimum score the heuristic considers "probable enough to risk" without human eyes.
96
+ **GATE [default: Y]**: if `{headless_mode}` is true and `headless_accept` is true: auto-confirm the `selected` candidate, log "headless: auto-confirm registry candidate `{path}` (score {score}/9)", and record it per the Workflow Rules: stage `{"step": "component-extraction", "gate": "registry-confirm", "decision": "Y", "value": "{path} score={score}/9", "rationale": "headless mode: high-confidence registry candidate auto-accepted", "timestamp": "{ISO}"}` as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-create-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"`. If `headless_accept` is false in headless mode, auto-reject the candidate (treat as "no registry found"), log "headless: auto-reject registry candidate `{path}` (score {score}/9), below the auto-accept threshold", record the decision the same way (`"decision": "reject-low-score"`), and fall through to the "no registry found" branch below.
89
97
 
90
- Wait for user response (interactive only).
98
+ Wait for user response (interactive only). On `Y`, the registry is `selected`: set `registry_answer` ← its path, with `registry_evidence` ← "score {score}/9, {count} entries". When the user gives a path instead, run the `--path` command above with it: when its `selected` is null, show its `error` and ask again; otherwise use that file, with `registry_answer` ← the path and `registry_evidence` ← "given by the user, {count} entries". On `n` with no path, no registry was found.
91
99
 
92
- **If no registry found and no `registry_path` in brief:**
100
+ **If no registry was found and the brief holds no usable `scope.registry_path`:**
93
101
 
94
102
  "**No component registry detected.** Component-library extraction works best with a registry file. Options:
95
103
  - **[P]** Provide the registry file path
96
104
  - **[S]** Skip registry — proceed with standard props-first extraction only"
97
105
 
98
- **GATE [default: S]** — if `{headless_mode}` is true: auto-select [S] Skip (props-first extraction without registry), log "headless: no registry detected, auto-skip to props-first extraction (no path was provided in brief.scope.registry_path)", and append `{step: "component-extraction", gate: "provide-or-skip-registry", decision: "S", rationale: "headless mode — no human to provide registry path", timestamp: {ISO}}` to `headless_decisions[]` 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). The default is `[S]` rather than `[P]` because providing a path requires user input that headless cannot supply; skipping degrades gracefully to a smaller but valid extraction.
106
+ **GATE [default: S]**: if `{headless_mode}` is true: auto-select [S] Skip (props-first extraction without registry), log "headless: no registry detected, auto-skip to props-first extraction (no usable path in brief.scope.registry_path)", and record it per the Workflow Rules: stage `{"step": "component-extraction", "gate": "provide-or-skip-registry", "decision": "S", "rationale": "headless mode: no human to provide registry path", "timestamp": "{ISO}"}` as `{run_dir}/decision.json` and run `uv run {emitEnvelopeHelper} record --workflow skf-create-skill --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"`. The default is `[S]` rather than `[P]` because providing a path requires user input that headless cannot supply; skipping degrades gracefully to a smaller but valid extraction.
107
+
108
+ Wait for user response (interactive only). On [P], run the `--path` command above with the path given: when its `selected` is null, show its `error` and ask again; otherwise use that file, with `registry_answer` ← the path and `registry_evidence` ← "given by the user, {count} entries".
109
+
110
+ ### Phase 2b: Record the Answers in the Brief
111
+
112
+ Write back only what a user answered at a gate above, never a headless auto-decision, so that a second run of the same brief asks neither question: `demo_answer`, which the brief never set, and `registry_answer`, which fills an unset `scope.registry_path` or replaces one Phase 2 could not read (`registry_path_unreadable`). **Skip this phase when neither `demo_answer` nor `registry_answer` is set.**
113
+
114
+ Resolve `{writeSkillBriefHelper}` from `{writeSkillBriefProbeOrder}` and, from `{project-root}`, pipe it each answer that is set (leave out the key of one that is not), with its amendment entries: one per glob of `demo_answer` (`action: "demo-excluded"`, `evidence`: "{files} files" from the glob's `patterns[]` entry) and one for `registry_answer` (`action: "registry-confirmed"`, `evidence`: `registry_evidence`). Every entry takes `category: "demo-and-registry"`, today's ISO `date`, `workflow: "skf-create-skill"` and a `reason`: the user's own, else "user confirmed the demo exclusion at create-skill step 3d", "user adjusted the demo patterns at create-skill step 3d", "user confirmed the detected registry at create-skill step 3d", "user gave the registry path at create-skill step 3d" or, when `registry_path_unreadable` is true, "user replaced the unreadable registry path at create-skill step 3d":
99
115
 
100
- Wait for user response (interactive only).
116
+ ```bash
117
+ uv run {writeSkillBriefHelper} amend --target "{brief_file}" <<'SKF_BRIEF_ANSWERS'
118
+ {"demo_patterns": ["{glob}", ...], "registry_path": "{registry_answer}", "amendments": [{"path": "{glob or registry file}", "action": "{action}", "category": "demo-and-registry", "reason": "{reason}", "evidence": "{evidence}", "date": "{today ISO}", "workflow": "skf-create-skill"}, ...]}
119
+ SKF_BRIEF_ANSWERS
120
+ ```
121
+
122
+ It reads the brief again (step 3 §2a may have amended it since step 1 loaded it), sets the fields, appends the entries, keeps the previous brief as `{brief_file}.bak` and writes the new one atomically. On exit 0, display: "**Recorded in the brief:** {`scope.demo_patterns` and/or `scope.registry_path`}, with a `demo-and-registry` amendment for each." When it exits non-zero, or no candidate resolves, warn "The step 3d answers were not saved to the brief ({its stderr}): the next run asks again." and continue.
101
123
 
102
124
  ### Phase 3: Parse Registry
103
125
 
104
- If a registry was confirmed, parse it into `component_catalog[]`:
126
+ If a registry was confirmed, bind `{registry_file}` ← its path (the brief's `scope.registry_path`, `selected` or the path the user gave) and list its entries, from `{project-root}`, with the `--source-root` Phase 2 used:
127
+
128
+ ```bash
129
+ uv run {detectRegistryHelper} registry --source-root "{source_root}" --path "{registry_file}" --entries
130
+ ```
105
131
 
106
- **Per-component entry:**
132
+ Map each of its `entries[]` (one per object literal of the registry's array, each with its `line`, its `keys` and the `id`, `name`, `component`, `category`, `tags` and `description` it has) to one `component_catalog[]` entry:
107
133
 
108
- - `id` — registry key (used for CLI `add` command)
109
- - `name` — display name (PascalCase)
110
- - `description` — from registry or empty
111
- - `category` — from registry field or directory structure
112
- - `available_in[]` — which design system variants include this component
113
- - `code_paths[]` — source file path for each variant
114
- - `tags[]` — from registry or empty
115
- - Provenance citation: `[SRC:{registry_file}:L{line}]`
134
+ - `id`: the entry's `id` (used for the CLI `add` command)
135
+ - `name`: display name (PascalCase), from `name` or `component`
136
+ - `description`: `description`, or empty
137
+ - `category`: `category`, or from the directory structure
138
+ - `available_in[]`: which design system variants include this component
139
+ - `code_paths[]`: source file path for each variant (from the entry's other `keys`, read at its `line` in the registry file, or from the directory structure)
140
+ - `tags[]`: `tags`, or empty
141
+ - Provenance citation: `[SRC:{registry_file}:L{line}]`, with the entry's `line`
142
+
143
+ When the command exits non-zero, or no candidate resolves, read the entries from the registry file by eye instead.
116
144
 
117
145
  Display: "**Parsed component catalog: {N} components across {M} categories.**"
118
146
 
@@ -122,47 +150,35 @@ Display: "**Parsed component catalog: {N} components across {M} categories.**"
122
150
 
123
151
  Extract props interfaces as the primary API contracts, then link to components.
124
152
 
125
- **Step 1 — Extract Props interfaces:**
153
+ At Quick tier no recipe runs: read the shapes the steps below name from source, as T1-low. At Forge, Forge+ and Deep tiers, run the component-library recipes over `{scan_list}` in one call. Resolve `{extractPublicApiHelper}` from `{extractPublicApiProbeOrder}`; it writes `{extraction_json}`, which step 3 §2b bound beside the staging folder: step 3 §5's `init` seeds the inventory from it, so it sits outside the scratch folder Phase 6 removes. From `{project-root}`, create its folder (the runner creates none), remove the JSON an earlier run left there and run the runner with `{tier}` the forge tier (when `{scan_list}` is null, pass `--brief "{brief_file}"` in place of `--files-from "{scan_list}"`: the runner then lists the brief's files itself):
126
154
 
127
- Load `{extractionPatternsData}` and use the component-library-specific patterns.
155
+ ```bash
156
+ mkdir -p "{project-root}/_bmad-output/.skf-stage"
157
+ rm -f "{extraction_json}"
158
+ uv run {extractPublicApiHelper} --mode full --source-root "{source_root}" --files-from "{scan_list}" --recipe-set component-library --scope-type component-library --tier {tier} -o "{extraction_json}"
159
+ ```
128
160
 
129
- Using AST tools (Forge/Deep) or source reading (Quick):
161
+ Act on the JSON's `status`, never on the exit code. **On `ok` or `incomplete`**, each of the `exports[]` in `{extraction_json}` is T1: it carries its `citation` (`[AST:{file}:L{line}]`), `ast_recipe`, `ast_node_type`, `export_type`, `confidence` and `extraction_method`, and the steps below sort the exports by `ast_recipe`. Read by eye, as T1-low, each file its `file_issues` lists as `syntax-errors` or `not-utf8`, where a recipe can miss an export. A `no-recipes` issue is a file no recipe reads, such as a stylesheet: there is nothing to extract from it. A `missing` or `unreadable` issue is a listed file the runner could not read: record it for the evidence report as not extracted. Step 3 §5's `init` records the runner's warnings, and Gate 2 shows them: the head-cap warning when `truncated` is true (a recipe, which `recipes[]` marks, found more matches than the head cap keeps), and each `errors[]` item of an `incomplete` run (an ast-grep run failed or timed out, so its files may be unread).
130
162
 
131
- ```yaml
132
- # React/TypeScript props interfaces
133
- id: react-props-interfaces
134
- language: typescript
135
- rule:
136
- pattern: 'export interface $NAME { $$$ }'
137
- constraints:
138
- NAME:
139
- regex: '.*Props$'
140
- ```
163
+ **On `no-ast-grep`, or with no JSON at `{extraction_json}`** (an input error, or no candidate resolves): load `{extractionPatternsData}`, which holds every recipe the steps below name and the forms each does not cover (Known Limitation #11), and run each of them as its AST Extraction Protocol says: its **When the Runner Cannot Run** loads the recipes' notes, the languages each runs in among them.
141
164
 
142
- For each `*Props` interface found:
143
- - Extract all fields with types, optionality, and default values
165
+ **Step 1 (extract Props interfaces):**
166
+
167
+ The Props contracts are the exports `react-props-interfaces` finds (`typescript` for `.ts` files, `tsx` for `.tsx` files) and, in a Vue component library, those `vue-define-props` finds in the `.vue` files (`vue-define-props-tsx` for a `<script setup lang="tsx">` block): each such match's `$NAME` is the props type of the component its `.vue` file defines. Without the runner, the Vue recipes run through the CLI with the scratch `sgconfig.yml` the Vue note in `extraction-patterns-by-hand.md` describes.
168
+
169
+ For each Props contract found (a `*Props` interface, or a Vue props type):
170
+ - Extract all fields with types, optionality, and default values (for a Vue props type, from the interface or type literal it names)
144
171
  - Extract JSDoc descriptions per field (if present)
145
172
  - Record: interface name, fields[], source file, line number
146
173
  - Provenance: `[AST:{file}:L{line}]` or `[SRC:{file}:L{line}]`
147
174
 
148
- **Step 2 — Extract component exports:**
149
-
150
- ```yaml
151
- # React component exports (PascalCase)
152
- id: react-component-exports
153
- language: tsx # Use 'tsx' for .tsx files, 'typescript' for .ts files
154
- rule:
155
- pattern: 'export function $NAME($$$PARAMS)'
156
- constraints:
157
- NAME:
158
- regex: '^[A-Z]'
159
- ```
175
+ **Step 2 (extract component exports):**
160
176
 
161
- Also run `export const $NAME` patterns for arrow function components.
177
+ The component exports are those `react-component-functions` (its `javascript` form for `.js` and `.jsx` files), `react-component-arrow-functions` and `react-wrapped-components` (for `memo`, `forwardRef` and `lazy` components) find, and the items of a local list such as the `export { Button, buttonVariants }` that ends a shadcn/ui component file, which `js-local-exports` finds. Sort a local list's items by what they name: the runner records an item's `export_type` as the kind of the declaration it names (`interface`, `type` or `enum` for a type). A type-only item (one in an `export type { ... }` list, or a `type X` specifier) is a type: one whose name ends in `Props` is a Props contract for Steps 1 and 3 (read its fields from the interface or type the list names), and any other is a shared type for Step 4. A PascalCase value item is a component, and any other value item (such as `buttonVariants`) is a shared export: record it with the shared types of Step 4.
162
178
 
163
179
  For each component export: record name, source file, line number. Do not document the function signature in detail (it's always `(props: XProps) => JSX.Element`).
164
180
 
165
- **Step 3 — Link Props to Components:**
181
+ **Step 3 (link Props to components):**
166
182
 
167
183
  Use a 3-level fallback chain:
168
184
 
@@ -170,14 +186,11 @@ Use a 3-level fallback chain:
170
186
  2. **File co-location (fallback):** If naming doesn't match, check if a Props interface and a component are defined in the same file
171
187
  3. **Generic parameter (deep fallback):** Look for `ComponentProps<typeof Foo>` or similar generic patterns that reference the component
172
188
 
173
- For each linked pair, record the association. For unlinked Props interfaces, include them as standalone type exports.
189
+ For each linked pair, record the association. For unlinked Props interfaces, include them as standalone type exports. Include an unlinked component export with a note that no Props interface was found (signature-only, T1-low confidence for API contract).
174
190
 
175
- **Step 4 — Extract shared types:**
191
+ **Step 4 (extract shared types):**
176
192
 
177
- Extract non-Props type exports using standard AST patterns (same as Forge tier):
178
- - `export type $NAME = $VALUE`
179
- - `export enum $NAME { $$$ }`
180
- - `export interface $NAME { $$$ }` (excluding `*Props` already captured)
193
+ The shared types are the exports `ts-exported-types` finds: the exported interfaces, type aliases and enums, generic, `extends` and `export declare` forms included, less the `*Props` interfaces Step 1 took. It returns top-level exports only: a member of an `export namespace` block is not a module export.
181
194
 
182
195
  ### Phase 5: Variant Consolidation
183
196
 
@@ -204,17 +217,20 @@ Display: "**Variant consolidation: {unique} unique components across {variant_co
204
217
 
205
218
  ### Phase 6: Build Component Extraction Results
206
219
 
207
- Compile all extracted data into the format expected by step 3 section 5:
220
+ Step 3 §5 takes the runner's exports from `{extraction_json}` as it wrote them. Prepare what it sends on top: an entry below for each export read by eye (Quick tier, a `file_issues` file, or the runner's fallback), each Props interface's fields as its `params`, and `component_catalog[]`; keep the aggregate counts below in context for step 5's `metadata.json` stats:
208
221
 
209
222
  **Per-export entry (for Props interfaces — primary API):**
210
223
 
211
224
  - Interface name (e.g., `NativeLiquidButtonProps`)
212
225
  - Full interface with all fields and types
213
- - Parameters: each field as name, type, required/optional, default
226
+ - `params`: each field as `{name, type, default, optional, description}`, sent with `patch`
214
227
  - Linked component name (e.g., `NativeLiquidButton`)
215
228
  - Source file and line number
216
229
  - Provenance citation
217
- - Confidence tier (T1 or T1-low)
230
+ - Confidence tier: T1 when an ast-grep rule matched the interface, T1-low when it was read by eye
231
+ - `extraction_method`: `ast-grep` or `source-read`, the tool that produced the entry
232
+ - `ast_node_type`: the `kind` the matching recipe declares (`export_statement` for `react-props-interfaces`: the recipe matches the whole export, not the `interface_declaration` inside it), or `null` when read by eye
233
+ - `ast_recipe`: the `id` of the recipe that matched it, or `null` when read by eye
218
234
 
219
235
  **Per-export entry (for component functions):**
220
236
 
@@ -222,7 +238,7 @@ Compile all extracted data into the format expected by step 3 section 5:
222
238
  - Linked Props interface (if found)
223
239
  - Source file and line number
224
240
  - Provenance citation
225
- - Confidence tier
241
+ - Confidence tier, `extraction_method`, `ast_node_type` and `ast_recipe`, labeled by the tool that produced the entry as for Props interfaces above (a component `js-local-exports` found records `export_specifier`, the kind that recipe declares)
226
242
 
227
243
  **Per-export entry (for shared types):**
228
244
 
@@ -239,6 +255,12 @@ Compile all extracted data into the format expected by step 3 section 5:
239
255
 
240
256
  **Store `component_catalog[]` in context** — this is consumed by step 5 for the Component Catalog section.
241
257
 
258
+ Remove this step's scratch folder, from `{project-root}` (the `case` guard deletes nothing unless `{component_scan}` is the folder Phase 1 made):
259
+
260
+ ```bash
261
+ case "{component_scan}" in "{project-root}/_bmad-output/.skf-run/skf-create-skill-3d-"*) rm -rf "{component_scan}" ;; esac
262
+ ```
263
+
242
264
  Display: "**Component extraction complete.** Returning to main extraction flow."
243
265
 
244
266
  ## RETURN PROTOCOL
@@ -1,5 +1,15 @@
1
1
  ---
2
2
  nextStepFile: 'compile.md'
3
+ forgeTierConfig: '{sidecar_path}/forge-tier.yaml'
4
+ # If neither path exists, §2 finds no enrichment collection and the step is
5
+ # skipped.
6
+ forgeTierRwProbeOrder:
7
+ - '{project-root}/_bmad/skf/shared/scripts/skf-forge-tier-rw.py'
8
+ - '{project-root}/src/shared/scripts/skf-forge-tier-rw.py'
9
+ # §4 appends the T2 annotations to the extraction inventory through it.
10
+ extractionInventoryProbeOrder:
11
+ - '{project-root}/_bmad/skf/shared/scripts/skf-extraction-inventory.py'
12
+ - '{project-root}/src/shared/scripts/skf-extraction-inventory.py'
3
13
  ---
4
14
 
5
15
  <!-- Config: communicate in {communication_language}. -->
@@ -31,44 +41,47 @@ Continue to step 2.
31
41
 
32
42
  ### 2. Collection Inventory Pre-check (Deep Tier Only)
33
43
 
34
- Before searching, check which QMD collections are available:
44
+ Before searching, find this skill's enrichment collections. Resolve `{forgeTierRwHelper}` from `{forgeTierRwProbeOrder}` and read the registry as JSON, from `{project-root}`:
35
45
 
36
- 1. Read the sidecar `forge-tier.yaml` to get registered `qmd_collections` entries
37
- 2. Identify which collections contain enrichment context — collections with `type` equal to `"temporal"` (issues, PRs, changelogs) or `"docs"` (fetched external documentation). Do not include `"extraction"` or `"brief"` type collections.
38
- 3. **If no enrichment collections exist** (no `"temporal"` or `"docs"` type collections): report this and auto-proceed. Display:
46
+ ```bash
47
+ uv run {forgeTierRwHelper} read --target "{forgeTierConfig}"
48
+ ```
49
+
50
+ 1. Bind `{enrichment_collections}` ← the `name` of each entry of its `data.qmd_collections` whose `skill_name` is `{skill-name}` and whose `type` is `"temporal"` (issues, PRs and changelogs, from step 3b) or `"docs"` (fetched external documentation, from step 3c): at most `{skill-name}-temporal` and `{skill-name}-docs`. Another skill's collections never count, and neither do `"extraction"` or `"brief"` collections. The list is empty when `exists` is false, the command fails or no candidate resolves.
51
+ 2. **If `{enrichment_collections}` is empty:** report this and auto-proceed. Display:
39
52
 
40
53
  "**Enrichment: no enrichment collections available.**
41
- Only brief-type or extraction-type QMD collections found — no temporal context (issues, PRs, changelogs) or docs collections indexed. {IF extraction_mode is 'docs-only' AND T3 items exist in extraction_inventory: 'T3 documentation content is available in extraction inventory — enrichment via QMD is skipped but T3 content will be compiled.'} {ELSE: 'Enrichment skipped (expected for first-run skill creation). Enrichment becomes available when temporal or docs context is indexed into QMD collections.'}
54
+ No temporal context (issues, PRs, changelogs) or docs collection of this skill is indexed in QMD. {IF extraction_mode is 'docs-only' AND T3 items exist in extraction_inventory: 'T3 documentation content is available in the extraction inventory: enrichment through QMD is skipped, and the T3 content will be compiled.'} {ELSE: 'Enrichment skipped (expected for first-run skill creation). Enrichment becomes available when temporal or docs context is indexed into QMD collections.'}
42
55
 
43
56
  Proceeding to compilation..."
44
57
 
45
58
  Then immediately load, read entire file, then execute `{nextStepFile}`.
46
59
 
47
- 4. **If temporal collections exist:** Continue to step 3.
60
+ 3. **Otherwise** (a temporal collection, a docs collection, or both): continue to step 3.
48
61
 
49
62
  ### 3. QMD Enrichment Searches (Deep Tier Only)
50
63
 
51
- For each major exported function — limited to the **top-level public API surface** (typically 10-20 functions that will appear in the context-snippet), not all extracted exports — search the temporal QMD collections for context:
64
+ For each major exported function (the **top-level public API surface**, typically the 10-20 functions that will appear in the context-snippet, not all extracted exports), search `{enrichment_collections}` for context. Every query below passes them as its collections, so no other skill's issues or docs can annotate this one:
52
65
 
53
66
  **Search query construction:**
54
67
 
55
- For each function, derive the **module context** from the extraction inventory's source file path (e.g., `src/graph/neo4j/index.ts` → module context `graph neo4j`). This context improves search relevance by scoping results to the function's subsystem without adding extra queries.
68
+ Read the functions and their source files from `{extraction_inventory}`, the extraction inventory step 3 §5 wrote. For each function, derive the **module context** from its source file path (e.g., `src/graph/neo4j/index.ts` → module context `graph neo4j`). This context improves search relevance by scoping results to the function's subsystem without adding extra queries.
56
69
 
57
70
  **Primary searches (BM25 — always runs, no GPU/VRAM dependency):**
58
71
 
59
- 1. **Issues/PRs:** `qmd_bridge.query(searches=[{type:'lex', query:'{module_context} {function_name}', intent:'issues-prs'}])` — find related discussions scoped by module context
60
- 2. **Changelog entries:** `qmd_bridge.query(searches=[{type:'lex', query:'{function_name} changelog', intent:'changelog'}])` — find version history, breaking changes (kept generic — changelogs rarely use module paths)
61
- 3. **Migration notes:** `qmd_bridge.query(searches=[{type:'lex', query:'{function_name} migration deprecated breaking', intent:'migration'}])` — find deprecation or migration context using exact keyword matching
72
+ 1. **Issues/PRs:** `qmd_bridge.query(searches=[{type:'lex', query:'{module_context} {function_name}', intent:'issues-prs'}], collections={enrichment_collections})`: related discussions, scoped by module context
73
+ 2. **Changelog entries:** `qmd_bridge.query(searches=[{type:'lex', query:'{function_name} changelog', intent:'changelog'}], collections={enrichment_collections})`: version history and breaking changes (kept generic, since changelogs rarely use module paths)
74
+ 3. **Migration notes:** `qmd_bridge.query(searches=[{type:'lex', query:'{function_name} migration deprecated breaking', intent:'migration'}], collections={enrichment_collections})`: deprecation or migration context, by exact keyword matching
62
75
 
63
76
  **Supplemental search (best-effort — requires GPU/VRAM, may fail):**
64
77
 
65
- 4. **Semantic migration context:** `qmd_bridge.query(searches=[{type:'vec', query:'{module_context} {function_name} migration deprecated', intent:'semantic-migration'}])` — adds semantic matches (synonyms, paraphrases) that BM25 keyword search may miss. Merge results with search #3, deduplicating by document ID. If the `vec`-type search fails (VRAM, GPU driver, model loading), discard silently — the BM25 (`lex`) results from search #3 provide baseline coverage.
78
+ 4. **Semantic migration context:** `qmd_bridge.query(searches=[{type:'vec', query:'{module_context} {function_name} migration deprecated', intent:'semantic-migration'}], collections={enrichment_collections})`: adds semantic matches (synonyms, paraphrases) that BM25 keyword search may miss. Merge results with search #3, deduplicating by document ID. If the `vec`-type search fails (VRAM, GPU driver, model loading), discard silently: the BM25 (`lex`) results from search #3 provide baseline coverage.
66
79
 
67
- **Tool resolution for qmd_bridge:** QMD MCP exposes a single `query` tool that accepts a `searches[]` array. Each entry has a `type` field — `'lex'` for BM25 keyword search, `'vec'` for semantic vector search, `'hyde'` for hypothetical-document retrieval — plus `query` and `intent` fields. Claude Code: `mcp__plugin_qmd-plugin_qmd__query`. Cursor: qmd MCP server. CLI: `qmd search "{query}"` (BM25) / `qmd vector-search "{query}"` (semantic). See `knowledge/tool-resolution.md`.
80
+ **Tool resolution for qmd_bridge:** QMD MCP exposes a single `query` tool that accepts a `searches[]` array and a `collections` list. Each search has a `type` field (`'lex'` for BM25 keyword search, `'vec'` for semantic vector search, `'hyde'` for hypothetical-document retrieval) plus `query` and `intent` fields. Claude Code: `mcp__plugin_qmd-plugin_qmd__query`. Cursor: qmd MCP server. CLI: `qmd search "{query}"` (BM25) or `qmd vsearch "{query}"` (semantic), with one `-c {collection}` for each collection of `{enrichment_collections}`. See `knowledge/tool-resolution.md`.
68
81
 
69
82
  **Tool probe (graceful degradation):** If any tool-not-found error surfaces while invoking `query` (e.g., legacy `vector_search` still expected by an older client, or a bridge returns "tool not registered"), treat it as a non-fatal failure for that function's enrichment and continue with the remaining functions. Do not retry against the stale `vector_search` tool name — that name was removed from the QMD MCP server. Record the degradation in context for the evidence report.
70
83
 
71
- **For each QMD result:**
84
+ **For each QMD result from a collection of `{enrichment_collections}`** (drop a result from any other collection):
72
85
 
73
86
  - Create a T2 annotation: `[QMD:{collection}:{doc}]`
74
87
  - Classify temporal relevance:
@@ -83,19 +96,24 @@ For each function, derive the **module context** from the extraction inventory's
83
96
 
84
97
  ### 4. Annotate Extraction Inventory
85
98
 
86
- Add enrichment annotations to the extraction inventory without modifying extraction data:
99
+ Add the enrichment annotations to `{extraction_inventory}` without modifying its extraction data, so compile reads them from disk. One annotation per finding, for each function that has one:
87
100
 
88
- **Per-function enrichment (if found):**
89
101
  - Related issues/PRs with summary
90
102
  - Changelog history (version changes, breaking changes)
91
103
  - Migration/deprecation context
92
104
  - T2 provenance citation for each annotation
93
105
 
94
- **Enrichment summary counts:**
95
- - Functions enriched: {count} of {total}
96
- - T2 annotations added: {count}
97
- - T2-past annotations: {count}
98
- - T2-future annotations: {count}
106
+ Resolve `{extractionInventoryHelper}` ← first existing path in `{extractionInventoryProbeOrder}` and, from `{project-root}`, append them all in one call:
107
+
108
+ ```bash
109
+ uv run {extractionInventoryHelper} add --inventory "{extraction_inventory}" --field t2_annotations <<'SKF_T2'
110
+ [{"export_name": "...", "kind": "issue|pr|changelog|migration", "temporal": "T2-past|T2-future", "summary": "...", "citation": "[QMD:{collection}:{doc}]"}]
111
+ SKF_T2
112
+ ```
113
+
114
+ When it exits non-zero, fix the JSON and run it once more: an annotation the inventory already holds is not added twice. When it fails again, or no path resolves, warn "T2 annotations were not saved to the extraction inventory: {its message}" and continue without them: enrichment never halts the workflow.
115
+
116
+ **Enrichment summary counts** come from the call's output, never counted by hand: `counts.functions_enriched` (the functions with at least one annotation), `counts.t2_annotations`, `counts.t2_past` and `counts.t2_future` (the annotations by their `temporal`). When the call failed, each is 0.
99
117
 
100
118
  ### 5. Report Enrichment (Deep Tier Only)
101
119
 
@@ -103,8 +121,8 @@ Display brief enrichment summary:
103
121
 
104
122
  "**Enrichment complete.**
105
123
 
106
- **Functions enriched:** {enriched_count} of {total_count}
107
- **T2 annotations:** {t2_count} ({t2_past} historical, {t2_future} forward-looking)
124
+ **Functions enriched:** {counts.functions_enriched} of {the functions §3 searched}
125
+ **T2 annotations:** {counts.t2_annotations} ({counts.t2_past} historical, {counts.t2_future} forward-looking)
108
126
 
109
127
  Proceeding to compilation..."
110
128
 
@@ -0,0 +1,20 @@
1
+ <!-- Config: communicate in {communication_language}. -->
2
+
3
+ # Entry Points by Hand
4
+
5
+ Step 3 §4b loads this file only when the recipe runner did not diff the entry points: at Quick tier, for extraction by source reading, for a brief whose language no recipe reads, and in the AST Extraction Protocol's fallback. Read the entry points yourself and compare them with the extracted exports, then count `exports_public_api` (the entry points' public names) and `exports_internal` (every other non-underscore export) for step 5 §4:
6
+
7
+ - **Python:** Read `{source_root}/__init__.py`: extract imports to build the public export list. Compare against AST results:
8
+ - In AST but not entry point → mark as internal (exclude from `metadata.json` exports)
9
+ - In entry point but not AST → flag as extraction gap (trace via re-export protocol)
10
+ - **TypeScript/JS:** Read `index.ts`/`index.js`: same comparison logic.
11
+ - **Rust:** Read `lib.rs`: extract `pub use` items. Same logic. **Go:** Scan for exported (capitalized) identifiers.
12
+
13
+ **Multi-entry packages (`exports` map / declaration-file entry points).** A single per-language entry-point read misses public surface that a package ships through its `package.json` `exports` map, especially committed `.d.ts` / `.d.mts` declaration files that resolve **outside** the conventional source dir (e.g. a monorepo package whose `./macro` subpath maps to `macro/index.d.mts`, listed in `files[]` but not under `src/`). When the in-scope package declares an `exports` map:
14
+
15
+ - Resolve each `exports` subpath to its target file and treat that file, and any committed `.d.ts` / `.d.mts` declaration it resolves to, as an authoritative public entry point, reading it the same way as the primary barrel above even when it lives outside `src/`.
16
+ - If a resolved `exports` subpath target falls **outside** the brief's `scope.include` globs, surface a note: `"warn: public entry point {path} (exports subpath '{subpath}') resolves outside scope.include: widen scope.include before extraction, or this surface stays undocumented while exports_public_api still counts it, so public_api_coverage drops (only effective_denominator, for the curated-subset shapes, leaves it out)."` Widening `scope.include` here keeps the documented surface aligned with the `effective_denominator` that compile.md §4 derives from those same globs, without mid-run scope surgery.
17
+
18
+ Use the entry point as the authoritative source for `metadata.json`'s `exports[]` array.
19
+
20
+ **If entry point is missing or unreadable:** Skip validation with a warning.