bmad-module-skill-forge 2.2.0 → 4.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 (437) 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 +143 -18
  18. package/docs/verifying-a-skill.md +87 -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 +3 -3
  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 +31 -59
  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 +233 -64
  64. package/src/shared/scripts/skf-build-change-manifest.py +2753 -28
  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 +772 -0
  69. package/src/shared/scripts/skf-comention-pairs.py +1333 -123
  70. package/src/shared/scripts/skf-compare-file-hashes.py +267 -105
  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 +21 -3
  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 +197 -55
  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 +5247 -96
  86. package/src/shared/scripts/skf-extraction-inventory.py +1280 -0
  87. package/src/shared/scripts/skf-extraction-snapshot.py +664 -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 +469 -205
  92. package/src/shared/scripts/skf-github-fetch.py +365 -0
  93. package/src/shared/scripts/skf-github-probe.py +700 -0
  94. package/src/shared/scripts/skf-hash-content.py +180 -20
  95. package/src/shared/scripts/skf-language-corpora.py +1 -1
  96. package/src/shared/scripts/skf-load-provenance.py +161 -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 +143 -20
  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 +176 -28
  105. package/src/shared/scripts/skf-promote-staged.py +430 -0
  106. package/src/shared/scripts/skf-provenance-gap-dispatch.py +64 -8
  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 +155 -14
  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 +787 -121
  127. package/src/shared/scripts/skf-tessl-review.py +706 -0
  128. package/src/shared/scripts/skf-update-active-symlink.py +120 -67
  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 +23 -2
  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 +3945 -152
  138. package/src/shared/scripts/skf-write-skill-brief.py +406 -25
  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 +28 -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/health-check.md +2 -0
  168. package/src/skf-audit-skill/references/init.md +149 -210
  169. package/src/skf-audit-skill/references/re-index.md +103 -110
  170. package/src/skf-audit-skill/references/report.md +96 -33
  171. package/src/skf-audit-skill/references/semantic-diff.md +34 -25
  172. package/src/skf-audit-skill/references/severity-classify.md +79 -65
  173. package/src/skf-audit-skill/references/severity-rules.md +15 -6
  174. package/src/skf-audit-skill/references/structural-diff.md +80 -90
  175. package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
  176. package/src/skf-audit-skill/scripts/render-drift-tables.py +712 -0
  177. package/src/skf-brief-skill/SKILL.md +37 -26
  178. package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
  179. package/src/skf-brief-skill/assets/scope-templates.md +18 -25
  180. package/src/skf-brief-skill/assets/skill-brief-schema.md +30 -23
  181. package/src/skf-brief-skill/customize.toml +48 -20
  182. package/src/skf-brief-skill/references/analyze-target.md +144 -127
  183. package/src/skf-brief-skill/references/confirm-brief.md +11 -9
  184. package/src/skf-brief-skill/references/draft-checkpoint.md +36 -17
  185. package/src/skf-brief-skill/references/gather-intent-ratify.md +68 -0
  186. package/src/skf-brief-skill/references/gather-intent.md +87 -182
  187. package/src/skf-brief-skill/references/headless-args.md +84 -16
  188. package/src/skf-brief-skill/references/health-check.md +1 -1
  189. package/src/skf-brief-skill/references/invocation-contract.md +18 -13
  190. package/src/skf-brief-skill/references/portfolio-similarity-check.md +1 -1
  191. package/src/skf-brief-skill/references/qmd-collection-registration.md +7 -10
  192. package/src/skf-brief-skill/references/scope-definition.md +123 -47
  193. package/src/skf-brief-skill/references/step-auto-brief.md +26 -100
  194. package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
  195. package/src/skf-brief-skill/references/version-resolution.md +7 -10
  196. package/src/skf-brief-skill/references/write-brief.md +66 -57
  197. package/src/skf-campaign/SKILL.md +31 -34
  198. package/src/skf-campaign/assets/campaign-state-schema.json +25 -4
  199. package/src/skf-campaign/customize.toml +47 -16
  200. package/src/skf-campaign/references/campaign-contracts.md +39 -29
  201. package/src/skf-campaign/references/campaign-directive-spec.md +4 -2
  202. package/src/skf-campaign/references/health-check.md +7 -16
  203. package/src/skf-campaign/references/step-01-setup.md +46 -84
  204. package/src/skf-campaign/references/step-02-strategy.md +31 -30
  205. package/src/skf-campaign/references/step-03-pins.md +26 -18
  206. package/src/skf-campaign/references/step-04-provenance.md +24 -23
  207. package/src/skf-campaign/references/step-05-skill-loop.md +67 -48
  208. package/src/skf-campaign/references/step-06-batch.md +41 -34
  209. package/src/skf-campaign/references/step-07-capstone.md +40 -25
  210. package/src/skf-campaign/references/step-08-verify.md +28 -29
  211. package/src/skf-campaign/references/step-09-refine.md +29 -30
  212. package/src/skf-campaign/references/step-10-export.md +48 -36
  213. package/src/skf-campaign/references/step-11-maintenance.md +31 -34
  214. package/src/skf-campaign/references/step-resume.md +37 -68
  215. package/src/skf-campaign/scripts/campaign-deps.py +57 -18
  216. package/src/skf-campaign/scripts/campaign-parse-manifest.py +361 -54
  217. package/src/skf-campaign/scripts/campaign-provenance.py +96 -53
  218. package/src/skf-campaign/scripts/campaign-quality-gate.py +592 -0
  219. package/src/skf-campaign/scripts/campaign-render-batch.py +257 -49
  220. package/src/skf-campaign/scripts/campaign-render-kickoff.py +343 -50
  221. package/src/skf-campaign/scripts/campaign-report.py +204 -37
  222. package/src/skf-campaign/scripts/campaign-state.py +1128 -0
  223. package/src/skf-campaign/scripts/campaign-status.py +10 -74
  224. package/src/skf-campaign/scripts/campaign-validate-pins.py +30 -3
  225. package/src/skf-campaign/scripts/campaign-validate-state.py +34 -4
  226. package/src/skf-campaign/templates/campaign-brief-template.yaml +4 -5
  227. package/src/skf-campaign/templates/campaign-report-template.md +5 -1
  228. package/src/skf-campaign/templates/kickoff-template.md +0 -14
  229. package/src/skf-create-skill/SKILL.md +27 -20
  230. package/src/skf-create-skill/assets/compile-assembly-rules.md +11 -8
  231. package/src/skf-create-skill/assets/skill-sections.md +21 -11
  232. package/src/skf-create-skill/customize.toml +20 -8
  233. package/src/skf-create-skill/references/authoritative-files-protocol.md +36 -58
  234. package/src/skf-create-skill/references/batch-mode.md +81 -0
  235. package/src/skf-create-skill/references/ccc-index-check.md +27 -0
  236. package/src/skf-create-skill/references/compile.md +119 -70
  237. package/src/skf-create-skill/references/component-extraction.md +113 -91
  238. package/src/skf-create-skill/references/enrich.md +41 -23
  239. package/src/skf-create-skill/references/entry-points-by-hand.md +37 -0
  240. package/src/skf-create-skill/references/extract.md +204 -162
  241. package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
  242. package/src/skf-create-skill/references/extraction-patterns-tracing.md +11 -11
  243. package/src/skf-create-skill/references/extraction-patterns.md +588 -201
  244. package/src/skf-create-skill/references/generate-artifacts.md +145 -93
  245. package/src/skf-create-skill/references/health-check.md +1 -1
  246. package/src/skf-create-skill/references/load-brief.md +53 -36
  247. package/src/skf-create-skill/references/relabel-rule.md +12 -0
  248. package/src/skf-create-skill/references/report.md +37 -57
  249. package/src/skf-create-skill/references/source-resolution-protocols.md +58 -169
  250. package/src/skf-create-skill/references/step-auto-shard.md +20 -93
  251. package/src/skf-create-skill/references/step-doc-rot.md +44 -60
  252. package/src/skf-create-skill/references/step-doc-sources.md +28 -19
  253. package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
  254. package/src/skf-create-skill/references/sub/fetch-docs.md +106 -59
  255. package/src/skf-create-skill/references/sub/fetch-temporal.md +53 -166
  256. package/src/skf-create-skill/references/tier-degradation-rules.md +18 -9
  257. package/src/skf-create-skill/references/validate.md +173 -99
  258. package/src/skf-create-skill/scripts/scan-doc-rot.py +232 -99
  259. package/src/skf-create-stack-skill/SKILL.md +29 -56
  260. package/src/skf-create-stack-skill/assets/metadata-contract.md +51 -0
  261. package/src/skf-create-stack-skill/assets/provenance-map-schema.md +15 -15
  262. package/src/skf-create-stack-skill/assets/stack-skill-template.md +23 -57
  263. package/src/skf-create-stack-skill/customize.toml +23 -12
  264. package/src/skf-create-stack-skill/references/compile-stack.md +57 -66
  265. package/src/skf-create-stack-skill/references/compose-mode-rules.md +24 -44
  266. package/src/skf-create-stack-skill/references/detect-integrations.md +92 -95
  267. package/src/skf-create-stack-skill/references/detect-manifests.md +46 -71
  268. package/src/skf-create-stack-skill/references/generate-output.md +138 -128
  269. package/src/skf-create-stack-skill/references/init.md +90 -32
  270. package/src/skf-create-stack-skill/references/integration-patterns.md +1 -17
  271. package/src/skf-create-stack-skill/references/invocation-contract.md +34 -0
  272. package/src/skf-create-stack-skill/references/manifest-patterns.md +32 -20
  273. package/src/skf-create-stack-skill/references/parallel-extract.md +112 -38
  274. package/src/skf-create-stack-skill/references/rank-and-confirm.md +57 -75
  275. package/src/skf-create-stack-skill/references/report.md +39 -33
  276. package/src/skf-create-stack-skill/references/validate.md +20 -39
  277. package/src/skf-drop-skill/SKILL.md +28 -51
  278. package/src/skf-drop-skill/customize.toml +44 -30
  279. package/src/skf-drop-skill/references/execute.md +83 -146
  280. package/src/skf-drop-skill/references/health-check.md +2 -0
  281. package/src/skf-drop-skill/references/invocation-contract.md +64 -0
  282. package/src/skf-drop-skill/references/report.md +46 -30
  283. package/src/skf-drop-skill/references/select.md +122 -124
  284. package/src/skf-drop-skill/scripts/dir-sizes.py +54 -26
  285. package/src/skf-drop-skill/scripts/drop-roster.py +322 -0
  286. package/src/skf-export-skill/SKILL.md +40 -62
  287. package/src/skf-export-skill/assets/managed-section-format.md +14 -50
  288. package/src/skf-export-skill/assets/snippet-format.md +3 -1
  289. package/src/skf-export-skill/customize.toml +42 -13
  290. package/src/skf-export-skill/references/generate-snippet.md +54 -46
  291. package/src/skf-export-skill/references/health-check.md +2 -0
  292. package/src/skf-export-skill/references/invocation-contract.md +15 -0
  293. package/src/skf-export-skill/references/load-skill.md +88 -62
  294. package/src/skf-export-skill/references/manifest-rebuild.md +9 -10
  295. package/src/skf-export-skill/references/multi-skill-mode.md +4 -4
  296. package/src/skf-export-skill/references/orphan-context-detection.md +13 -5
  297. package/src/skf-export-skill/references/orphan-row-detection.md +31 -22
  298. package/src/skf-export-skill/references/package.md +15 -73
  299. package/src/skf-export-skill/references/preflight-snippet-root-probe.md +51 -70
  300. package/src/skf-export-skill/references/result-envelope.md +31 -16
  301. package/src/skf-export-skill/references/summary.md +41 -17
  302. package/src/skf-export-skill/references/token-report.md +4 -12
  303. package/src/skf-export-skill/references/update-context.md +118 -237
  304. package/src/skf-forger/SKILL.md +61 -37
  305. package/src/skf-forger/bmad-skill-manifest.yaml +4 -1
  306. package/src/skf-forger/customize.toml +43 -0
  307. package/src/skf-forger/references/pipeline-mode.md +73 -18
  308. package/src/skf-forger/scripts/forge-status.py +299 -0
  309. package/src/skf-forger/scripts/parse-pipeline.py +322 -54
  310. package/src/skf-forger/scripts/pipeline-gate.py +428 -0
  311. package/src/skf-forger/scripts/pipeline-journal.py +1052 -0
  312. package/src/skf-quick-skill/SKILL.md +54 -53
  313. package/src/skf-quick-skill/assets/skill-template.md +4 -2
  314. package/src/skf-quick-skill/customize.toml +51 -20
  315. package/src/skf-quick-skill/references/batch-mode.md +74 -21
  316. package/src/skf-quick-skill/references/compile.md +30 -31
  317. package/src/skf-quick-skill/references/ecosystem-check.md +7 -57
  318. package/src/skf-quick-skill/references/finalize.md +69 -18
  319. package/src/skf-quick-skill/references/halt-contract.md +41 -29
  320. package/src/skf-quick-skill/references/health-check.md +5 -3
  321. package/src/skf-quick-skill/references/quick-extract.md +114 -45
  322. package/src/skf-quick-skill/references/registry-resolution.md +9 -64
  323. package/src/skf-quick-skill/references/resolve-target.md +116 -66
  324. package/src/skf-quick-skill/references/write-and-validate.md +79 -40
  325. package/src/skf-refine-architecture/SKILL.md +43 -53
  326. package/src/skf-refine-architecture/customize.toml +49 -20
  327. package/src/skf-refine-architecture/references/compile.md +97 -54
  328. package/src/skf-refine-architecture/references/exit-codes.md +30 -0
  329. package/src/skf-refine-architecture/references/finding-storage.md +21 -0
  330. package/src/skf-refine-architecture/references/gap-analysis.md +101 -38
  331. package/src/skf-refine-architecture/references/improvements.md +14 -20
  332. package/src/skf-refine-architecture/references/init.md +98 -57
  333. package/src/skf-refine-architecture/references/issue-detection.md +32 -39
  334. package/src/skf-refine-architecture/references/refinement-rules.md +37 -48
  335. package/src/skf-refine-architecture/references/report.md +65 -54
  336. package/src/skf-refine-architecture/scripts/skf-check-preservation.py +1619 -0
  337. package/src/skf-rename-skill/SKILL.md +19 -54
  338. package/src/skf-rename-skill/customize.toml +32 -26
  339. package/src/skf-rename-skill/references/execute.md +230 -184
  340. package/src/skf-rename-skill/references/exit-codes.md +7 -7
  341. package/src/skf-rename-skill/references/health-check.md +1 -7
  342. package/src/skf-rename-skill/references/invocation-contract.md +25 -0
  343. package/src/skf-rename-skill/references/report.md +63 -52
  344. package/src/skf-rename-skill/references/select.md +197 -115
  345. package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -21
  346. package/src/skf-setup/SKILL.md +26 -26
  347. package/src/skf-setup/customize.toml +14 -10
  348. package/src/skf-setup/references/auto-index.md +50 -63
  349. package/src/skf-setup/references/ccc-index.md +29 -90
  350. package/src/skf-setup/references/detect-and-tier.md +58 -67
  351. package/src/skf-setup/references/health-check.md +2 -0
  352. package/src/skf-setup/references/invocation-contract.md +14 -0
  353. package/src/skf-setup/references/report.md +43 -166
  354. package/src/skf-setup/references/tier-rules.md +5 -5
  355. package/src/skf-setup/references/write-config.md +34 -57
  356. package/src/skf-test-skill/SKILL.md +17 -57
  357. package/src/skf-test-skill/assets/output-section-formats.md +33 -34
  358. package/src/skf-test-skill/customize.toml +27 -13
  359. package/src/skf-test-skill/references/coherence-check.md +134 -62
  360. package/src/skf-test-skill/references/coverage-check-tiers.md +35 -0
  361. package/src/skf-test-skill/references/coverage-check.md +209 -264
  362. package/src/skf-test-skill/references/detect-mode.md +5 -5
  363. package/src/skf-test-skill/references/external-validators.md +94 -82
  364. package/src/skf-test-skill/references/health-check.md +6 -7
  365. package/src/skf-test-skill/references/init.md +164 -91
  366. package/src/skf-test-skill/references/invocation-contract.md +66 -0
  367. package/src/skf-test-skill/references/migration-section-rules.md +5 -2
  368. package/src/skf-test-skill/references/report.md +164 -142
  369. package/src/skf-test-skill/references/score.md +80 -107
  370. package/src/skf-test-skill/references/scoring-rules.md +42 -155
  371. package/src/skf-test-skill/references/source-access-protocol.md +18 -94
  372. package/src/skf-test-skill/references/step-hard-gate.md +51 -33
  373. package/src/skf-test-skill/scripts/aggregate-coherence.py +218 -30
  374. package/src/skf-test-skill/scripts/build-result-context.py +380 -0
  375. package/src/skf-test-skill/scripts/check-metadata-coherence.py +37 -4
  376. package/src/skf-test-skill/scripts/combine-external-scores.py +23 -6
  377. package/src/skf-test-skill/scripts/compute-score.py +223 -45
  378. package/src/skf-test-skill/scripts/gap-ledger.py +1666 -0
  379. package/src/skf-test-skill/scripts/hard-gate.py +203 -0
  380. package/src/skf-test-skill/scripts/load-coverage-inputs.py +1198 -0
  381. package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
  382. package/src/skf-test-skill/scripts/reconcile-coverage.py +547 -79
  383. package/src/skf-test-skill/scripts/score-signatures.py +479 -0
  384. package/src/skf-test-skill/scripts/stage-helper-payload.py +148 -0
  385. package/src/skf-test-skill/scripts/validate-inventory.py +311 -16
  386. package/src/skf-test-skill/scripts/verify-declared-numerator.py +133 -56
  387. package/src/skf-test-skill/templates/test-report-template.md +21 -15
  388. package/src/skf-update-skill/SKILL.md +38 -25
  389. package/src/skf-update-skill/customize.toml +27 -12
  390. package/src/skf-update-skill/references/detect-changes.md +253 -223
  391. package/src/skf-update-skill/references/gap-driven.md +336 -0
  392. package/src/skf-update-skill/references/health-check.md +31 -5
  393. package/src/skf-update-skill/references/init.md +254 -84
  394. package/src/skf-update-skill/references/invocation-contract.md +12 -0
  395. package/src/skf-update-skill/references/manual-section-rules.md +6 -23
  396. package/src/skf-update-skill/references/merge.md +182 -49
  397. package/src/skf-update-skill/references/re-extract.md +53 -262
  398. package/src/skf-update-skill/references/report.md +102 -35
  399. package/src/skf-update-skill/references/write.md +357 -155
  400. package/src/skf-update-skill/scripts/skf-new-file-diff.py +183 -46
  401. package/src/skf-verify-stack/SKILL.md +23 -42
  402. package/src/skf-verify-stack/assets/feasibility-report-template.md +11 -5
  403. package/src/skf-verify-stack/customize.toml +55 -22
  404. package/src/skf-verify-stack/references/coverage-patterns.md +17 -8
  405. package/src/skf-verify-stack/references/coverage.md +67 -64
  406. package/src/skf-verify-stack/references/exit-codes.md +21 -8
  407. package/src/skf-verify-stack/references/init.md +107 -62
  408. package/src/skf-verify-stack/references/integration-verification-rules.md +12 -13
  409. package/src/skf-verify-stack/references/integrations.md +106 -65
  410. package/src/skf-verify-stack/references/report.md +59 -42
  411. package/src/skf-verify-stack/references/requirements.md +32 -9
  412. package/src/skf-verify-stack/references/synthesize.md +53 -39
  413. package/src/skf-verify-stack/scripts/skf-coverage-tally.py +398 -52
  414. package/src/skf-verify-stack/scripts/skf-previous-report.py +330 -0
  415. package/src/skf-verify-stack/scripts/skf-report-delta.py +453 -49
  416. package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +240 -27
  417. package/tools/cli/commands/install.js +11 -4
  418. package/tools/cli/commands/status.js +15 -3
  419. package/tools/cli/commands/update.js +11 -4
  420. package/tools/cli/lib/tool-check.js +320 -0
  421. package/tools/cli/lib/version-check.js +22 -9
  422. package/tools/cli/skf-cli.js +4 -1
  423. package/.gitattributes +0 -16
  424. package/.nvmrc +0 -1
  425. package/docs/_internal/RELEASING.md +0 -679
  426. package/release-audits/v1.0.0-launch-audit.md +0 -728
  427. package/src/skf-audit-skill/references/step-doc-drift.md +0 -177
  428. package/src/skf-brief-skill/references/headless-source-authority-detection.md +0 -26
  429. package/src/skf-campaign/manifest.yaml +0 -15
  430. package/src/skf-create-skill/assets/tessl-dismissal-rules.md +0 -106
  431. package/src/skf-create-skill/references/ecosystem-check.md +0 -74
  432. package/src/skf-drop-skill/references/headless-contract.md +0 -18
  433. package/src/skf-update-skill/references/merge-conflict-rules.md +0 -15
  434. package/src/skf-update-skill/references/remote-source-resolution.md +0 -98
  435. package/src/skf-update-skill/references/validate.md +0 -124
  436. package/tools/validate-docs-drift.js +0 -233
  437. package/tools/validate-docs-links.js +0 -665
