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,6 +2,10 @@
|
|
|
2
2
|
stateSchemaFile: 'assets/campaign-state-schema.json'
|
|
3
3
|
stateFile: '{campaignWorkspacePath}/_campaign-state.yaml'
|
|
4
4
|
backupFile: '{campaignWorkspacePath}/_campaign-state.yaml.bak'
|
|
5
|
+
briefFile: '{campaignWorkspacePath}/campaign-brief.yaml'
|
|
6
|
+
resultContextFile: '{campaignWorkspacePath}/_result-context.json'
|
|
7
|
+
decisionLogFile: '{campaignWorkspacePath}/_campaign-decision-log.md'
|
|
8
|
+
stateScript: 'scripts/campaign-state.py'
|
|
5
9
|
validateScript: 'scripts/campaign-validate-state.py'
|
|
6
10
|
statusScript: 'scripts/campaign-status.py'
|
|
7
11
|
---
|
|
@@ -12,104 +16,69 @@ statusScript: 'scripts/campaign-status.py'
|
|
|
12
16
|
|
|
13
17
|
## STEP GOAL:
|
|
14
18
|
|
|
15
|
-
Validate campaign state integrity,
|
|
19
|
+
Validate campaign state integrity, recover it from its backup when it must, get the resume point from the state helper, and chain to that stage's step file.
|
|
16
20
|
|
|
17
21
|
## RULES
|
|
18
22
|
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
- If `{headless_mode}` is true, auto-proceed through any confirmation gates with the default action and log each auto-decision.
|
|
23
|
+
- Leave state untouched except for the two recovery or reset choices below (§1 backup restore, §3 `[R]e-run`), each through `{stateScript}`, and on a non-zero exit HALT with the same code. A log entry is `uv run {stateScript} log --log-file {decisionLogFile} --type <decision|auto|event> --text '<entry>'`.
|
|
24
|
+
- The chain target is the `step_file` the helper's `resume` operation (`{stateScript}`) returns: never work the stage out by hand.
|
|
25
|
+
- If `{headless_mode}` is true, auto-proceed through any confirmation gates with the default action and log each auto-decision (type `auto`); emit the progress events, and at any HARD HALT the error envelope, per `references/campaign-contracts.md`. A campaign already complete (§3) is no error halt: it ends with the success line.
|
|
23
26
|
|
|
24
27
|
## TASKS
|
|
25
28
|
|
|
26
|
-
### §1
|
|
29
|
+
### §1: Read + Validate State (with `.bak` recovery)
|
|
27
30
|
|
|
28
|
-
|
|
31
|
+
If neither `{stateFile}` nor `{backupFile}` exists, HALT (exit code 2, `invalid-input`): "No campaign state found. Run `campaign` to start a new campaign."
|
|
29
32
|
|
|
30
33
|
Run `uv run {validateScript} --state-file {stateFile}`. If it succeeds (exit 0), proceed to §2.
|
|
31
34
|
|
|
32
|
-
If it fails (primary missing
|
|
35
|
+
If it fails (primary missing, corrupt YAML or schema-invalid), recover from the backup rather than dead-halting. `{stateScript}` writes atomically, so its writes never leave a broken primary: the cause is a hand edit, disk damage, or a state written before v3.0.0.
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
### §2 — Backup Consistency Check
|
|
39
|
-
|
|
40
|
-
Check if `{backupFile}` exists.
|
|
41
|
-
|
|
42
|
-
**If `.bak` does not exist:** warn "No backup file found — campaign may have been created but never modified." Continue.
|
|
43
|
-
|
|
44
|
-
**If `.bak` exists** (and §1 did not already recover from it):
|
|
45
|
-
|
|
46
|
-
1. Run `uv run {validateScript} --state-file {backupFile}`. If invalid, warn: "Backup file fails validation — cannot use for recovery." Continue with the primary.
|
|
47
|
-
2. Compare primary vs backup deterministically: run `uv run {statusScript} --state-file {stateFile} --backup-file {backupFile}` and read `backup_comparison.primary_behind` (the script does the ISO-8601 timestamp and `current_stage` compares — do not order the timestamps by hand). If it is `true`, the primary looks behind the backup (possible crash during last write). Present a recovery choice:
|
|
48
|
-
- `[R]ecover` — copy `{backupFile}` over `{stateFile}` and resume from the backup's state.
|
|
49
|
-
- `[K]eep` — keep the primary as authoritative (the default).
|
|
50
|
-
|
|
51
|
-
In headless mode, default to `[K]eep` and log the auto-decision (a behind-backup primary may be intentional; never silently overwrite without a clear corruption signal — that case is handled in §1). Otherwise the primary is authoritative.
|
|
37
|
+
```
|
|
38
|
+
uv run {stateScript} recover --state-file {stateFile}
|
|
39
|
+
```
|
|
52
40
|
|
|
53
|
-
|
|
41
|
+
It copies `{backupFile}` over `{stateFile}` only when the backup validates. On exit 0, log "primary corrupt: recovered from backup as of {last_updated}" (type `event`, with the `last_updated` it returns), inform the operator, and continue with the recovered state. On exit 9 (the backup is missing or invalid too), HALT with exit code 9 (`corrupt-state`), reporting both the primary's validation errors and the recover call's `errors[]`, so the operator knows neither is usable.
|
|
54
42
|
|
|
55
|
-
|
|
43
|
+
### §2: Backup Check
|
|
56
44
|
|
|
57
|
-
|
|
45
|
+
Unless §1 recovered from it, check `{backupFile}`. When it does not exist, warn "No backup file found: campaign may have been created but never modified." When `uv run {validateScript} --state-file {backupFile}` fails, warn "Backup file fails validation: cannot use for recovery." Continue with the primary either way: each write copies the primary it replaces to `.bak`, so a valid primary is never older than its backup.
|
|
58
46
|
|
|
59
|
-
|
|
60
|
-
2. If not found → HALT (exit code 2, `invalid-input`): "Unknown skill '{name}'. Known skills: {comma-separated list of all skill names from state}."
|
|
61
|
-
3. If the skill's `status` is `"completed"`, `"failed"`, or `"skipped"`, the operator may have meant to re-run it (e.g. it passed with a low score) rather than skip past it. Present a choice:
|
|
62
|
-
- `[R]e-run` — reset the named skill to `"pending"` and resume from its stage. (Read-only step caveat: this single status reset follows read-backup-modify-write — back up first.)
|
|
63
|
-
- `[N]ext` — find the next skill in `dependency_graph.execution_order` after the named one whose `status` is `"pending"` or `"active"` and resume there. If none found → HALT (exit code 0, campaign already complete): "All remaining skills are complete. Run `campaign` to start a new campaign."
|
|
64
|
-
- `[H]alt` — stop without resuming.
|
|
47
|
+
### §3: Determine Resume Point
|
|
65
48
|
|
|
66
|
-
|
|
67
|
-
4. If an active skill already exists in `skills[]` AND it is a different skill from the `--from` target, warn: "Skill '{active_name}' is currently active — honoring explicit --from override."
|
|
68
|
-
5. Determine the target step file:
|
|
69
|
-
- Tier A skill with status `"pending"` or `"active"` → stage 4 (`step-05-skill-loop.md`)
|
|
70
|
-
- Tier B skill with status `"pending"` or `"active"` → stage 5 (`step-06-batch.md`)
|
|
49
|
+
Ask the state helper, passing `--from` when the invocation named a skill:
|
|
71
50
|
|
|
72
|
-
|
|
51
|
+
```
|
|
52
|
+
uv run {stateScript} resume --state-file {stateFile} [--from <skill>]
|
|
53
|
+
```
|
|
73
54
|
|
|
74
|
-
|
|
75
|
-
- If found and `tier == "A"` → resume target is stage 4 (`step-05-skill-loop.md`). The skill loop's §4 will skip completed skills until it reaches the active one.
|
|
76
|
-
- If found and `tier == "B"` → resume target is stage 5 (`step-06-batch.md`). The batch step processes Tier B skills.
|
|
77
|
-
2. If no active skill → the next stage to run is `campaign.current_stage + 1`, because `current_stage` records the highest **completed** stage (each stage writes its own number only after its work and gates finish, so a mid-stage halt leaves the previous stage's number on disk). **Terminal cap:** if `campaign.current_stage` is `10`, the resolved stage is `10` itself (`step-11-maintenance.md`) — never `11`; the existing terminal-HALT check in §4 governs whether a stage-10 campaign is already done.
|
|
78
|
-
3. Map the resolved stage number to the corresponding step file using the stage table in §4.
|
|
55
|
+
It returns the stage to resume and its `step_file`, with the `reason`: `active-skill` (a skill an interruption left `active` resumes its own stage, with no `+1`: a Tier A skill the skill loop, which skips finished skills until it reaches it; a Tier B skill the batch stage, whose batch script, `campaign-render-batch.py`, selects the interrupted active Tier B skills together with the pending ones, so resume resets no status), `next-stage` (the stage after `current_stage`, the highest completed stage), `terminal-cap` (stage 10 runs again, never a stage 11), `from-skill` or `from-next`. Then:
|
|
79
56
|
|
|
80
|
-
|
|
57
|
+
- **`complete: true`:** nothing is left to resume, which is no error halt: stop with exit code 0 and display "Campaign has reached its final stage. All skills have been processed." (after `--next`: "All remaining skills are complete. Run `campaign` to start a new campaign.") In headless mode, end with the campaign's success line instead of an error envelope. When `reason` is `complete` and `{resultContextFile}` exists (step-11 §2 wrote it), run `uv run {emitEnvelopeHelper} emit --workflow skf-campaign < {resultContextFile}` (the shared emitter: Result Contract in `references/campaign-contracts.md`); otherwise give the same command `{"status": "success", "skills_completed": <completed>, "skills_failed": <failed>, "decision_log": "{decisionLogFile}"}` on stdin, with the counts `uv run {statusScript} --state-file {stateFile}` returns. Display the line it prints verbatim as the run's last line, with nothing after it.
|
|
58
|
+
- **`stage` 1 with no `{briefFile}`:** Setup stopped after it wrote the state but before the brief, which every later stage reads: HALT (exit code 8, `missing-brief`): "Setup did not finish. Run `campaign` and choose overwrite to start the campaign again."
|
|
59
|
+
- **Exit 2** (an unknown `--from` skill): HALT (exit code 2, `invalid-input`) with its `error`, which lists the known skills.
|
|
60
|
+
- **`needs_choice: true`:** the `--from` skill is already `completed`, `failed` or `skipped` (`from_status`), and the operator may have meant to re-run it (e.g. it passed with a low score) rather than skip past it. Present a choice:
|
|
61
|
+
- `[R]e-run`: reset it with `uv run {stateScript} set-skill --state-file {stateFile} --skill <skill> --status pending`, then run the `resume` call again: it now resumes that skill's stage.
|
|
62
|
+
- `[N]ext`: run the `resume` call again with `--next`, which resumes at the next pending or active skill after it in `dependency_graph.execution_order`.
|
|
63
|
+
- `[H]alt`: stop without resuming.
|
|
81
64
|
|
|
82
|
-
|
|
65
|
+
**GATE [default: N]**: in headless mode, default to `[N]ext` and log the auto-decision. Log the chosen action (type `decision`).
|
|
66
|
+
- **`active_other`** set: warn "Skill '{active_other}' is currently active: honoring explicit --from override."
|
|
83
67
|
|
|
84
|
-
|
|
85
|
-
|-------|-----------|
|
|
86
|
-
| 0 | step-01-setup.md |
|
|
87
|
-
| 1 | step-02-strategy.md |
|
|
88
|
-
| 2 | step-03-pins.md |
|
|
89
|
-
| 3 | step-04-provenance.md |
|
|
90
|
-
| 4 | step-05-skill-loop.md |
|
|
91
|
-
| 5 | step-06-batch.md |
|
|
92
|
-
| 6 | step-07-capstone.md |
|
|
93
|
-
| 7 | step-08-verify.md |
|
|
94
|
-
| 8 | step-09-refine.md |
|
|
95
|
-
| 9 | step-10-export.md |
|
|
96
|
-
| 10 | step-11-maintenance.md |
|
|
68
|
+
### §4: Resume Routing
|
|
97
69
|
|
|
98
|
-
Derive the skill counts deterministically
|
|
70
|
+
Derive the skill counts deterministically: `uv run {statusScript} --state-file {stateFile}` returns `completed`, `total`, and the per-status counts (`pending` / `active` / `failed` / `skipped`); do not hand-count `skills[]`. Display a resume summary before chaining:
|
|
99
71
|
|
|
100
72
|
```
|
|
101
73
|
CAMPAIGN RESUME: {campaign.name}
|
|
102
74
|
|
|
103
|
-
Resuming from: Stage {
|
|
104
|
-
Target skill: {
|
|
75
|
+
Resuming from: Stage {stage} ({step_file})
|
|
76
|
+
Target skill: {skill} (if --from was used, otherwise "auto-detected" or "N/A")
|
|
105
77
|
Skills completed: {completed} / {total}
|
|
106
78
|
Skills remaining: {pending} pending, {active} active, {failed} failed, {skipped} skipped
|
|
107
79
|
Last updated: {campaign.last_updated}
|
|
108
80
|
```
|
|
109
81
|
|
|
110
|
-
If `campaign.current_stage` is `10` and all skills have status `"completed"`, `"failed"`, or `"skipped"`:
|
|
111
|
-
HALT (exit code 0, campaign already complete): "Campaign has reached its final stage. All skills have been processed."
|
|
112
|
-
|
|
113
82
|
## OUTPUT
|
|
114
83
|
|
|
115
|
-
Chain to the
|
|
84
|
+
Chain to the `step_file` §3 returned (a file in `references/`).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# /// script
|
|
2
|
-
# requires-python = ">=3.
|
|
2
|
+
# requires-python = ">=3.11"
|
|
3
3
|
# dependencies = ["pyyaml"]
|
|
4
4
|
# ///
|
|
5
5
|
"""Campaign Deps — dependency computation and enforcement for campaign skills.
|
|
@@ -8,6 +8,19 @@ Two modes:
|
|
|
8
8
|
--compute: topological sort of all skills from depends_on edges
|
|
9
9
|
--check: verify a single skill's dependencies are satisfied
|
|
10
10
|
|
|
11
|
+
A Tier A skill may not depend on a Tier B skill: Tier B skills are built in
|
|
12
|
+
the batch stage, after the skill loop that builds Tier A skills, so the Tier A
|
|
13
|
+
skill could never pass its dependency gate. --compute reports each such edge
|
|
14
|
+
in `tier_inversions` and exits 1, so the strategy stage rejects the plan
|
|
15
|
+
before any skill is built. That rule and the dangling-reference rule come
|
|
16
|
+
from campaign-parse-manifest.py's dependency_problems, the one statement of
|
|
17
|
+
both, so Setup and Strategy report the same entries.
|
|
18
|
+
|
|
19
|
+
At a blocked skill, --check names the status of each unmet dependency and the
|
|
20
|
+
headless default: `skip` when every unmet dependency failed or was skipped
|
|
21
|
+
(it can never complete in this run), `halt` when one is still pending or
|
|
22
|
+
active (an order the loop cannot follow).
|
|
23
|
+
|
|
11
24
|
CLI:
|
|
12
25
|
uv run campaign-deps.py --compute --state-file <path>
|
|
13
26
|
uv run campaign-deps.py --check --state-file <path> --skill <name>
|
|
@@ -16,28 +29,41 @@ CLI:
|
|
|
16
29
|
Output (JSON on stdout):
|
|
17
30
|
--compute:
|
|
18
31
|
{"execution_order": [...], "circular_deps_detected": bool,
|
|
19
|
-
"cycle_participants": [...] | null, "tier_counts": {"A": int, "B": int}
|
|
32
|
+
"cycle_participants": [...] | null, "tier_counts": {"A": int, "B": int},
|
|
33
|
+
"tier_inversions": [{"skill": "<Tier A>", "depends_on": "<Tier B>"}]}
|
|
20
34
|
|
|
21
35
|
--check:
|
|
22
|
-
{"skill": "name", "ready": bool, "unmet_deps": [...], "forced": bool
|
|
36
|
+
{"skill": "name", "ready": bool, "unmet_deps": [...], "forced": bool,
|
|
37
|
+
"unmet_status": {"<dep>": "<status>"}, "default_action": "skip" | "halt" | null}
|
|
23
38
|
|
|
24
39
|
Exit codes:
|
|
25
40
|
0 success / ready / force-override
|
|
26
|
-
1 circular deps / unmet deps / dangling reference
|
|
41
|
+
1 circular deps / tier inversion / unmet deps / dangling reference
|
|
27
42
|
2 error (missing file, bad YAML)
|
|
28
43
|
"""
|
|
29
44
|
|
|
30
45
|
from __future__ import annotations
|
|
31
46
|
|
|
32
47
|
import argparse
|
|
48
|
+
import importlib.util
|
|
33
49
|
import json
|
|
34
50
|
import sys
|
|
35
51
|
import heapq
|
|
36
52
|
from pathlib import Path
|
|
37
|
-
from typing import Any, Dict, List
|
|
53
|
+
from typing import Any, Dict, List
|
|
38
54
|
|
|
39
55
|
import yaml
|
|
40
56
|
|
|
57
|
+
MANIFEST_SCRIPT = Path(__file__).resolve().with_name("campaign-parse-manifest.py")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _dependency_problems(skills: List[Dict[str, Any]]) -> Dict[str, List[Dict[str, str]]]:
|
|
61
|
+
"""campaign-parse-manifest.py's dependency_problems (one rule for Setup and Strategy)."""
|
|
62
|
+
spec = importlib.util.spec_from_file_location("campaign_parse_manifest", MANIFEST_SCRIPT)
|
|
63
|
+
manifest = importlib.util.module_from_spec(spec)
|
|
64
|
+
spec.loader.exec_module(manifest)
|
|
65
|
+
return manifest.dependency_problems(skills)
|
|
66
|
+
|
|
41
67
|
|
|
42
68
|
def _emit_error(message: str, code: str) -> None:
|
|
43
69
|
json.dump({"error": message, "code": code}, sys.stderr)
|
|
@@ -53,17 +79,6 @@ def _build_skill_map(skills: List[Dict[str, Any]]) -> Dict[str, Dict[str, Any]]:
|
|
|
53
79
|
return {s["name"]: s for s in skills}
|
|
54
80
|
|
|
55
81
|
|
|
56
|
-
def _validate_deps(
|
|
57
|
-
skill_map: Dict[str, Dict[str, Any]],
|
|
58
|
-
) -> Optional[List[str]]:
|
|
59
|
-
dangling: List[str] = []
|
|
60
|
-
for name, skill in skill_map.items():
|
|
61
|
-
for dep in skill.get("depends_on", []) or []:
|
|
62
|
-
if dep not in skill_map:
|
|
63
|
-
dangling.append(f"{name} depends on unknown skill '{dep}'")
|
|
64
|
-
return dangling if dangling else None
|
|
65
|
-
|
|
66
|
-
|
|
67
82
|
def compute(state_file: str) -> int:
|
|
68
83
|
path = Path(state_file)
|
|
69
84
|
if not path.is_file():
|
|
@@ -89,7 +104,11 @@ def compute(state_file: str) -> int:
|
|
|
89
104
|
if tier in tier_counts:
|
|
90
105
|
tier_counts[tier] += 1
|
|
91
106
|
|
|
92
|
-
|
|
107
|
+
problems = _dependency_problems(list(skill_map.values()))
|
|
108
|
+
dangling = [
|
|
109
|
+
f"{d['skill']} depends on unknown skill '{d['depends_on']}'"
|
|
110
|
+
for d in problems["dangling_depends_on"]
|
|
111
|
+
]
|
|
93
112
|
if dangling:
|
|
94
113
|
_emit_error(
|
|
95
114
|
f"Dangling dependency references: {'; '.join(dangling)}",
|
|
@@ -97,6 +116,8 @@ def compute(state_file: str) -> int:
|
|
|
97
116
|
)
|
|
98
117
|
return 1
|
|
99
118
|
|
|
119
|
+
inversions = problems["tier_inversions"]
|
|
120
|
+
|
|
100
121
|
in_degree: Dict[str, int] = {name: 0 for name in skill_map}
|
|
101
122
|
adjacency: Dict[str, List[str]] = {name: [] for name in skill_map}
|
|
102
123
|
|
|
@@ -133,20 +154,29 @@ def compute(state_file: str) -> int:
|
|
|
133
154
|
"circular_deps_detected": True,
|
|
134
155
|
"cycle_participants": cycle_participants,
|
|
135
156
|
"tier_counts": tier_counts,
|
|
157
|
+
"tier_inversions": inversions,
|
|
136
158
|
}
|
|
137
159
|
json.dump(output, sys.stdout, separators=(",", ":"))
|
|
138
160
|
sys.stdout.write("\n")
|
|
139
161
|
return 1
|
|
140
162
|
|
|
163
|
+
if inversions:
|
|
164
|
+
_emit_error(
|
|
165
|
+
"Tier A skills depend on Tier B skills, which are built after them: "
|
|
166
|
+
+ "; ".join(f"{i['skill']} depends on {i['depends_on']}" for i in inversions),
|
|
167
|
+
"TIER_INVERSION",
|
|
168
|
+
)
|
|
169
|
+
|
|
141
170
|
output = {
|
|
142
171
|
"execution_order": execution_order,
|
|
143
172
|
"circular_deps_detected": False,
|
|
144
173
|
"cycle_participants": None,
|
|
145
174
|
"tier_counts": tier_counts,
|
|
175
|
+
"tier_inversions": inversions,
|
|
146
176
|
}
|
|
147
177
|
json.dump(output, sys.stdout, separators=(",", ":"))
|
|
148
178
|
sys.stdout.write("\n")
|
|
149
|
-
return 0
|
|
179
|
+
return 1 if inversions else 0
|
|
150
180
|
|
|
151
181
|
|
|
152
182
|
def check(state_file: str, skill_name: str, force: bool = False) -> int:
|
|
@@ -186,6 +216,13 @@ def check(state_file: str, skill_name: str, force: bool = False) -> int:
|
|
|
186
216
|
|
|
187
217
|
ready = len(unmet) == 0
|
|
188
218
|
forced = force and not ready
|
|
219
|
+
unmet_status = {dep: skill_map[dep].get("status") for dep in unmet}
|
|
220
|
+
if ready:
|
|
221
|
+
default_action = None
|
|
222
|
+
elif all(status in ("failed", "skipped") for status in unmet_status.values()):
|
|
223
|
+
default_action = "skip"
|
|
224
|
+
else:
|
|
225
|
+
default_action = "halt"
|
|
189
226
|
|
|
190
227
|
if forced:
|
|
191
228
|
json.dump(
|
|
@@ -199,6 +236,8 @@ def check(state_file: str, skill_name: str, force: bool = False) -> int:
|
|
|
199
236
|
"ready": ready,
|
|
200
237
|
"unmet_deps": unmet,
|
|
201
238
|
"forced": forced,
|
|
239
|
+
"unmet_status": unmet_status,
|
|
240
|
+
"default_action": default_action,
|
|
202
241
|
}
|
|
203
242
|
json.dump(output, sys.stdout, separators=(",", ":"))
|
|
204
243
|
sys.stdout.write("\n")
|