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.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +49 -49
- package/docs/404.md +10 -8
- package/docs/_data/pinned.yaml +22 -13
- package/docs/_internal/STABILITY.md +58 -35
- package/docs/agents.md +39 -53
- package/docs/architecture.md +65 -51
- package/docs/bmad-synergy.md +53 -51
- package/docs/campaign.md +127 -75
- package/docs/concepts.md +34 -28
- package/docs/examples.md +70 -68
- package/docs/forge-auto.md +34 -31
- package/docs/getting-started.md +118 -57
- package/docs/how-it-works.md +25 -21
- package/docs/index.md +15 -15
- package/docs/skill-model.md +70 -59
- package/docs/troubleshooting.md +143 -18
- package/docs/verifying-a-skill.md +87 -57
- package/docs/why-skf.md +24 -22
- package/docs/workflows.md +274 -110
- package/package.json +18 -10
- package/src/forger/preferences.yaml +8 -1
- package/src/knowledge/agentskills-spec.md +2 -0
- package/src/knowledge/ccc-bridge.md +40 -24
- package/src/knowledge/confidence-tiers.md +9 -5
- package/src/knowledge/overview.md +3 -3
- package/src/knowledge/progressive-capability.md +8 -8
- package/src/knowledge/provenance-tracking.md +9 -5
- package/src/knowledge/qmd-registry.md +3 -3
- package/src/knowledge/skf-knowledge-index.csv +2 -2
- package/src/knowledge/skill-lifecycle.md +18 -11
- package/src/knowledge/split-body-strategy.md +0 -3
- package/src/knowledge/tool-resolution.md +4 -2
- package/src/knowledge/version-paths.md +101 -15
- package/src/module-help.csv +3 -3
- package/src/module.yaml +10 -0
- package/src/shared/data/ast-grep-recipes.yaml +608 -0
- package/src/shared/data/ide-context-files.json +30 -0
- package/src/shared/health-check.md +31 -59
- package/src/shared/references/description-guard-protocol.md +12 -9
- package/src/shared/references/feasibility-report-schema.md +19 -13
- package/src/shared/references/headless-gate-convention.md +55 -3
- package/src/shared/references/output-contract-schema.md +19 -8
- package/src/shared/references/pipeline-contracts.md +94 -29
- package/src/shared/references/tessl-review.md +77 -0
- package/src/shared/scripts/schemas/skf-analyze-result-envelope.v1.json +194 -0
- package/src/shared/scripts/schemas/skf-audit-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +32 -4
- package/src/shared/scripts/schemas/skf-campaign-result-envelope.v1.json +174 -0
- package/src/shared/scripts/schemas/skf-create-skill-result-envelope.v1.json +284 -0
- package/src/shared/scripts/schemas/skf-drop-skill-result-envelope.v1.json +164 -0
- package/src/shared/scripts/schemas/skf-export-result-envelope.v1.json +160 -0
- package/src/shared/scripts/schemas/skf-quick-skill-result-envelope.v1.json +261 -0
- package/src/shared/scripts/schemas/skf-refine-architecture-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-rename-skill-result-envelope.v1.json +179 -0
- package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +27 -11
- package/src/shared/scripts/schemas/skf-stack-result-envelope.v1.json +176 -0
- package/src/shared/scripts/schemas/skf-test-result-envelope.v1.json +173 -0
- package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +19 -5
- package/src/shared/scripts/schemas/skf-verify-stack-result-envelope.v1.json +180 -0
- package/src/shared/scripts/schemas/skill-brief.v1.json +34 -0
- package/src/shared/scripts/schemas/workspace-detection.v1.json +1 -1
- package/src/shared/scripts/skf-atomic-write.py +233 -64
- package/src/shared/scripts/skf-build-change-manifest.py +2753 -28
- package/src/shared/scripts/skf-ccc-git-hygiene.py +532 -0
- package/src/shared/scripts/skf-check-unit-records.py +184 -0
- package/src/shared/scripts/skf-check-workspace-drift.py +538 -9
- package/src/shared/scripts/skf-classify-changed-files.py +772 -0
- package/src/shared/scripts/skf-comention-pairs.py +1333 -123
- package/src/shared/scripts/skf-compare-file-hashes.py +267 -105
- package/src/shared/scripts/skf-count-imports.py +1867 -0
- package/src/shared/scripts/skf-count-tokens.py +1 -1
- package/src/shared/scripts/skf-derive-assembly-shape.py +21 -3
- package/src/shared/scripts/skf-description-guard.py +99 -11
- package/src/shared/scripts/skf-detect-docs.py +694 -2
- package/src/shared/scripts/skf-detect-language.py +486 -107
- package/src/shared/scripts/skf-detect-registry.py +887 -0
- package/src/shared/scripts/skf-detect-scripts-assets.py +197 -55
- package/src/shared/scripts/skf-detect-tools.py +209 -27
- package/src/shared/scripts/skf-detect-workspaces.py +506 -30
- package/src/shared/scripts/skf-disqualify-candidates.py +821 -182
- package/src/shared/scripts/skf-emit-brief-result-envelope.py +69 -191
- package/src/shared/scripts/skf-emit-result-envelope.py +1604 -106
- package/src/shared/scripts/skf-enumerate-stack-skills.py +986 -117
- package/src/shared/scripts/skf-extract-public-api.py +5247 -96
- package/src/shared/scripts/skf-extraction-inventory.py +1280 -0
- package/src/shared/scripts/skf-extraction-snapshot.py +664 -0
- package/src/shared/scripts/skf-fetch-temporal.py +674 -0
- package/src/shared/scripts/skf-find-cycles.py +97 -29
- package/src/shared/scripts/skf-find-test-report.py +476 -0
- package/src/shared/scripts/skf-forge-tier-rw.py +469 -205
- package/src/shared/scripts/skf-github-fetch.py +365 -0
- package/src/shared/scripts/skf-github-probe.py +700 -0
- package/src/shared/scripts/skf-hash-content.py +180 -20
- package/src/shared/scripts/skf-language-corpora.py +1 -1
- package/src/shared/scripts/skf-load-provenance.py +161 -27
- package/src/shared/scripts/skf-manifest-ops.py +1 -1
- package/src/shared/scripts/skf-merge-ccc-exclusions.py +2307 -223
- package/src/shared/scripts/skf-merge-doc-urls.py +143 -20
- package/src/shared/scripts/skf-names-present.py +221 -0
- package/src/shared/scripts/skf-pair-intersect.py +119 -28
- package/src/shared/scripts/skf-parse-gaps.py +1384 -0
- package/src/shared/scripts/skf-preapply.py +1 -1
- package/src/shared/scripts/skf-preflight.py +176 -28
- package/src/shared/scripts/skf-promote-staged.py +430 -0
- package/src/shared/scripts/skf-provenance-gap-dispatch.py +64 -8
- package/src/shared/scripts/skf-qmd-classify-collections.py +229 -45
- package/src/shared/scripts/skf-quick-batch.py +774 -0
- package/src/shared/scripts/skf-rebuild-managed-sections.py +972 -88
- package/src/shared/scripts/skf-recommend-scope-type.py +323 -156
- package/src/shared/scripts/skf-render-metadata-stats.py +156 -12
- package/src/shared/scripts/skf-render-quick-metadata.py +132 -28
- package/src/shared/scripts/skf-render-stack-metadata.py +976 -0
- package/src/shared/scripts/skf-resolve-authoritative-files.py +155 -14
- package/src/shared/scripts/skf-resolve-package.py +523 -106
- package/src/shared/scripts/skf-rewrite-skill-name.py +433 -47
- package/src/shared/scripts/skf-run-lock.py +577 -0
- package/src/shared/scripts/skf-scan-manifests.py +998 -57
- package/src/shared/scripts/skf-scan-skill-md-structure.py +1341 -37
- package/src/shared/scripts/skf-severity-classify.py +712 -108
- package/src/shared/scripts/skf-shape-detect.py +298 -204
- package/src/shared/scripts/skf-shard-body.py +9 -8
- package/src/shared/scripts/skf-skill-inventory.py +2412 -89
- package/src/shared/scripts/skf-skills-module.py +472 -0
- package/src/shared/scripts/skf-source-tree.py +1796 -0
- package/src/shared/scripts/skf-structural-diff.py +787 -121
- package/src/shared/scripts/skf-tessl-review.py +706 -0
- package/src/shared/scripts/skf-update-active-symlink.py +120 -67
- package/src/shared/scripts/skf-update-run-state.py +624 -0
- package/src/shared/scripts/skf-validate-brief-inputs.py +92 -29
- package/src/shared/scripts/skf-validate-brief-schema.py +23 -2
- package/src/shared/scripts/skf-validate-feasibility-report.py +577 -66
- package/src/shared/scripts/skf-validate-frontmatter.py +103 -26
- package/src/shared/scripts/skf-validate-output.py +712 -64
- package/src/shared/scripts/skf-validate-pins.py +1 -1
- package/src/shared/scripts/skf-verify-no-trace.py +116 -10
- package/src/shared/scripts/skf-verify-provenance-completeness.py +3945 -152
- package/src/shared/scripts/skf-write-skill-brief.py +406 -25
- package/src/shared/tool-requirements.yaml +201 -0
- package/src/skf-analyze-source/SKILL.md +41 -36
- package/src/skf-analyze-source/assets/skill-brief-schema.md +7 -8
- package/src/skf-analyze-source/customize.toml +36 -24
- package/src/skf-analyze-source/references/auto-docs-only.md +58 -20
- package/src/skf-analyze-source/references/continue.md +2 -13
- package/src/skf-analyze-source/references/discover-additional-source.md +147 -0
- package/src/skf-analyze-source/references/generate-briefs.md +121 -55
- package/src/skf-analyze-source/references/headless-contract.md +42 -15
- package/src/skf-analyze-source/references/identify-units.md +96 -110
- package/src/skf-analyze-source/references/init.md +73 -71
- package/src/skf-analyze-source/references/map-and-detect.md +123 -105
- package/src/skf-analyze-source/references/map-unit-exports.md +68 -0
- package/src/skf-analyze-source/references/recommend.md +51 -70
- package/src/skf-analyze-source/references/scan-project.md +60 -84
- package/src/skf-analyze-source/references/scan-root.md +39 -0
- package/src/skf-analyze-source/references/step-auto-scope-coexistence.md +47 -0
- package/src/skf-analyze-source/references/step-auto-scope-corpora.md +53 -0
- package/src/skf-analyze-source/references/step-auto-scope-split.md +91 -0
- package/src/skf-analyze-source/references/step-auto-scope.md +208 -293
- package/src/skf-analyze-source/references/step-shape-detect.md +14 -12
- package/src/skf-analyze-source/references/unit-detection-heuristics.md +37 -42
- package/src/skf-audit-skill/SKILL.md +43 -51
- package/src/skf-audit-skill/assets/drift-report-template.md +28 -3
- package/src/skf-audit-skill/customize.toml +41 -20
- package/src/skf-audit-skill/references/constituent-freshness.md +91 -0
- package/src/skf-audit-skill/references/doc-drift.md +141 -0
- package/src/skf-audit-skill/references/headless-contract.md +29 -0
- package/src/skf-audit-skill/references/health-check.md +2 -0
- package/src/skf-audit-skill/references/init.md +149 -210
- package/src/skf-audit-skill/references/re-index.md +103 -110
- package/src/skf-audit-skill/references/report.md +96 -33
- package/src/skf-audit-skill/references/semantic-diff.md +34 -25
- package/src/skf-audit-skill/references/severity-classify.md +79 -65
- package/src/skf-audit-skill/references/severity-rules.md +15 -6
- package/src/skf-audit-skill/references/structural-diff.md +80 -90
- package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
- package/src/skf-audit-skill/scripts/render-drift-tables.py +712 -0
- package/src/skf-brief-skill/SKILL.md +37 -26
- package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
- package/src/skf-brief-skill/assets/scope-templates.md +18 -25
- package/src/skf-brief-skill/assets/skill-brief-schema.md +30 -23
- package/src/skf-brief-skill/customize.toml +48 -20
- package/src/skf-brief-skill/references/analyze-target.md +144 -127
- package/src/skf-brief-skill/references/confirm-brief.md +11 -9
- package/src/skf-brief-skill/references/draft-checkpoint.md +36 -17
- package/src/skf-brief-skill/references/gather-intent-ratify.md +68 -0
- package/src/skf-brief-skill/references/gather-intent.md +87 -182
- package/src/skf-brief-skill/references/headless-args.md +84 -16
- package/src/skf-brief-skill/references/health-check.md +1 -1
- package/src/skf-brief-skill/references/invocation-contract.md +18 -13
- package/src/skf-brief-skill/references/portfolio-similarity-check.md +1 -1
- package/src/skf-brief-skill/references/qmd-collection-registration.md +7 -10
- package/src/skf-brief-skill/references/scope-definition.md +123 -47
- package/src/skf-brief-skill/references/step-auto-brief.md +26 -100
- package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
- package/src/skf-brief-skill/references/version-resolution.md +7 -10
- package/src/skf-brief-skill/references/write-brief.md +66 -57
- package/src/skf-campaign/SKILL.md +31 -34
- package/src/skf-campaign/assets/campaign-state-schema.json +25 -4
- package/src/skf-campaign/customize.toml +47 -16
- package/src/skf-campaign/references/campaign-contracts.md +39 -29
- package/src/skf-campaign/references/campaign-directive-spec.md +4 -2
- package/src/skf-campaign/references/health-check.md +7 -16
- package/src/skf-campaign/references/step-01-setup.md +46 -84
- package/src/skf-campaign/references/step-02-strategy.md +31 -30
- package/src/skf-campaign/references/step-03-pins.md +26 -18
- package/src/skf-campaign/references/step-04-provenance.md +24 -23
- package/src/skf-campaign/references/step-05-skill-loop.md +67 -48
- package/src/skf-campaign/references/step-06-batch.md +41 -34
- package/src/skf-campaign/references/step-07-capstone.md +40 -25
- package/src/skf-campaign/references/step-08-verify.md +28 -29
- package/src/skf-campaign/references/step-09-refine.md +29 -30
- package/src/skf-campaign/references/step-10-export.md +48 -36
- package/src/skf-campaign/references/step-11-maintenance.md +31 -34
- package/src/skf-campaign/references/step-resume.md +37 -68
- package/src/skf-campaign/scripts/campaign-deps.py +57 -18
- package/src/skf-campaign/scripts/campaign-parse-manifest.py +361 -54
- package/src/skf-campaign/scripts/campaign-provenance.py +96 -53
- package/src/skf-campaign/scripts/campaign-quality-gate.py +592 -0
- package/src/skf-campaign/scripts/campaign-render-batch.py +257 -49
- package/src/skf-campaign/scripts/campaign-render-kickoff.py +343 -50
- package/src/skf-campaign/scripts/campaign-report.py +204 -37
- package/src/skf-campaign/scripts/campaign-state.py +1128 -0
- package/src/skf-campaign/scripts/campaign-status.py +10 -74
- package/src/skf-campaign/scripts/campaign-validate-pins.py +30 -3
- package/src/skf-campaign/scripts/campaign-validate-state.py +34 -4
- package/src/skf-campaign/templates/campaign-brief-template.yaml +4 -5
- package/src/skf-campaign/templates/campaign-report-template.md +5 -1
- package/src/skf-campaign/templates/kickoff-template.md +0 -14
- package/src/skf-create-skill/SKILL.md +27 -20
- package/src/skf-create-skill/assets/compile-assembly-rules.md +11 -8
- package/src/skf-create-skill/assets/skill-sections.md +21 -11
- package/src/skf-create-skill/customize.toml +20 -8
- package/src/skf-create-skill/references/authoritative-files-protocol.md +36 -58
- package/src/skf-create-skill/references/batch-mode.md +81 -0
- package/src/skf-create-skill/references/ccc-index-check.md +27 -0
- package/src/skf-create-skill/references/compile.md +119 -70
- package/src/skf-create-skill/references/component-extraction.md +113 -91
- package/src/skf-create-skill/references/enrich.md +41 -23
- package/src/skf-create-skill/references/entry-points-by-hand.md +37 -0
- package/src/skf-create-skill/references/extract.md +204 -162
- package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +11 -11
- package/src/skf-create-skill/references/extraction-patterns.md +588 -201
- package/src/skf-create-skill/references/generate-artifacts.md +145 -93
- package/src/skf-create-skill/references/health-check.md +1 -1
- package/src/skf-create-skill/references/load-brief.md +53 -36
- package/src/skf-create-skill/references/relabel-rule.md +12 -0
- package/src/skf-create-skill/references/report.md +37 -57
- package/src/skf-create-skill/references/source-resolution-protocols.md +58 -169
- package/src/skf-create-skill/references/step-auto-shard.md +20 -93
- package/src/skf-create-skill/references/step-doc-rot.md +44 -60
- package/src/skf-create-skill/references/step-doc-sources.md +28 -19
- package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
- package/src/skf-create-skill/references/sub/fetch-docs.md +106 -59
- package/src/skf-create-skill/references/sub/fetch-temporal.md +53 -166
- package/src/skf-create-skill/references/tier-degradation-rules.md +18 -9
- package/src/skf-create-skill/references/validate.md +173 -99
- package/src/skf-create-skill/scripts/scan-doc-rot.py +232 -99
- package/src/skf-create-stack-skill/SKILL.md +29 -56
- package/src/skf-create-stack-skill/assets/metadata-contract.md +51 -0
- package/src/skf-create-stack-skill/assets/provenance-map-schema.md +15 -15
- package/src/skf-create-stack-skill/assets/stack-skill-template.md +23 -57
- package/src/skf-create-stack-skill/customize.toml +23 -12
- package/src/skf-create-stack-skill/references/compile-stack.md +57 -66
- package/src/skf-create-stack-skill/references/compose-mode-rules.md +24 -44
- package/src/skf-create-stack-skill/references/detect-integrations.md +92 -95
- package/src/skf-create-stack-skill/references/detect-manifests.md +46 -71
- package/src/skf-create-stack-skill/references/generate-output.md +138 -128
- package/src/skf-create-stack-skill/references/init.md +90 -32
- package/src/skf-create-stack-skill/references/integration-patterns.md +1 -17
- package/src/skf-create-stack-skill/references/invocation-contract.md +34 -0
- package/src/skf-create-stack-skill/references/manifest-patterns.md +32 -20
- package/src/skf-create-stack-skill/references/parallel-extract.md +112 -38
- package/src/skf-create-stack-skill/references/rank-and-confirm.md +57 -75
- package/src/skf-create-stack-skill/references/report.md +39 -33
- package/src/skf-create-stack-skill/references/validate.md +20 -39
- package/src/skf-drop-skill/SKILL.md +28 -51
- package/src/skf-drop-skill/customize.toml +44 -30
- package/src/skf-drop-skill/references/execute.md +83 -146
- package/src/skf-drop-skill/references/health-check.md +2 -0
- package/src/skf-drop-skill/references/invocation-contract.md +64 -0
- package/src/skf-drop-skill/references/report.md +46 -30
- package/src/skf-drop-skill/references/select.md +122 -124
- package/src/skf-drop-skill/scripts/dir-sizes.py +54 -26
- package/src/skf-drop-skill/scripts/drop-roster.py +322 -0
- package/src/skf-export-skill/SKILL.md +40 -62
- package/src/skf-export-skill/assets/managed-section-format.md +14 -50
- package/src/skf-export-skill/assets/snippet-format.md +3 -1
- package/src/skf-export-skill/customize.toml +42 -13
- package/src/skf-export-skill/references/generate-snippet.md +54 -46
- package/src/skf-export-skill/references/health-check.md +2 -0
- package/src/skf-export-skill/references/invocation-contract.md +15 -0
- package/src/skf-export-skill/references/load-skill.md +88 -62
- package/src/skf-export-skill/references/manifest-rebuild.md +9 -10
- package/src/skf-export-skill/references/multi-skill-mode.md +4 -4
- package/src/skf-export-skill/references/orphan-context-detection.md +13 -5
- package/src/skf-export-skill/references/orphan-row-detection.md +31 -22
- package/src/skf-export-skill/references/package.md +15 -73
- package/src/skf-export-skill/references/preflight-snippet-root-probe.md +51 -70
- package/src/skf-export-skill/references/result-envelope.md +31 -16
- package/src/skf-export-skill/references/summary.md +41 -17
- package/src/skf-export-skill/references/token-report.md +4 -12
- package/src/skf-export-skill/references/update-context.md +118 -237
- package/src/skf-forger/SKILL.md +61 -37
- package/src/skf-forger/bmad-skill-manifest.yaml +4 -1
- package/src/skf-forger/customize.toml +43 -0
- package/src/skf-forger/references/pipeline-mode.md +73 -18
- package/src/skf-forger/scripts/forge-status.py +299 -0
- package/src/skf-forger/scripts/parse-pipeline.py +322 -54
- package/src/skf-forger/scripts/pipeline-gate.py +428 -0
- package/src/skf-forger/scripts/pipeline-journal.py +1052 -0
- package/src/skf-quick-skill/SKILL.md +54 -53
- package/src/skf-quick-skill/assets/skill-template.md +4 -2
- package/src/skf-quick-skill/customize.toml +51 -20
- package/src/skf-quick-skill/references/batch-mode.md +74 -21
- package/src/skf-quick-skill/references/compile.md +30 -31
- package/src/skf-quick-skill/references/ecosystem-check.md +7 -57
- package/src/skf-quick-skill/references/finalize.md +69 -18
- package/src/skf-quick-skill/references/halt-contract.md +41 -29
- package/src/skf-quick-skill/references/health-check.md +5 -3
- package/src/skf-quick-skill/references/quick-extract.md +114 -45
- package/src/skf-quick-skill/references/registry-resolution.md +9 -64
- package/src/skf-quick-skill/references/resolve-target.md +116 -66
- package/src/skf-quick-skill/references/write-and-validate.md +79 -40
- package/src/skf-refine-architecture/SKILL.md +43 -53
- package/src/skf-refine-architecture/customize.toml +49 -20
- package/src/skf-refine-architecture/references/compile.md +97 -54
- package/src/skf-refine-architecture/references/exit-codes.md +30 -0
- package/src/skf-refine-architecture/references/finding-storage.md +21 -0
- package/src/skf-refine-architecture/references/gap-analysis.md +101 -38
- package/src/skf-refine-architecture/references/improvements.md +14 -20
- package/src/skf-refine-architecture/references/init.md +98 -57
- package/src/skf-refine-architecture/references/issue-detection.md +32 -39
- package/src/skf-refine-architecture/references/refinement-rules.md +37 -48
- package/src/skf-refine-architecture/references/report.md +65 -54
- package/src/skf-refine-architecture/scripts/skf-check-preservation.py +1619 -0
- package/src/skf-rename-skill/SKILL.md +19 -54
- package/src/skf-rename-skill/customize.toml +32 -26
- package/src/skf-rename-skill/references/execute.md +230 -184
- package/src/skf-rename-skill/references/exit-codes.md +7 -7
- package/src/skf-rename-skill/references/health-check.md +1 -7
- package/src/skf-rename-skill/references/invocation-contract.md +25 -0
- package/src/skf-rename-skill/references/report.md +63 -52
- package/src/skf-rename-skill/references/select.md +197 -115
- package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -21
- package/src/skf-setup/SKILL.md +26 -26
- package/src/skf-setup/customize.toml +14 -10
- package/src/skf-setup/references/auto-index.md +50 -63
- package/src/skf-setup/references/ccc-index.md +29 -90
- package/src/skf-setup/references/detect-and-tier.md +58 -67
- package/src/skf-setup/references/health-check.md +2 -0
- package/src/skf-setup/references/invocation-contract.md +14 -0
- package/src/skf-setup/references/report.md +43 -166
- package/src/skf-setup/references/tier-rules.md +5 -5
- package/src/skf-setup/references/write-config.md +34 -57
- package/src/skf-test-skill/SKILL.md +17 -57
- package/src/skf-test-skill/assets/output-section-formats.md +33 -34
- package/src/skf-test-skill/customize.toml +27 -13
- package/src/skf-test-skill/references/coherence-check.md +134 -62
- package/src/skf-test-skill/references/coverage-check-tiers.md +35 -0
- package/src/skf-test-skill/references/coverage-check.md +209 -264
- package/src/skf-test-skill/references/detect-mode.md +5 -5
- package/src/skf-test-skill/references/external-validators.md +94 -82
- package/src/skf-test-skill/references/health-check.md +6 -7
- package/src/skf-test-skill/references/init.md +164 -91
- package/src/skf-test-skill/references/invocation-contract.md +66 -0
- package/src/skf-test-skill/references/migration-section-rules.md +5 -2
- package/src/skf-test-skill/references/report.md +164 -142
- package/src/skf-test-skill/references/score.md +80 -107
- package/src/skf-test-skill/references/scoring-rules.md +42 -155
- package/src/skf-test-skill/references/source-access-protocol.md +18 -94
- package/src/skf-test-skill/references/step-hard-gate.md +51 -33
- package/src/skf-test-skill/scripts/aggregate-coherence.py +218 -30
- package/src/skf-test-skill/scripts/build-result-context.py +380 -0
- package/src/skf-test-skill/scripts/check-metadata-coherence.py +37 -4
- package/src/skf-test-skill/scripts/combine-external-scores.py +23 -6
- package/src/skf-test-skill/scripts/compute-score.py +223 -45
- package/src/skf-test-skill/scripts/gap-ledger.py +1666 -0
- package/src/skf-test-skill/scripts/hard-gate.py +203 -0
- package/src/skf-test-skill/scripts/load-coverage-inputs.py +1198 -0
- package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
- package/src/skf-test-skill/scripts/reconcile-coverage.py +547 -79
- package/src/skf-test-skill/scripts/score-signatures.py +479 -0
- package/src/skf-test-skill/scripts/stage-helper-payload.py +148 -0
- package/src/skf-test-skill/scripts/validate-inventory.py +311 -16
- package/src/skf-test-skill/scripts/verify-declared-numerator.py +133 -56
- package/src/skf-test-skill/templates/test-report-template.md +21 -15
- package/src/skf-update-skill/SKILL.md +38 -25
- package/src/skf-update-skill/customize.toml +27 -12
- package/src/skf-update-skill/references/detect-changes.md +253 -223
- package/src/skf-update-skill/references/gap-driven.md +336 -0
- package/src/skf-update-skill/references/health-check.md +31 -5
- package/src/skf-update-skill/references/init.md +254 -84
- package/src/skf-update-skill/references/invocation-contract.md +12 -0
- package/src/skf-update-skill/references/manual-section-rules.md +6 -23
- package/src/skf-update-skill/references/merge.md +182 -49
- package/src/skf-update-skill/references/re-extract.md +53 -262
- package/src/skf-update-skill/references/report.md +102 -35
- package/src/skf-update-skill/references/write.md +357 -155
- package/src/skf-update-skill/scripts/skf-new-file-diff.py +183 -46
- package/src/skf-verify-stack/SKILL.md +23 -42
- package/src/skf-verify-stack/assets/feasibility-report-template.md +11 -5
- package/src/skf-verify-stack/customize.toml +55 -22
- package/src/skf-verify-stack/references/coverage-patterns.md +17 -8
- package/src/skf-verify-stack/references/coverage.md +67 -64
- package/src/skf-verify-stack/references/exit-codes.md +21 -8
- package/src/skf-verify-stack/references/init.md +107 -62
- package/src/skf-verify-stack/references/integration-verification-rules.md +12 -13
- package/src/skf-verify-stack/references/integrations.md +106 -65
- package/src/skf-verify-stack/references/report.md +59 -42
- package/src/skf-verify-stack/references/requirements.md +32 -9
- package/src/skf-verify-stack/references/synthesize.md +53 -39
- package/src/skf-verify-stack/scripts/skf-coverage-tally.py +398 -52
- package/src/skf-verify-stack/scripts/skf-previous-report.py +330 -0
- package/src/skf-verify-stack/scripts/skf-report-delta.py +453 -49
- package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +240 -27
- package/tools/cli/commands/install.js +11 -4
- package/tools/cli/commands/status.js +15 -3
- package/tools/cli/commands/update.js +11 -4
- package/tools/cli/lib/tool-check.js +320 -0
- package/tools/cli/lib/version-check.js +22 -9
- package/tools/cli/skf-cli.js +4 -1
- package/.gitattributes +0 -16
- package/.nvmrc +0 -1
- package/docs/_internal/RELEASING.md +0 -679
- package/release-audits/v1.0.0-launch-audit.md +0 -728
- package/src/skf-audit-skill/references/step-doc-drift.md +0 -177
- package/src/skf-brief-skill/references/headless-source-authority-detection.md +0 -26
- package/src/skf-campaign/manifest.yaml +0 -15
- package/src/skf-create-skill/assets/tessl-dismissal-rules.md +0 -106
- package/src/skf-create-skill/references/ecosystem-check.md +0 -74
- package/src/skf-drop-skill/references/headless-contract.md +0 -18
- package/src/skf-update-skill/references/merge-conflict-rules.md +0 -15
- package/src/skf-update-skill/references/remote-source-resolution.md +0 -98
- package/src/skf-update-skill/references/validate.md +0 -124
- package/tools/validate-docs-drift.js +0 -233
- package/tools/validate-docs-links.js +0 -665
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'health-check.md'
|
|
3
3
|
|
|
4
|
-
outputFile: '{
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
outputFile: '{report_file}'
|
|
5
|
+
# §4c gives the report this public name once its checks pass (a run the hard
|
|
6
|
+
# gate blocked included), the name export-skill and update-skill read.
|
|
7
|
+
publishedReportFile: '{forge_version}/test-report-{skill_name}-{run_id}.md'
|
|
8
|
+
# The run's gap ledger: the stages recorded their gaps in it, §4b adds the
|
|
9
|
+
# discovery outcome, and §4c renders the Gap Report from it.
|
|
10
|
+
ledgerFile: '{forge_version}/test-findings-{run_id}.json'
|
|
11
|
+
gapLedgerScript: 'scripts/gap-ledger.py'
|
|
12
|
+
# §4c builds the shared emitter's payload from the run's records with it.
|
|
13
|
+
resultContextScript: 'scripts/build-result-context.py'
|
|
14
|
+
scoringRulesFile: 'references/scoring-rules.md'
|
|
15
|
+
outputFormatsFile: 'assets/output-section-formats.md'
|
|
7
16
|
# outputContractSchema and healthCheck resolve relative to the SKF module root
|
|
8
17
|
# (`{project-root}/_bmad/skf/` when installed, `{project-root}/src/` during
|
|
9
|
-
# development), NOT relative to this step file.
|
|
10
|
-
# order
|
|
18
|
+
# development), NOT relative to this step file. §4c probes both health-check
|
|
19
|
+
# paths in order and HALTs, before anything is published, if neither exists.
|
|
11
20
|
outputContractSchema: 'shared/references/output-contract-schema.md'
|
|
12
21
|
healthCheckProbeOrder:
|
|
13
22
|
- '{project-root}/_bmad/skf/shared/health-check.md'
|
|
14
23
|
- '{project-root}/src/shared/health-check.md'
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
# Resolve `{skillInventoryHelper}` to the first existing path. §4b.0 reads the
|
|
25
|
+
# inventory to count the folders that hold a skill.
|
|
26
|
+
skillInventoryProbeOrder:
|
|
27
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-skill-inventory.py'
|
|
28
|
+
- '{project-root}/src/shared/scripts/skf-skill-inventory.py'
|
|
18
29
|
---
|
|
19
30
|
|
|
20
31
|
<!-- Config: communicate in {communication_language}. Test report prose in {document_output_language}. -->
|
|
@@ -23,57 +34,62 @@ atomicWriteProbeOrder:
|
|
|
23
34
|
|
|
24
35
|
## STEP GOAL:
|
|
25
36
|
|
|
26
|
-
|
|
37
|
+
Publish the run. Record the discovery outcome in the gap ledger, render the Gap Report from the ledger, check that every stage ran and wrote its section, then publish the report under its public name, write the result contract, run the on_complete hook and present the result. Do not recalculate scores (step 5 ran them) or classify the stages' gaps again (each stage recorded its own). A run the hard gate blocked comes here straight from step 4c and takes the same sequence, with the blocked-run branch each section names. This step chains to the local health-check step via `{nextStepFile}` after completion; the user-facing report is not the terminal step.
|
|
27
38
|
|
|
28
|
-
|
|
39
|
+
**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:
|
|
29
40
|
|
|
30
|
-
|
|
41
|
+
```bash
|
|
42
|
+
uv run {emitEnvelopeHelper} emit-halt --workflow skf-test-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"
|
|
43
|
+
```
|
|
31
44
|
|
|
32
|
-
|
|
33
|
-
- Missing documentation (exports in source but not in SKILL.md)
|
|
34
|
-
- Signature mismatches (documented signature differs from source)
|
|
35
|
-
- Stale documentation (documented but no longer in source)
|
|
36
|
-
- Type coverage gaps (undocumented types/interfaces)
|
|
45
|
+
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.
|
|
37
46
|
|
|
38
|
-
|
|
39
|
-
- Broken references (file paths, skill references, type imports that don't resolve)
|
|
40
|
-
- Incomplete integration patterns (contextual mode)
|
|
41
|
-
- Structural issues (naive mode — missing sections, broken examples)
|
|
47
|
+
§7 releases the lock when the run ends.
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
- skill-check diagnostics (unresolved errors and warnings)
|
|
45
|
-
- tessl judge suggestions (content quality and actionability improvements)
|
|
49
|
+
### 1. Collect All Issues
|
|
46
50
|
|
|
47
|
-
|
|
51
|
+
The stages before this one recorded every gap they found in the gap ledger `{ledgerFile}`, each with the severity and the category the Gap Severity table gives it. The ledger is the record of the run's gaps: the hard gate counted it, and the Gap Report, the result contract and update-skill `--from-test-report` read it. Do not collect gaps again from the report's sections. The one source of gaps left is discovery testing (§4b), which runs after the gate.
|
|
48
52
|
|
|
49
|
-
|
|
53
|
+
**A run the hard gate blocked** (frontmatter `hardGate: 'blocked'`, set by step 4c §3) was not scored and skips discovery testing (§4b) and the loads in §2 and §3: after §4, continue at §4c.
|
|
50
54
|
|
|
51
|
-
###
|
|
55
|
+
### 2. Load Severity Rules
|
|
56
|
+
|
|
57
|
+
For the discovery record §4b writes, load the **Gap Severity** table from `{scoringRulesFile}`, the single source of truth for a gap's severity and category; do not restate its rows here.
|
|
52
58
|
|
|
53
|
-
|
|
59
|
+
### 3. Load the Record Format
|
|
54
60
|
|
|
55
|
-
|
|
61
|
+
Load `{outputFormatsFile}` for the Ledger Record Format and the remediation quality rules the discovery record follows. The ledger numbers the gaps and the Gap Report orders them, so nothing is ordered by hand.
|
|
56
62
|
|
|
57
|
-
### 4.
|
|
63
|
+
### 4. The Terminal Sequence
|
|
58
64
|
|
|
59
|
-
|
|
65
|
+
Every run that reaches this step, a blocked one included, ends through one sequence, and a check that fails stops it before anything is published:
|
|
60
66
|
|
|
61
|
-
|
|
67
|
+
1. §4b records the discovery outcome in the ledger (a blocked run skips it).
|
|
68
|
+
2. §4c renders the Gap Report from the ledger, checks that every stage ran and wrote its section and that the health check is installed, then builds the result payload, publishes the report, writes the result contract and runs the on_complete hook.
|
|
69
|
+
3. §6 presents the result, §6b keeps the headless envelope for the run's last line, and §7 releases the run lock and hands over to the health check.
|
|
62
70
|
|
|
63
71
|
### 4b. Discovery Testing
|
|
64
72
|
|
|
65
|
-
**`--no-discovery` flag bypass (precedes the precondition check).** If `no_discovery: true` is set in workflow context (from §1 of `init.md
|
|
73
|
+
**`--no-discovery` flag bypass (precedes the precondition check).** If `no_discovery: true` is set in workflow context (from §1 of `init.md`: the `--no-discovery` flag on invocation), record the skip (below) with the reason `--no-discovery flag set`, log the bypass, and SKIP §4b.1 to §4b.3. Proceed to §4b.4 (description optimization) only if Tessl Review's description score is below 90% or skill-check flagged description issues; otherwise skip directly to §4b.5.
|
|
74
|
+
|
|
75
|
+
Perform minimum-viable discovery testing. Its outcome is at most one gap (§4b.5), and the Discovery Quality subsection §4c writes shows it.
|
|
66
76
|
|
|
67
|
-
|
|
77
|
+
**Recording a skip.** A discovery test that does not run is still counted. Each skip branch (the bypass above, §4b.0 and the §4b.2 guard) is one Info `discovery` gap, the Gap Severity table's "Discovery testing not performed" row, titled `Discovery testing not performed: {reason}`, with the SKILL.md frontmatter `description` as its Source and a Remediation that names what lets the test run: a run without `--no-discovery`, a second skill in the catalog (or `--discovery-catalog=all`), or an environment that can spawn subagents. The Discovery Quality subsection also gets the note `discovery: skipped, {reason}`. §4b.5 records the gap.
|
|
68
78
|
|
|
69
79
|
**4b.0 Precondition — catalog size check:**
|
|
70
80
|
|
|
71
|
-
Count the
|
|
81
|
+
Count the folders that hold a skill, not every folder: SKF's own `_batch/` holds none, and a versioned skill keeps its `SKILL.md` under `active/`. Resolve `{skillInventoryHelper}` ← first existing path in `{skillInventoryProbeOrder}` and run:
|
|
72
82
|
|
|
73
|
-
|
|
83
|
+
```bash
|
|
84
|
+
uv run {skillInventoryHelper} {skillsOutputFolder}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Bind `{not_skf_output}` ← `not_skf_output` and `{discovery_catalog}` ← every `skills[]` entry whose `has_skill_md` is true and whose `skf_skill` is true or whose `name` is in `{not_skf_output}`, each as its `name` plus `{active_path}/SKILL.md`. Skills SKF did not generate stay in the catalog: they compete for the same prompts. `catalog_size` ← the number of `{discovery_catalog}` entries. Without the helper (no candidate resolves, or the status is not `ok`), build the same set with your file tools, never a shell pipeline: each folder directly in `{skillsOutputFolder}` whose name does not start with `.`, is not `_batch` and holds no `.skf-`, and that holds `SKILL.md` directly or at `active/<folder>/SKILL.md`.
|
|
88
|
+
|
|
89
|
+
- If `catalog_size < 2`: **skip §4b.1 to §4b.3**. Record the skip with the reason `catalog size N={catalog_size}, requires ≥2 candidates for meaningful routing`. The routing test is vacuous with one candidate (any prompt returns the sole skill); reporting `3/3 PASS` under those conditions inflates the Discovery score and masks genuinely bad description triggers. Proceed to §4b.4 (description optimization) if Tessl Review's description score is below 90% or skill-check flagged description issues; otherwise skip to §4b.5.
|
|
74
90
|
- If `catalog_size >= 2`: continue with §4b.1 as written.
|
|
75
91
|
|
|
76
|
-
Optional escape hatch: the workflow accepts `--discovery-catalog=all` to broaden the candidate pool to `{project-root}/.claude/skills/` or `{project-root}/_bmad/agents/` for single-skill repos where the repo-local catalog is trivially too small. When
|
|
92
|
+
Optional escape hatch: the workflow accepts `--discovery-catalog=all` (init.md §1 stores `discovery_catalog_all: true`) to broaden the candidate pool to `{project-root}/.claude/skills/` or `{project-root}/_bmad/agents/` for single-skill repos where the repo-local catalog is trivially too small. When `discovery_catalog_all` is true, add each folder directly in `{project-root}/.claude/skills/` or `{project-root}/_bmad/agents/` that holds a `SKILL.md` directly to `{discovery_catalog}` (a name already in it counts once), then recount `catalog_size` before the precondition check.
|
|
77
93
|
|
|
78
94
|
**4b.1 Extract realistic prompts from the skill under test:**
|
|
79
95
|
|
|
@@ -86,10 +102,10 @@ If SKILL.md does not contain enough organic examples, synthesize 3 from the skil
|
|
|
86
102
|
|
|
87
103
|
**4b.2 Spawn a discovery subagent:**
|
|
88
104
|
|
|
89
|
-
**Subagents-unavailable guard (precedes the spawn).** If subagents cannot be spawned in this environment (e.g. a headless/CI pipeline with no subagent capability), do not fall back to answering the routing in the main thread
|
|
105
|
+
**Subagents-unavailable guard (precedes the spawn).** If subagents cannot be spawned in this environment (e.g. a headless/CI pipeline with no subagent capability), do not fall back to answering the routing in the main thread: the main thread knows which skill is under test, so it would self-route to `3/3 PASS` and inflate the Discovery score, the exact false confidence §4b.0 warns against. Instead record the skip with the reason `subagents unavailable, routing test requires isolated context`, exclude the discovery check from Discovery Quality scoring (do not count it PASS or FAIL), and skip to §4b.5.
|
|
90
106
|
|
|
91
107
|
For each of the 3 prompts, spawn an isolated subagent with NO prior context about which skill is under test. Provide only:
|
|
92
|
-
1. A compact list of
|
|
108
|
+
1. A compact list of every skill in `{discovery_catalog}` (the same set §4b.0 counted): name + description line from that entry's SKILL.md frontmatter
|
|
93
109
|
2. The prompt text
|
|
94
110
|
|
|
95
111
|
Instruction to the subagent:
|
|
@@ -102,13 +118,13 @@ Parse the 3 responses. Schema-validate (required: `selected_skill`, `confidence`
|
|
|
102
118
|
|
|
103
119
|
For each prompt, PASS = `selected_skill == skill_name` (the skill under test), FAIL otherwise.
|
|
104
120
|
|
|
105
|
-
- **3 of 3 PASS** → discovery check PASS
|
|
106
|
-
- **2 of 3 PASS** → discovery check WARN
|
|
107
|
-
- **≤1 of 3 PASS** → discovery check FAIL
|
|
121
|
+
- **3 of 3 PASS** → discovery check PASS: no gap.
|
|
122
|
+
- **2 of 3 PASS** → discovery check WARN: a Medium `discovery` gap titled `discovery: 1/3 realistic prompts misrouted`.
|
|
123
|
+
- **≤1 of 3 PASS** → discovery check FAIL: a High `discovery` gap titled `discovery: {N}/3 realistic prompts misrouted; description triggers are not pulling the skill`.
|
|
108
124
|
|
|
109
|
-
|
|
125
|
+
Either gap has the SKILL.md frontmatter `description` as its Source, the misrouted prompts and the skills they reached as its Issue, and a Remediation that names the trigger phrases to add (§4b.4). Keep the prompts, the selected skills and the outcomes for the Discovery Quality table, which §4c writes after the Gap Report.
|
|
110
126
|
|
|
111
|
-
**4b.4 Description optimization (secondary):** If
|
|
127
|
+
**4b.4 Description optimization (secondary):** If the Tessl Review description score (the test report's `### Tessl Review` block; absent when Tessl Review did not run) is below 90%, or skill-check flagged description issues, keep these remediation hints for the Discovery Quality subsection §4c writes:
|
|
112
128
|
- Third-person voice check
|
|
113
129
|
- Explicit trigger keywords matching real user phrasing
|
|
114
130
|
- Negative triggers ("NOT for: ...") to prevent false positives
|
|
@@ -119,45 +135,37 @@ Realistic prompt patterns for synthesis (§4b.1 fallback):
|
|
|
119
135
|
- Implicit: "why did {metric} drop last {period}"
|
|
120
136
|
- Abbreviated: "run the {keyword} thing on this data"
|
|
121
137
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
**Resolve `{atomicWriteHelper}`:** probe `{atomicWriteProbeOrder}`. HALT if neither candidate exists — the contract is a downstream-consumer protocol and must never be written non-atomically. **Headless envelope (if `{headless_mode}`):** emit to **stderr** before halting:
|
|
138
|
+
**4b.5 Record the discovery gap.** A skip, a WARN or a FAIL is one gap; a PASS records none. Record it in the ledger, with the record between the two markers exactly as it is (`{gapLedgerScript}` resolves relative to the skill root):
|
|
125
139
|
|
|
126
|
-
```
|
|
127
|
-
|
|
140
|
+
```bash
|
|
141
|
+
uv run {gapLedgerScript} append --ledger "{ledgerFile}" --stage report <<'SKF_GAPS'
|
|
142
|
+
<the discovery record, a JSON array of one>
|
|
143
|
+
SKF_GAPS
|
|
128
144
|
```
|
|
129
145
|
|
|
130
|
-
|
|
131
|
-
- Per-run record: `{forge_version}/skf-test-skill-result-{run_id}.json` (the `{run_id}` set in step 1 §6a — already carries UTC timestamp + PID + random suffix, so no same-second collision).
|
|
132
|
-
- Latest copy: `{forge_version}/skf-test-skill-result-latest.json` (stable path for pipeline consumers — copy, not symlink).
|
|
146
|
+
Exit 0: continue. Exit 2: nothing was written; correct the record `errors[]` names and run the command again. Exit 1: HALT with the script's `error` (`halt_reason: "helper-failed"`, phase `report:discovery`). Discovery runs after the hard gate, so a discovery gap blocks nothing, a High one included: it is counted in the Gap Report's totals and in the counts §6 presents, never as a blocking gap.
|
|
133
147
|
|
|
134
|
-
|
|
148
|
+
### 4c. Result Contract
|
|
149
|
+
|
|
150
|
+
Nothing is published until the report is whole: render the Gap Report and check the report first, and only then give the report its public name, write the result files and run the on_complete hook.
|
|
151
|
+
|
|
152
|
+
**Render the Gap Report.** The ledger now holds every gap of the run (`{gapLedgerScript}` resolves relative to the skill root):
|
|
135
153
|
|
|
136
154
|
```bash
|
|
137
|
-
|
|
138
|
-
cat payload.json | python3 {atomicWriteHelper} write --target {forge_version}/skf-test-skill-result-{run_id}.json
|
|
139
|
-
cat payload.json | python3 {atomicWriteHelper} write --target {forge_version}/skf-test-skill-result-latest.json
|
|
155
|
+
uv run {gapLedgerScript} render --ledger "{ledgerFile}" --heading
|
|
140
156
|
```
|
|
141
157
|
|
|
142
|
-
|
|
143
|
-
- `outputs[]` — include the test report path at `{outputFile}` with its `{run_id}` suffix
|
|
144
|
-
- `summary` — `score`, `threshold`, `result` (`"PASS"`, `"PASS_WITH_DRIFT"`, `"FAIL"`, or **`"INCONCLUSIVE"`**), `testMode` (naive/contextual), `activeCategories[]`, `inconclusiveReasons[]` (when present). `PASS_WITH_DRIFT` is set when the workflow observed workspace drift and the user passed `--allow-workspace-drift` — see step 5 §5 drift override. Downstream consumers must treat `PASS_WITH_DRIFT` as a non-exportable result: re-run against the pinned commit before export. When threshold fallback occurred, add `threshold_fallback: true`, `original_threshold: {N}`, and `evidence_report_path: '{path}'` to the summary — these fields are absent (not `false`/`null`) when no fallback occurred.
|
|
145
|
-
- `runId` — the workflow's `{run_id}` for downstream correlation
|
|
146
|
-
- `healthCheckDispatched` — boolean, set by §7 after the dispatch decision
|
|
158
|
+
Exit 0: its output is the whole Gap Report section, heading included: the totals, the Remediation Summary and one entry per gap, by severity (with no gaps, it says none were found). Write it unchanged in place of the template's `## Gap Report` heading and the placeholder comment under it, in `{outputFile}`, then add the **Discovery Quality** subsection under it (format in `{outputFormatsFile}`): the §4b outcome, its prompt table or skip note, and the §4b.4 hints, or, for a run the hard gate blocked, the line that discovery testing did not run. Any other exit printed its error on stderr: HALT with it (`halt_reason: "helper-failed"`, phase `report:gap-report`).
|
|
147
159
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
**Post-finalization hook.** If `{onCompleteCommand}` (resolved in SKILL.md On Activation §3 from `workflow.on_complete` scalar) is non-empty, invoke it as:
|
|
160
|
+
Then take the gap counts from the ledger:
|
|
151
161
|
|
|
152
162
|
```bash
|
|
153
|
-
{
|
|
163
|
+
uv run {gapLedgerScript} summary --ledger "{ledgerFile}"
|
|
154
164
|
```
|
|
155
165
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
### 5. Finalize Output Document — Enforce Step Completeness
|
|
166
|
+
Bind `{gap_counts}` ← `counts`, `{total_gaps}` ← `total` and `{blocking_gaps}` ← `blocking`: §6 presents them. Exit 1: HALT with its `error` (`halt_reason: "helper-failed"`, phase `report:gap-report`).
|
|
159
167
|
|
|
160
|
-
**
|
|
168
|
+
**Enforce step completeness.** Read `stepsCompleted` from the `{outputFile}` frontmatter. Each stage appended its own token when it finished, and `'report'` is appended only once the result files are written, so it is not in the expected set:
|
|
161
169
|
|
|
162
170
|
```
|
|
163
171
|
['init',
|
|
@@ -166,47 +174,84 @@ Run it with a bounded timeout (default 60s). On success: log Info note "on_compl
|
|
|
166
174
|
'coherence-check',
|
|
167
175
|
'external-validators',
|
|
168
176
|
'hard-gate',
|
|
169
|
-
'score'
|
|
170
|
-
'report']
|
|
177
|
+
'score']
|
|
171
178
|
```
|
|
172
179
|
|
|
173
|
-
If any expected entry is missing, HALT with "step completeness violation
|
|
180
|
+
A run the hard gate blocked was never scored: its expected set ends at `'hard-gate'`. If any expected entry is missing, HALT (`halt_reason: "step-completeness-violation"`, phase `report:steps`) with "step completeness violation: missing {list}; workflow state is inconsistent, do not finalize the report".
|
|
174
181
|
|
|
182
|
+
**Check the report sections.** Each stage wrote its section in place of its heading and the placeholder comment under it in the template, so a stage that skipped its section left the placeholder behind, and one that appended its section instead left its heading twice. Count them with grep, not by eye, and read the counts it prints (a count of 0 also makes grep exit 1):
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
for heading in '## Test Summary' '## Coverage Analysis' '## Coherence Analysis' '## External Validation' '## Completeness Score' '## Gap Report'; do
|
|
186
|
+
printf '%s: ' "$heading"; grep -cxF "$heading" "{outputFile}"
|
|
187
|
+
done
|
|
188
|
+
printf 'placeholders: '; grep -c '^<!-- Populated by' "{outputFile}"
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Each heading must print 1, standing alone on exactly one line, and `placeholders` must print 0. A run the hard gate blocked has all six: step 4c §3 wrote the Completeness Score section in scoring's place. On a heading whose count is not 1, or a placeholder left, HALT (`halt_reason: "report-anchor-missing"`, phase `report:anchors`) with "report anchor missing: {each heading whose count is not 1, with its count}, or {N} placeholder comments left; the section was not written once by its owning step".
|
|
192
|
+
|
|
193
|
+
**Find the health check** unless `no_health_check` is true (the `--no-health-check` flag): resolve `{healthCheckFile}` ← first existing path in `{healthCheckProbeOrder}`. It ends the run (§7), so check it now, while a HALT still leaves the previous run's report and result files in place. If neither candidate exists, HALT (`halt_reason: "health-check-missing"`, phase `report:health-check`):
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
Error: cannot locate shared/health-check.md at either of:
|
|
197
|
+
- {project-root}/_bmad/skf/shared/health-check.md
|
|
198
|
+
- {project-root}/src/shared/health-check.md
|
|
199
|
+
|
|
200
|
+
test-skill delegates its terminal step to the shared health-check. Install
|
|
201
|
+
the SKF module or run from a development checkout with src/ present.
|
|
175
202
|
```
|
|
176
|
-
|
|
203
|
+
|
|
204
|
+
**Renew the run lock** before anything below writes. The lock init.md §6a took goes stale 60 minutes after it was taken, and a long run can outlast that; an acquire by the owner that holds the lock renews it. From `{project-root}`, run:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
uv run {runLockHelper} acquire --lock "{forge_version}/.test-skill.lock" --owner "{run_owner}"
|
|
177
208
|
```
|
|
178
209
|
|
|
179
|
-
|
|
210
|
+
- Exit 0: the lock is this run's again; continue.
|
|
211
|
+
- Exit 3 (`acquired` is false): another run took the lock over after this run's lock went stale. HALT before writing anything (`halt_reason: "another-run-active"`, phase `report:run-lock`), with "**Another test-skill run took over the run lock for {skill_name}.** This run wrote no result files. {message}", where `{message}` is the helper's.
|
|
212
|
+
- Exit 1 or 2, or no JSON: HALT with the helper's stderr message (`halt_reason: "helper-failed"`, phase `report:run-lock`), as init.md §6b does.
|
|
180
213
|
|
|
181
|
-
|
|
182
|
-
report template ships six canonical H2 anchors — one per populating step. An
|
|
183
|
-
off-sequence run (e.g. a step wrote its section into the wrong anchor, or a
|
|
184
|
-
subagent truncated the file) can leave `stepsCompleted` intact while a section
|
|
185
|
-
is missing. `grep -n` each anchor below against `{outputFile}`; each must
|
|
186
|
-
return ≥1 match:
|
|
214
|
+
The run lock renewed here stays held until §7 releases it, so no other run publishes over this run's report or result files meanwhile.
|
|
187
215
|
|
|
216
|
+
**Build the result payload** before the report takes its public name. Every value in it comes from the run's own records: `{resultContextScript}` (it resolves relative to the skill root) reads the report frontmatter, the gap ledger and the scoring output, checks the verdict fields score.md §7 wrote (`testResult`, `score`, `threshold` and the fallback fields) against the scoring output, derives `verdict`, `exit_code` and `next_workflow` from `testResult`, and writes the shared emitter's payload, which names the report by its public name. Pass `--score` for a scored run (a run the hard gate blocked has no scoring output), `--no-health-check` when that flag was given, and `--warning` when SKILL.md On Activation step 3 kept a `{customization_resolver_unavailable}` reason: first write `customization_resolver_unavailable: {customization_resolver_unavailable}` to `{run_dir}/resolver-warning.txt` with a file write, never `echo` (the reason can hold quotes, backticks or `$( )`), and pass that file's text (the emitter adds the warnings a stage recorded in the run's sink):
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
uv run {resultContextScript} --report "{report_file}" --report-path "{publishedReportFile}" --ledger "{ledgerFile}" [--score "{run_dir}/score.json"] [--no-health-check] [--warning "$(cat "{run_dir}/resolver-warning.txt")"] --output "{run_dir}/result-context.json"
|
|
188
220
|
```
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
221
|
+
|
|
222
|
+
Bind `{emit_target}` ← `target` from its JSON (`stderr` for a run the hard gate blocked, else `stdout`). Exit 2: correct the command and run it again. Exit 1: HALT with its `error` (`halt_reason: "helper-failed"`, phase `report:result-contract`); the report keeps its in-progress name, so export-skill never reads a verdict the scoring output did not settle.
|
|
223
|
+
|
|
224
|
+
**Publish the report.** Set `health_check_dispatched` in the `{outputFile}` frontmatter: `false` when `no_health_check` is true (the `--no-health-check` flag), else `true`, since the health check now runs with no menu before it. The checks passed, so the report takes its public name, the one export-skill and update-skill read, a blocked run's included. From `{project-root}`, run:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
mv "{report_file}" "{publishedReportFile}"
|
|
195
228
|
```
|
|
196
229
|
|
|
197
|
-
|
|
198
|
-
|
|
230
|
+
and bind `{report_file}` ← `{publishedReportFile}`. If the move fails, HALT (`halt_reason: "write-failed"`, phase `report:publish`, `"path": "{publishedReportFile}"`): no result file has been written, so the previous run's verdict still stands.
|
|
231
|
+
|
|
232
|
+
**Write the result contract.** The shared emitter writes it, per `{outputContractSchema}`. In every mode, run:
|
|
199
233
|
|
|
234
|
+
```bash
|
|
235
|
+
uv run {emitEnvelopeHelper} emit --workflow skf-test-skill --run-dir "{run_dir}" --result-dir "{forge_version}" --target {emit_target} < "{run_dir}/result-context.json"
|
|
200
236
|
```
|
|
201
|
-
|
|
237
|
+
|
|
238
|
+
It writes `{forge_version}/skf-test-skill-result-{YYYYMMDD-HHmmss}.json` (UTC; it picks the name) and then its `skf-test-skill-result-latest.json` copy (stable path for pipeline consumers: a copy, not a symlink), each atomically, so a partial write is never observable; stamps the timestamp, `run_id`, `headless_decisions` and `warnings` into both; and prints the `SKF_TEST_RESULT_JSON:` line. Bind `{result_line}` ← that line and `{result_path}` ← its `result_path`. A run the hard gate blocked writes the record too, as a FAIL (`status: "error"`, `verdict: "FAIL"`, `halt_reason: "hard-gate-blocked"`, `exit_code` 2), so `skf-test-skill-result-latest.json` never holds an earlier run's verdict. A result file that could not be written leaves `result_path` null and a `result_file_write_failed` warning in the line, and the run still finishes. If the emitter exits non-zero, run it once more; if it fails again, HALT (`halt_reason: "write-failed"`, phase `report:result-contract`) with its stderr: the run's result contract could not be written. `references/invocation-contract.md` lists the record's fields.
|
|
239
|
+
|
|
240
|
+
Once the result files are written, append `'report'` to `stepsCompleted` in the `{outputFile}` frontmatter (it stays out of the expected set above).
|
|
241
|
+
|
|
242
|
+
**Post-finalization hook.** If `{onCompleteCommand}` (resolved in SKILL.md On Activation §3 from `workflow.on_complete` scalar) is non-empty and `{result_path}` is not null, invoke it as:
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
{onCompleteCommand} --result-path={result_path}
|
|
202
246
|
```
|
|
203
247
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
248
|
+
Run it with a bounded timeout (default 60s). On success: log Info note "on_complete: invoked {command}" and continue. On non-zero exit, timeout, or any failure: keep the reason (for example `on_complete failed (exit {N}): {stderr_first_line}`) for a line of its own in §6, and continue. **The hook must never fail the workflow**: its purpose is integration glue (notify a CI router, post to a queue, archive the result) and any failure there is orthogonal to the test verdict, which the result files already hold. If `{onCompleteCommand}` is empty, this hook is a no-op (no log entry needed).
|
|
249
|
+
|
|
250
|
+
### 5. Finalize Output Document
|
|
251
|
+
|
|
252
|
+
The report is final once §4c published it and wrote the result files: no later section changes it.
|
|
208
253
|
|
|
209
|
-
**INCONCLUSIVE as gate:** if `testResult == 'inconclusive'` (from step 5),
|
|
254
|
+
**INCONCLUSIVE as gate:** if `testResult == 'inconclusive'` (from step 5), §4c wrote the result contract with that verdict and §6 presents it. Do not auto-map INCONCLUSIVE to PASS or FAIL. Recommend `manual-review`. The step must still complete (§7 dispatches the health check): INCONCLUSIVE is a report-time signal, not a workflow abort.
|
|
210
255
|
|
|
211
256
|
### 6. Present Final Report
|
|
212
257
|
|
|
@@ -216,17 +261,22 @@ skipped its append.
|
|
|
216
261
|
|
|
217
262
|
**Result:** **{PASS|PASS_WITH_DRIFT|FAIL|INCONCLUSIVE}** — **{score}%** (threshold: {threshold}%)
|
|
218
263
|
|
|
264
|
+
{If the hard gate blocked the run, in place of the line above:}
|
|
265
|
+
**Result:** **FAIL**, not scored: the hard gate blocked the run on {blocking_gaps} Critical or High gap(s).
|
|
266
|
+
|
|
219
267
|
{If `thresholdFallback` is present in output frontmatter:}
|
|
220
268
|
**Threshold fallback:** scored {score}% against {originalThreshold} target — accepted at 80% floor. Evidence report: {evidenceReportPath}
|
|
221
269
|
|
|
222
270
|
**Gaps Found:** {total_gaps}
|
|
223
|
-
- Critical: {
|
|
224
|
-
- High: {
|
|
225
|
-
- Medium: {
|
|
226
|
-
- Low: {
|
|
227
|
-
- Info: {
|
|
271
|
+
- Critical: {gap_counts.Critical}
|
|
272
|
+
- High: {gap_counts.High}
|
|
273
|
+
- Medium: {gap_counts.Medium}
|
|
274
|
+
- Low: {gap_counts.Low}
|
|
275
|
+
- Info: {gap_counts.Info}
|
|
228
276
|
|
|
229
277
|
**Report saved to:** `{outputFile}`
|
|
278
|
+
{If the on_complete hook failed:}
|
|
279
|
+
**on_complete hook failed:** {its reason}. The verdict and the result files stand.
|
|
230
280
|
|
|
231
281
|
---
|
|
232
282
|
|
|
@@ -238,8 +288,11 @@ skipped its append.
|
|
|
238
288
|
{IF PASS_WITH_DRIFT:}
|
|
239
289
|
**update-skill** — The skill scored above threshold, but `--allow-workspace-drift` was in effect: the test ran against workspace HEAD, not `metadata.source_commit`. A conditional PASS is not trustworthy enough to export. Re-sync the source tree to the pinned commit (or re-extract against current HEAD) and re-run test-skill without the drift override before exporting.
|
|
240
290
|
|
|
241
|
-
{IF FAIL:}
|
|
242
|
-
**update-skill
|
|
291
|
+
{IF FAIL after scoring:}
|
|
292
|
+
**update-skill `--from-test-report`**: This skill needs remediation. Review the Gap Report above, then run `@Ferris US {skill_name} --from-test-report`: Update Skill reads this report's gaps and repairs the skill at its pinned commit. Test it again afterwards.
|
|
293
|
+
|
|
294
|
+
{IF the hard gate blocked the run:}
|
|
295
|
+
**update-skill `--from-test-report`**: The hard gate stopped this run before scoring on {blocking_gaps} Critical or High gap(s), listed first in the Gap Report. Run `@Ferris US {skill_name} --from-test-report` to repair them, then test again.
|
|
243
296
|
|
|
244
297
|
{IF INCONCLUSIVE:}
|
|
245
298
|
**manual-review** — The evidence base was too thin to grade automatically. See `inconclusiveReasons` in the Completeness Score section. Typical fixes: upgrade forge tier, enable external validators, or re-extract with a wider scope. Do not export.
|
|
@@ -250,55 +303,24 @@ skipped its append.
|
|
|
250
303
|
|
|
251
304
|
**Test report finalized.**"
|
|
252
305
|
|
|
253
|
-
### 6b.
|
|
306
|
+
### 6b. Keep the Headless Result Envelope for the Last Line
|
|
254
307
|
|
|
255
|
-
|
|
308
|
+
If `{headless_mode}`, bind `{result_envelope_line}` ← `{result_line}`, the `SKF_TEST_RESULT_JSON` line §4c's emitter printed, a blocked run's included. Do not display it here and never retype it: the shared health check displays it verbatim as the run's last line, after everything else it shows (§7 displays it itself under `--no-health-check`), so it is the final message of a headless run. Non-headless runs bind nothing: the §6 presentation is their result.
|
|
256
309
|
|
|
257
|
-
|
|
258
|
-
- `testResult: 'pass'` → exit code 0
|
|
259
|
-
- `testResult: 'pass-with-drift'` → exit code 4 (distinct from clean pass — see the pass-with-drift row in SKILL.md Exit Codes; exiting 0 under a drift override would wrongly signal a clean pass)
|
|
260
|
-
- `testResult: 'fail'` → exit code 2 (the result contract was written in §4c — never exit before it)
|
|
261
|
-
- `testResult: 'inconclusive'` → exit code 3 (distinct from fail so orchestrators can route to manual-review queues)
|
|
310
|
+
### 7. Health-Check Dispatch
|
|
262
311
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
If `{headless_mode}`, emit the terminal result envelope to **stdout** as a single line before chaining to §7 — this is the branchable record a headless orchestrator reads for the happy path (PASS / FAIL / INCONCLUSIVE / pass-with-drift). The SKILL.md Result Contract owns the shape and the field rules; the on-disk copy written in §4c is the richer form. Build it from the settled verdict and the values already in the output frontmatter:
|
|
266
|
-
|
|
267
|
-
```
|
|
268
|
-
SKF_TEST_RESULT_JSON: {"status":"success","skill_name":"{skill_name}","verdict":"{PASS|FAIL|INCONCLUSIVE|pass-with-drift}","score":{score},"threshold":{threshold},"report_path":"{outputFile}","next_workflow":{export-skill when PASS | update-skill when FAIL or pass-with-drift | null when INCONCLUSIVE},"exit_code":{headless_exit_code},"halt_reason":null}
|
|
269
|
-
```
|
|
312
|
+
**`--no-health-check` flag bypass.** If `no_health_check: true` is set in workflow context (from the `--no-health-check` flag, `init.md` §1), §4c already recorded `health_check_dispatched: false` in the report and `healthCheckDispatched: false` in the result files. Release the run lock now, from `{project-root}`, with `uv run {runLockHelper} release --lock "{forge_version}/.test-skill.lock" --owner "{run_owner}"`, and remove the run folder with `rm -rf "{project-root}/_bmad-output/.skf-run/skf-test-skill-{run_id}"`. Log Info note "health-check: skipped, --no-health-check flag set", then, in `{headless_mode}`, display `{result_envelope_line}` verbatim as the run's last line, with nothing after it. The workflow ends there (non-headless, after the §6 presentation): do not chain to `{nextStepFile}`. This flag is the one path where §7 does not dispatch the health-check.
|
|
270
313
|
|
|
271
|
-
|
|
314
|
+
**Release the run lock:** §4c's write of the result files was the run's last, and the health check writes none, so no run waits on this one while the health check runs. From `{project-root}`, run:
|
|
272
315
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
**`--no-health-check` flag bypass (precedes the health-check resolution).** If `no_health_check: true` is set in workflow context (from §1 of `init.md` — `--no-health-check` flag on invocation), set `health_check_dispatched: false` in the output report frontmatter and mirror `healthCheckDispatched: false` into the result contract written in §4c (re-write atomically via `{atomicWriteHelper}`). Log Info note "health-check — skipped: --no-health-check flag set" and exit the workflow: in `{headless_mode}`, exit with `{headless_exit_code}` (determined in §6b); non-headless, simply terminate after the §6 presentation. Do not resolve `{healthCheckFile}`, do not display the menu, do not chain to `{nextStepFile}`. This flag is the one path where §7 does not dispatch the health-check.
|
|
276
|
-
|
|
277
|
-
Resolve `{healthCheckFile}`: probe `{healthCheckProbeOrder}` in order. **HALT** if neither candidate exists — the health-check is the true terminal step; without it the workflow cannot complete honestly:
|
|
278
|
-
|
|
279
|
-
```
|
|
280
|
-
Error: cannot locate shared/health-check.md at either of:
|
|
281
|
-
- {project-root}/_bmad/skf/shared/health-check.md
|
|
282
|
-
- {project-root}/src/shared/health-check.md
|
|
283
|
-
|
|
284
|
-
test-skill delegates its terminal step to the shared health-check. Install
|
|
285
|
-
the SKF module or run from a development checkout with src/ present.
|
|
316
|
+
```bash
|
|
317
|
+
uv run {runLockHelper} release --lock "{forge_version}/.test-skill.lock" --owner "{run_owner}"
|
|
286
318
|
```
|
|
287
319
|
|
|
288
|
-
|
|
320
|
+
Then remove the run folder init.md §6b created: no later step reads it.
|
|
289
321
|
|
|
322
|
+
```bash
|
|
323
|
+
rm -rf "{project-root}/_bmad-output/.skf-run/skf-test-skill-{run_id}"
|
|
290
324
|
```
|
|
291
|
-
SKF_TEST_RESULT_JSON: {"status":"error","skill_name":"{skill_name}","verdict":null,"score":null,"threshold":null,"report_path":"{outputFile}","next_workflow":null,"exit_code":1,"halt_reason":"health-check-missing"}
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
Before displaying the menu, write the dispatch decision into the output report frontmatter (so the artifact records whether the health-check ran):
|
|
295
|
-
|
|
296
|
-
- `health_check_dispatched: true` — when the C menu choice will be taken (headless, or user will select C)
|
|
297
|
-
- `health_check_dispatched: false` — should be rare (only if operator explicitly skips, e.g. future flag)
|
|
298
|
-
|
|
299
|
-
Also mirror the boolean into the `healthCheckDispatched` field of the result contract written in §4c (re-write atomically via `{atomicWriteHelper}` if the dispatch decision is made after the initial contract write).
|
|
300
|
-
|
|
301
|
-
Display: "**Test complete.** [C] Finish"
|
|
302
|
-
|
|
303
|
-
On [C] (or auto-proceed in `{headless_mode}` — log: "headless: auto-continue past report menu"): set `health_check_dispatched: true` in frontmatter, then load and execute `{nextStepFile}` (the local health-check dispatcher). The test report document at `{outputFile}` contains the full analysis: Test Summary, Coverage Analysis, Coherence Analysis, Completeness Score, and Gap Report. In `{headless_mode}`, once the dispatched health-check completes, the workflow makes its terminal process-exit with `{headless_exit_code}` (determined in §6b) — this is the single terminal exit for the headless happy path.
|
|
304
325
|
|
|
326
|
+
Then load and execute `{nextStepFile}` (the local health-check step, which hands over to the `{healthCheckFile}` §4c found), with no menu before it: the run is finished, and the health check is informational. The test report at `{outputFile}` contains the full analysis: Test Summary, Coverage Analysis, Coherence Analysis, Completeness Score, and Gap Report. In `{headless_mode}`, `{result_envelope_line}` (§6b) is bound, and the health check displays it as the run's last line.
|