@@ -6,112 +6,40 @@
6
6
 
7
7
  **Source API surface** = the package's top-level public exports. These are the symbols reachable from the primary entry point without importing internal modules:
8
8
 
9
- - **Python:** symbols exported in `__init__.py` (including re-exports) — exclude private (`_prefixed`) names
9
+ - **Python:** symbols exported in the package root's `__init__.py` (including re-exports), excluding private (`_prefixed`) names. A sub-package behind a folder with no `__init__.py` (a FastAPI `routers/__init__.py`, say) is not a second package root when the folder of another package root that exports a name holds it, unless `scope.include` or `scope.tier_a_include` lists that `__init__.py`: its names stay out of the `all` and `root` sets (`excluded.nestedEntries`), while the `scope.include` and `tier_a_include` sets still count them and their signatures are still compared
10
10
  - **TypeScript/JavaScript:** named exports from `index.ts` / `index.js` — exclude unexported locals
11
11
  - **Go:** exported identifiers (capitalized) from the package's public-facing files
12
12
  - **Rust:** items in `pub use` from `lib.rs` or `mod.rs`
13
- - **Empty-barrel packages (copy-paste / subpath-only distribution):** If the primary entry point is empty or re-exports nothing (e.g., `export {};` in `index.ts`, an empty `__init__.py`, `lib.rs` with no `pub use`), the package does not expose a barrel API. Do **not** compute coverage against the empty barrel — the denominator would be zero and the score meaningless. Instead, consult the skill brief's `scope.include` globs (`forge-data/{skill_name}/skill-brief.yaml`) to identify the authorized entry points, and build the public API surface from the **union of named exports across those files**. The skill brief's `scope.notes` field should document this distribution model explicitly; if present, treat it as confirmation that the empty barrel is by design rather than a bug. If no skill brief is available and the barrel is empty, set `analysis_confidence: docs-only` and report that the source API surface could not be determined.
14
13
 
