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
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Campaign Contracts
|
|
4
4
|
|
|
5
|
-
The self-contained contracts consulted at a specific moment
|
|
5
|
+
The self-contained contracts consulted at a specific moment: when a step HALTs, writes state or the decision log, or emits a headless progress event. Each stands alone so it survives context compaction.
|
|
6
6
|
|
|
7
7
|
## Exit Codes
|
|
8
8
|
|
|
@@ -10,51 +10,61 @@ Every HARD HALT exits with a stable, documented code so headless automators can
|
|
|
10
10
|
|
|
11
11
|
| Code | Meaning | Raised by |
|
|
12
12
|
| ---- | -------------------- | ----------------------------------------------------------- |
|
|
13
|
-
| 0 | success | step-11 (terminal); step-resume §3
|
|
14
|
-
| 2 | invalid-input | step-01 §1 (no targets, or a malformed
|
|
15
|
-
| 3 | invalid-state | any step §1 (`campaign-validate-state.py` non-zero on load) |
|
|
16
|
-
| 4 | circular-deps | step-02 §
|
|
17
|
-
| 5 | invalid-pin | step-03 §5
|
|
18
|
-
| 6 | inaccessible-repo | step-04 §5
|
|
19
|
-
| 7 | dependency-deadlock | step-05 §4 (no skill ready and no recovery chosen)
|
|
20
|
-
| 8 | missing-brief | step-03/04/05 §2 and step-06 §
|
|
13
|
+
| 0 | success | step-11 (terminal: the success line, which the health check displays last); step-resume §3 (campaign already complete: nothing to resume, and in headless mode the success line again). Never an error halt: no `emit-halt` |
|
|
14
|
+
| 2 | invalid-input | step-01 §1 (no targets, or a target the parse script rejects: a malformed manifest line or brief target, a `repo_url` that is no GitHub repository, a name that is no skill name, a Tier A pin that is no X.Y.Z version, a duplicate name) and §2 (a quality gate the gate script rejects, a brief it cannot read, or a state file or backup that already exists); steps 02/03/04 §3 and step-06 §3 (a helper reports unreadable input or a required tool such as `gh` unavailable); step-05 §4 and §5, step-07 §2 and step-10 §3 (a directive override that breaks the quality gate, or a directive the gate script cannot read); step-05 §5 (the kickoff script cannot read its template, state, directive or a facts file, or a `file:` fact path names no file); step-resume §1/§3 (resume targets a missing campaign or unknown skill) |
|
|
15
|
+
| 3 | invalid-state | any step §1 (`campaign-validate-state.py` non-zero on load), and any `campaign-state.py` write that exits 3 (the state, or the change, fails validation) |
|
|
16
|
+
| 4 | circular-deps | step-02 §4 (a dependency cycle, a dangling `depends_on` reference, or a Tier A skill that depends on a Tier B skill: either way the plan cannot be followed) and §7 (`apply-plan` refuses the plan) |
|
|
17
|
+
| 5 | invalid-pin | step-03 §4 and §5 (`apply-pins` refuses an invalid pin) |
|
|
18
|
+
| 6 | inaccessible-repo | step-04 §4 and §5 (`apply-provenance` refuses an inaccessible repo) |
|
|
19
|
+
| 7 | dependency-deadlock | step-05 §4 (no skill ready and no recovery chosen; defensive, since Strategy rejects every order the loop cannot follow) |
|
|
20
|
+
| 8 | missing-brief | step-03/04/05 §2, step-05 §4 and §5, step-06 §3 (brief missing/unreadable, or a skill has no matching brief target), and step-resume §3 (Setup stopped before it wrote the brief) |
|
|
21
21
|
| 9 | corrupt-state | step-resume §1 (primary unrecoverable, `.bak` also invalid) |
|
|
22
22
|
| 10 | report-failure | step-11 §2 — **degraded only**: the report could not be generated; the campaign still completes and state stays intact (never a hard halt that discards a finished campaign) |
|
|
23
23
|
| 11 | export-cancelled | step-10 §4 (operator chose `[C]ancel` — graceful, resumable) |
|
|
24
24
|
| 12 | user-cancelled | any interactive gate (operator typed `cancel` / `exit` / `:q` at a prompt between Setup and the Export gate — graceful, resumable) |
|
|
25
|
+
| 13 | dependency-blocked | step-05 §4 (`[H]alt` at a skill whose dependency has not completed: the operator's choice, or the headless default while a dependency is still pending or active; graceful, resumable) |
|
|
25
26
|
|
|
26
27
|
## Result Contract on HARD HALT
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
`shared/scripts/schemas/skf-campaign-result-envelope.v1.json` (in the SKF module: `{project-root}/_bmad/skf/` when installed, `{project-root}/src/` during development) is the one definition of the `SKF_CAMPAIGN_RESULT_JSON` envelope, and the shared emitter, `{emitEnvelopeHelper}`, is the only thing that prints it. That helper is `{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py` when installed, `{project-root}/src/shared/scripts/skf-emit-result-envelope.py` during development. Exit code 0 is never an error halt: step-11 builds the success line, and step-resume prints it again for a campaign already complete. Every HARD HALT in headless mode emits the error variant, so automators don't silently break:
|
|
29
30
|
|
|
30
|
-
```
|
|
31
|
-
|
|
31
|
+
```bash
|
|
32
|
+
uv run scripts/campaign-state.py halt-payload --state-file {campaignWorkspacePath}/_campaign-state.yaml --phase <step slug> --halt-reason <class> <<'SKF_CAMPAIGN_HALT' | uv run {emitEnvelopeHelper} emit-halt --workflow skf-campaign --target stderr
|
|
33
|
+
<the halt message>
|
|
34
|
+
SKF_CAMPAIGN_HALT
|
|
32
35
|
```
|
|
33
36
|
|
|
34
|
-
`<class>` is the Exit Codes meaning (e.g. `circular-deps`, `inaccessible-repo`)
|
|
37
|
+
`<class>` is the Exit Codes meaning (e.g. `circular-deps`, `inaccessible-repo`), from which the emitter derives `exit_code`; `<step slug>` is the kebab portion of the step file where the HALT occurred. `halt-payload` adds the `completed` and `failed` counts of the state (0 before Setup wrote it) and the decision log (null before the campaign workspace exists). The emitter prints one line on stderr, with `status` `error`, `exit_code`, `halt_reason`, `phase` and an `error` object holding `code` and `message`. If either command exits non-zero, display the halt message alone.
|
|
35
38
|
|
|
36
39
|
## State Contract
|
|
37
40
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
1. **Read** `_campaign-state.yaml`
|
|
41
|
-
2. **Validate** via `uv run scripts/campaign-validate-state.py --state-file {stateFile}` (halt on invalid)
|
|
42
|
-
3. **Backup** — copy current `_campaign-state.yaml` to `_campaign-state.yaml.bak`
|
|
43
|
-
4. **Modify** in memory
|
|
44
|
-
5. **Update** `campaign.last_updated` to current ISO-8601 timestamp
|
|
45
|
-
6. **Write** modified state back to `_campaign-state.yaml`
|
|
41
|
+
Every write to `_campaign-state.yaml` goes through `scripts/campaign-state.py`. Each write reads the state and validates it (an invalid state is never rotated into `.bak`, and nothing is written), applies the operation, stamps `campaign.last_updated` (and any `started_at` or `completed_at` the operation sets) from the clock in UTC, validates the result (a change that would make the state invalid is refused), copies the valid primary it read to `_campaign-state.yaml.bak`, and writes the new state to a temporary file renamed over the old one. A crash therefore leaves the old file or the new one, never half of one, and `.bak` always holds the last valid state. `--stage N` on a write also sets `campaign.current_stage`: each stage writes its number only in its final write, after every gate, because resume starts at `current_stage + 1`.
|
|
46
42
|
|
|
47
|
-
|
|
43
|
+
| Operation | Step | What it writes |
|
|
44
|
+
| --- | --- | --- |
|
|
45
|
+
| `init` | step-01 | the state, from `campaign-parse-manifest.py`'s targets and the gate `campaign-quality-gate.py check` settles, then `campaign-brief.yaml` from the same targets (`--brief-out`); refuses a state or backup that exists |
|
|
46
|
+
| `apply-plan` | step-02 | `dependency_graph` from `campaign-deps.py --compute` |
|
|
47
|
+
| `apply-pins` | step-03 | each resolved pin, from `campaign-validate-pins.py`'s output |
|
|
48
|
+
| `apply-provenance` | step-04 | each `commit_sha`, from `campaign-provenance.py`'s output |
|
|
49
|
+
| `set-skill` | step-05, step-10, step-resume | a skill's `status`, `quality_score`, `skill_path`, `brief_path` or `export` outcome (`--export`); `active` stamps `started_at` once, `completed` stamps `completed_at`, `pending` clears both and the `export` outcome |
|
|
50
|
+
| `append-workarounds` | step-05 | entries of a skill's `workarounds_applied`, each once |
|
|
51
|
+
| `apply-batch` | step-06 | the Tier B batch from its line-to-skill map: `--start`, `--results-file` or `--no-results` |
|
|
52
|
+
| `set-campaign` | steps 07 to 09 | `architecture_doc_path`, and the capstone, verification or refinement summary read from the sub-skill's envelope line (`capstone.verified` with the verification) |
|
|
53
|
+
| `set-stage` | steps 05, 10, 11 | `current_stage` alone |
|
|
54
|
+
| `recover` | step-resume | `.bak` over the primary, when `.bak` validates (exit 9 otherwise) |
|
|
55
|
+
| `archive` | SKILL.md (overwrite) | nothing: it moves the state, its `.bak` and the brief into a new folder under `archive/` and returns it |
|
|
56
|
+
| `resume` | step-resume | nothing: it returns the stage and step file to resume |
|
|
57
|
+
| `halt-payload` | any HARD HALT | nothing: it prints the error envelope's payload (Result Contract above) |
|
|
48
58
|
|
|
49
|
-
|
|
59
|
+
Its exit codes are the campaign's: 2 for invalid input (an unknown skill, an input file it cannot read, a script output that holds an error), 3 for an invalid state or change, 4 for a plan `apply-plan` refuses, 5 for a pin `apply-pins` refuses, 6 for a repository `apply-provenance` refuses, 9 for a `recover` with no valid backup. HALT with the same code.
|
|
50
60
|
|
|
51
|
-
|
|
61
|
+
## Decision Log
|
|
52
62
|
|
|
53
|
-
|
|
54
|
-
SKF_CAMPAIGN_RESULT_JSON: {"status":"success|error","skills_completed":0,"skills_failed":0,"quality_scores":{},"campaign_report_path":"","decision_log":"","duration":""}
|
|
55
|
-
```
|
|
63
|
+
`_campaign-decision-log.md` is append-only, one typed and timestamped line per entry, written with `uv run scripts/campaign-state.py log --log-file {campaignWorkspacePath}/_campaign-decision-log.md --type <decision|auto|event> --text '<entry>'` (single-quote the entry, so the shell expands no `$` or backtick in it, and write an apostrophe inside it as `'\''`). Its types:
|
|
56
64
|
|
|
57
|
-
|
|
65
|
+
- `decision`: the operator's choice at a gate (skip or force, overwrite, export or cancel, re-run or next, a cancel)
|
|
66
|
+
- `auto`: the default a headless run took at a gate
|
|
67
|
+
- `event`: what happened without a choice: a failed skill and why, a skip the directive or a dependency forced, a recovery from the backup, a report or hook failure
|
|
58
68
|
|
|
59
69
|
## Headless Progress Events
|
|
60
70
|
|
|
@@ -64,4 +74,4 @@ When `{headless_mode}` is true, emit a single-line JSON progress event to **stde
|
|
|
64
74
|
- exit (just before chaining): `{"stage":N,"name":"<slug>","status":"done"}`
|
|
65
75
|
- on HARD HALT: `{"stage":N,"name":"<slug>","status":"halt","exit":<code>}` instead of `"done"`
|
|
66
76
|
|
|
67
|
-
`N` is the 0-indexed stage number (0
|
|
77
|
+
`N` is the 0-indexed stage number (0 to 10) and `<slug>` is the kebab portion of the step filename. For the non-numbered routing/terminal steps (`resume`, `health-check`) emit `"stage":null` with the slug. One line per event; do not pretty-print.
|
|
@@ -16,11 +16,13 @@ required; default filename `_campaign-directive.md`.
|
|
|
16
16
|
|
|
17
17
|
All optional — the directive may hold any combination of these, or none:
|
|
18
18
|
|
|
19
|
-
- **`## Quality Overrides
|
|
20
|
-
- **`## Skip List
|
|
19
|
+
- **`## Quality Overrides`**: operator adjustments to the quality gate, one list item each. `- soft_target: 85` and `- soft_fallback: 75` set the campaign-wide values, and `- <skill>: soft_target 80, soft_fallback 70` sets one skill's (either key alone is fine). A skill's line beats a campaign-wide line, and both beat the campaign brief and customize.toml. The hard gate cannot be overridden. They apply to each skill's test threshold (skill loop) and to the export classification (Capstone and Export).
|
|
20
|
+
- **`## Skip List`**: skills to skip during processing, one list item each: `- <skill>: <reason>`, the reason optional. The skill loop and the Tier B batch mark a listed skill `skipped` before it runs and log the reason.
|
|
21
21
|
- **`## Pipeline Flags`** — per-skill or campaign-wide pipeline modifiers.
|
|
22
22
|
- **`## Notes`** — free-form operator context for the agent processing the campaign.
|
|
23
23
|
|
|
24
|
+
`scripts/campaign-quality-gate.py` reads the Quality Overrides and Skip List sections (a section runs to the next `#` or `##` heading; backticks around a name are dropped), so their effect never depends on how a step reads the prose. A list item in them it cannot read is reported and logged, never applied, and a name that is no skill in the campaign is logged as a warning.
|
|
25
|
+
|
|
24
26
|
Any heading not listed above is treated as general guidance: read it and apply
|
|
25
27
|
judgment based on the content. This lets operators add ad-hoc context without
|
|
26
28
|
modifying this specification.
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
# ({project-root}/_bmad/skf/ when installed, {project-root}/src/ during
|
|
4
4
|
# development), NOT relative to this step file.
|
|
5
5
|
nextStepFile: 'shared/health-check.md'
|
|
6
|
-
stateFile: '{campaignWorkspacePath}/_campaign-state.yaml'
|
|
7
6
|
---
|
|
8
7
|
|
|
9
8
|
<!-- Config: communicate in {communication_language}. -->
|
|
@@ -12,24 +11,16 @@ stateFile: '{campaignWorkspacePath}/_campaign-state.yaml'
|
|
|
12
11
|
|
|
13
12
|
## STEP GOAL:
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
Chain to the shared workflow self-improvement health check at `{nextStepFile}`. This is the terminal step of skf-campaign: after the shared health check completes, the workflow is fully done.
|
|
15
|
+
|
|
16
|
+
In headless mode step 11 bound `{result_envelope_line}` to the campaign's `SKF_CAMPAIGN_RESULT_JSON` line without displaying it: the shared health check displays that line verbatim as the run's last line wherever it stops, so a `claude -p` caller reads the envelope as the final message.
|
|
16
17
|
|
|
17
18
|
## Rules
|
|
18
19
|
|
|
19
|
-
- No user-facing reports, file writes, or result contracts in this step
|
|
20
|
-
-
|
|
20
|
+
- No user-facing reports, file writes, or result contracts in this step: those belong in step 11
|
|
21
|
+
- Delegate directly to `{nextStepFile}` with no additional commentary
|
|
22
|
+
- Do not attempt any other action between loading this step and executing `{nextStepFile}`
|
|
21
23
|
|
|
22
24
|
## MANDATORY SEQUENCE
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
Read `campaign.health_findings_queue` from `{stateFile}` and carry it into the shared health check as the operator's **already-decided** routing consent (so the shared step does not re-prompt, satisfying its "explicit opt-in" requirement for non-bug findings):
|
|
27
|
-
|
|
28
|
-
- `"improvement"` — the operator opted in at setup: route this campaign's friction/gap findings to the shared improvement queue (the shared step's opt-in is pre-satisfied; do not re-prompt).
|
|
29
|
-
- `"local"` (default) — keep findings in the local queue only; do not submit to the shared queue.
|
|
30
|
-
|
|
31
|
-
If the state file is unreadable, default to `"local"` (never submit without consent).
|
|
32
|
-
|
|
33
|
-
### 2. Delegate
|
|
34
|
-
|
|
35
|
-
Load `{nextStepFile}`, read it fully, then execute it — applying the routing consent from step 1.
|
|
26
|
+
Load `{nextStepFile}`, read it fully, then execute it.
|
|
@@ -3,8 +3,9 @@ nextStepFile: 'step-02-strategy.md'
|
|
|
3
3
|
stateSchemaFile: 'assets/campaign-state-schema.json'
|
|
4
4
|
stateFile: '{campaignWorkspacePath}/_campaign-state.yaml'
|
|
5
5
|
briefFile: '{campaignWorkspacePath}/campaign-brief.yaml'
|
|
6
|
+
decisionLogFile: '{campaignWorkspacePath}/_campaign-decision-log.md'
|
|
6
7
|
templateFile: '{briefTemplatePath}'
|
|
7
|
-
|
|
8
|
+
stateScript: 'scripts/campaign-state.py'
|
|
8
9
|
manifestScript: 'scripts/campaign-parse-manifest.py'
|
|
9
10
|
---
|
|
10
11
|
|
|
@@ -16,99 +17,61 @@ manifestScript: 'scripts/campaign-parse-manifest.py'
|
|
|
16
17
|
|
|
17
18
|
Collect campaign inputs from the operator, create the initial `_campaign-state.yaml`, and generate `campaign-brief.yaml` so the campaign has a persistent starting point that survives context death.
|
|
18
19
|
|
|
19
|
-
This is the only step that creates the state file (it does not yet exist). All subsequent steps use **read-backup-modify-write** per the State Contract in `references/campaign-contracts.md`.
|
|
20
|
-
|
|
21
20
|
## RULES
|
|
22
21
|
|
|
23
|
-
- This step creates the state file
|
|
24
|
-
-
|
|
25
|
-
- If `{headless_mode}` is true, draw inputs from `--brief`/`--manifest` (On Activation step 4) and auto-proceed through confirmation gates with the default action, logging each auto-decision to the decision log.
|
|
22
|
+
- This is the only step that creates the state file, with the helper's `init` operation (`{stateScript}`); every later write goes through `{stateScript}` too (State Contract in `references/campaign-contracts.md`), so no target, timestamp or gate value is ever typed into the state or the brief by hand.
|
|
23
|
+
- If `{headless_mode}` is true, draw inputs from `--brief`/`--manifest` (On Activation step 4) and auto-proceed through confirmation gates with the default action, logging each auto-decision with `uv run {stateScript} log --log-file {decisionLogFile} --type auto --text '<entry>'`; emit this stage's progress events, and at any HARD HALT the error envelope, per `references/campaign-contracts.md`.
|
|
26
24
|
|
|
27
25
|
## TASKS
|
|
28
26
|
|
|
29
|
-
### §1
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
- `
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
- `
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
Default to `"local"` (project-local findings queue). Present the opt-in prompt:
|
|
50
|
-
|
|
51
|
-
> Send anonymized quality findings to the shared improvement queue? [y/N]
|
|
52
|
-
|
|
53
|
-
- **y** — set `health_findings_queue` to `"improvement"`
|
|
54
|
-
- **N** (default) — keep `health_findings_queue` as `"local"`
|
|
55
|
-
|
|
56
|
-
In headless mode: auto-select `"local"` (N) and log the auto-decision.
|
|
57
|
-
|
|
58
|
-
### §3 — Build State Object
|
|
59
|
-
|
|
60
|
-
Construct `_campaign-state.yaml` in memory from collected inputs. Use the campaign-wide quality gate resolved in On Activation: `{qualityGateHard}` / `{qualityGateSoftTarget}` / `{qualityGateSoftFallback}`. Note: `repo_url` (collected in §1) is NOT part of the state schema — it belongs in the brief only (§5). The state schema enforces `additionalProperties: false`, so including it would fail validation.
|
|
61
|
-
|
|
62
|
-
```yaml
|
|
63
|
-
campaign:
|
|
64
|
-
name: "{campaign_name}"
|
|
65
|
-
started_at: "{current_iso8601_with_tz}"
|
|
66
|
-
last_updated: "{current_iso8601_with_tz}"
|
|
67
|
-
current_stage: 0
|
|
68
|
-
directive_path: "{directive_path or omit if not provided}"
|
|
69
|
-
architecture_doc_path: "{architecture_doc_path or omit if not provided}"
|
|
70
|
-
quality_gate:
|
|
71
|
-
hard: "{qualityGateHard}"
|
|
72
|
-
soft_target: {qualityGateSoftTarget}
|
|
73
|
-
soft_fallback: {qualityGateSoftFallback}
|
|
74
|
-
health_findings_queue: "{local or improvement}"
|
|
75
|
-
skills:
|
|
76
|
-
# One entry per target:
|
|
77
|
-
- name: "{target.name}"
|
|
78
|
-
status: "pending"
|
|
79
|
-
depends_on: [] # from target.depends_on
|
|
80
|
-
tier: "{target.tier}"
|
|
81
|
-
pin: null # from target.pin
|
|
82
|
-
brief_path: null # populated in step-05 once BS produces the skill's brief
|
|
83
|
-
skill_path: null
|
|
84
|
-
quality_score: null
|
|
85
|
-
workarounds_applied: []
|
|
86
|
-
started_at: null
|
|
87
|
-
completed_at: null
|
|
88
|
-
dependency_graph:
|
|
89
|
-
execution_order: [] # populated by step-02-strategy
|
|
90
|
-
circular_deps_detected: false
|
|
91
|
-
```
|
|
27
|
+
### §1: Collect Inputs
|
|
28
|
+
|
|
29
|
+
A campaign needs a `campaign_name` and its target libraries. Each target has:
|
|
30
|
+
|
|
31
|
+
- `name`: skill name
|
|
32
|
+
- `repo_url`: source repository URL
|
|
33
|
+
- `tier`: `"A"` (full pipeline) or `"B"` (batch)
|
|
34
|
+
- `pin`: version pin (string), or `null` for latest
|
|
35
|
+
- `depends_on`: array of skill names this target depends on (may be empty)
|
|
36
|
+
|
|
37
|
+
Two paths are optional:
|
|
38
|
+
|
|
39
|
+
- `directive_path`: a `_campaign-directive.md` file with operator directives (contract: `references/campaign-directive-spec.md`)
|
|
40
|
+
- `architecture_doc_path`: the architecture document the verify (Stage 7) and refine (Stage 8) stages consume. If omitted here, those stages discover it at runtime (`{project-root}/docs/architecture.md`, then `{project-root}/_bmad-output/planning-artifacts/architecture.md`). Capturing it now persists the choice across resume and avoids re-prompting.
|
|
41
|
+
|
|
42
|
+
A field no source gives takes its default: `tier` `"A"`, `pin` `null`, `depends_on` empty, and `campaign_name` the brief's `campaign_name`, else `{project_name}`. A Tier A target may not depend on a Tier B target: Tier B skills are built after the skill loop, so Strategy rejects that plan.
|
|
43
|
+
|
|
44
|
+
Every target goes through `{manifestScript}`, whatever its source, so no target reaches state unchecked. It rejects a malformed target, a `repo_url` that is no GitHub repository (it reads a URL, an SSH URL or `owner/repo`, and writes each as `https://github.com/<owner>/<repo>`), a name that is no skill name (lower-case letters, digits and hyphens, at most 64 characters), a Tier A pin that is no X.Y.Z version (the only pin brief-skill builds from) and a duplicate name. It fills an empty name from the repository (`filled_names`), and lists each `depends_on` name that is no target (`dangling_depends_on`) and each Tier A target that depends on a Tier B target (`tier_inversions`), each entry naming its `skill` and `depends_on`. The state and the brief take their targets from the script's `targets[]`, never from the raw source.
|
|
45
|
+
|
|
46
|
+
**Manifest format** (a `--manifest` file, and a pasted list rewritten for the script): one `name,repo_url,tier,pin` target per line, where an empty `name` takes the repository's name and an empty `pin` means the latest release; a trailing `;dep1,dep2` segment sets `depends_on`; blank and `#` lines are skipped.
|
|
92
47
|
|
|
93
|
-
|
|
48
|
+
**Headless** (`--brief` and `--manifest` imply it): take the inputs from the source On Activation parsed. Parse a `--manifest` file with `uv run {manifestScript} <manifest-file>` and a `--brief` file with `uv run {manifestScript} --brief <brief-file>`, which also returns the brief's `campaign_name`, `quality_gate`, `architecture_doc_path` and `notes` under `brief`. Headless asks nothing about `dangling_depends_on` or `tier_inversions`: Strategy halts on them (exit code 4).
|
|
94
49
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
50
|
+
**Interactive:** open with this one question, and ask nothing before it:
|
|
51
|
+
|
|
52
|
+
> Share the targets for this campaign in whatever form you have them: a manifest or `campaign-brief.yaml` path, a pasted list, or repository URLs. Add a campaign name and a directive or architecture document path if you have them.
|
|
53
|
+
|
|
54
|
+
Turn the answer into targets: a manifest path goes through `uv run {manifestScript} <manifest-file>`, and a brief path through `uv run {manifestScript} --brief <brief-file>`. A pasted list or bare repository URLs are first rewritten as manifest lines in the manifest format above (leave the name empty when none is given: the script takes it from the repository), then piped to `uv run {manifestScript} -`. Show the drafted campaign once for correction: the campaign name, the directive and architecture paths (or none), and one table of the targets with `name`, `repo_url`, `tier`, `pin` and `depends_on`. After the operator's corrections, ask only about what is still missing or ambiguous, all in one question, read from the script's output rather than by matching names yourself: each `dangling_depends_on` entry (a `depends_on` name that is no target), each `tier_inversions` entry (make the dependency Tier A, or drop it) and each `filled_names` entry (confirm the name). Run a corrected set through the script again before §2.
|
|
55
|
+
|
|
56
|
+
A target the script rejects (`errors[]` non-empty, exit 1: a malformed manifest line or brief target, a `repo_url` that is no GitHub repository, a name that is no skill name, a Tier A pin that is no X.Y.Z version, a duplicate name, a brief `pin` that is not a string) never yields a partial target set: in headless, HALT (exit code 2, `invalid-input`) listing each error's line or target number and message; interactively, show them and ask for those targets corrected. An exit 2 (a file that is missing, unreadable or not a YAML mapping) HALTs (exit code 2, `invalid-input`) with its `error`.
|
|
57
|
+
|
|
58
|
+
If no targets can be collected (an empty answer, or an empty `--brief` or `--manifest`), HALT (exit code 2, `invalid-input`) with guidance: a campaign needs at least one target.
|
|
59
|
+
|
|
60
|
+
### §2: Create State
|
|
61
|
+
|
|
62
|
+
Settle the campaign name (the brief's `campaign_name`, else the operator's, else `{project_name}`), then create the state in one call. Pipe in the parse of the settled targets: the last §1 parse run again (the manifest file, `--brief <brief-file>`, or the corrected manifest lines on stdin), so the state takes its targets from the script's `targets[]`, never from the raw source:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
uv run {manifestScript} <the settled source> | uv run {stateScript} init --state-file {stateFile} --targets-file - --name "<campaign_name>" --hard "{qualityGateHard}" --soft-target {qualityGateSoftTarget} --soft-fallback {qualityGateSoftFallback} [--brief-file <brief-file>] [--directive-path <directive_path>] [--architecture-doc-path <architecture_doc_path>] --brief-out {briefFile} --brief-template {templateFile} [--notes '<operator notes>']
|
|
66
|
+
```
|
|
98
67
|
|
|
99
|
-
|
|
68
|
+
Pass `--brief-file` when the targets came from a campaign brief: each value its `quality_gate` gives wins over the customize.toml one. The directive's `## Quality Overrides` apply later, while the campaign runs, and are never written here. The helper settles and checks the gate with `campaign-quality-gate.py check`, creates `{campaignWorkspacePath}/`, writes every target as a `pending` skill, stamps `started_at` and `last_updated` from the clock, and validates the state before it writes it. There is no earlier state, so no `.bak` is written. It then writes `{briefFile}` from `{templateFile}`: the campaign name, `created_at` (the state's `started_at`), the same `targets[]`, one entry per target with `name`, `repo_url`, `tier`, `pin` and `depends_on`, plus every other field its source gave it (a language or scope hint, for example), the settled `quality_gate`, `architecture_doc_path` and `notes`. `repo_url` lives only in the brief: the state schema has no place for it. Pass `--notes` only with notes the operator gave, single-quoted as a decision-log entry is (`references/campaign-contracts.md`); without it a brief's own `notes` carry over.
|
|
100
69
|
|
|
101
|
-
|
|
70
|
+
On exit 2, HALT (exit code 2, `invalid-input`) with its `error` and `errors[]`; nothing is written: a gate the gate script rejects (a hard gate other than `zero-critical-high`, a soft value outside 0 to 100, a fallback above the target, or a brief it cannot read), targets that hold errors, a brief template that is no YAML mapping, or a state file or backup that already exists. On exit 3, HALT (exit code 3, `invalid-state`) with its `errors[]`.
|
|
102
71
|
|
|
103
|
-
|
|
104
|
-
- `created_at` — current ISO-8601 timestamp with timezone
|
|
105
|
-
- `targets` — array of target entries with `name`, `repo_url`, `tier`, `pin`, `depends_on`
|
|
106
|
-
- `quality_gate` — `{qualityGateHard}` / `{qualityGateSoftTarget}` / `{qualityGateSoftFallback}`
|
|
107
|
-
- `health_findings_queue` — from the §2 preference decision
|
|
108
|
-
- `architecture_doc_path` — from collected input, or empty string if not provided
|
|
109
|
-
- `notes` — operator-provided context, or empty string
|
|
72
|
+
### §3: The Brief
|
|
110
73
|
|
|
111
|
-
|
|
74
|
+
`init` (§2) wrote `{briefFile}` from the same `targets[]`, so write nothing by hand: it is the machine-readable snapshot a fresh session resumes from.
|
|
112
75
|
|
|
113
76
|
## OUTPUT
|
|
114
77
|
|
|
@@ -116,6 +79,5 @@ Confirm state file creation and brief generation. Display summary:
|
|
|
116
79
|
|
|
117
80
|
- Campaign name
|
|
118
81
|
- Number of targets
|
|
119
|
-
- Health queue setting
|
|
120
82
|
|
|
121
83
|
Chain to `{nextStepFile}`.
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
nextStepFile: 'step-03-pins.md'
|
|
3
3
|
stateSchemaFile: 'assets/campaign-state-schema.json'
|
|
4
4
|
stateFile: '{campaignWorkspacePath}/_campaign-state.yaml'
|
|
5
|
-
|
|
5
|
+
decisionLogFile: '{campaignWorkspacePath}/_campaign-decision-log.md'
|
|
6
6
|
depsScript: 'scripts/campaign-deps.py'
|
|
7
|
+
stateScript: 'scripts/campaign-state.py'
|
|
7
8
|
validateScript: 'scripts/campaign-validate-state.py'
|
|
8
9
|
---
|
|
9
10
|
|
|
@@ -17,51 +18,41 @@ Compute the execution order from dependency edges, detect circular dependencies,
|
|
|
17
18
|
|
|
18
19
|
## RULES
|
|
19
20
|
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
- Update `campaign.current_stage` to `1`.
|
|
24
|
-
- Update `campaign.last_updated` to current ISO-8601 with timezone on every write.
|
|
25
|
-
- If `{headless_mode}` is true, auto-proceed through confirmation gates with the default action and log each auto-decision.
|
|
21
|
+
- Write `campaign.current_stage` = 1 only in this stage's final state write, after every gate: step-resume resumes at `current_stage + 1`, so an early write skips unfinished work. Here that write follows the §6 plan gate, so a campaign cancelled at the plan shows the plan again when it resumes.
|
|
22
|
+
- Write state and decision-log entries only through `{stateScript}`, and on a non-zero exit HALT with the same code (State Contract in `references/campaign-contracts.md`). A log entry is `uv run {stateScript} log --log-file {decisionLogFile} --type <decision|auto|event> --text '<entry>'`.
|
|
23
|
+
- If `{headless_mode}` is true, auto-proceed through the plan gate with its default action and log the auto-decision; emit this stage's progress events, and at any HARD HALT the error envelope, per `references/campaign-contracts.md`.
|
|
26
24
|
|
|
27
25
|
## TASKS
|
|
28
26
|
|
|
29
|
-
### §1
|
|
27
|
+
### §1: Read + Validate State
|
|
30
28
|
|
|
31
29
|
Load `{stateFile}`. Run `uv run {validateScript} --state-file {stateFile}`; on non-zero, HALT (exit 3) with the script's `errors[]`.
|
|
32
30
|
|
|
33
|
-
### §2
|
|
34
|
-
|
|
35
|
-
Copy `{stateFile}` to `{backupFile}` before any modification.
|
|
36
|
-
|
|
37
|
-
### §3 — Read Directive
|
|
31
|
+
### §2: Read Directive
|
|
38
32
|
|
|
39
33
|
If `campaign.directive_path` is set in state, load the file at that path and apply its contents as campaign-wide context for this stage's processing, per the directive contract in `references/campaign-directive-spec.md`. If the file is not found, continue without error (directive is optional).
|
|
40
34
|
|
|
41
|
-
### §
|
|
35
|
+
### §3: Compute Execution Order
|
|
42
36
|
|
|
43
|
-
Run the deterministic topological sort
|
|
37
|
+
Run the deterministic topological sort; do not hand-compute it:
|
|
44
38
|
|
|
45
39
|
```
|
|
46
40
|
uv run {depsScript} --compute --state-file {stateFile}
|
|
47
41
|
```
|
|
48
42
|
|
|
49
|
-
Parse the JSON output: `execution_order` (the ordered skill names
|
|
43
|
+
Parse the JSON output: `execution_order` (the ordered skill names: Kahn's sort with Tier A placed before Tier B within a dependency level), `circular_deps_detected` (bool), `cycle_participants` (the unplaced skills when a cycle exists, else null), `tier_counts` (`{"A": n, "B": m}`, for the §5 strategy view) and `tier_inversions` (each Tier A `skill` that `depends_on` a Tier B skill). Script exit 1 signals a plan the stages cannot follow (a cycle, a dangling `depends_on` reference or a tier inversion), handled at §4 before the §5 view shows any order. Script exit 2 signals the helper could not read/parse the state file; HALT (exit code 2, `invalid-input`) surfacing its error.
|
|
50
44
|
|
|
51
|
-
### §
|
|
45
|
+
### §4: Handle Unorderable Graph
|
|
52
46
|
|
|
53
|
-
If the graph cannot be
|
|
47
|
+
If the graph cannot be followed (script exit 1), HALT (exit code 4, `circular-deps`): the execution order is impossible, so do not proceed. Three cases:
|
|
54
48
|
|
|
55
49
|
- **Cycle** (`circular_deps_detected: true`): list `cycle_participants` and their mutual `depends_on` edges.
|
|
56
50
|
- **Dangling reference** (a `DANGLING_DEPENDENCY` error with no `execution_order`): name the skill and the unknown dependency it references.
|
|
51
|
+
- **Tier A on Tier B** (`tier_inversions` non-empty, a `TIER_INVERSION` error): name each `skill` and the Tier B skill it `depends_on`. Tier B skills are built in the batch stage, after the skill loop, so the Tier A skill could never pass its dependency gate. Guidance: make the dependency Tier A, or drop the dependency, then re-run `campaign` and choose overwrite.
|
|
57
52
|
|
|
58
|
-
### §
|
|
59
|
-
|
|
60
|
-
Set `dependency_graph.execution_order` to the computed order. Set `dependency_graph.circular_deps_detected` to the detection result. Set `campaign.current_stage` to `1`. Set `campaign.last_updated` to current ISO-8601 with timezone. Write to `{stateFile}`.
|
|
53
|
+
### §5: Present Strategy View
|
|
61
54
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
Display a human-readable strategy summary to the operator (not written to a file — display only):
|
|
55
|
+
Display a human-readable strategy summary to the operator (display only: it is not written to a file):
|
|
65
56
|
|
|
66
57
|
```
|
|
67
58
|
CAMPAIGN STRATEGY: {campaign_name}
|
|
@@ -86,17 +77,27 @@ TIER DISTRIBUTION:
|
|
|
86
77
|
Tier B (QS batch): {count}
|
|
87
78
|
```
|
|
88
79
|
|
|
89
|
-
Fill the TIER DISTRIBUTION counts from `tier_counts` in the §
|
|
80
|
+
Fill the TIER DISTRIBUTION counts from `tier_counts` in the §3 script output; do not re-tally `skills[]` by hand.
|
|
90
81
|
|
|
91
|
-
### §
|
|
82
|
+
### §6: Plan Confirmation Gate
|
|
92
83
|
|
|
93
84
|
The strategy view is the last review surface before a potentially long, mostly-unattended run begins. Present a confirmation gate:
|
|
94
85
|
|
|
95
|
-
- `[P]roceed
|
|
96
|
-
- `[C]ancel
|
|
86
|
+
- `[P]roceed`: write the plan (§7), then chain to `{nextStepFile}`.
|
|
87
|
+
- `[C]ancel`: log the cancel, then stop with exit code 12 (`user-cancelled`). Nothing of this stage is written, so the state is intact and a resume shows this plan again. To change targets, tiers, pins or dependencies, re-run `campaign` and choose overwrite: they live in the state that Setup wrote, and editing `campaign-brief.yaml` does not reach them.
|
|
88
|
+
|
|
89
|
+
**HALT and wait for operator input.** **GATE [default: P]**: in headless mode, auto-proceed with `[P]` and log "headless: auto-proceed past plan-confirmation gate" (type `auto`).
|
|
90
|
+
|
|
91
|
+
### §7: Write State
|
|
92
|
+
|
|
93
|
+
On `[P]roceed`, write the plan and the stage in one write:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
uv run {stateScript} apply-plan --state-file {stateFile} --stage 1
|
|
97
|
+
```
|
|
97
98
|
|
|
98
|
-
|
|
99
|
+
It sets `dependency_graph.execution_order` and `circular_deps_detected` from the same `campaign-deps.py --compute` the §3 view came from, so the order on disk is the order shown. On exit 4 (the graph can no longer be followed: the state changed since §3), HALT (exit code 4, `circular-deps`) with its `errors[]`; on exit 3, HALT (exit code 3, `invalid-state`).
|
|
99
100
|
|
|
100
101
|
## OUTPUT
|
|
101
102
|
|
|
102
|
-
Confirm strategy computed, display the strategy view, and
|
|
103
|
+
Confirm strategy computed, display the strategy view, resolve the §6 gate and write the §7 plan. Chain to `{nextStepFile}`.
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
nextStepFile: 'step-04-provenance.md'
|
|
3
3
|
stateSchemaFile: 'assets/campaign-state-schema.json'
|
|
4
4
|
stateFile: '{campaignWorkspacePath}/_campaign-state.yaml'
|
|
5
|
-
backupFile: '{campaignWorkspacePath}/_campaign-state.yaml.bak'
|
|
6
5
|
briefFile: '{campaignWorkspacePath}/campaign-brief.yaml'
|
|
6
|
+
pinResultsFile: '{campaignWorkspacePath}/_pin-results.json'
|
|
7
|
+
decisionLogFile: '{campaignWorkspacePath}/_campaign-decision-log.md'
|
|
7
8
|
pinScript: 'scripts/campaign-validate-pins.py'
|
|
9
|
+
stateScript: 'scripts/campaign-state.py'
|
|
8
10
|
validateScript: 'scripts/campaign-validate-state.py'
|
|
9
11
|
---
|
|
10
12
|
|
|
@@ -18,39 +20,45 @@ Validate all version pins against real releases/branches before the campaign pro
|
|
|
18
20
|
|
|
19
21
|
## RULES
|
|
20
22
|
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
- HALT (exit code 5, `invalid-pin`) on any invalid pin — invalid pins are errors, not gates.
|
|
26
|
-
- If `{headless_mode}` is true, auto-proceed through confirmation gates with the default action and log each auto-decision.
|
|
23
|
+
- Write `campaign.current_stage` = 2 only in this stage's final state write, after every gate: step-resume resumes at `current_stage + 1`, so an early write skips unfinished work.
|
|
24
|
+
- Write state and decision-log entries only through `{stateScript}`, and on a non-zero exit HALT with the same code (State Contract in `references/campaign-contracts.md`). A log entry is `uv run {stateScript} log --log-file {decisionLogFile} --type <decision|auto|event> --text '<entry>'`.
|
|
25
|
+
- HALT (exit code 5, `invalid-pin`) on any invalid pin: invalid pins are errors, not gates.
|
|
26
|
+
- If `{headless_mode}` is true, emit this stage's progress events, and at any HARD HALT the error envelope, per `references/campaign-contracts.md`.
|
|
27
27
|
|
|
28
28
|
## TASKS
|
|
29
29
|
|
|
30
|
-
### §1
|
|
30
|
+
### §1: Read + Validate State
|
|
31
31
|
|
|
32
32
|
Load `{stateFile}`. Run `uv run {validateScript} --state-file {stateFile}`; on non-zero, HALT (exit 3) with the script's `errors[]`.
|
|
33
33
|
|
|
34
|
-
### §2
|
|
34
|
+
### §2: Read Brief
|
|
35
35
|
|
|
36
|
-
Load `{briefFile}
|
|
36
|
+
Load `{briefFile}` only to confirm it parses (the pin script reads it directly). HALT (exit code 8, `missing-brief`) if the brief is missing or unreadable.
|
|
37
37
|
|
|
38
|
-
### §3
|
|
38
|
+
### §3: Validate Pins
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
Run the pin script, keeping its JSON output in `{pinResultsFile}` for §5:
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
```
|
|
43
|
+
uv run {pinScript} --state-file {stateFile} --brief-file {briefFile} > {pinResultsFile}
|
|
44
|
+
```
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
If the script exits 2 (a required tool such as `gh` is unavailable, a file is unreadable, or `INVALID_BRIEF`: a brief that is no mapping or holds a target with no `name` or no `repo_url`), HALT (exit code 2, `invalid-input`) surfacing its error; only when `gh` is what is missing, add that pins cannot be validated without it. Otherwise read `{pinResultsFile}`. For each result: if `status` is `"valid"` or `"resolved"`, the pin is good; if `"invalid"`, collect the failure with suggestions.
|
|
45
47
|
|
|
46
|
-
### §
|
|
48
|
+
### §4: Handle Invalid Pins
|
|
47
49
|
|
|
48
50
|
If ANY pins are invalid, collect ALL failures first (all-or-nothing pattern), then HALT (exit code 5, `invalid-pin`) with a clear error listing each invalid pin, the skill name, the attempted pin value, and suggested corrections. Do NOT partially proceed.
|
|
49
51
|
|
|
50
|
-
### §
|
|
52
|
+
### §5: Write State
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
Write every resolved pin and the stage in one write:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
uv run {stateScript} apply-pins --state-file {stateFile} --results-file {pinResultsFile} --stage 2
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
It sets each skill's `pin` to the script's `resolved_ref` wherever the two differ: a null pin that resolved to the latest release, or a pin written without its tag's form (`2.0.0` for the tag `v2.0.0`), so downstream steps use the exact ref name. It refuses results that hold an invalid pin (exit 5, nothing written: HALT as in §4); on exit 3, HALT (exit code 3, `invalid-state`).
|
|
53
61
|
|
|
54
62
|
## OUTPUT
|
|
55
63
|
|
|
56
|
-
Display pin validation summary
|
|
64
|
+
Display pin validation summary: for each skill, name, pin, resolved ref, ref type. Chain to `{nextStepFile}`.
|