bmad-module-skill-forge 2.2.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +135 -18
- package/docs/verifying-a-skill.md +83 -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 +2 -2
- 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 +32 -12
- 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 +30 -14
- package/src/shared/scripts/skf-build-change-manifest.py +2203 -24
- 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 +694 -0
- package/src/shared/scripts/skf-comention-pairs.py +1333 -123
- package/src/shared/scripts/skf-compare-file-hashes.py +1 -1
- 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 +3 -2
- 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 +1 -1
- 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 +4084 -85
- package/src/shared/scripts/skf-extraction-inventory.py +746 -0
- package/src/shared/scripts/skf-extraction-snapshot.py +539 -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 +444 -203
- package/src/shared/scripts/skf-github-fetch.py +365 -0
- package/src/shared/scripts/skf-github-probe.py +661 -0
- package/src/shared/scripts/skf-hash-content.py +166 -12
- package/src/shared/scripts/skf-language-corpora.py +1 -1
- package/src/shared/scripts/skf-load-provenance.py +159 -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 +1 -1
- 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 +161 -27
- package/src/shared/scripts/skf-promote-staged.py +430 -0
- package/src/shared/scripts/skf-provenance-gap-dispatch.py +39 -7
- 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 +128 -13
- 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 +670 -119
- package/src/shared/scripts/skf-tessl-review.py +706 -0
- package/src/shared/scripts/skf-update-active-symlink.py +5 -5
- 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 +4 -1
- 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 +2919 -54
- package/src/shared/scripts/skf-write-skill-brief.py +367 -19
- 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 +27 -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/init.md +148 -210
- package/src/skf-audit-skill/references/re-index.md +96 -108
- package/src/skf-audit-skill/references/report.md +96 -33
- package/src/skf-audit-skill/references/semantic-diff.md +27 -18
- 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 +75 -90
- package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
- package/src/skf-audit-skill/scripts/render-drift-tables.py +685 -0
- package/src/skf-brief-skill/SKILL.md +36 -25
- package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
- package/src/skf-brief-skill/assets/scope-templates.md +17 -24
- package/src/skf-brief-skill/assets/skill-brief-schema.md +29 -15
- package/src/skf-brief-skill/customize.toml +48 -20
- package/src/skf-brief-skill/references/analyze-target.md +142 -125
- package/src/skf-brief-skill/references/confirm-brief.md +10 -8
- 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 +24 -80
- package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
- package/src/skf-brief-skill/references/version-resolution.md +3 -2
- 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 +6 -5
- package/src/skf-create-skill/assets/skill-sections.md +15 -5
- package/src/skf-create-skill/customize.toml +20 -8
- package/src/skf-create-skill/references/authoritative-files-protocol.md +41 -42
- 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 +107 -29
- 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 +20 -0
- package/src/skf-create-skill/references/extract.md +200 -161
- package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +2 -2
- package/src/skf-create-skill/references/extraction-patterns.md +584 -196
- 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 +28 -59
- package/src/skf-create-skill/references/source-resolution-protocols.md +49 -155
- 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 +79 -146
- 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 +118 -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 +217 -254
- 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 +163 -88
- 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 +162 -142
- package/src/skf-test-skill/references/score.md +80 -107
- package/src/skf-test-skill/references/scoring-rules.md +41 -155
- package/src/skf-test-skill/references/source-access-protocol.md +19 -92
- 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 +287 -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 +1381 -0
- package/src/skf-test-skill/scripts/hard-gate.py +203 -0
- package/src/skf-test-skill/scripts/load-coverage-inputs.py +760 -0
- package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
- package/src/skf-test-skill/scripts/reconcile-coverage.py +273 -79
- package/src/skf-test-skill/scripts/score-signatures.py +459 -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 +127 -52
- 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 +233 -222
- 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 +250 -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 +180 -47
- package/src/skf-update-skill/references/re-extract.md +53 -262
- package/src/skf-update-skill/references/report.md +100 -35
- package/src/skf-update-skill/references/write.md +331 -149
- package/src/skf-update-skill/scripts/skf-new-file-diff.py +29 -7
- 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,7 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'integrations.md'
|
|
3
|
-
coveragePatternsData: '
|
|
3
|
+
coveragePatternsData: 'references/coverage-patterns.md'
|
|
4
4
|
coverageTallyScript: 'scripts/skf-coverage-tally.py'
|
|
5
|
+
comentionProbeOrder:
|
|
6
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-comention-pairs.py'
|
|
7
|
+
- '{project-root}/src/shared/scripts/skf-comention-pairs.py'
|
|
5
8
|
feasibilitySchemaProbeOrder:
|
|
6
9
|
- '{project-root}/_bmad/skf/shared/references/feasibility-report-schema.md'
|
|
7
10
|
- '{project-root}/src/shared/references/feasibility-report-schema.md'
|
|
@@ -9,7 +12,11 @@ atomicWriteProbeOrder:
|
|
|
9
12
|
- '{project-root}/_bmad/skf/shared/scripts/skf-atomic-write.py'
|
|
10
13
|
- '{project-root}/src/shared/scripts/skf-atomic-write.py'
|
|
11
14
|
outputFile: '{outputFolderPath}/feasibility-report-{project_slug}-{timestamp}.md'
|
|
12
|
-
|
|
15
|
+
emitEnvelopeProbeOrder:
|
|
16
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py'
|
|
17
|
+
- '{project-root}/src/shared/scripts/skf-emit-result-envelope.py'
|
|
18
|
+
inventoryFile: '{run_dir}/skill-inventory.json'
|
|
19
|
+
docMentionsFile: '{run_dir}/doc-mentions.json'
|
|
13
20
|
---
|
|
14
21
|
|
|
15
22
|
<!-- Config: communicate in {communication_language}. Append the Coverage Analysis section to the report in {document_output_language}. -->
|
|
@@ -27,26 +34,36 @@ Verify that a generated skill exists for every technology, library, or framework
|
|
|
27
34
|
|
|
28
35
|
## MANDATORY SEQUENCE
|
|
29
36
|
|
|
30
|
-
|
|
37
|
+
**Halt envelope.** Every HALT in this step names its exit code, `halt_reason` and phase. In headless mode, stage `{run_dir}/halt.json` as `{"phase": "<phase>", "reason": "<the halt message>", "halt_reason": "<halt_reason>", "report_path": "{outputFile}"}`, adding `"path"` when the halt names one, resolve `{emitEnvelopeHelper}` from `{emitEnvelopeProbeOrder}` if it is not bound (first existing path wins), then run:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
uv run {emitEnvelopeHelper} emit-halt --workflow skf-verify-stack --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"
|
|
41
|
+
```
|
|
31
42
|
|
|
32
|
-
|
|
43
|
+
Display the line it prints, then stop with the halt's exit code (`references/exit-codes.md` describes the envelope). If no candidate exists, or the emitter exits non-zero or prints no line, display the halt message alone. An interactive HALT displays its message and emits nothing.
|
|
33
44
|
|
|
34
|
-
|
|
45
|
+
### 1. Load Coverage Patterns
|
|
46
|
+
|
|
47
|
+
Load `{coveragePatternsData}`: which technologies the mentions helper finds and which the model finds, the aliases a skill goes by, and what fenced code hides from both.
|
|
35
48
|
|
|
36
49
|
### 2. Extract Technology References
|
|
37
50
|
|
|
38
|
-
|
|
51
|
+
**Run the mentions helper once.** Resolve `{comentionHelper}` from `{comentionProbeOrder}`; first existing path wins. Take the architecture document's path from `architectureDoc` in the `{outputFile}` frontmatter, then run:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
uv run {comentionHelper} mentions --doc "<architectureDoc>" --skills - > "{docMentionsFile}"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
piping on stdin a JSON array with one object per `skills[]` entry of `{inventoryFile}`: `{"name": "<name>", "aliases": [...]}`, where `aliases` holds the entry's `source_repo_basename` and `source_root_basename` that are not null, and each other name a persistent fact gives the skill. If no candidate exists, or the command exits non-zero, HALT (exit code 3, `halt_reason: "resolution-failure"`) at phase `coverage:mentions`, naming its first stderr line. The integrations stage reads its `candidates[]` from `{docMentionsFile}` too.
|
|
39
58
|
|
|
40
|
-
**
|
|
59
|
+
**Skills the document names:** each skill in the helper's `mentioned` list is a referenced technology, labelled with the skill's `name`, whose source section is the `header` of its first `skills[].paragraphs[]` entry (none when that `header` is null or the document names the skill only in a heading).
|
|
60
|
+
|
|
61
|
+
**Other technologies:** find the document's other technology, library and framework names, skipping each term that names a `mentioned` skill:
|
|
41
62
|
|
|
42
63
|
**Section-based detection:**
|
|
43
64
|
- Identify section headings that indicate technology listings (e.g., "Tech Stack", "Dependencies", "Technologies", "Libraries", layer-specific headings)
|
|
44
65
|
- Extract technology names listed under these headings
|
|
45
66
|
|
|
46
|
-
**Direct name matching:**
|
|
47
|
-
- Scan the full document for names that match loaded skill names (case-insensitive)
|
|
48
|
-
- Apply alias resolution from {coveragePatternsData} (e.g., "React" matches "react", "PostgreSQL" matches "postgres")
|
|
49
|
-
|
|
50
67
|
**Contextual detection:**
|
|
51
68
|
- Identify technology names mentioned in prose alongside architectural descriptions
|
|
52
69
|
- Look for version-pinned references (e.g., "Express v4", "Tailwind CSS 3.x")
|
|
@@ -57,15 +74,11 @@ Parse the architecture document for technology, library, and framework names.
|
|
|
57
74
|
|
|
58
75
|
For each referenced technology in the list:
|
|
59
76
|
|
|
60
|
-
**Check if a matching skill exists** in the skill inventory
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
2. For `source_root`: take the last path segment (after the final `/` or `\`), lowercase
|
|
66
|
-
3. Lowercase each architecture tech token
|
|
67
|
-
4. Compare the resulting basenames/segments against the tech tokens via case-insensitive equality (no substring/fuzzy matching)
|
|
68
|
-
5. A match on either `source_repo` basename or `source_root` last segment counts as a hit
|
|
77
|
+
**Check if a matching skill exists** in the skill inventory step 1 wrote to `{inventoryFile}`.
|
|
78
|
+
- A `mentioned` skill matches its own row: the helper already matched its name and aliases.
|
|
79
|
+
- A technology §2's own detection found matches a skill by the skill's name (case-insensitive), or by a common alias from {coveragePatternsData} (e.g., "PostgreSQL" for `postgres`), so a document that writes only "PostgreSQL" still covers a `postgres` skill.
|
|
80
|
+
|
|
81
|
+
**Run the mentions helper again when the model matched a skill.** When a technology §2's own detection found matches a skill that is not in `mentioned`, add the technology's term, as the document writes it, to that skill's `aliases`. Once every technology is checked, run the §2 `mentions` command once more with the extended array, overwriting `{docMentionsFile}` (the same HALT applies), and take §2's skill rows from the new file: each such skill is in `mentioned` now, and its row, labelled with its `name`, replaces the technology's. The integrations stage then finds that skill's pairs in `candidates[]`. With no such match, skip the second run.
|
|
69
82
|
|
|
70
83
|
**Detect a deliberate-removal signal (from the architecture document):** Before assigning Covered/Missing, check whether the referenced technology is explicitly marked for removal or replacement in the architecture document itself. Be conservative — recognize a removal signal only when one of these is present, and when in doubt leave it as a normal reference (a false removal signal silently drops a real coverage gap):
|
|
71
84
|
- The technology is listed under a section whose heading matches (case-insensitive) one of: "deprecated", "removed", "legacy", "migrating away", "being replaced", "to be removed", "sunset", "retiring".
|
|
@@ -78,37 +91,43 @@ Record the cited section heading or annotation text as evidence for every techno
|
|
|
78
91
|
- **Replaced** — no matching skill exists AND a deliberate-removal signal (above) was found; the technology is intentionally being removed/replaced, so no skill should exist for it
|
|
79
92
|
- **Missing** — no matching skill found and no removal signal
|
|
80
93
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
**Tally the matrix deterministically.** Assigning each verdict is judgment; counting the classes and computing the percentage has one correct answer, so delegate it. Serialize the matrix as `{"rows": [{"technology": "…", "verdict": "Covered|Missing|Replaced"}, …]}` and run:
|
|
94
|
+
**Tally the matrix deterministically.** Assigning each verdict is judgment; counting the classes and computing the percentage has one correct answer, so delegate it. Write the matrix to `{run_dir}/coverage-rows.json` as `{"rows": [{"technology": "…", "section": "<its source section, or null>", "skill": "<the matching skill's name, or null>", "verdict": "Covered|Missing|Replaced"}, …]}`, one row per technology, and run:
|
|
84
95
|
|
|
85
96
|
```bash
|
|
86
|
-
|
|
97
|
+
uv run {coverageTallyScript} --stdin < "{run_dir}/coverage-rows.json"
|
|
87
98
|
```
|
|
88
99
|
|
|
89
|
-
The script (run `uv run {coverageTallyScript} --help` for the contract) returns `covered_count`, `missing_count`, `replaced_count`, `live_count` (the denominator
|
|
100
|
+
The script (run `uv run {coverageTallyScript} --help` for the contract) returns `covered_count`, `missing_count`, `replaced_count`, `live_count` (the denominator: Covered + Missing, with Replaced excluded because a technology being removed is not a gap to close), `total_referenced`, and `coverage_percentage` (Replaced excluded from the denominator, half-up rounding pinned so the same matrix always yields the same integer). Consume these values in §5, §6 and §7 rather than recomputing them. When it exits non-zero, it rejected the rows and says why (its JSON `error`): fix them and run it again.
|
|
90
101
|
|
|
91
102
|
### 4. Detect Extra Skills
|
|
92
103
|
|
|
93
|
-
Check if any skills in the inventory are not referenced in the architecture document.
|
|
104
|
+
Check if any skills in the inventory are not referenced in the architecture document: a skill in the `unmentioned` or `fenced_only` list of `{docMentionsFile}`, as §3 left it.
|
|
94
105
|
|
|
95
|
-
**Subdivide into two categories (both informational
|
|
96
|
-
- **Extra (unreferenced)
|
|
97
|
-
- **Orphan (source_repo unresolvable)
|
|
106
|
+
**Subdivide into two categories (both informational, not errors), by the skill's `source_repo_basename` in `{inventoryFile}`:**
|
|
107
|
+
- **Extra (unreferenced):** `source_repo_basename` is set, but no architecture document tech token matches the skill.
|
|
108
|
+
- **Orphan (source_repo unresolvable):** `source_repo_basename` is null: metadata.json records no `source_repo`, or none a repository name can be read from. Cross-reference against architecture tokens is not possible for this skill.
|
|
98
109
|
|
|
99
110
|
**For each extra skill:**
|
|
100
|
-
- If `
|
|
101
|
-
- If `
|
|
111
|
+
- If `source_repo_basename` is set → mark as **Extra (unreferenced)**, note: "Skill `{skill_name}` exists and has a resolvable `source_repo`, but no architecture reference was found."
|
|
112
|
+
- If `source_repo_basename` is null → mark as **Orphan (source_repo unresolvable)**, note: "Skill `{skill_name}` has no resolvable `source_repo`, so it cannot be cross-referenced against the architecture. Re-run [CS] or update the skill's metadata."
|
|
102
113
|
|
|
103
114
|
Extra and Orphan skills are informational only. They do not affect the coverage verdict.
|
|
104
115
|
|
|
105
116
|
### 5. Display Coverage Results
|
|
106
117
|
|
|
118
|
+
Render the matrix's table rows from the §3 rows file, once, for this display and the report (§6):
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
uv run {coverageTallyScript} --render --stdin < "{run_dir}/coverage-rows.json"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
It prints one row per technology, its Source Section and Skill Match `none` where the rows file names none. On a non-zero exit it prints a JSON `error` instead: fix the row it names in `{run_dir}/coverage-rows.json`, run the §3 tally again, then this call, and never paste that output into the table.
|
|
125
|
+
|
|
107
126
|
"**Pass 1: Technology Coverage**
|
|
108
127
|
|
|
109
128
|
| Technology | Source Section | Skill Match | Verdict |
|
|
110
129
|
|------------|---------------|-------------|---------|
|
|
111
|
-
|
|
130
|
+
{the rendered rows, as printed}
|
|
112
131
|
|
|
113
132
|
**Coverage: {covered_count}/{live_count} ({coverage_percentage}%)** (from the §3 tally; `live_count` excludes **Replaced** technologies)
|
|
114
133
|
|
|
@@ -128,53 +147,37 @@ Extra and Orphan skills are informational only. They do not affect the coverage
|
|
|
128
147
|
{IF any Extra:}
|
|
129
148
|
**Extra Skills (informational):**
|
|
130
149
|
{For each extra skill:}
|
|
131
|
-
- `{skill_name}
|
|
150
|
+
- `{skill_name}`: not referenced in architecture document
|
|
151
|
+
|
|
152
|
+
{IF a skill of the helper's `fenced_only` list is Extra:}
|
|
153
|
+
**Detection limitation:** {those skills} appear only inside fenced code, which coverage does not read, so they count as Extra. {IF a `fenced_blocks[]` entry of `{docMentionsFile}` has the `info` string `mermaid`:}Part of the stack is drawn in a Mermaid diagram: list its technologies in prose (a Tech Stack section, say), then re-run **[VS]**.{ELSE:}Name them in prose, then re-run **[VS]**."
|
|
132
154
|
|
|
133
155
|
### 6. Append to Report
|
|
134
156
|
|
|
135
|
-
**Resolve `{atomicWriteHelper}`** from `{atomicWriteProbeOrder}`; first existing path wins. If no candidate exists: HALT (exit code 3, `halt_reason: "resolution-failure"`)
|
|
157
|
+
**Resolve `{atomicWriteHelper}`** from `{atomicWriteProbeOrder}`; first existing path wins. If no candidate exists: HALT (exit code 3, `halt_reason: "resolution-failure"`) at phase `coverage:report`.
|
|
136
158
|
|
|
137
159
|
**Resolve `{feasibilitySchemaRef}`** from `{feasibilitySchemaProbeOrder}`; first existing path wins (installed SKF module path first, dev-checkout `src/` fallback).
|
|
138
160
|
|
|
139
161
|
Write the **Coverage Analysis** section to `{outputFile}` (see `{feasibilitySchemaRef}` — section headings are fixed and ordered: `## Executive Summary`, `## Coverage Analysis`, `## Integration Verdicts`, `## Recommendations`, `## Evidence Sources`):
|
|
140
|
-
- Include the full coverage table
|
|
162
|
+
- Include the full coverage table: the §5 header `| Technology | Source Section | Skill Match | Verdict |`, its delimiter row and the rows §5 rendered, as printed, so each Verdict cell holds one token alone (`Covered`, `Missing` or `Replaced`): the next run's delta reads the Technology and Verdict columns
|
|
141
163
|
- Include coverage percentage
|
|
142
164
|
- Include missing skill recommendations
|
|
143
165
|
- Include the Replaced (being removed/replaced) subdivision from section 3, with the cited removal evidence — these are not gaps and carry no [CS]/[QS] recommendation
|
|
144
|
-
- Include the Extra (unreferenced) and Orphan (source_repo unresolvable) subdivisions from section 4
|
|
145
|
-
- Update frontmatter: append `'coverage'` to `stepsCompleted`; set `coveragePercentage`
|
|
146
|
-
- Pipe the updated full content through `python3 {atomicWriteHelper} write --target {outputFile}`
|
|
166
|
+
- Include the Extra (unreferenced) and Orphan (source_repo unresolvable) subdivisions from section 4, and the §5 detection limitation when it shows
|
|
167
|
+
- Update frontmatter: append `'coverage'` to `stepsCompleted`; from the §3 tally, set `coveragePercentage` ← `coverage_percentage` (integer 0..100), `coverageCovered` ← `covered_count`, `coverageMissing` ← `missing_count` and `coverageReplaced` ← `replaced_count` (synthesize's verdict rollup reads the three counts)
|
|
168
|
+
- Pipe the updated full content through `python3 {atomicWriteHelper} write --target {outputFile}`. On a non-zero exit: HALT (exit code 4, `halt_reason: "write-failed"`) at phase `coverage:report`, with `"path": "{outputFile}"`.
|
|
147
169
|
|
|
148
170
|
### 7. Auto-Proceed to Next Step
|
|
149
171
|
|
|
150
|
-
{IF
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
**
|
|
154
|
-
|
|
155
|
-
**Select:** [X] Halt workflow (recommended) | [C] Continue anyway"
|
|
156
|
-
|
|
157
|
-
**GATE [default: C]** — Interactive-only guard. If `{headless_mode}`: auto-proceed with [C] Continue, log: "headless: continuing past all-Replaced coverage gate (nothing live to verify)". Headless never takes [X], so step 6 still emits the result contract — the run resolves to `NOT_FEASIBLE` via the synthesize zero-coverage short-circuit.
|
|
158
|
-
|
|
159
|
-
- IF X: "**Workflow halted.** Coverage Analysis saved to `{outputFile}`. Update the architecture document and re-run [VS] when ready." HALT (exit code 8, `halt_reason: "analysis-halted"`).
|
|
160
|
-
- IF C: "**Continuing — the analysis covers only technologies marked for removal and will be limited.**" Load, read the full file and then execute `{nextStepFile}`.
|
|
172
|
+
{IF coverage_percentage is 0:} display one warning line (headless: log it), record it in the run sink, and continue; the run resolves to `NOT_FEASIBLE` in synthesize, and the report still carries a recommendation for each Missing or Replaced technology:
|
|
173
|
+
- when `total_referenced` is 0: "**Warning:** the architecture document names no technology, so there is nothing to verify. Name the stack's technologies in it (a Tech Stack section, say), then re-run [VS]." Record `no_technology_referenced: the architecture document names no technology`.
|
|
174
|
+
- when `live_count` is 0 (every referenced technology is Replaced): "**Warning:** every referenced technology is marked for removal or replacement, so nothing live is left to verify. Update the architecture document to describe the technologies that remain, then re-run [VS]." Record `no_live_technology: every referenced technology is marked for removal or replacement`.
|
|
175
|
+
- otherwise: "**Warning:** 0% coverage: no generated skill matches a referenced technology, so the integration and requirements passes have nothing to check. Generate skills with [CS] or [QS] for the Missing technologies, then re-run [VS]." Record `zero_coverage: no generated skill matches a referenced technology`.
|
|
161
176
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
**Recommended:** Generate skills with [CS] or [QS] for your architecture technologies, then re-run [VS].
|
|
166
|
-
|
|
167
|
-
**Select:** [X] Halt workflow (recommended) | [C] Continue anyway"
|
|
168
|
-
|
|
169
|
-
**GATE [default: C]** — Interactive-only guard. If `{headless_mode}`: auto-proceed with [C] Continue, log: "headless: continuing past 0%-coverage gate". Headless never takes [X], so step 6 still emits the result contract — the run resolves to `NOT_FEASIBLE` via the synthesize zero-coverage short-circuit.
|
|
170
|
-
|
|
171
|
-
- IF X: "**Workflow halted.** Coverage Analysis saved to `{outputFile}`. Generate skills and re-run [VS] when ready." HALT (exit code 8, `halt_reason: "analysis-halted"`).
|
|
172
|
-
- IF C: "**Continuing with 0% coverage — results will be limited.**"
|
|
173
|
-
|
|
174
|
-
Load, read the full file and then execute `{nextStepFile}`.
|
|
177
|
+
```bash
|
|
178
|
+
uv run {emitEnvelopeHelper} record --run-dir "{run_dir}" --warning '<the warning to record>'
|
|
179
|
+
```
|
|
175
180
|
|
|
176
|
-
{IF coveragePercentage is not 0:}
|
|
177
181
|
"**Proceeding to integration analysis...**"
|
|
178
182
|
|
|
179
183
|
Load, read the full file and then execute `{nextStepFile}`.
|
|
180
|
-
|
|
@@ -1,14 +1,27 @@
|
|
|
1
|
-
# Exit Codes
|
|
1
|
+
# Exit Codes and Result Envelope
|
|
2
2
|
|
|
3
|
-
Every hard halt in this workflow exits with a stable code so headless automators can branch on the failure class without grepping message text. Each code pairs with a `halt_reason` string carried in the headless result envelope.
|
|
3
|
+
Every hard halt in this workflow exits with a stable code so headless automators can branch on the failure class without grepping message text. Each code pairs with a `halt_reason` string carried in the headless result envelope. This file stands alone: a halting stage needs nothing else in context to emit its envelope.
|
|
4
4
|
|
|
5
5
|
| Code | Meaning | Raised by |
|
|
6
6
|
| ---- | -------------------- | -------------------------------------------------------------------------------------------- |
|
|
7
7
|
| 0 | success | step 7 (terminal) |
|
|
8
8
|
| 2 | input-missing / input-invalid | step 1 §1 (headless missing `architecture-doc` arg, or invalid path) → `input-missing`; non-existent file → `input-invalid` |
|
|
9
|
-
| 3 | resolution-failure | step 1 §2 (`{skills_output_folder}` does not exist or is empty → `skills-folder-missing`); step 1
|
|
10
|
-
| 4 | write-failure |
|
|
11
|
-
| 5 | state-conflict | step 1 §3 (fewer than 2 valid skills found
|
|
12
|
-
| 6 | user-cancelled | step 1 §1 prompt cancelled; any prompt that accepted `cancel`/`exit`/`:q
|
|
13
|
-
| 7 | inventory-unreliable | step 1 §2 (
|
|
14
|
-
|
|
9
|
+
| 3 | resolution-failure | step 1 §2 (`{skills_output_folder}` does not exist or is empty → `skills-folder-missing`); step 1 pre-flight (forge_data_folder unconfigured → `forge-folder-unconfigured`); any stage that cannot resolve a required helper from its probe order (result emitter, atomic-write, schema ref, validate-feasibility-report, enumerate-stack-skills, comention-pairs, scan-skill-md-structure, find-cycles), or cannot start a helper it runs, the previous-report helper and the verdict rollup that find no shared report reader included → `resolution-failure` |
|
|
10
|
+
| 4 | write-failure | step 1 pre-flight (the run folder or the write probe); steps 1 to 5 (a write of `{outputFile}`); step 6 §1 (the `-latest` copy); step 6 §4b (the emitter refuses the result payload twice) → `write-failed` |
|
|
11
|
+
| 5 | state-conflict | step 1 §3 (fewer than 2 valid skills found: a stack requires ≥2 → `insufficient-skills`); step 1 §1 (in headless, `--previous-report` is `{outputFile}` or `{outputFileLatest}`, a file this run writes → `previous-report-collision`; an interactive run asks for another path); step 5 §1 (the report frontmatter lacks, or holds disagreeing, counts the verdict rollup reads → `schema-violation`); step 6 §1 (the report fails the feasibility-report check → `schema-violation`) |
|
|
12
|
+
| 6 | user-cancelled | step 1 §1 prompt cancelled; any prompt that accepted `cancel`/`exit`/`:q` |
|
|
13
|
+
| 7 | inventory-unreliable | step 1 §2 (enumerate-stack-skills warnings exceed its failure budget); step 3 §3 (>20% API-surface subagents return malformed JSON); skills SKF did not generate are not counted |
|
|
14
|
+
|
|
15
|
+
## Result Envelope
|
|
16
|
+
|
|
17
|
+
When `{headless_mode}` is true, step 6 prints one `SKF_VERIFY_STACK_RESULT_JSON: {...}` line on **stdout** before chaining to step 7, and every HARD HALT prints one on **stderr** with `status: "error"`. The shared emitter builds each line from the payload the stage stages in `{run_dir}`, folds in the decisions and warnings the run recorded there, and checks it against `{project-root}/_bmad/skf/shared/scripts/schemas/skf-verify-stack-result-envelope.v1.json` (`{project-root}/src/shared/scripts/schemas/skf-verify-stack-result-envelope.v1.json` in a dev checkout), whose descriptions say what each field holds: `status`, `report_path`, `report_latest_path`, `overall_verdict`, `coverage_percentage`, `recommendation_count`, `exit_code`, `halt_reason`, `run_id`, `result_path`, and `headless_decisions`, `warnings` and `error` when they apply. Never type the line yourself.
|
|
18
|
+
|
|
19
|
+
## Emitting a Halt
|
|
20
|
+
|
|
21
|
+
Every HALT names its exit code, `halt_reason` and phase. In headless mode, stage `{run_dir}/halt.json` as `{"phase": "<phase>", "reason": "<the halt message>", "halt_reason": "<halt_reason>"}`, adding `"report_path": "{outputFile}"` once step 1 §4 wrote the report, `"report_latest_path": "{outputFileLatest}"` once step 6 §1 published it, and `"path"` when the halt names one. `{emitEnvelopeHelper}` is the first of `{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py` and `{project-root}/src/shared/scripts/skf-emit-result-envelope.py` that exists (each stage lists both as `emitEnvelopeProbeOrder`). Run:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
uv run {emitEnvelopeHelper} emit-halt --workflow skf-verify-stack --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The emitter sets `status: "error"`, derives `exit_code` from `halt_reason`, stamps `run_id` and gives every other field its default. Display the line it prints, then stop with the halt's exit code. If neither path exists, or the emitter exits non-zero or prints no line, display the halt message alone. An interactive HALT displays its message and emits nothing. A HALT before the run folder exists passes the payload on stdin instead (init.md's pre-flight shows the command).
|
|
@@ -8,16 +8,17 @@ atomicWriteProbeOrder:
|
|
|
8
8
|
- '{project-root}/src/shared/scripts/skf-atomic-write.py'
|
|
9
9
|
outputFile: '{outputFolderPath}/feasibility-report-{project_slug}-{timestamp}.md'
|
|
10
10
|
outputFileLatest: '{outputFolderPath}/feasibility-report-{project_slug}-latest.md'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
# metadata-hash for change-detection, confidence-tier mapping). If neither
|
|
16
|
-
# candidate exists, §2 does NOT halt — it falls through to the LLM-driven
|
|
17
|
-
# subagent fan-out as graceful degradation (see §2).
|
|
11
|
+
inventoryFile: '{run_dir}/skill-inventory.json'
|
|
12
|
+
emitEnvelopeProbeOrder:
|
|
13
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py'
|
|
14
|
+
- '{project-root}/src/shared/scripts/skf-emit-result-envelope.py'
|
|
18
15
|
enumerateStackSkillsProbeOrder:
|
|
19
16
|
- '{project-root}/_bmad/skf/shared/scripts/skf-enumerate-stack-skills.py'
|
|
20
17
|
- '{project-root}/src/shared/scripts/skf-enumerate-stack-skills.py'
|
|
18
|
+
validateFeasibilityReportProbeOrder:
|
|
19
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-validate-feasibility-report.py'
|
|
20
|
+
- '{project-root}/src/shared/scripts/skf-validate-feasibility-report.py'
|
|
21
|
+
previousReportScript: 'scripts/skf-previous-report.py'
|
|
21
22
|
---
|
|
22
23
|
|
|
23
24
|
<!-- Config: communicate in {communication_language}. Initialize the feasibility report skeleton in {document_output_language}. -->
|
|
@@ -35,90 +36,134 @@ Load all generated skills from the skills output folder, accept the architecture
|
|
|
35
36
|
|
|
36
37
|
## MANDATORY SEQUENCE
|
|
37
38
|
|
|
39
|
+
**Halt envelope.** Every HALT in this step names its exit code, `halt_reason` and phase. In headless mode, stage `{run_dir}/halt.json` as `{"phase": "<phase>", "reason": "<the halt message>", "halt_reason": "<halt_reason>"}`, adding `"report_path": "{outputFile}"` once §4 wrote the report and `"path"` when the halt names one, resolve `{emitEnvelopeHelper}` from `{emitEnvelopeProbeOrder}` if it is not bound (first existing path wins), then run:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
uv run {emitEnvelopeHelper} emit-halt --workflow skf-verify-stack --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Display the line it prints, then stop with the halt's exit code (`references/exit-codes.md` describes the envelope). If no candidate exists, or the emitter exits non-zero or prints no line, display the halt message alone. An interactive HALT displays its message and emits nothing.
|
|
46
|
+
|
|
47
|
+
**Pre-flight: run folder and write probe.** Both run before the first prompt. Create the run folder:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
mkdir -p "{project-root}/_bmad-output/.skf-run" && mkdir "{run_dir}"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If the command fails, HALT (exit code 4, `halt_reason: "write-failed"`) at phase `init:run-folder`: "Cannot create the run folder `{run_dir}`: {the first stderr line}." With no folder to stage in, a headless run passes the payload to the emitter directly, with `"customization_resolver_unavailable": "<reason>"` added when SKILL.md On Activation step 4 kept one:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
uv run {emitEnvelopeHelper} emit-halt --workflow skf-verify-stack --target stderr <<'SKF_VS_HALT'
|
|
57
|
+
{"phase": "init:run-folder", "reason": "<the halt message>", "halt_reason": "write-failed"}
|
|
58
|
+
SKF_VS_HALT
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Once the folder exists and `{customization_resolver_unavailable}` is set (SKILL.md On Activation step 4), record the reason in the run sink: write `customization_resolver_unavailable: {customization_resolver_unavailable}` to `{run_dir}/resolver-warning.txt` with a file write, never `echo` (the reason can hold quotes or `$( )`), then run `uv run {emitEnvelopeHelper} record --run-dir "{run_dir}" --warning "$(cat "{run_dir}/resolver-warning.txt")"`.
|
|
62
|
+
|
|
63
|
+
Then check that `forge_data_folder`, which `{outputFolderPath}` names, was resolved from config.yaml and is non-empty. If it is undefined or empty: "**Cannot proceed.** `forge_data_folder` is not configured in config.yaml. Re-run [SF] Setup Forge to initialize." HALT (exit code 3, `halt_reason: "forge-folder-unconfigured"`) at phase `init:forge-data-folder`.
|
|
64
|
+
|
|
65
|
+
Then verify `{outputFolderPath}` is writable: a read-only mount, full disk, or permissions-denied path otherwise only surfaces at §4's atomic write, after the user has gone through the input prompts.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
mkdir -p "{outputFolderPath}" && \
|
|
69
|
+
printf 'probe' > "{outputFolderPath}/.skf-write-probe" && \
|
|
70
|
+
rm "{outputFolderPath}/.skf-write-probe"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
On any non-zero exit: HALT (exit code 4, `halt_reason: "write-failed"`) at phase `init:write-probe`, with `"path": "{outputFolderPath}"`.
|
|
74
|
+
|
|
75
|
+
**Bind `{project_slug}`.** Resolve `{validateFeasibilityReportHelper}` from `{validateFeasibilityReportProbeOrder}`; first existing path wins. Run:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
uv run {validateFeasibilityReportHelper} --locate "{outputFolderPath}" --project-name "{project_name}"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Bind `{project_slug}` ← `projectSlug`, whatever `status` says: this run needs only the slug, and the helper holds the one slug rule that the consumers of this report apply when they look for it. If no candidate exists, or the command prints no JSON: HALT (exit code 3, `halt_reason: "resolution-failure"`) at phase `init:project-slug`.
|
|
82
|
+
|
|
38
83
|
### 1. Accept Input Documents
|
|
39
84
|
|
|
40
|
-
|
|
85
|
+
**Ask only for what no flag answered.** A path the invocation gave (`{architecture_doc_path}`, `{prd_path}`, `{previous_report_path}`, bound at activation) is used in every mode and never asked for again. An interactive run with any of the three still null shows this prompt, with only the numbered lines whose input is null:
|
|
86
|
+
|
|
87
|
+
"**Verify Stack: Feasibility Analysis** (read-only: never modifies your skills, architecture doc, or PRD).
|
|
41
88
|
|
|
42
89
|
If you meant to *generate* skills first, type `cancel` and run `[CS] Create Skill` or `[QS] Quick Skill`. Otherwise, please provide the following:
|
|
43
|
-
1. **Architecture document path** (REQUIRED)
|
|
44
|
-
2. **PRD or vision document path** (OPTIONAL)
|
|
45
|
-
3. **Previous feasibility report path** (OPTIONAL)
|
|
90
|
+
1. **Architecture document path** (REQUIRED): your project's architecture doc
|
|
91
|
+
2. **PRD or vision document path** (OPTIONAL): for requirements coverage analysis
|
|
92
|
+
3. **Previous feasibility report path** (OPTIONAL): a timestamped report from an earlier run, for delta comparison. Leave it empty to compare against the most recent one found.
|
|
46
93
|
|
|
47
94
|
Or type `cancel` / `exit` / `:q` at any prompt to abort cleanly."
|
|
48
95
|
|
|
49
|
-
|
|
96
|
+
When the prompt shows, wait for user input, and bind each answer to its variable (an empty answer leaves an optional one null). **GATE [default: use args]**: headless asks nothing. With `{architecture_doc_path}` set it auto-proceeds and logs "headless: using provided architecture path"; with it null: HALT (exit code 2, `halt_reason: "input-missing"`) at phase `init:input-documents`. A null `{prd_path}` skips the requirements pass, and a null `{previous_report_path}` compares against the newest earlier report.
|
|
50
97
|
|
|
51
98
|
- If the user enters `cancel`, `exit`, `[X]`, `q`, or `:q` at any sub-prompt below: Display "Cancelled — no analysis was performed." and HALT (exit code 6, `halt_reason: "user-cancelled"`).
|
|
52
99
|
|
|
53
|
-
**Validate architecture document
|
|
100
|
+
**Validate the architecture document** (`{architecture_doc_path}`):
|
|
54
101
|
- Confirm the file exists and is readable
|
|
55
102
|
- If missing or unreadable → "Architecture document not found at `{path}`. Provide a valid path."
|
|
56
|
-
- HALT (exit code 2, `halt_reason: "input-invalid"`) if the user cannot provide a valid path
|
|
103
|
+
- HALT (exit code 2, `halt_reason: "input-invalid"`) at phase `init:architecture-doc`, with `"path"` set to the path given, if the user cannot provide a valid path; a headless run has no one to ask, so it halts at once.
|
|
57
104
|
|
|
58
|
-
**Validate PRD
|
|
105
|
+
**Validate the PRD (when `{prd_path}` is set):**
|
|
59
106
|
- Confirm the file exists and is readable
|
|
60
|
-
- If missing → "PRD document not found at `{path}`. Proceeding without PRD
|
|
107
|
+
- If missing → "PRD document not found at `{path}`. Proceeding without PRD: the requirements pass will be skipped." Set `{prd_path}` to null.
|
|
61
108
|
- Store PRD availability as `prdAvailable: true|false`
|
|
62
109
|
|
|
63
|
-
**
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
110
|
+
**Resolve the previous report.** Run the previous-report helper, with `--provided` set to `{previous_report_path}` when it is set, and without it otherwise:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
uv run {previousReportScript} --folder "{outputFolderPath}" --slug "{project_slug}" --timestamp "{timestamp}" [--provided "<path>"]
|
|
114
|
+
```
|
|
68
115
|
|
|
69
|
-
|
|
70
|
-
- Interactive: offer "Found a prior report from `{date}` — compare against it? **[Y]** use it / paste a different path / **[skip]**". On [Y], set `previousReport` to that path; on a pasted path, use it; on `skip`, leave `previousReport` empty.
|
|
71
|
-
- **GATE [default: Y]** — If `{headless_mode}`: auto-select the most recent match, set `previousReport` to it, log: "headless: delta comparison against `{path}`".
|
|
72
|
-
- Excluding this run's `{timestamp}` and `-latest` files guarantees the auto-selected path is a distinct inode from `{outputFile}`, so it can never trip the collision check above.
|
|
73
|
-
- If no match remains, leave `previousReport` empty — first run, no delta.
|
|
116
|
+
It never returns a file this run writes (`{outputFile}` or `{outputFileLatest}`); without `--provided` it picks the newest earlier report that finished. When it prints no JSON (exit 2, a usage error), the line it prints names the flag it rejected: fix that flag's value and run it again. Otherwise branch on `status`:
|
|
74
117
|
|
|
75
|
-
|
|
118
|
+
- `collision` (exit 1): "`{provided}` is `{collidesWith}`, which this run overwrites. Give a timestamped report from an earlier run, or leave the path empty to compare against the most recent one." Interactive: wait for the answer, run the helper again with `--provided` set to it (or without `--provided` for an empty answer), and branch on its `status` as here. In headless, where the path came from `--previous-report`: HALT (exit code 5, `halt_reason: "previous-report-collision"`) at phase `init:previous-report`, with `"path"` set to the path given.
|
|
119
|
+
- `not-found`: "Previous report not found at `{provided}`. Proceeding without delta comparison." Set `previousReport` to empty.
|
|
120
|
+
- `provided`: set `previousReport` to the returned `previousReport`.
|
|
121
|
+
- `discovered` (no path was given): interactive, offer "Found a prior report from `{previousTimestamp}`: compare against it? **[Y]** use it / paste a different path / **[skip]** / **[X]** cancel". On [Y], set `previousReport` to the returned `previousReport`; on a pasted path, run the helper again with `--provided` set to it and branch on its `status` as above; on `skip`, leave `previousReport` empty; on [X], cancel as above (exit code 6).
|
|
122
|
+
**GATE [default: Y]**: if `{headless_mode}`, set `previousReport` to the returned `previousReport`, log: "headless: delta comparison against `{previousReport}`", and record the decision in the run sink the moment it is taken. Stage `{run_dir}/decision.json` as `{"gate": "init.previous-report", "default_action": "Y", "taken_action": "Y", "reason": "headless: delta comparison against <previousReport>", "evidence": {"previous_report": "<previousReport>"}}` and run:
|
|
76
123
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
124
|
+
```bash
|
|
125
|
+
uv run {emitEnvelopeHelper} record --workflow skf-verify-stack --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"
|
|
126
|
+
```
|
|
80
127
|
|
|
81
|
-
|
|
128
|
+
- `none`: leave `previousReport` empty (no finished earlier report, no delta).
|
|
129
|
+
- `reader-missing` (exit 3): the shared report reader the helper loads is not installed: HALT (exit code 3, `halt_reason: "resolution-failure"`) at phase `init:previous-report`, naming the file its `error` gives.
|
|
82
130
|
|
|
83
|
-
|
|
131
|
+
### 2. Scan Skills Folder
|
|
84
132
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
133
|
+
**Pre-flight: skills folder existence.**
|
|
134
|
+
- If `{skills_output_folder}` does not exist on disk: HALT (exit code 3, `halt_reason: "skills-folder-missing"`) at phase `init:skills-folder` with "**Cannot proceed.** `{skills_output_folder}` does not exist: run **[SF] Setup Forge** to initialize the forge, then generate skills with [CS] or [QS]."
|
|
135
|
+
- If `{skills_output_folder}` exists but is empty (no subdirectories at all): HALT (exit code 3, `halt_reason: "skills-folder-missing"`) at phase `init:skills-folder` with "**Cannot proceed.** `{skills_output_folder}` contains 0 skills. Generate skills with [CS] Create Skill or [QS] Quick Skill, then re-run [VS]."
|
|
88
136
|
|
|
89
|
-
|
|
137
|
+
**Resolve `{enumerateStackSkillsHelper}`** from `{enumerateStackSkillsProbeOrder}`; first existing path wins. If no candidate exists: HALT (exit code 3, `halt_reason: "resolution-failure"`) at phase `init:inventory`.
|
|
90
138
|
|
|
91
|
-
|
|
139
|
+
**Enumerate the skills with the shared helper:**
|
|
92
140
|
|
|
93
|
-
|
|
141
|
+
```bash
|
|
142
|
+
uv run {enumerateStackSkillsHelper} enumerate {skills_output_folder} --reliability > "{inventoryFile}"
|
|
143
|
+
```
|
|
94
144
|
|
|
95
|
-
|
|
145
|
+
If the command exits non-zero, HALT (exit code 3, `halt_reason: "resolution-failure"`) at phase `init:inventory`, naming its first stderr line. Read `{inventoryFile}` now: every later stage reads the inventory from it, not from context.
|
|
96
146
|
|
|
97
|
-
|
|
147
|
+
The helper reads only the skills SKF generated (its `--help` says how it picks each package and resolves its exports). The later stages read these fields of each `skills[]` entry: `name` (the folder name), `path` (the package, relative to `{skills_output_folder}`), `exports`, `exports_source`, `confidence` (from the exports source, not metadata's `confidence_tier`), `evidence_tier` (`T1`, `T1-low`, `T2` or `T3`, one scale for every skill type), `confidence_tier`, `metadata_schema_version`, `language` (a string, or a list for a stack), `exports_documented`, `source_repo_basename` and `source_root_basename`, so no stage opens `metadata.json`. `warnings[]` names per-skill problems, each starting `<name>: `. The file is `skill_inventory` (used by §3, §4, §5, the coverage and integrations stages, and synthesize's delta and Evidence Sources table), and bind `{not_skf_output}` ← `not_skf_output`, `{inventory_reliable}` ← `inventory_reliable`, `{warning_count}` ← `warning_count`, `{skill_count}` ← `skill_count` and `{inventory_warnings}` ← `warnings`. When `{not_skf_output}` is non-empty, display it once: "Skipped (not SKF output): {not_skf_output}". Those folders, such as a module's own skills in a shared skills folder, are not in `skills[]` and count toward neither `{skill_count}` nor `{warning_count}`.
|
|
98
148
|
|
|
99
|
-
**
|
|
149
|
+
**Failure-budget guard:** If `{inventory_reliable}` is false, HALT (exit code 7, `halt_reason: "inventory-unreliable"`) at phase `init:inventory` with: "Inventory scan unreliable: {warning_count} warning(s) across {skill_count} skill(s) SKF generated: {inventory_warnings}. Fix the skills named there (re-save an unreadable `metadata.json` as plain UTF-8 JSON or restore it from version control, and regenerate a skill whose exports are missing), then re-run [VS]."
|
|
100
150
|
|
|
101
151
|
### 3. Validate Minimum Requirements
|
|
102
152
|
|
|
103
153
|
**Check skill count:**
|
|
104
|
-
- At least 2
|
|
105
|
-
- If fewer than 2 → "**Cannot proceed.** Only {
|
|
106
|
-
- HALT (exit code 5, `halt_reason: "insufficient-skills"`)
|
|
107
|
-
|
|
108
|
-
**Check forge_data_folder:**
|
|
109
|
-
- Verify `forge_data_folder` was resolved from config.yaml and is non-empty
|
|
110
|
-
- If undefined or empty → "**Cannot proceed.** `forge_data_folder` is not configured in config.yaml. Re-run [SF] Setup Forge to initialize."
|
|
111
|
-
- HALT (exit code 3, `halt_reason: "forge-folder-unconfigured"`). In headless, emit the error envelope.
|
|
154
|
+
- At least 2 skills SKF generated must exist (`{skill_count}`; a stack requires multiple libraries)
|
|
155
|
+
- If fewer than 2 → "**Cannot proceed.** Only {skill_count} skill(s) SKF generated were found in `{skills_output_folder}`. A stack requires at least 2 skills. Generate more skills with [CS] Create Skill or [QS] Quick Skill, then re-run [VS]." When `{not_skf_output}` is non-empty, append: "Skipped (not SKF output): {not_skf_output}."
|
|
156
|
+
- HALT (exit code 5, `halt_reason: "insufficient-skills"`) at phase `init:skill-count`.
|
|
112
157
|
|
|
113
158
|
### 4. Create Feasibility Report
|
|
114
159
|
|
|
115
|
-
**Resolve `{atomicWriteHelper}`** from `{atomicWriteProbeOrder}`; first existing path wins. If no candidate exists: HALT (exit code 3, `halt_reason: "resolution-failure"`)
|
|
160
|
+
**Resolve `{atomicWriteHelper}`** from `{atomicWriteProbeOrder}`; first existing path wins. If no candidate exists: HALT (exit code 3, `halt_reason: "resolution-failure"`) at phase `init:report`.
|
|
116
161
|
|
|
117
|
-
**Resolve `{feasibilitySchemaRef}`** from `{feasibilitySchemaProbeOrder}`; first existing path wins (installed SKF module path first, dev-checkout `src/` fallback). If no candidate exists: HALT (exit code 3, `halt_reason: "resolution-failure"`)
|
|
162
|
+
**Resolve `{feasibilitySchemaRef}`** from `{feasibilitySchemaProbeOrder}`; first existing path wins (installed SKF module path first, dev-checkout `src/` fallback). If no candidate exists: HALT (exit code 3, `halt_reason: "resolution-failure"`) at phase `init:report`.
|
|
118
163
|
|
|
119
164
|
This skill produces the feasibility report schema defined in `{feasibilitySchemaRef}`; every output conforms to that schema — `schemaVersion: "1.0"`, the verdict token set (`Verified|Plausible|Risky|Blocked`; overall `FEASIBLE|CONDITIONALLY_FEASIBLE|NOT_FEASIBLE`), the filename pattern, and the section-heading order.
|
|
120
165
|
|
|
121
|
-
**Filename variables:** `
|
|
166
|
+
**Filename variables:** `timestamp` was fixed at activation (SKILL.md On Activation §2) and `project_slug` by the Bind block at the top of this step; reuse them, do not re-derive. `{outputFile}` and `{outputFileLatest}` resolve from them per the stage frontmatter template, the latter as a copy, not a symlink (per schema), which only report.md §1 writes.
|
|
122
167
|
|
|
123
168
|
**Load** `{reportTemplatePath}` (the customize-aware template path resolved in SKILL.md On Activation §4) and stage the initial content. Substitute the template's `Schema contract:` line `{feasibilitySchemaRef}` placeholder with the resolved schema path so every emitted report cites a path that exists on the running machine.
|
|
124
169
|
|
|
@@ -136,13 +181,13 @@ This skill produces the feasibility report schema defined in `{feasibilitySchema
|
|
|
136
181
|
- `prdAvailable: true|false` (from section 1 validation)
|
|
137
182
|
|
|
138
183
|
**Populate producer-local bookkeeping keys (not part of the consumer contract):**
|
|
139
|
-
- `architectureDoc`, `prdDoc` (or "none"), `previousReport` (or empty string)
|
|
140
|
-
- `skillsAnalyzed: {
|
|
184
|
+
- `architectureDoc` ← `{architecture_doc_path}`, `prdDoc` ← `{prd_path}` (or "none"), `previousReport` (or empty string)
|
|
185
|
+
- `skillsAnalyzed: {skill_count}`
|
|
141
186
|
- `stepsCompleted: ['init']`
|
|
142
187
|
|
|
143
|
-
**Atomic write:** Pipe the staged content through `python3 {atomicWriteHelper} write --target {outputFile}
|
|
188
|
+
**Atomic write:** Pipe the staged content through `python3 {atomicWriteHelper} write --target {outputFile}`: a plain `rm`+rewrite risks a partial write corrupting the report.
|
|
144
189
|
|
|
145
|
-
On
|
|
190
|
+
On a non-zero exit: HALT (exit code 4, `halt_reason: "write-failed"`) at phase `init:report`, with `"path": "{outputFile}"` and no `report_path`: the report was not written.
|
|
146
191
|
|
|
147
192
|
### 5. Display Initialization Summary
|
|
148
193
|
|
|
@@ -150,16 +195,16 @@ On any non-zero exit from either write: HALT (exit code 4, `halt_reason: "write-
|
|
|
150
195
|
|
|
151
196
|
| Field | Value |
|
|
152
197
|
|-------|-------|
|
|
153
|
-
| **Skills Loaded** | {
|
|
154
|
-
| **Architecture Doc** | {
|
|
155
|
-
| **PRD Document** | {
|
|
198
|
+
| **Skills Loaded** | {skill_count} |
|
|
199
|
+
| **Architecture Doc** | {architecture_doc_path} |
|
|
200
|
+
| **PRD Document** | {prd_path or 'Not provided: requirements pass will be skipped'} |
|
|
156
201
|
| **Previous Report** | {previousReport or 'Not provided — no delta comparison'} |
|
|
157
202
|
|
|
158
203
|
**Skill Inventory:**
|
|
159
204
|
|
|
160
|
-
| Skill |
|
|
161
|
-
|
|
162
|
-
| {
|
|
205
|
+
| Skill | Exports | Exports source | Confidence |
|
|
206
|
+
|-------|---------|----------------|------------|
|
|
207
|
+
| {name} | {number of exports} | {exports_source} | {confidence} |
|
|
163
208
|
|
|
164
209
|
**Proceeding to coverage analysis...**"
|
|
165
210
|
|