15
- - **Stratified-scope monorepo packages (curated subsets of multi-package repos):** If the source is a monorepo (detect via `packages/` layout, `workspaces` field in root `package.json`, `lerna.json`, `rush.json`, `nx.json`, or Cargo `[workspace]`) AND the skill brief's `scope.include` lists a curated file/directory subset rather than the full workspace, the coverage denominator must reflect only the authored surface, not the monorepo's global export count. This is distinct from the empty-barrel case: each workspace package may have a non-empty barrel, but the skill intentionally documents only a tiered subset.
14
+ The clauses below decide which part of that surface is the coverage denominator. `load-coverage-inputs.py surface` picks the clause from the brief (`{forge_data_folder}/{skill_name}/skill-brief.yaml`), `{source_is_monorepo}` (coverage-check.md §0b, passed as `--monorepo`), the extraction and `metadata.json`, and writes it to `surface.json` `denominator` with the branch, the name set, the rung it takes (coverage-check.md §2b) and the entry points' state it read (`barrel`), beside the counts each clause names (`sets`, `candidates` and `guards`). Three of its inputs are yours to pass as flags, the last two only where no file gives them:
16
15
 
17
- **Resolution order:**
16
+ - **Pattern-reference intent** (`--pattern-reference-intent`): `scope.notes` says the skill demonstrates an integration pattern rather than a library API ("Reference app, not a library", "pattern-reference", "embedded-pattern skill", "skill value is the … pattern"; the author's words are authoritative).
17
+ - **A curated monorepo subset** (`--curated-subset`), where the extraction has no `counts.curated_subset` (Quick tier, the fallback per-file scan, States 2 to 4): `{source_is_monorepo}` is true and the brief's `scope.include` lists a curated subset rather than the full workspace.
18
+ - **The entry points' state** (`--barrel`), where no complete extraction or quick output gives it (the fallback per-file scan when the runner listed entry points, Quick tier read by eye, State 4): `none` when no barrel file is at any recognized entry-point path (`__init__.py`, `index.ts`/`index.js`, `lib.rs`, `mod.rs`), `empty` when the primary entry point exports nothing (`export {};`, an empty `__init__.py`, a `lib.rs` with no `pub use`), else `barrel`.
18
19
 
19
- 1. **Prefer `metadata.json.stats.effective_denominator`** when present. `skf-create-skill` step 5 §4 writes this field for stratified-scope skills. When set, use it directly as the `exports_public_api` count for coverage scoring — **subject to the deflation guard below**.
20
+ The recipe runner already re-derives each barrel (multi-line re-export blocks, star re-exports and a Rust `pub use` chain included) and counts each name once, at the file that defines it, so a barrel that only re-exports adds nothing of its own. Without the runner's names (Quick tier, the fallback per-file scan, States 2 to 4) the script builds the `scope.include` and `tier_a_include` sets from the files the names carry and the brief's globs (the runner's JSON the fallback scan passes adds only its scope and stale globs), and there is no `subpaths` or `root` set (coverage-check.md §2b). Never re-count a barrel by hand. A `scope.tier_a_include` glob counts a name only in a file a `scope.include` glob also matches, and one that matches no file (`guards.staleScope.unmatchedTierAInclude`, a brief older than the source) counts none: when the tier A globs count no name, `surface.json` has no `tier_a_include` set. Each clause, by its `denominator.clause`, with what stays yours:
20
21
 
21
- **Denominator deflation guard (when `effective_denominator` is used).** `effective_denominator` is a stored count, and a gap-driven `skf-update-skill` run can lower it — legitimately (a real rescope expressed in the brief) or by gaming (deleting in-scope public exports from `metadata`/provenance and setting `effective_denominator` to the documented total to force 100% coverage). When source is readable (State 1, or State ≥ 2 with remote tools), validate it: re-derive the public surface from `scope.include` filtered by `scope.exclude` — the same union step 2 computes — and compare. If the re-derived source barrel exceeds `effective_denominator` by **more than 25%** AND the brief carries no `scope.tier_a_include` (the only legitimate narrowing mechanism), treat `effective_denominator` as **deflated**: use the re-derived source-barrel count as `total_exports` instead, and emit a **Medium**-severity gap `denominator deflation — effective_denominator below source public surface without tier_a_include` reporting both counts (`effective_denominator: {N}`, `re-derived source barrel: {M}`, `{percent}% below source`). A legitimate scope reduction is expressed in the brief — via `scope.tier_a_include`, or by adding the removed exports to `scope.exclude` so the re-derived barrel shrinks to match (the mechanism `skf-update-skill` gap-driven rescope uses) — **never** by editing `metadata.stats` to equal the documented count. This is the directional counterpart to the inflation check in step 3: inflation fires when the coarse surface is too large, deflation when the stored denominator is suspiciously small. When source is unavailable, skip the guard and annotate the report: `effective_denominator used unverified — no source access to re-derive the barrel`.
22
+ - **Empty-barrel packages (`empty-barrel`; copy-paste or subpath-only distribution):** the primary entry point is empty, so the denominator is the `scope.include` set. The brief's `scope.notes` should say the distribution model is by design; when it does, treat the empty barrel as intended rather than a bug. With no brief and an empty barrel, set `analysis_confidence: docs-only` and report that the source API surface could not be determined. Annotate: `Empty barrel, denominator: scope.include union ({N} exports)`.
22
23
 
23
- **Rust barrel re-derivation (when ast-grep `pub`-fn extraction is unreliable).** The Rust-skill condition documents the ast-grep `pub-fn` extractor as unreliable, so re-deriving a crate's barrel surface — for this guard or for the live fallback below — falls back to grep. A naive `pub`-token sweep over-counts badly: it pulls in `pub(crate)`/`pub(super)` internals, impl-block associated consts and methods, test modules, and foreign re-export files (such sweeps routinely land 30–40% above the true barrel). Enumerate deterministically instead:
24
+ - **Stratified-scope monorepo packages (`stratified-scope`; curated subsets of multi-package repos):** the denominator reflects only the authored surface, not the monorepo's global export count: the `stats.effective_denominator` Create Skill stored, unless `guards.deflation.fires` (a Medium `metadata-drift` gap, coverage-check.md §4: a legitimate scope reduction goes in the brief, through `scope.tier_a_include` or `scope.exclude`, never into `metadata.stats`), then the `tier_a_include` and `scope.include` sets. With no surface read from the source (`guards.deflation.applicable` false), annotate the report `effective_denominator used unverified: no source access to re-derive the barrel`. When `guards.inflation.fires` (the coarse globs sweep in internal infrastructure, a Medium `denominator-inflation` gap) and `guards.umbrella.umbrella` is true (the root barrel is mostly re-exports), recommend `stats.effective_denominator` rather than `scope.tier_a_include`. Leave `analysis_confidence` unchanged. Annotate the report: `Stratified scope, denominator: {effective_denominator | tier_a_include union | scope.include union} ({N} files matched, {M} exports union)`. `scope.notes` should document the stratification (for example "Tier A: fully documented; Tier B: deferred to references; Tier C: excluded"); when it does, treat the curated subset as intended, not a scope gap.
24
25
 
25
- - Trace the `pub use` re-export chain from the crate root (`lib.rs` / `mod.rs`) to find which modules the barrel actually re-exports; count from those, not from every file containing a `pub` token.
26
- - Count only **unrestricted, module-level (column-0) `pub`** item declarations: `pub struct` / `pub enum` / `pub trait` / `pub type` / `pub const` / `pub fn` (free functions) that start at column 0.
27
- - Exclude `pub(crate)` / `pub(super)` / `pub(in …)` (crate-internal, not barrel surface); anything indented (impl-block associated consts and methods are not free barrel items); `*tests.rs` and `#[cfg(test)]` modules; and files listed under `scope.exclude` (e.g. foreign re-export files).
26
+ - **Standard barrel (`standard-barrel`, the `all` set):** `full-library` skills, single-package repositories and briefs where the full monorepo is intentionally in scope. A `scope.include` glob that matches no file (a brief written for an older layout of the source) does not shrink that barrel: `guards.staleScope` restores the root exports defined in a file no glob covers, unless `scope.exclude` or a `scope-expansion` amendment whose latest action is `skipped` or `demoted-include` matches the file. The stale glob is a Medium `brief-scope-stale` gap (coverage-check.md §4), which also names each `scope.tier_a_include` glob that matches no file.
28
27
 
29
- **TypeScript / JavaScript barrel re-derivation (multi-line re-export blocks).** When re-deriving a TS/JS barrel — for the deflation guard above or the live fallback below — a line-oriented `^export` regex undercounts: a named re-export block spans continuation lines (`export type {\n A,\n B,\n} from "./x"`), and a single-line match captures only the opening line, dropping every member listed on the continuation lines. Enumerate the full block instead:
28
+ - **Pattern-reference apps (`pattern-reference`; non-library source):** a single-package repo that demonstrates an integration pattern rather than distributing a library API. The denominator is the `tier_a_include` set when `surface.json` has it, else the canonicalized provenance map, since `skf-create-skill`'s extraction already curated the map to the authored pattern surface. Leave `analysis_confidence` unchanged. Annotate: `Pattern-reference, denominator: {tier_a_include union | canonicalized provenance-map count} ({N} pattern surfaces)`.
30
29
 
31
- - For each `export { … }` / `export type { … }` (including the `import`-then-`export` re-export form), accumulate named members across continuation lines until the closing `}` — count every identifier in the brace list, not only those on the opening line. A renamed re-export (`export { A as B }`) counts once under its public name (`B`).
32
- - Resolve `export * from "…"` to the target module's own public names — a star re-export contributes that module's surface, not a single entry.
33
- - Prefer a `tsc` / `ts-morph` / AST entry-point resolution over the line regex when a TS toolchain is reachable; it resolves multi-line blocks and star re-exports natively. Fall back to the brace-accumulation grep only when no AST tool is available — the same grep-fallback posture the Rust note above takes.
34
- 2. **Fall back to live re-derivation** when `effective_denominator` is absent (older skills, quick-tier output, or skills compiled before this rule existed). Read the brief's scope globs from `forge-data/{skill_name}/skill-brief.yaml`, resolve them against `source_path`, filter out files matching `scope.exclude`, and compute the source API surface as the **union of named exports across the matched files only**. The skill brief's `scope.notes` field should document the stratification strategy (e.g., "Tier A: fully documented; Tier B: deferred to references; Tier C: excluded") — when present, treat it as confirmation that the curated subset is by design, not a scope gap.
30
+ - **Single-crate curated subset (`specific-modules`):** a single-package repo whose brief carves a subset of the crate's public surface with `scope.include` and `scope.exclude`: the in-scope reachable barrel, or the `stats.effective_denominator` Create Skill stored for it, under the same deflation guard. Annotate: `Specific-modules subset, denominator: in-scope reachable barrel ({N} items from {M} modules, after scope.include/exclude filtering)`.
35
31
 
36
- **Honor `scope.tier_a_include` when present.** When re-deriving, prefer the brief-level `scope.tier_a_include` narrow include list over the coarse `scope.include`. `tier_a_include` is an optional brief field that lists only the authoring surface the brief actually intends to document (tier A), letting the denominator match the brief's authoring-vs-installing intent even when `scope.include` uses coarse globs that also match internal infrastructure. When `tier_a_include` is present, resolve its globs (still filtered by `scope.exclude`), compute the union across those files, and use that count as the denominator. When absent, fall back to resolving `scope.include`.
32
+ - **Multi-entry (exports-map) packages (`multi-entry`):** an in-scope `package.json` declares an `exports` map with more than one non-root subpath (`extraction.arms.multi_subpath_exports`). Installers reach every published subpath, so the denominator is the `subpaths` set (wildcard subpaths are left out: their surface is unbounded), or a stored count or `tier_a_include` set ahead of it. The root-barrel count (`candidates.rootBarrel`) is the secondary candidate in coverage-check.md §4's Denominator Candidates block. Annotate: `Multi-entry (exports-map), denominator: {effective_denominator | tier_a_include union | subpath union} ({N} subpaths resolved, {M} exports union; root barrel: {R})`.
37
33
 
38
- **Exclude umbrella barrel files from a `tier_a_include` re-derivation.** A barrel file (`lib.rs`, `mod.rs`, `index.ts`/`index.js`, `__init__.py`) whose public surface is dominated by `pub use` / re-export leaves re-exports the *entire* crate/package surface. Including such a file in the resolved `tier_a_include` set makes the union **grow** rather than shrink — defeating the narrowing and producing a denominator larger than `scope.include` would have. Detect an umbrella barrel as a file whose exported names are mostly (>50%) re-exports of symbols defined in other files. When a `tier_a_include` file set resolves to include an umbrella barrel, drop the barrel and count only the concrete-definition files; if dropping it leaves no meaningful surface, prefer `effective_denominator` (priority 1) instead of the inflated `tier_a_include` union.
39
-
40
- 3. **Denominator inflation check (absent `tier_a_include`).** If re-derivation used `scope.include` because no `tier_a_include` was provided, compare the resulting union count against the provenance-map entry count (when provenance-map exists). If the `scope.include` union is more than 25% larger than the provenance-map entry count, the coarse globs are almost certainly sweeping in internal infrastructure that the brief did not intend to document. Emit a **Medium**-severity gap titled `denominator inflation — coarse scope.include union exceeds authored surface` that points the user at the brief for rescoping via `scope.tier_a_include`. **When the package's barrel is an umbrella re-export file** (public surface mostly `pub use` / re-export leaves — see the umbrella-barrel note in step 2), recommend `stats.effective_denominator` (priority 1) as the **primary** remediation instead of `tier_a_include`: a `tier_a_include` that lists the umbrella barrel would recount *larger* than `scope.include`, not smaller, so it cannot clear the inflation. Report both counts (`scope.include union: {N}`, `provenance-map entries: {M}`, `{percent}% inflation`) and state that the coverage score it produced is driven by denominator inflation rather than documentation gaps. The check is skipped when provenance-map is unavailable (there is no baseline to compare against).
41
-
42
- Leave `analysis_confidence` unchanged (still `full` or `provenance-map` per the waterfall) — stratified scope does not degrade confidence, only the denominator. Annotate the coverage report with: `Stratified scope — denominator: {effective_denominator | tier_a_include union | scope.include union} ({N} files matched, {M} exports union)`.
43
-
44
- **When this clause does not apply:** `scope.type: "full-library"` skills, single-package repositories, or stratified briefs where the full monorepo is intentionally in scope. For those, use the standard barrel-based denominator — **unless** the single-package repo is a pattern-reference app (see next bullet) or publishes a multi-subpath `exports` map (use the multi-entry clause below).
45
-
46
- - **Pattern-reference apps (non-library source):** If the source is a single-package repo whose purpose is demonstrating an integration pattern rather than distributing a library API — typical markers are `scope.type: "full-library"` **without** a barrel file at any recognized entry-point path (`__init__.py`, `index.ts`/`index.js`, `lib.rs`, `mod.rs`) AND without a monorepo layout — the skill's value lives in wiring patterns, not exports. None of the preceding three clauses fits: there is no barrel to count from, no empty-barrel `scope.include` to consult, and no monorepo stratification to re-derive.
47
-
48
- **Trigger (either fires):**
49
-
50
- 1. `scope.notes` in `forge-data/{skill_name}/skill-brief.yaml` flags pattern-reference intent (phrases such as "Reference app, not a library", "pattern-reference", "embedded-pattern skill", or "skill value is the … pattern"). The `scope.notes` field is authoritative when the author wrote it.
51
- 2. Source tree lacks a barrel file at every recognized entry-point path AND the repo is not a monorepo (no `packages/`, `workspaces`, `lerna.json`, `rush.json`, `nx.json`, or Cargo `[workspace]`) AND the package does not declare a multi-subpath `exports` map (those route to the multi-entry clause below). Detected at test time by filesystem inspection of `{source_path}`.
52
-
53
- **Denominator:** canonicalized provenance-map entry count (same canonicalization as the "Provenance-map canonicalization" section below). `skf-create-skill`'s extraction pass has already curated the provenance-map to the authored pattern surface; treat it as the authoritative enumeration of the skill's documented reach.
54
-
55
- **Recommendation — prefer `tier_a_include`:** authors should add `scope.tier_a_include` to the brief listing the files that constitute the authored pattern surface, the same way stratified-scope briefs do. When `tier_a_include` is present, use its re-derived union (filtered by `scope.exclude`) as the denominator exactly as in the stratified-scope clause. When absent, fall back to the canonicalized provenance-map count — do not fabricate a denominator from arbitrary source-tree sweeps.
56
-
57
- **Confidence:** leave `analysis_confidence` unchanged (still `full` or `provenance-map` per the waterfall). Pattern-reference does not degrade confidence — the surface is smaller than a library barrel, not lower quality. Annotate the coverage report with: `Pattern-reference — denominator: {tier_a_include union | canonicalized provenance-map count} ({N} pattern surfaces)`.
58
-
59
- **When this clause does not apply:** any repo with a non-empty barrel file, any monorepo (use the stratified-scope clause), or any single-package repo whose `scope.type` is explicitly `specific-modules` (use the specific-modules clause), `public-api` with a multi-subpath `exports` map (use the multi-entry clause below — a `public-api` package WITHOUT such a map keeps the standard root-barrel rule), `component-library`, or `docs-only`. Also does not apply when `scope.type: "reference-app"` — that scope type carries its own pattern-surface denominator semantics (the brief speaks for itself), so this clause's filesystem trigger is moot.
60
-
61
- - **Single-crate curated subset (`scope.type: "specific-modules"`):** If the source is a single-package (non-monorepo) repo whose skill brief sets `scope.type: "specific-modules"` and uses `scope.include`/`scope.exclude` to carve a subset of the crate's public surface, the coverage denominator is the **in-scope reachable barrel** — not the full barrel.
62
-
63
- **Resolution:** Derive the barrel as normal for the language (e.g., Rust: `pub use` chain from `lib.rs`), then filter:
64
-
65
- 1. **Exclude** any modules or items that fall under `scope.exclude` patterns.
66
- 2. **Include only** items reachable from the modules listed in `scope.include`.
67
- 3. **Respect module visibility:** items behind `mod` (not `pub mod`) boundaries that are not re-exported through the barrel are unreachable and excluded. For Rust: count only unrestricted, module-level (column-0) `pub` item declarations in barrel-reachable modules; exclude `pub(crate)` / `pub(super)` / `pub(in …)` restricted items.
68
-
69
- The resulting count is the denominator. Annotate the coverage report with: `Specific-modules subset — denominator: in-scope reachable barrel ({N} items from {M} modules, after scope.include/exclude filtering)`.
70
-
71
- **When `effective_denominator` is present:** prefer `metadata.json.stats.effective_denominator` (same priority-1 rule as the stratified-scope clause), subject to the same deflation guard.
72
-
73
- **When this clause does not apply:** monorepo packages (use the stratified-scope clause), `scope.type: "full-library"` (use the standard barrel), or empty-barrel packages (use the empty-barrel clause). This clause is specifically for single-crate repos where the brief intentionally documents a curated subset rather than the full public surface.
74
-
75
- - **Multi-entry (exports-map) packages (single-package libraries publishing via a `package.json` `exports` map):** If the in-scope `package.json` declares an `exports` map with **multiple non-root subpath entries** (more than just `"."`) and the repo carries **no** monorepo markers (`packages/` layout, `workspaces` field, `lerna.json`, `rush.json`, `nx.json`, Cargo `[workspace]`), the package's public surface spans every published subpath, not just the root barrel. The standard "named exports from `index.ts`" rule undercounts: it measures only the `"."` barrel while installers reach the full subpath set. This clause covers both `scope.type: "full-library"` AND `scope.type: "public-api"` for such packages.
76
-
77
- **Denominator:** the **union of named exports across the files each NON-WILDCARD `exports` subpath resolves to**. Resolve each subpath to its target file (or its committed `.d.ts` / `.d.mts` declaration), then apply the same multi-line brace-accumulation and `export *` star-resolution rules documented for barrel re-derivation earlier in this file ("TypeScript / JavaScript barrel re-derivation"). **Explicitly exclude wildcard subpaths** (`"./*"` forms — they map to an open-ended file set whose surface is unbounded and uncountable). If the `exports` map has only a root `"."` entry, or only wildcard subpaths, fall back to the standard root-barrel rule.
78
-
79
- **Curation/priority (same ladder the specific-modules clause uses):** prefer `metadata.json.stats.effective_denominator` first (subject to the existing deflation guard), then `scope.tier_a_include` globs (filtered by `scope.exclude`, the umbrella-barrel note applies) when the brief supplies it, else the full subpath union.
80
-
81
- **Audit:** the root-barrel named-export count must be reported as a **secondary candidate** in the Denominator Candidates audit block (coverage-check.md §4) so the root-barrel-vs-subpath-union choice is auditable. Annotate the coverage report with: `Multi-entry (exports-map) — denominator: {effective_denominator | tier_a_include union | subpath union} ({N} subpaths resolved, {M} exports union; root barrel: {R})`.
82
-
83
- **When this clause does not apply:** monorepo packages (use the stratified-scope clause), empty-barrel packages (use the empty-barrel clause), pattern-reference apps (use the pattern-reference clause), `scope.type: "specific-modules"` (use the specific-modules clause), or single-entry / wildcard-only `exports` maps (use the standard root-barrel rule).
84
-
85
- Internal module symbols are **excluded** from the coverage denominator unless they are explicitly documented in SKILL.md (in which case they count as documented extras, not missing coverage).
34
+ Internal module symbols are **excluded** from the coverage denominator unless they are explicitly documented in SKILL.md (in which case they count as documented extras, not missing coverage): the surface holds only the names the entry points export, and the extraction's `internal` names never reach it. A documented extra reaches coverage-check.md §2c as a stale name. In a Python or TS/JS source, on a run where §2c runs `classify-stale` (the Forge, Forge+ or Deep tier, `analysis_confidence` `full`, `workspaceDrift` not `overridden` and a bound provenance map) and whose `surface.json` came from a complete extraction, it is an Info `observation` at the line where `classify-stale` finds the source still declares it (`defined_at`, or among several declaring files the one the skill cites on a line naming it), which update-skill never routes. Otherwise, and for a name a brief scopes out (`excluded.outsideScope`), it stays a Medium `stale-documentation` gap.
86
35
 
87
36
  This matches the extraction-patterns.md convention used during skill creation: coverage measures how well SKILL.md documents what users actually import, not the entire internal codebase.
88
37
 
89
38
  ### Provenance-map canonicalization
90
39
 
91
- When the test-side intersects documented SKILL.md exports against a stratified-scope provenance-map, raw provenance-map entry names may include **bookkeeping variants** of the same underlying export. These variants are artifacts of how the source library structures its registry (e.g., Storybook's component-plus-story decomposition, accessibility renderer shadowing, exact-match versus fuzzy-match renderer disambiguation). Counting them as separate exports inflates the denominator and produces false "missing documentation" findings for names that are structurally duplicates of an already-documented base export.
92
-
93
- Before intersecting documented names against the provenance-map entry list, **fold bookkeeping variants back to their base name** using the rules below. This matches the convention `skf-create-skill` records in `metadata.json.stats.effective_denominator_source` (e.g., `"provenance-map canonicalized count (ThemesGlobals_def folds with ThemesGlobals under _def convention)"`) — the base form is authoritative; the variant form is a sibling record, not an independent export.
94
-
95
- **Folding rules (apply in order, case-sensitive):**
96
-
97
- 1. **Suffix `_def`** — registry definition twin. `ThemesGlobals_def` folds to `ThemesGlobals`. Common in Storybook-style component registries where the definition object and the rendered component share the same public name.
98
- 2. **Suffix `_exact`** — exact-match variant. `ButtonSpec_exact` folds to `ButtonSpec`. Common in matcher/renderer registries where an `_exact` sibling signals a stricter resolution path.
99
- 3. **Prefix `a11y_`** — accessibility renderer shadow. `a11y_Checkbox` folds to `Checkbox`. Common in accessibility-wrapper layers that re-export every component under a parallel prefixed namespace.
100
- 4. **Other renderer-prefix disambiguation** — when the library uses a prefix-namespace convention (e.g., `mobile_`, `web_`, `ssr_`) to shadow the base export, fold the prefix form back to the base. **Only apply when the base form is also present in the provenance-map** — otherwise the prefix form is the real export and should be kept. Document the specific prefix used in the test report so the rule is auditable.
101
-
102
- **How to apply:**
103
-
104
- 1. Read all entry names from the provenance-map.
105
- 2. Build a canonical-name set by applying the folding rules above — each variant maps to its base. Retain the original variant → base mapping for reporting.
106
- 3. Intersect the documented SKILL.md export names against the **canonical** set, not the raw entry list.
107
- 4. When computing `Export Coverage`, use the **canonical count** as the denominator — not the raw provenance-map entry count. This aligns the denominator with `metadata.json.stats.effective_denominator` (when present), which `skf-create-skill` already writes as the canonicalized count.
108
- 5. In the test report, note the fold summary: `Provenance-map canonicalization: {N} raw entries → {M} canonical bases ({N−M} bookkeeping variants folded: _def×{a}, _exact×{b}, a11y_×{c}, other×{d})`. This makes the reduction auditable by future testers and update runs.
109
-
110
- **When to skip canonicalization:**
40
+ A provenance map may hold **bookkeeping variants** of one export, artifacts of how the library structures its registry (Storybook's component-plus-story decomposition, accessibility renderer shadowing, exact-match renderer disambiguation). Counting them as separate exports inflates the denominator with names that are structural duplicates of a documented base export. When a clause takes its denominator from the provenance map, pass `--fold` to `surface`: it folds `X_def`, `X_exact` and `a11y_X` back to `X`, and `<prefix>X` back to `X` for each renderer prefix you pass as `--fold-prefix` (`mobile_`, `web_`, `ssr_`, only folded when `X` is an entry too), and reports the fold summary in `canonical.summary` for the report. This matches the convention `skf-create-skill` records in `metadata.json.stats.effective_denominator_source`: the base form is authoritative, the variant a sibling record.
111
41
 
112
- - If the library's public surface genuinely distinguishes the variants (e.g., `a11y_Checkbox` is a separately-documented, separately-installed component and not a shadow), do not fold — the variant is a real export. Check SKILL.md for explicit documentation of the variant before folding. When in doubt, err on the side of not folding and report both forms.
113
- - If `metadata.json.stats.effective_denominator` is present and the provenance-map raw count matches it (no drift), canonicalization is not needed — the denominator is already canonical. Fold only when raw count > `effective_denominator` and the drift corresponds to recognizable bookkeeping suffixes/prefixes.
114
- - If drift remains after folding (e.g., raw 222 → canonical 215 but `effective_denominator` says 216), record the residual 1-count drift as an unexplained-reconciliation note in the test report. Do not fabricate additional fold rules to close the gap.
42
+ A map whose raw count equals `stats.effective_denominator` is already canonical: `surface` folds nothing (`canonical.skipped`). A non-zero `canonical.residual` after folding (raw 222, canonical 215, `effective_denominator` 216) is an unexplained-reconciliation note; do not invent fold rules to close it. One judgment stays here: a variant the library's public surface genuinely distinguishes (an `a11y_Checkbox` documented and installed on its own) is a real export: pass it as `--keep`. Check SKILL.md for explicit documentation of the variant first; when in doubt, keep it and report both forms.
115
43
 
116
44
  ## Source Access Resolution
117
45
 
@@ -121,13 +49,9 @@ Before analysis, determine source access level. Walk through these states in ord
121
49
  Check if `{source_path}` (from metadata.json `source_root`) exists on disk. If yes → full analysis at detected tier (AST + signatures). Set `analysis_confidence: full`.
122
50
 
123
51
  **State 2 — Local absent, provenance-map exists:**
124
- Check `{forge_data_folder}/{skill_name}/provenance-map.json`. If present AND contains at least 1 entry, use it as the baseline export inventory — each entry contains structured fields: `export_name`, `export_type`, `params[]`, `return_type`, `source_file`, `source_line`, `confidence`, and `ast_node_type`. Cross-reference against SKILL.md documented exports for name-matching and param-by-param coverage. Signature verification compares SKILL.md's documented params/return types against provenance-map entries directly.
52
+ Read `{forge_provenance_map}`, the provenance map init.md §2 bound (the skill version folder's, or the flat copy an older skill may still keep). When it is set and contains at least 1 entry, use it as the baseline export inventory. Each entry contains the structured fields `export_name`, `export_type`, `params[]`, `return_type`, `source_file`, `source_line`, `confidence`, and `ast_node_type`. Set `analysis_confidence: provenance-map`.
125
53
 
126
- **Cross-reference with metadata.json:** After loading provenance-map entries, compare the entry count against `metadata.json`'s `exports[]` array length and `stats.exports_public_api` count. If metadata reports more exports than provenance-map entries:
127
- - Compute `gap = metadata.exports.length - provenance_map.entries.length`
128
- - Report: "Provenance-map contains {pmap_count} entries but metadata.json lists {meta_count} exports ({gap} gap). Coverage denominator uses the union."
129
- - Build the coverage denominator from the **union** of provenance-map entry names and metadata.json `exports[]` names. Exports present in metadata but absent from provenance-map are counted as "missing documentation" in the coverage calculation.
130
- - If metadata.json is unavailable or has no `exports[]` array, use provenance-map count alone with a note: "Coverage denominator is provenance-map only — may undercount if extraction was incomplete." If remote reading tools are available (zread, deepwiki, gh API, or similar), supplement by reading the entry point file for live signature verification. Set `analysis_confidence: provenance-map`.
54
+ **Cross-reference with metadata.json:** the coverage denominator is the **union** of the provenance-map named exports and the `metadata.json` `exports[]` names, which `surface --provenance --metadata` (coverage-check.md §2) builds: an export in metadata but absent from the map counts as missing documentation, and the `state2` counts (`provenanceCount`, `metadataCount`, `unionCount`) go to step 5, whose scoring script decides whether the two disagree enough for the State 2 undercount deduction. When the union exceeds the map, report: "Provenance-map contains {provenanceCount} named exports but metadata.json lists {metadataCount} exports. Coverage denominator uses the union ({unionCount})." With no `metadata.json` `exports[]`, the map alone is the surface, with the note "Coverage denominator is provenance-map only: it may undercount if extraction was incomplete." If remote reading tools are available (zread, deepwiki, gh API, or similar), supplement by reading the entry point file for live signature verification.
131
55
 
132
56
  **State 2 limitations:** Signature verification at State 2 is **string comparison only**, not semantic. Provenance-map stores parameters as flat string arrays (e.g., `["data: Union[BinaryIO, list, str]"]`), so `str` vs `String` or `list` vs `List[Any]` would be treated as mismatches even when semantically equivalent. For full type-aware verification (handling type aliases, generic equivalence), State 1 (local source) with AST re-parsing is required. When the SKILL.md was compiled from the same provenance-map (typical for create-then-test flows), most strings will match. However, enrichment (step 4) and doc-fetching (step 3c) during compilation may alter parameter descriptions, add type annotations, or normalize signatures, causing mismatches even in create-then-test flows. Expect some string-level mismatches and treat them as compilation artifacts, not source drift signals, until signature fidelity is enforced by step 5's Signature Fidelity Rule (see `signature_source` field in provenance-map entries).
133
57
 
@@ -140,7 +64,7 @@ If neither provenance-map nor metadata exports provide a usable baseline, but re
140
64
  **State 5 — No source access at all:**
141
65
  If none of the above succeed, fall through to docs-only mode (as defined in coverage-check.md Section 0: pre-analysis source type detection). Set `analysis_confidence: docs-only`. Warn: "**No source access available.** Coverage check evaluates documentation self-consistency only. Re-run with local clone or remote access for source-backed verification."
142
66
 
143
- Set `analysis_confidence` in context for use in Section 2 analysis depth, step 5 output, and step 5 scoring.
67
+ Set `analysis_confidence` in context for use in Section 2 analysis depth, step 5 output, and step 5 scoring. It names the source access only: tooling health is `toolingStatus`, which init.md records, and the two never overwrite each other.
144
68
 
145
69
  **Confidence tier mapping:** `full` = T1, `provenance-map` = T1, `metadata-only` = T1-low, `remote-only` = T1-low, `docs-only` = T3. This aligns with the T1/T1-low/T2/T3 scale used across all SKF workflows.
146
70
 
@@ -1,6 +1,14 @@
1
1
  ---
2
2
  nextStepFile: 'score.md'
3
- outputFile: '{forge_version}/test-report-{skill_name}-{run_id}.md'
3
+ # A run the gate blocks is never scored: it ends through the report step's
4
+ # terminal sequence instead (§3).
5
+ blockedStepFile: 'report.md'
6
+ outputFile: '{report_file}'
7
+ # The public name report.md §4c gives the report once its checks pass, a
8
+ # blocked run's included: §1 names it in the blocked payload.
9
+ publishedReportFile: '{forge_version}/test-report-{skill_name}-{run_id}.md'
10
+ ledgerFile: '{forge_version}/test-findings-{run_id}.json'
11
+ hardGateScript: 'scripts/hard-gate.py'
4
12
  ---
5
13
 
6
14
  <!-- Config: communicate in {communication_language}. -->
@@ -9,63 +17,73 @@ outputFile: '{forge_version}/test-report-{skill_name}-{run_id}.md'
9
17
 
10
18
  ## STEP GOAL:
11
19
 
12
- Scan accumulated findings from coverage and coherence analysis for critical or high severity gaps. If any exist, block the pipeline with a clear listing of every blocking finding — no coverage score is computed or reported. If only medium, low, or info findings exist, pass through to scoring.
20
+ Decide from the gap ledger whether this run may be scored. Coverage, coherence and external validation recorded every gap they found in `{ledgerFile}`, each with the severity and the category the Gap Severity table gives it. Any Critical or High gap blocks the run: no score is computed, and the report step publishes the run as a FAIL. When only Medium, Low or Info gaps exist, the run passes through to scoring.
13
21
 
14
- ### §1. Read Findings from Output
22
+ **Halt envelope.** Every HALT in this step names its `halt_reason` and phase and carries exit code 1. It releases the run lock first, whatever the release prints: from `{project-root}`, run `uv run {runLockHelper} release --lock "{forge_version}/.test-skill.lock" --owner "{run_owner}"` (SKILL.md Workflow Rules). In headless mode it then writes `{"phase": "<phase>", "reason": "<the halt message>", "halt_reason": "<halt_reason>", "skill_name": "{skill_name}", "report_path": "{report_file}"}`, adding `"path"` when the halt names one, to `{run_dir}/halt.json` and runs:
15
23
 
16
- Read `{outputFile}` and scan the **Coverage Analysis** and **Coherence Analysis** sections for GAP entries. Each GAP entry contains a severity marker in this format:
17
-
18
- ```
19
- **Severity:** {Critical|High|Medium|Low|Info}
24
+ ```bash
25
+ uv run {emitEnvelopeHelper} emit-halt --workflow skf-test-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"
20
26
  ```
21
27
 
22
- Extract every line matching `**Severity:** Critical` or `**Severity:** High`. For each match, also capture the parent GAP heading (`### GAP-{NNN}: {title}`) and the `**Source:**` line to build a blocking-findings list.
28
+ Display the line it prints, as the run's last line, then stop. If the emitter exits non-zero or prints no line, display the halt message alone. An interactive HALT displays its message and emits nothing.
23
29
 
24
- ### §2. Evaluate Gate
30
+ ### §1. Run the Gate
31
+
32
+ The gate reads the ledger, not the report: a gap the report shows only in a table still counts, and a stage that never recorded its gaps cannot pass for one that found none. Run it (`{hardGateScript}` resolves relative to the skill root):
25
33
 
26
- **Count blocking findings** (Critical + High severity).
34
+ ```bash
35
+ uv run {hardGateScript} check --ledger "{ledgerFile}" --skill-name "{skill_name}" --report-path "{publishedReportFile}" --require-stage coverage-check --require-stage coherence-check --require-stage external-validators
36
+ ```
37
+
38
+ Rely on its JSON and do not count the gaps again by hand.
27
39
 
28
- **IF blocking findings exist → BLOCK (§3)**
40
+ ### §2. Evaluate Gate
29
41
 
30
- **IF no blocking findings → PASS (§4)**
42
+ - `gate` is `blocked` (exit 0): `blocking` lists every Critical and High gap, Critical first. Go to §3.
43
+ - `gate` is `passed` (exit 0): no gap is Critical or High. Go to §4.
44
+ - Exit 1 with `code` `LEDGER_MISSING` or `STAGE_NOT_RECORDED`: a stage before the gate recorded nothing in the ledger (`missing_stages` names it; with no ledger, none of them did), so the gate cannot decide. HALT (`halt_reason: "step-completeness-violation"`, phase `hard-gate:check`) with "step completeness violation: {the stages} never recorded their gaps in `{ledgerFile}`; workflow state is inconsistent, do not score or finalize the report".
45
+ - Any other `code` (`LEDGER_INVALID`, `HELPER_MISSING`) or exit, or no JSON: HALT (`halt_reason: "helper-failed"`, phase `hard-gate:check`) with the script's `error`, or with its stderr when it printed no JSON.
31
46
 
32
- ### §3. Block — Critical/High Findings Detected
47
+ ### §3. Block: Critical or High Gaps
33
48
 
34
- The hard gate blocks the pipeline. No scoring step runs.
49
+ The gate blocks the run, and scoring never runs. The run still ends through the report step's terminal sequence: the Gap Report, the FAIL result contract and the on_complete hook, then the health check (unless `--no-health-check` was passed). Its result envelope and result files carry `exit_code` 2 and verdict `FAIL`, and the report keeps its in-progress name until report.md §4c's checks pass, so a halt there leaves no partial report under the public name.
35
50
 
36
51
  Update `{outputFile}` frontmatter:
52
+ - Set `hardGate: 'blocked'`
37
53
  - Set `testResult: 'fail'`
54
+ - Set `nextWorkflow: 'update-skill'`
38
55
  - Append `'hard-gate'` to `stepsCompleted`
39
56
 
40
- Report to the user:
57
+ Write the **Completeness Score** section, which scoring would otherwise write, in place of the template's `## Completeness Score` heading and the placeholder comment under it:
41
58
 
42
- "**Hard gate BLOCKED — {N} critical/high finding(s) must be resolved before scoring.**
59
+ ```markdown
60
+ ## Completeness Score
43
61
 
44
- | # | GAP | Severity | Source |
45
- |---|-----|----------|--------|
46
- {for each blocking finding:}
47
- | {i} | {GAP-NNN}: {title} | {severity} | {source} |
62
+ **Result:** **FAIL**, not scored: the hard gate blocked this run on {blocking_count} Critical or High gap(s), listed first in the Gap Report.
63
+ ```
64
+
65
+ Report to the user:
48
66
 
49
- **{M} medium/low/info findings also noted (non-blocking).**
67
+ "**Hard gate BLOCKED: {blocking_count} Critical or High gap(s) must be resolved before scoring.**
50
68
 
51
- **Action required:** resolve all Critical and High findings, then re-run test-skill.
52
- **Recommended next step:** update-skill"
69
+ | # | Gap | Severity | Source |
70
+ |---|-----|----------|--------|
71
+ {for each `blocking` entry:}
72
+ | {i} | {id}: {title} | {severity} | {source} |
53
73
 
54
- **Headless envelope (if `{headless_mode}`):** emit to **stderr**:
74
+ **{non_blocking_count} Medium, Low or Info gap(s) also recorded (non-blocking).**
55
75
 
56
- ```
57
- SKF_TEST_RESULT_JSON: {"status":"error","skill_name":"{skill_name}","verdict":"FAIL","score":null,"threshold":null,"report_path":"{outputFile}","next_workflow":"update-skill","exit_code":2,"halt_reason":"hard-gate-blocked"}
58
- ```
76
+ **Recommended next step:** `@Ferris US {skill_name} --from-test-report` (update-skill repairs the gaps this report lists), once the report step has written the Gap Report and the result files."
59
77
 
60
- HALT — do not chain to `{nextStepFile}`.
78
+ Then load and execute `{blockedStepFile}`. Do not chain to `{nextStepFile}`: a blocked run is never scored.
61
79
 
62
- ### §4. Pass — No Critical/High Findings
80
+ ### §4. Pass: No Critical or High Gaps
63
81
 
64
- The hard gate passes. Medium, low, and info findings are documented in the gap report but do not block.
82
+ The hard gate passes. The Medium, Low and Info gaps stay in the ledger for the Gap Report and do not block.
65
83
 
66
84
  Update `{outputFile}` frontmatter:
67
- - Append `'hard-gate'` to `stepsCompleted`
85
+ - Set `hardGate: 'passed'`
68
86
 
69
- Report that the hard gate passed, noting the count of non-blocking medium/low/info finding(s), then proceed to scoring.
87
+ Report that the hard gate passed, noting the count of non-blocking Medium, Low and Info gap(s) (`non_blocking_count`), then proceed to scoring.
70
88
 
71
- Update stepsCompleted, then load and execute `{nextStepFile}`.
89
+ Append `'hard-gate'` to `stepsCompleted` in the `{outputFile}` frontmatter, then load and execute `{nextStepFile}`.