bmad-module-skill-forge 2.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +49 -49
- package/docs/404.md +10 -8
- package/docs/_data/pinned.yaml +22 -13
- package/docs/_internal/STABILITY.md +58 -35
- package/docs/agents.md +39 -53
- package/docs/architecture.md +65 -51
- package/docs/bmad-synergy.md +53 -51
- package/docs/campaign.md +127 -75
- package/docs/concepts.md +34 -28
- package/docs/examples.md +70 -68
- package/docs/forge-auto.md +34 -31
- package/docs/getting-started.md +118 -57
- package/docs/how-it-works.md +25 -21
- package/docs/index.md +15 -15
- package/docs/skill-model.md +70 -59
- package/docs/troubleshooting.md +143 -18
- package/docs/verifying-a-skill.md +87 -57
- package/docs/why-skf.md +24 -22
- package/docs/workflows.md +274 -110
- package/package.json +18 -10
- package/src/forger/preferences.yaml +8 -1
- package/src/knowledge/agentskills-spec.md +2 -0
- package/src/knowledge/ccc-bridge.md +40 -24
- package/src/knowledge/confidence-tiers.md +9 -5
- package/src/knowledge/overview.md +3 -3
- package/src/knowledge/progressive-capability.md +8 -8
- package/src/knowledge/provenance-tracking.md +9 -5
- package/src/knowledge/qmd-registry.md +3 -3
- package/src/knowledge/skf-knowledge-index.csv +2 -2
- package/src/knowledge/skill-lifecycle.md +18 -11
- package/src/knowledge/split-body-strategy.md +0 -3
- package/src/knowledge/tool-resolution.md +4 -2
- package/src/knowledge/version-paths.md +101 -15
- package/src/module-help.csv +3 -3
- package/src/module.yaml +10 -0
- package/src/shared/data/ast-grep-recipes.yaml +608 -0
- package/src/shared/data/ide-context-files.json +30 -0
- package/src/shared/health-check.md +31 -59
- package/src/shared/references/description-guard-protocol.md +12 -9
- package/src/shared/references/feasibility-report-schema.md +19 -13
- package/src/shared/references/headless-gate-convention.md +55 -3
- package/src/shared/references/output-contract-schema.md +19 -8
- package/src/shared/references/pipeline-contracts.md +94 -29
- package/src/shared/references/tessl-review.md +77 -0
- package/src/shared/scripts/schemas/skf-analyze-result-envelope.v1.json +194 -0
- package/src/shared/scripts/schemas/skf-audit-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +32 -4
- package/src/shared/scripts/schemas/skf-campaign-result-envelope.v1.json +174 -0
- package/src/shared/scripts/schemas/skf-create-skill-result-envelope.v1.json +284 -0
- package/src/shared/scripts/schemas/skf-drop-skill-result-envelope.v1.json +164 -0
- package/src/shared/scripts/schemas/skf-export-result-envelope.v1.json +160 -0
- package/src/shared/scripts/schemas/skf-quick-skill-result-envelope.v1.json +261 -0
- package/src/shared/scripts/schemas/skf-refine-architecture-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-rename-skill-result-envelope.v1.json +179 -0
- package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +27 -11
- package/src/shared/scripts/schemas/skf-stack-result-envelope.v1.json +176 -0
- package/src/shared/scripts/schemas/skf-test-result-envelope.v1.json +173 -0
- package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +19 -5
- package/src/shared/scripts/schemas/skf-verify-stack-result-envelope.v1.json +180 -0
- package/src/shared/scripts/schemas/skill-brief.v1.json +34 -0
- package/src/shared/scripts/schemas/workspace-detection.v1.json +1 -1
- package/src/shared/scripts/skf-atomic-write.py +233 -64
- package/src/shared/scripts/skf-build-change-manifest.py +2753 -28
- package/src/shared/scripts/skf-ccc-git-hygiene.py +532 -0
- package/src/shared/scripts/skf-check-unit-records.py +184 -0
- package/src/shared/scripts/skf-check-workspace-drift.py +538 -9
- package/src/shared/scripts/skf-classify-changed-files.py +772 -0
- package/src/shared/scripts/skf-comention-pairs.py +1333 -123
- package/src/shared/scripts/skf-compare-file-hashes.py +267 -105
- package/src/shared/scripts/skf-count-imports.py +1867 -0
- package/src/shared/scripts/skf-count-tokens.py +1 -1
- package/src/shared/scripts/skf-derive-assembly-shape.py +21 -3
- package/src/shared/scripts/skf-description-guard.py +99 -11
- package/src/shared/scripts/skf-detect-docs.py +694 -2
- package/src/shared/scripts/skf-detect-language.py +486 -107
- package/src/shared/scripts/skf-detect-registry.py +887 -0
- package/src/shared/scripts/skf-detect-scripts-assets.py +197 -55
- package/src/shared/scripts/skf-detect-tools.py +209 -27
- package/src/shared/scripts/skf-detect-workspaces.py +506 -30
- package/src/shared/scripts/skf-disqualify-candidates.py +821 -182
- package/src/shared/scripts/skf-emit-brief-result-envelope.py +69 -191
- package/src/shared/scripts/skf-emit-result-envelope.py +1604 -106
- package/src/shared/scripts/skf-enumerate-stack-skills.py +986 -117
- package/src/shared/scripts/skf-extract-public-api.py +5247 -96
- package/src/shared/scripts/skf-extraction-inventory.py +1280 -0
- package/src/shared/scripts/skf-extraction-snapshot.py +664 -0
- package/src/shared/scripts/skf-fetch-temporal.py +674 -0
- package/src/shared/scripts/skf-find-cycles.py +97 -29
- package/src/shared/scripts/skf-find-test-report.py +476 -0
- package/src/shared/scripts/skf-forge-tier-rw.py +469 -205
- package/src/shared/scripts/skf-github-fetch.py +365 -0
- package/src/shared/scripts/skf-github-probe.py +700 -0
- package/src/shared/scripts/skf-hash-content.py +180 -20
- package/src/shared/scripts/skf-language-corpora.py +1 -1
- package/src/shared/scripts/skf-load-provenance.py +161 -27
- package/src/shared/scripts/skf-manifest-ops.py +1 -1
- package/src/shared/scripts/skf-merge-ccc-exclusions.py +2307 -223
- package/src/shared/scripts/skf-merge-doc-urls.py +143 -20
- package/src/shared/scripts/skf-names-present.py +221 -0
- package/src/shared/scripts/skf-pair-intersect.py +119 -28
- package/src/shared/scripts/skf-parse-gaps.py +1384 -0
- package/src/shared/scripts/skf-preapply.py +1 -1
- package/src/shared/scripts/skf-preflight.py +176 -28
- package/src/shared/scripts/skf-promote-staged.py +430 -0
- package/src/shared/scripts/skf-provenance-gap-dispatch.py +64 -8
- package/src/shared/scripts/skf-qmd-classify-collections.py +229 -45
- package/src/shared/scripts/skf-quick-batch.py +774 -0
- package/src/shared/scripts/skf-rebuild-managed-sections.py +972 -88
- package/src/shared/scripts/skf-recommend-scope-type.py +323 -156
- package/src/shared/scripts/skf-render-metadata-stats.py +156 -12
- package/src/shared/scripts/skf-render-quick-metadata.py +132 -28
- package/src/shared/scripts/skf-render-stack-metadata.py +976 -0
- package/src/shared/scripts/skf-resolve-authoritative-files.py +155 -14
- package/src/shared/scripts/skf-resolve-package.py +523 -106
- package/src/shared/scripts/skf-rewrite-skill-name.py +433 -47
- package/src/shared/scripts/skf-run-lock.py +577 -0
- package/src/shared/scripts/skf-scan-manifests.py +998 -57
- package/src/shared/scripts/skf-scan-skill-md-structure.py +1341 -37
- package/src/shared/scripts/skf-severity-classify.py +712 -108
- package/src/shared/scripts/skf-shape-detect.py +298 -204
- package/src/shared/scripts/skf-shard-body.py +9 -8
- package/src/shared/scripts/skf-skill-inventory.py +2412 -89
- package/src/shared/scripts/skf-skills-module.py +472 -0
- package/src/shared/scripts/skf-source-tree.py +1796 -0
- package/src/shared/scripts/skf-structural-diff.py +787 -121
- package/src/shared/scripts/skf-tessl-review.py +706 -0
- package/src/shared/scripts/skf-update-active-symlink.py +120 -67
- package/src/shared/scripts/skf-update-run-state.py +624 -0
- package/src/shared/scripts/skf-validate-brief-inputs.py +92 -29
- package/src/shared/scripts/skf-validate-brief-schema.py +23 -2
- package/src/shared/scripts/skf-validate-feasibility-report.py +577 -66
- package/src/shared/scripts/skf-validate-frontmatter.py +103 -26
- package/src/shared/scripts/skf-validate-output.py +712 -64
- package/src/shared/scripts/skf-validate-pins.py +1 -1
- package/src/shared/scripts/skf-verify-no-trace.py +116 -10
- package/src/shared/scripts/skf-verify-provenance-completeness.py +3945 -152
- package/src/shared/scripts/skf-write-skill-brief.py +406 -25
- package/src/shared/tool-requirements.yaml +201 -0
- package/src/skf-analyze-source/SKILL.md +41 -36
- package/src/skf-analyze-source/assets/skill-brief-schema.md +7 -8
- package/src/skf-analyze-source/customize.toml +36 -24
- package/src/skf-analyze-source/references/auto-docs-only.md +58 -20
- package/src/skf-analyze-source/references/continue.md +2 -13
- package/src/skf-analyze-source/references/discover-additional-source.md +147 -0
- package/src/skf-analyze-source/references/generate-briefs.md +121 -55
- package/src/skf-analyze-source/references/headless-contract.md +42 -15
- package/src/skf-analyze-source/references/identify-units.md +96 -110
- package/src/skf-analyze-source/references/init.md +73 -71
- package/src/skf-analyze-source/references/map-and-detect.md +123 -105
- package/src/skf-analyze-source/references/map-unit-exports.md +68 -0
- package/src/skf-analyze-source/references/recommend.md +51 -70
- package/src/skf-analyze-source/references/scan-project.md +60 -84
- package/src/skf-analyze-source/references/scan-root.md +39 -0
- package/src/skf-analyze-source/references/step-auto-scope-coexistence.md +47 -0
- package/src/skf-analyze-source/references/step-auto-scope-corpora.md +53 -0
- package/src/skf-analyze-source/references/step-auto-scope-split.md +91 -0
- package/src/skf-analyze-source/references/step-auto-scope.md +208 -293
- package/src/skf-analyze-source/references/step-shape-detect.md +14 -12
- package/src/skf-analyze-source/references/unit-detection-heuristics.md +37 -42
- package/src/skf-audit-skill/SKILL.md +43 -51
- package/src/skf-audit-skill/assets/drift-report-template.md +28 -3
- package/src/skf-audit-skill/customize.toml +41 -20
- package/src/skf-audit-skill/references/constituent-freshness.md +91 -0
- package/src/skf-audit-skill/references/doc-drift.md +141 -0
- package/src/skf-audit-skill/references/headless-contract.md +29 -0
- package/src/skf-audit-skill/references/health-check.md +2 -0
- package/src/skf-audit-skill/references/init.md +149 -210
- package/src/skf-audit-skill/references/re-index.md +103 -110
- package/src/skf-audit-skill/references/report.md +96 -33
- package/src/skf-audit-skill/references/semantic-diff.md +34 -25
- package/src/skf-audit-skill/references/severity-classify.md +79 -65
- package/src/skf-audit-skill/references/severity-rules.md +15 -6
- package/src/skf-audit-skill/references/structural-diff.md +80 -90
- package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
- package/src/skf-audit-skill/scripts/render-drift-tables.py +712 -0
- package/src/skf-brief-skill/SKILL.md +37 -26
- package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
- package/src/skf-brief-skill/assets/scope-templates.md +18 -25
- package/src/skf-brief-skill/assets/skill-brief-schema.md +30 -23
- package/src/skf-brief-skill/customize.toml +48 -20
- package/src/skf-brief-skill/references/analyze-target.md +144 -127
- package/src/skf-brief-skill/references/confirm-brief.md +11 -9
- package/src/skf-brief-skill/references/draft-checkpoint.md +36 -17
- package/src/skf-brief-skill/references/gather-intent-ratify.md +68 -0
- package/src/skf-brief-skill/references/gather-intent.md +87 -182
- package/src/skf-brief-skill/references/headless-args.md +84 -16
- package/src/skf-brief-skill/references/health-check.md +1 -1
- package/src/skf-brief-skill/references/invocation-contract.md +18 -13
- package/src/skf-brief-skill/references/portfolio-similarity-check.md +1 -1
- package/src/skf-brief-skill/references/qmd-collection-registration.md +7 -10
- package/src/skf-brief-skill/references/scope-definition.md +123 -47
- package/src/skf-brief-skill/references/step-auto-brief.md +26 -100
- package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
- package/src/skf-brief-skill/references/version-resolution.md +7 -10
- package/src/skf-brief-skill/references/write-brief.md +66 -57
- package/src/skf-campaign/SKILL.md +31 -34
- package/src/skf-campaign/assets/campaign-state-schema.json +25 -4
- package/src/skf-campaign/customize.toml +47 -16
- package/src/skf-campaign/references/campaign-contracts.md +39 -29
- package/src/skf-campaign/references/campaign-directive-spec.md +4 -2
- package/src/skf-campaign/references/health-check.md +7 -16
- package/src/skf-campaign/references/step-01-setup.md +46 -84
- package/src/skf-campaign/references/step-02-strategy.md +31 -30
- package/src/skf-campaign/references/step-03-pins.md +26 -18
- package/src/skf-campaign/references/step-04-provenance.md +24 -23
- package/src/skf-campaign/references/step-05-skill-loop.md +67 -48
- package/src/skf-campaign/references/step-06-batch.md +41 -34
- package/src/skf-campaign/references/step-07-capstone.md +40 -25
- package/src/skf-campaign/references/step-08-verify.md +28 -29
- package/src/skf-campaign/references/step-09-refine.md +29 -30
- package/src/skf-campaign/references/step-10-export.md +48 -36
- package/src/skf-campaign/references/step-11-maintenance.md +31 -34
- package/src/skf-campaign/references/step-resume.md +37 -68
- package/src/skf-campaign/scripts/campaign-deps.py +57 -18
- package/src/skf-campaign/scripts/campaign-parse-manifest.py +361 -54
- package/src/skf-campaign/scripts/campaign-provenance.py +96 -53
- package/src/skf-campaign/scripts/campaign-quality-gate.py +592 -0
- package/src/skf-campaign/scripts/campaign-render-batch.py +257 -49
- package/src/skf-campaign/scripts/campaign-render-kickoff.py +343 -50
- package/src/skf-campaign/scripts/campaign-report.py +204 -37
- package/src/skf-campaign/scripts/campaign-state.py +1128 -0
- package/src/skf-campaign/scripts/campaign-status.py +10 -74
- package/src/skf-campaign/scripts/campaign-validate-pins.py +30 -3
- package/src/skf-campaign/scripts/campaign-validate-state.py +34 -4
- package/src/skf-campaign/templates/campaign-brief-template.yaml +4 -5
- package/src/skf-campaign/templates/campaign-report-template.md +5 -1
- package/src/skf-campaign/templates/kickoff-template.md +0 -14
- package/src/skf-create-skill/SKILL.md +27 -20
- package/src/skf-create-skill/assets/compile-assembly-rules.md +11 -8
- package/src/skf-create-skill/assets/skill-sections.md +21 -11
- package/src/skf-create-skill/customize.toml +20 -8
- package/src/skf-create-skill/references/authoritative-files-protocol.md +36 -58
- package/src/skf-create-skill/references/batch-mode.md +81 -0
- package/src/skf-create-skill/references/ccc-index-check.md +27 -0
- package/src/skf-create-skill/references/compile.md +119 -70
- package/src/skf-create-skill/references/component-extraction.md +113 -91
- package/src/skf-create-skill/references/enrich.md +41 -23
- package/src/skf-create-skill/references/entry-points-by-hand.md +37 -0
- package/src/skf-create-skill/references/extract.md +204 -162
- package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +11 -11
- package/src/skf-create-skill/references/extraction-patterns.md +588 -201
- package/src/skf-create-skill/references/generate-artifacts.md +145 -93
- package/src/skf-create-skill/references/health-check.md +1 -1
- package/src/skf-create-skill/references/load-brief.md +53 -36
- package/src/skf-create-skill/references/relabel-rule.md +12 -0
- package/src/skf-create-skill/references/report.md +37 -57
- package/src/skf-create-skill/references/source-resolution-protocols.md +58 -169
- package/src/skf-create-skill/references/step-auto-shard.md +20 -93
- package/src/skf-create-skill/references/step-doc-rot.md +44 -60
- package/src/skf-create-skill/references/step-doc-sources.md +28 -19
- package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
- package/src/skf-create-skill/references/sub/fetch-docs.md +106 -59
- package/src/skf-create-skill/references/sub/fetch-temporal.md +53 -166
- package/src/skf-create-skill/references/tier-degradation-rules.md +18 -9
- package/src/skf-create-skill/references/validate.md +173 -99
- package/src/skf-create-skill/scripts/scan-doc-rot.py +232 -99
- package/src/skf-create-stack-skill/SKILL.md +29 -56
- package/src/skf-create-stack-skill/assets/metadata-contract.md +51 -0
- package/src/skf-create-stack-skill/assets/provenance-map-schema.md +15 -15
- package/src/skf-create-stack-skill/assets/stack-skill-template.md +23 -57
- package/src/skf-create-stack-skill/customize.toml +23 -12
- package/src/skf-create-stack-skill/references/compile-stack.md +57 -66
- package/src/skf-create-stack-skill/references/compose-mode-rules.md +24 -44
- package/src/skf-create-stack-skill/references/detect-integrations.md +92 -95
- package/src/skf-create-stack-skill/references/detect-manifests.md +46 -71
- package/src/skf-create-stack-skill/references/generate-output.md +138 -128
- package/src/skf-create-stack-skill/references/init.md +90 -32
- package/src/skf-create-stack-skill/references/integration-patterns.md +1 -17
- package/src/skf-create-stack-skill/references/invocation-contract.md +34 -0
- package/src/skf-create-stack-skill/references/manifest-patterns.md +32 -20
- package/src/skf-create-stack-skill/references/parallel-extract.md +112 -38
- package/src/skf-create-stack-skill/references/rank-and-confirm.md +57 -75
- package/src/skf-create-stack-skill/references/report.md +39 -33
- package/src/skf-create-stack-skill/references/validate.md +20 -39
- package/src/skf-drop-skill/SKILL.md +28 -51
- package/src/skf-drop-skill/customize.toml +44 -30
- package/src/skf-drop-skill/references/execute.md +83 -146
- package/src/skf-drop-skill/references/health-check.md +2 -0
- package/src/skf-drop-skill/references/invocation-contract.md +64 -0
- package/src/skf-drop-skill/references/report.md +46 -30
- package/src/skf-drop-skill/references/select.md +122 -124
- package/src/skf-drop-skill/scripts/dir-sizes.py +54 -26
- package/src/skf-drop-skill/scripts/drop-roster.py +322 -0
- package/src/skf-export-skill/SKILL.md +40 -62
- package/src/skf-export-skill/assets/managed-section-format.md +14 -50
- package/src/skf-export-skill/assets/snippet-format.md +3 -1
- package/src/skf-export-skill/customize.toml +42 -13
- package/src/skf-export-skill/references/generate-snippet.md +54 -46
- package/src/skf-export-skill/references/health-check.md +2 -0
- package/src/skf-export-skill/references/invocation-contract.md +15 -0
- package/src/skf-export-skill/references/load-skill.md +88 -62
- package/src/skf-export-skill/references/manifest-rebuild.md +9 -10
- package/src/skf-export-skill/references/multi-skill-mode.md +4 -4
- package/src/skf-export-skill/references/orphan-context-detection.md +13 -5
- package/src/skf-export-skill/references/orphan-row-detection.md +31 -22
- package/src/skf-export-skill/references/package.md +15 -73
- package/src/skf-export-skill/references/preflight-snippet-root-probe.md +51 -70
- package/src/skf-export-skill/references/result-envelope.md +31 -16
- package/src/skf-export-skill/references/summary.md +41 -17
- package/src/skf-export-skill/references/token-report.md +4 -12
- package/src/skf-export-skill/references/update-context.md +118 -237
- package/src/skf-forger/SKILL.md +61 -37
- package/src/skf-forger/bmad-skill-manifest.yaml +4 -1
- package/src/skf-forger/customize.toml +43 -0
- package/src/skf-forger/references/pipeline-mode.md +73 -18
- package/src/skf-forger/scripts/forge-status.py +299 -0
- package/src/skf-forger/scripts/parse-pipeline.py +322 -54
- package/src/skf-forger/scripts/pipeline-gate.py +428 -0
- package/src/skf-forger/scripts/pipeline-journal.py +1052 -0
- package/src/skf-quick-skill/SKILL.md +54 -53
- package/src/skf-quick-skill/assets/skill-template.md +4 -2
- package/src/skf-quick-skill/customize.toml +51 -20
- package/src/skf-quick-skill/references/batch-mode.md +74 -21
- package/src/skf-quick-skill/references/compile.md +30 -31
- package/src/skf-quick-skill/references/ecosystem-check.md +7 -57
- package/src/skf-quick-skill/references/finalize.md +69 -18
- package/src/skf-quick-skill/references/halt-contract.md +41 -29
- package/src/skf-quick-skill/references/health-check.md +5 -3
- package/src/skf-quick-skill/references/quick-extract.md +114 -45
- package/src/skf-quick-skill/references/registry-resolution.md +9 -64
- package/src/skf-quick-skill/references/resolve-target.md +116 -66
- package/src/skf-quick-skill/references/write-and-validate.md +79 -40
- package/src/skf-refine-architecture/SKILL.md +43 -53
- package/src/skf-refine-architecture/customize.toml +49 -20
- package/src/skf-refine-architecture/references/compile.md +97 -54
- package/src/skf-refine-architecture/references/exit-codes.md +30 -0
- package/src/skf-refine-architecture/references/finding-storage.md +21 -0
- package/src/skf-refine-architecture/references/gap-analysis.md +101 -38
- package/src/skf-refine-architecture/references/improvements.md +14 -20
- package/src/skf-refine-architecture/references/init.md +98 -57
- package/src/skf-refine-architecture/references/issue-detection.md +32 -39
- package/src/skf-refine-architecture/references/refinement-rules.md +37 -48
- package/src/skf-refine-architecture/references/report.md +65 -54
- package/src/skf-refine-architecture/scripts/skf-check-preservation.py +1619 -0
- package/src/skf-rename-skill/SKILL.md +19 -54
- package/src/skf-rename-skill/customize.toml +32 -26
- package/src/skf-rename-skill/references/execute.md +230 -184
- package/src/skf-rename-skill/references/exit-codes.md +7 -7
- package/src/skf-rename-skill/references/health-check.md +1 -7
- package/src/skf-rename-skill/references/invocation-contract.md +25 -0
- package/src/skf-rename-skill/references/report.md +63 -52
- package/src/skf-rename-skill/references/select.md +197 -115
- package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -21
- package/src/skf-setup/SKILL.md +26 -26
- package/src/skf-setup/customize.toml +14 -10
- package/src/skf-setup/references/auto-index.md +50 -63
- package/src/skf-setup/references/ccc-index.md +29 -90
- package/src/skf-setup/references/detect-and-tier.md +58 -67
- package/src/skf-setup/references/health-check.md +2 -0
- package/src/skf-setup/references/invocation-contract.md +14 -0
- package/src/skf-setup/references/report.md +43 -166
- package/src/skf-setup/references/tier-rules.md +5 -5
- package/src/skf-setup/references/write-config.md +34 -57
- package/src/skf-test-skill/SKILL.md +17 -57
- package/src/skf-test-skill/assets/output-section-formats.md +33 -34
- package/src/skf-test-skill/customize.toml +27 -13
- package/src/skf-test-skill/references/coherence-check.md +134 -62
- package/src/skf-test-skill/references/coverage-check-tiers.md +35 -0
- package/src/skf-test-skill/references/coverage-check.md +209 -264
- package/src/skf-test-skill/references/detect-mode.md +5 -5
- package/src/skf-test-skill/references/external-validators.md +94 -82
- package/src/skf-test-skill/references/health-check.md +6 -7
- package/src/skf-test-skill/references/init.md +164 -91
- package/src/skf-test-skill/references/invocation-contract.md +66 -0
- package/src/skf-test-skill/references/migration-section-rules.md +5 -2
- package/src/skf-test-skill/references/report.md +164 -142
- package/src/skf-test-skill/references/score.md +80 -107
- package/src/skf-test-skill/references/scoring-rules.md +42 -155
- package/src/skf-test-skill/references/source-access-protocol.md +18 -94
- package/src/skf-test-skill/references/step-hard-gate.md +51 -33
- package/src/skf-test-skill/scripts/aggregate-coherence.py +218 -30
- package/src/skf-test-skill/scripts/build-result-context.py +380 -0
- package/src/skf-test-skill/scripts/check-metadata-coherence.py +37 -4
- package/src/skf-test-skill/scripts/combine-external-scores.py +23 -6
- package/src/skf-test-skill/scripts/compute-score.py +223 -45
- package/src/skf-test-skill/scripts/gap-ledger.py +1666 -0
- package/src/skf-test-skill/scripts/hard-gate.py +203 -0
- package/src/skf-test-skill/scripts/load-coverage-inputs.py +1198 -0
- package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
- package/src/skf-test-skill/scripts/reconcile-coverage.py +547 -79
- package/src/skf-test-skill/scripts/score-signatures.py +479 -0
- package/src/skf-test-skill/scripts/stage-helper-payload.py +148 -0
- package/src/skf-test-skill/scripts/validate-inventory.py +311 -16
- package/src/skf-test-skill/scripts/verify-declared-numerator.py +133 -56
- package/src/skf-test-skill/templates/test-report-template.md +21 -15
- package/src/skf-update-skill/SKILL.md +38 -25
- package/src/skf-update-skill/customize.toml +27 -12
- package/src/skf-update-skill/references/detect-changes.md +253 -223
- package/src/skf-update-skill/references/gap-driven.md +336 -0
- package/src/skf-update-skill/references/health-check.md +31 -5
- package/src/skf-update-skill/references/init.md +254 -84
- package/src/skf-update-skill/references/invocation-contract.md +12 -0
- package/src/skf-update-skill/references/manual-section-rules.md +6 -23
- package/src/skf-update-skill/references/merge.md +182 -49
- package/src/skf-update-skill/references/re-extract.md +53 -262
- package/src/skf-update-skill/references/report.md +102 -35
- package/src/skf-update-skill/references/write.md +357 -155
- package/src/skf-update-skill/scripts/skf-new-file-diff.py +183 -46
- package/src/skf-verify-stack/SKILL.md +23 -42
- package/src/skf-verify-stack/assets/feasibility-report-template.md +11 -5
- package/src/skf-verify-stack/customize.toml +55 -22
- package/src/skf-verify-stack/references/coverage-patterns.md +17 -8
- package/src/skf-verify-stack/references/coverage.md +67 -64
- package/src/skf-verify-stack/references/exit-codes.md +21 -8
- package/src/skf-verify-stack/references/init.md +107 -62
- package/src/skf-verify-stack/references/integration-verification-rules.md +12 -13
- package/src/skf-verify-stack/references/integrations.md +106 -65
- package/src/skf-verify-stack/references/report.md +59 -42
- package/src/skf-verify-stack/references/requirements.md +32 -9
- package/src/skf-verify-stack/references/synthesize.md +53 -39
- package/src/skf-verify-stack/scripts/skf-coverage-tally.py +398 -52
- package/src/skf-verify-stack/scripts/skf-previous-report.py +330 -0
- package/src/skf-verify-stack/scripts/skf-report-delta.py +453 -49
- package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +240 -27
- package/tools/cli/commands/install.js +11 -4
- package/tools/cli/commands/status.js +15 -3
- package/tools/cli/commands/update.js +11 -4
- package/tools/cli/lib/tool-check.js +320 -0
- package/tools/cli/lib/version-check.js +22 -9
- package/tools/cli/skf-cli.js +4 -1
- package/.gitattributes +0 -16
- package/.nvmrc +0 -1
- package/docs/_internal/RELEASING.md +0 -679
- package/release-audits/v1.0.0-launch-audit.md +0 -728
- package/src/skf-audit-skill/references/step-doc-drift.md +0 -177
- package/src/skf-brief-skill/references/headless-source-authority-detection.md +0 -26
- package/src/skf-campaign/manifest.yaml +0 -15
- package/src/skf-create-skill/assets/tessl-dismissal-rules.md +0 -106
- package/src/skf-create-skill/references/ecosystem-check.md +0 -74
- package/src/skf-drop-skill/references/headless-contract.md +0 -18
- package/src/skf-update-skill/references/merge-conflict-rules.md +0 -15
- package/src/skf-update-skill/references/remote-source-resolution.md +0 -98
- package/src/skf-update-skill/references/validate.md +0 -124
- package/tools/validate-docs-drift.js +0 -233
- package/tools/validate-docs-links.js +0 -665
|
@@ -16,7 +16,7 @@ liveSubmitSeverities: ['bug'] # friction/gap go local-queue-default with explic
|
|
|
16
16
|
|
|
17
17
|
Reflect on the workflow that just completed. If real friction, bugs, or gaps were encountered in the SKF workflow instructions, capture them as structured findings for the user to review and optionally submit as GitHub issues.
|
|
18
18
|
|
|
19
|
-
**Zero overhead for clean runs.** If nothing went wrong, say so and exit immediately.
|
|
19
|
+
**Zero overhead for clean runs.** If nothing went wrong, say so (or, on an envelope-only run, display only the setup envelope — see §0) and exit immediately.
|
|
20
20
|
|
|
21
21
|
## MANDATORY EXECUTION RULES:
|
|
22
22
|
|
|
@@ -24,17 +24,8 @@ Reflect on the workflow that just completed. If real friction, bugs, or gaps wer
|
|
|
24
24
|
- Read the complete step file before taking any action
|
|
25
25
|
- Speak in `{communication_language}`
|
|
26
26
|
|
|
27
|
-
###
|
|
28
|
-
|
|
29
|
-
- You report ONLY what you actually experienced during THIS session
|
|
30
|
-
- You are NOT a creative writer looking for things to say
|
|
31
|
-
|
|
32
|
-
### Anti-Hallucination Rules:
|
|
33
|
-
- **DO NOT FABRICATE ISSUES.** If the workflow ran smoothly, say so and exit. Inventing issues to appear thorough is a SYSTEM FAILURE.
|
|
34
|
-
- Only report issues you **ACTUALLY encountered** during THIS workflow execution
|
|
35
|
-
- Every finding MUST cite the **specific step file path and section** where the issue occurred
|
|
36
|
-
- If you are unsure whether something was a real issue or your own confusion, DO NOT report it
|
|
37
|
-
- Reporting zero issues is the EXPECTED outcome for a well-designed workflow
|
|
27
|
+
### Findings Rule:
|
|
28
|
+
Zero findings is the expected outcome of a good run. Report only a bug, friction or gap you hit in this session, each with the step file and section where it happened, and leave out anything you cannot tell apart from your own confusion: a finding you invent can become a real GitHub issue filed against the module.
|
|
38
29
|
|
|
39
30
|
---
|
|
40
31
|
|
|
@@ -42,11 +33,15 @@ Reflect on the workflow that just completed. If real friction, bugs, or gaps wer
|
|
|
42
33
|
|
|
43
34
|
### 0. Announce Arrival
|
|
44
35
|
|
|
36
|
+
**Envelope-only runs.** Treat `{quiet_mode}` as true only when the workflow that loaded this step is skf-setup and it set `{quiet_mode}` to true. In every other case (unset, another workflow ran, or the user asked for this health check directly) treat it as false. skf-setup sets it under `--quiet` or in headless mode because its result envelope must be the only line setup displays. When it is true, this whole step displays nothing of its own and writes no text between tool calls: skip this announcement and its headless log, and queue any findings locally through **[Q]** without presenting them (§3, §4). Wherever it stops (the clean-run stop in §2, or the end of §5c), it displays skf-setup's `{setup_envelope_line}` verbatim after every tool call, with no code fence and nothing of this step's own before or after it (nothing at all if that line is empty). In a standalone setup run that line is the final message, because `claude -p` prints only the final message. When `{pipeline_mode}` is true, skf-setup is one step of a forger pipeline: control then returns to the forger, which keeps chaining.
|
|
37
|
+
|
|
38
|
+
**Result envelope line.** Any other workflow may bind `{result_envelope_line}` before it loads this step, in headless mode only (Brief Skill also in an `[auto]` run), to the result envelope line its run printed through the shared emitter (its `SKF_<NAME>_RESULT_JSON: ...` line; skf-test-skill's report step binds its `SKF_TEST_RESULT_JSON` line). When it is bound and not empty, wherever this step stops (the clean-run stop in §2, or the end of §5c) it displays that line verbatim as its very last line, after everything else it displays, with no code fence and nothing after it. In a standalone headless run, such as `claude -p`, which prints only the final message, that line is then the final message a pipeline reads. A workflow that binds nothing gets nothing extra.
|
|
39
|
+
|
|
45
40
|
**Display in `{communication_language}`:**
|
|
46
41
|
|
|
47
42
|
"**Running a quick self-improvement check on this workflow.** If nothing rough came up, I'll close out immediately."
|
|
48
43
|
|
|
49
|
-
**GATE [default: skip]** — If `{headless_mode}`: skip the display entirely, log: "headless: skipped health-check arrival announcement".
|
|
44
|
+
**GATE [default: skip]** — If `{quiet_mode}` is true: skip the display and log nothing. Otherwise, if `{headless_mode}`: skip the display entirely, log: "headless: skipped health-check arrival announcement".
|
|
50
45
|
|
|
51
46
|
**If interactive:** display the line above, then proceed to step 1 (Read Workflow Context) without waiting. The line is informational, not a commitment gate — the user's commitment to continuing was already captured upstream (either via an explicit menu in the calling step or by auto-chain). This announcement just tells them what is about to happen.
|
|
52
47
|
|
|
@@ -68,16 +63,20 @@ Silently review the workflow execution. Ask yourself:
|
|
|
68
63
|
|
|
69
64
|
**If the answer to ALL of these is "no":**
|
|
70
65
|
|
|
71
|
-
|
|
66
|
+
If `{quiet_mode}` is true, display only `{setup_envelope_line}` (§0). Otherwise display:
|
|
72
67
|
|
|
73
68
|
"**Health Check: Clean run.** No workflow issues to report.
|
|
74
69
|
|
|
75
70
|
Workflow complete."
|
|
76
71
|
|
|
72
|
+
When `{result_envelope_line}` is bound (§0), display it verbatim after that, as the last line.
|
|
73
|
+
|
|
77
74
|
**STOP HERE. Do not proceed further. The workflow is done.**
|
|
78
75
|
|
|
79
76
|
### 3. Present Findings (Only If Issues Exist)
|
|
80
77
|
|
|
78
|
+
**If `{quiet_mode}` is true:** do not present the findings. Go to §4, which chooses **[Q]** without displaying anything, so every finding, whatever its severity, is written to the local queue per §5c and nothing is submitted to GitHub.
|
|
79
|
+
|
|
81
80
|
For each genuine finding, present it in this format:
|
|
82
81
|
|
|
83
82
|
"**Workflow Health Check — {N} finding(s)**
|
|
@@ -112,13 +111,16 @@ For each genuine finding, present it in this format:
|
|
|
112
111
|
|
|
113
112
|
### 4. User Review Gate
|
|
114
113
|
|
|
115
|
-
|
|
114
|
+
**GATE [default: Q]** — If `{quiet_mode}` is true, choose **[Q]** without displaying anything. Otherwise, if `{headless_mode}` is true, choose **[Q]** and log: "headless: queued {N} finding(s) locally". In both cases skip the question below and go to Menu Handling: live submission always needs an interactive **[Y]**.
|
|
115
|
+
|
|
116
|
+
**If interactive:** after presenting all findings, ask:
|
|
116
117
|
|
|
117
118
|
"**Submit these findings?**
|
|
118
119
|
|
|
119
120
|
- **[Y]** Yes — submit all findings
|
|
120
121
|
- **[N]** No — discard all findings
|
|
121
122
|
- **[E]** Edit — let me revise before submitting
|
|
123
|
+
- **[Q]** Queue locally — save every finding to {localFallbackFolder}/, submit nothing
|
|
122
124
|
|
|
123
125
|
_You are the final filter. Reject any finding that doesn't reflect a real issue you observed._"
|
|
124
126
|
|
|
@@ -129,6 +131,7 @@ _You are the final filter. Reject any finding that doesn't reflect a real issue
|
|
|
129
131
|
- **IF Y:** Proceed to step 5
|
|
130
132
|
- **IF N:** Display "Findings discarded. Workflow complete." — STOP
|
|
131
133
|
- **IF E:** Let user specify which findings to keep, modify, or remove. Then re-present the revised list and ask again.
|
|
134
|
+
- **IF Q:** Compute each finding's fingerprint as §5a sub-step 1 describes, then write every finding, whatever its severity, to the local queue per §5c — STOP after §5c
|
|
132
135
|
|
|
133
136
|
### 5. Route Each Finding by Severity
|
|
134
137
|
|
|
@@ -149,6 +152,12 @@ fp="fp-$(printf '%s|%s|%s|%s' "{severity}" "{workflow}" "{step_file}" "{section-
|
|
|
149
152
|
|
|
150
153
|
The `section-slug` is a kebab-case normalized section heading (e.g. `missing-staging-path`). Never include line numbers — they drift when files are edited.
|
|
151
154
|
|
|
155
|
+
`sha1sum` is not on stock macOS or Windows. On macOS, use `shasum -a 1` in its place. Anywhere neither exists, this prints the same 7 hex characters, to prefix the same way:
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
uv run python -c "import hashlib,sys; print(hashlib.sha1(sys.argv[1].encode()).hexdigest()[:7])" "{severity}|{workflow}|{step_file}|{section-slug}"
|
|
159
|
+
```
|
|
160
|
+
|
|
152
161
|
**2. Check the local seen-cache** at `{seenCachePath}`:
|
|
153
162
|
|
|
154
163
|
Read `{seenCachePath}`. A missing file, an empty file, or one that does not parse as JSON is an empty cache — never an error, never a reason to halt.
|
|
@@ -246,7 +255,6 @@ After the issue is created, write the fingerprint → issue-url mapping to the s
|
|
|
246
255
|
- **Respect the length budgets.** Finding, Expected, Actual, Impact are each ONE sentence. Evidence is 2-5 bullets, not prose. Suggested Fix is 1-3 sentences with ONE recommendation — multiple options go in the `Alternatives considered` collapsible or (better) not at all.
|
|
247
256
|
- **Quote, don't paraphrase.** In Evidence, cite the exact `file:line` and put the quoted text in quotes. Link the convention to the instruction that caused it.
|
|
248
257
|
- **Never narrate the session.** The reader wants the defect, not the story. If a sentence starts with "During my run..." or "I was trying to...", delete it.
|
|
249
|
-
- **If unsure whether it's a real issue, do not submit it.** Reporting zero findings is a healthy outcome.
|
|
250
258
|
|
|
251
259
|
**Issue body format:**
|
|
252
260
|
```markdown
|
|
@@ -290,7 +298,7 @@ After the issue is created, write the fingerprint → issue-url mapping to the s
|
|
|
290
298
|
|
|
291
299
|
## Suggested Fix
|
|
292
300
|
<!-- ONE recommended change. 1-3 sentences. Do NOT list multiple options here. -->
|
|
293
|
-
{e.g. Add a rule to step 5 naming `_bmad-output/{skill-name}/` as the staging directory used by step 6 validation.}
|
|
301
|
+
{e.g. Add a rule to step 5 naming `_bmad-output/.skf-stage/{skill-name}/` as the staging directory used by step 6 validation.}
|
|
294
302
|
|
|
295
303
|
<details>
|
|
296
304
|
<summary>Alternatives considered (optional)</summary>
|
|
@@ -339,11 +347,11 @@ Ensure the parent directory exists. This file is global across the user's machin
|
|
|
339
347
|
|
|
340
348
|
**The `action` vocabulary is `created`, `reacted`, `commented`, `resolved`.** The first three are written by this workflow. `resolved` is written by hand when the defect is fixed, and it is the only one that does not suppress. See the health-check section of `CONTRIBUTING.md` for when to record it.
|
|
341
349
|
|
|
342
|
-
### 5c. Local-Queue Path (gh unavailable
|
|
350
|
+
### 5c. Local-Queue Path (gh unavailable, friction/gap default, or Queue locally)
|
|
343
351
|
|
|
344
|
-
For findings that didn't go live (gh unavailable, user declined the friction/gap opt-in,
|
|
352
|
+
For findings that didn't go live (gh unavailable, user declined the friction/gap opt-in, user chose **\[S]** at the dedup gate, or the §4 review gate resolved to **\[Q]**), write a local file to `{localFallbackFolder}/`:
|
|
345
353
|
|
|
346
|
-
**Filename:** `hc-{workflow}-{timestamp}.md` (one file per finding, timestamp as YYYYMMDD-HHmmss)
|
|
354
|
+
**Filename:** `hc-{workflow}-{timestamp}.md` (one file per finding, timestamp as YYYYMMDD-HHmmss; when findings share a timestamp, append `-2`, `-3`, … to the later names so no file is overwritten)
|
|
347
355
|
|
|
348
356
|
**File content:** Same structured format as the issue body above, with YAML frontmatter:
|
|
349
357
|
|
|
@@ -358,52 +366,16 @@ date: {ISO date}
|
|
|
358
366
|
---
|
|
359
367
|
```
|
|
360
368
|
|
|
361
|
-
After writing all files, display:
|
|
369
|
+
After writing all files, if `{quiet_mode}` is true, display only `{setup_envelope_line}` (§0) and stop. Otherwise display the block below. `{reason}` is the sentence that says why the findings stayed local: "GitHub CLI is not available.", "Friction and gap findings stay local unless you opt in.", "You skipped these at the dedup gate." or "The review gate queued these locally."
|
|
362
370
|
|
|
363
371
|
"**{N} finding(s) saved locally:**
|
|
364
372
|
{list each file path}
|
|
365
373
|
|
|
366
|
-
|
|
374
|
+
{reason} To submit these as issues, run:
|
|
367
375
|
`gh issue create --repo {healthCheckRepo} --title \"[title]\" --body-file {file-path}`
|
|
368
376
|
|
|
369
377
|
Or open them manually at: <https://github.com/{healthCheckRepo}/issues/new/choose>
|
|
370
378
|
|
|
371
379
|
Workflow complete."
|
|
372
380
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
## CRITICAL STEP COMPLETION NOTE
|
|
376
|
-
|
|
377
|
-
This is the TERMINAL step — shared across all SKF workflows. After the health check completes (clean run or findings submitted/discarded), the workflow is fully done. No further steps to load.
|
|
378
|
-
|
|
379
|
-
---
|
|
380
|
-
|
|
381
|
-
## SYSTEM SUCCESS/FAILURE METRICS
|
|
382
|
-
|
|
383
|
-
### SUCCESS:
|
|
384
|
-
|
|
385
|
-
- Clean runs exit immediately with no findings (most common outcome)
|
|
386
|
-
- Findings cite specific step files and sections with real evidence
|
|
387
|
-
- User review gate presented before any submission
|
|
388
|
-
- Severity gate respected: only `bug` submits live by default; `friction`/`gap` require explicit opt-in
|
|
389
|
-
- Fingerprint computed deterministically and applied to both title prefix and `fp-*` label
|
|
390
|
-
- `fp-*` label is ensured idempotently (`gh label create ... || true`) before `gh issue create`, so a first reporter of a defect never hard-fails
|
|
391
|
-
- Remote dedup search performed before every live submission; existing issues get reactions/delta-comments rather than duplicates
|
|
392
|
-
- Seen-cache at `{seenCachePath}` updated after every submission/reaction and consulted before every search
|
|
393
|
-
- Local fallback files written with clear manual submission instructions (when `gh` unavailable)
|
|
394
|
-
- Workflow ends cleanly
|
|
395
|
-
|
|
396
|
-
### SYSTEM FAILURE:
|
|
397
|
-
|
|
398
|
-
- Fabricating issues that were not actually encountered during the session
|
|
399
|
-
- Reporting vague issues without step file citations ("the workflow was confusing")
|
|
400
|
-
- Skipping the user review gate
|
|
401
|
-
- Creating issues without user confirmation
|
|
402
|
-
- Creating a new issue when a matching `fp-*` open issue already exists (without explicit user \[N] override)
|
|
403
|
-
- Submitting `friction` or `gap` findings live without the explicit severity-gate opt-in
|
|
404
|
-
- Using LLM-judged "similarity" in place of the deterministic fingerprint
|
|
405
|
-
- Not updating the seen-cache, causing the same user to re-report identical fingerprints
|
|
406
|
-
- Not providing the local fallback when `gh` is unavailable
|
|
407
|
-
- Continuing to load steps after this one (this is terminal)
|
|
408
|
-
|
|
409
|
-
**Master Rule:** Honesty is the only policy. Zero findings is the expected, healthy outcome. Fabricating issues to appear thorough undermines the entire self-improvement system and constitutes SYSTEM FAILURE.
|
|
381
|
+
When `{result_envelope_line}` is bound (§0), display it verbatim after that block, as the last line.
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
External validators (`skill-check check --fix`, `skill-check split-body`, and any future tool that may rewrite SKILL.md frontmatter) occasionally replace, truncate, or otherwise mutate the `description` field — sometimes substituting a generic version, sometimes re-introducing angle-bracket tokens that earlier sanitization removed.
|
|
6
6
|
|
|
7
|
-
The on-disk description is **authoritative**: it has been compiled (in `skf-create-skill`) or merged (in `skf-update-skill`) with deliberate trigger-optimization. Losing it to a tool's well-meaning rewrite breaks agent discovery quality and can re-introduce
|
|
7
|
+
The on-disk description is **authoritative**: it has been compiled (in `skf-create-skill`) or merged (in `skf-update-skill`) with deliberate trigger-optimization. Losing it to a tool's well-meaning rewrite breaks agent discovery quality and can re-introduce angle brackets that create-skill removed, which the Claude platform does not accept in a skill description (it cannot contain XML tags).
|
|
8
8
|
|
|
9
|
-
Any tool invocation that may touch SKILL.md must run inside the four-phase guard below. Workflows invoke the deterministic phases (1, 3, 4) via `
|
|
9
|
+
Any tool invocation that may touch SKILL.md must run inside the four-phase guard below. Workflows invoke the deterministic phases (1, 3, 4) via `skf-description-guard.py`, which each calling step resolves as `{descriptionGuardHelper}` from its `descriptionGuardProbeOrder` (installed SKF module path first, src/ dev-checkout fallback); the LLM only performs phase 2 (the tool call itself).
|
|
10
10
|
|
|
11
11
|
## The Four-Phase Guard
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ Any tool invocation that may touch SKILL.md must run inside the four-phase guard
|
|
|
15
15
|
Before invoking the tool, snapshot the on-disk `description` value:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
uv run {
|
|
18
|
+
uv run {descriptionGuardHelper} \
|
|
19
19
|
capture <skill-md-path>
|
|
20
20
|
```
|
|
21
21
|
|
|
@@ -39,11 +39,13 @@ Run the tool as specified in its section. The LLM performs this step normally
|
|
|
39
39
|
After the tool completes, run:
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
uv run {
|
|
42
|
+
uv run {descriptionGuardHelper} \
|
|
43
43
|
verify-restore <skill-md-path> \
|
|
44
44
|
--captured-description "{guarded_description}"
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
In place of `--captured-description`, `--captured-file <path>` reads the snapshot from a JSON file's `description`: redirect `capture`'s output into the run folder (`capture <skill-md-path> > <run-folder>/description-guard.json`) and pass that file, so the value never passes through context or a shell string. quick-skill calls it this way. An empty or whitespace-only `description` in the file is refused like an empty `--captured-description` (below), and so is a file the helper cannot read or that holds no string `description`.
|
|
48
|
+
|
|
47
49
|
The script:
|
|
48
50
|
|
|
49
51
|
1. Re-reads on-disk `description`
|
|
@@ -61,7 +63,7 @@ Output JSON:
|
|
|
61
63
|
}
|
|
62
64
|
```
|
|
63
65
|
|
|
64
|
-
If `restored == true`, also update the in-context copy of `description` to match `guarded_description` so subsequent stages do not work from a stale tool-mutated version. Record `description_guard_restored: true` (with the tool name) in workflow context for the evidence report.
|
|
66
|
+
If `restored == true`, also update the in-context copy of `description` to match `guarded_description` so subsequent stages do not work from a stale tool-mutated version. Record `description_guard_restored: true` (with the tool name and the `diff_kind`) in workflow context for the evidence report.
|
|
65
67
|
|
|
66
68
|
**Empty snapshot refusal.** The helper exits 1 and leaves the file untouched when `--captured-description` is empty or whitespace-only. There is nothing to restore from: either `guarded_description` was lost from context between capture and verify, or the field was already empty before the tool ran. Never retry with the empty value — writing it back would blank the field the guard exists to protect. If the compiled description is still available in context (the in-context SKILL.md copy), re-run `verify-restore` with that value. Otherwise record `description_guard_restored: false` and `description_guard_refused: empty-capture` (with the tool name) in workflow context; the calling stage's evidence-report populator renders that as a fired guard (`Restored: false`, the triggering tool, `Original description preserved: false`, `Notes: guard refused — empty captured snapshot (empty-capture)`) rather than as the all-`—` clean-run state, and the frontmatter validator surfaces the empty field through the normal artifact path.
|
|
67
69
|
|
|
@@ -84,19 +86,20 @@ Splitting on whitespace and comparing token lists catches replaced words, trunca
|
|
|
84
86
|
|
|
85
87
|
## Post-Restore Re-Validation (Optional)
|
|
86
88
|
|
|
87
|
-
Skills that run frontmatter compliance checks (e.g. `skf-create-skill validate.md`) should additionally re-validate the restored description against the frontmatter contract after restore — a restored value must still satisfy length
|
|
89
|
+
Skills that run frontmatter compliance checks (e.g. `skf-create-skill validate.md`) should additionally re-validate the restored description against the frontmatter contract after restore — a restored value must still satisfy the length limit and required-field shape. (create-skill also checks the final description for angle brackets, in its validate §6, after every tool has run.) Run the frontmatter validator the calling step resolves (create-skill resolves `{frontmatterValidator}` from its `frontmatterValidatorProbeOrder`):
|
|
88
90
|
|
|
89
91
|
```bash
|
|
90
|
-
uv run {
|
|
92
|
+
uv run {frontmatterValidator} <skill-md-path>
|
|
91
93
|
```
|
|
92
94
|
|
|
93
95
|
If the validator reports failure for the `description` field, flip the Schema row in the evidence report back to `FAIL` and record `description_guard_revalidation: FAIL` with the validator diagnostic. Do not halt — let the failure surface through the normal artifact path so step health-check and the result contract record it.
|
|
94
96
|
|
|
95
97
|
## Why This Protocol Is Centralized
|
|
96
98
|
|
|
97
|
-
Previously, each tool invocation in each calling stage carried its own copy of the capture/verify/restore prose. Duplicated defensive logic drifts: a fix in one section did not propagate to the other, and adding a new tool invocation required remembering to copy the pattern.
|
|
99
|
+
Previously, each tool invocation in each calling stage carried its own copy of the capture/verify/restore prose. Duplicated defensive logic drifts: a fix in one section did not propagate to the other, and adding a new tool invocation required remembering to copy the pattern. This file is the maintainers' reference for the guard, and no stage loads this file at run time. The rules each calling stage acts on, the restore handling and the empty-snapshot refusal, are also stated in the stage's §0 (quick-skill states them beside its one guarded call): change them there, and keep this file in step.
|
|
98
100
|
|
|
99
101
|
## Calling Workflows
|
|
100
102
|
|
|
101
103
|
- `src/skf-create-skill/references/validate.md` — wraps `skill-check check --fix` (§2) and `split-body` (§4). Runs the optional post-restore re-validation.
|
|
102
|
-
- `src/skf-update-skill/references/write.md
|
|
104
|
+
- `src/skf-update-skill/references/write.md`: wraps `skill-check check --fix` and `skill-check split-body --write` in §7, then re-checks the [MANUAL] blocks. Does not run post-restore re-validation.
|
|
105
|
+
- `src/skf-quick-skill/references/write-and-validate.md`: wraps `skill-check check --fix` in §4, which also states the restore and empty-snapshot rules. With no guard helper it runs skill-check without `--fix`. Does not run post-restore re-validation.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Feasibility Report Schema
|
|
2
2
|
|
|
3
|
-
**Purpose:** Canonical contract shared between `skf-
|
|
3
|
+
**Purpose:** Canonical contract shared between `skf-verify-stack` (producer) and the skills that read its report, `skf-refine-architecture` and `skf-create-stack-skill` (consumers). Any change here must be applied to the producer and every consumer in lockstep.
|
|
4
4
|
|
|
5
5
|
## Filename
|
|
6
6
|
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
{forge_data_folder}/feasibility-report-{project_slug}-{YYYYMMDD-HHmmss}.md
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
`{project_slug}` is
|
|
11
|
+
`{project_slug}` is `project_name` slugified by one rule: NFKD-decompose it and drop the combining marks (so `Café` gives `cafe`), drop any letter or digit that has no ASCII form, lowercase the rest, turn every run of other characters (spaces, punctuation, symbols) into one hyphen, and trim hyphens from both ends. A name that leaves nothing, an empty one included, gets the slug `project`. A stable `feasibility-report-{project_slug}-latest.md` copy (not symlink) is written next to the timestamped file for pipeline consumers.
|
|
12
|
+
|
|
13
|
+
`skf-validate-feasibility-report.py` (in `{project-root}/_bmad/skf/shared/scripts/`, or `{project-root}/src/shared/scripts/` in a dev checkout) holds the slug rule, so no skill derives the file name by hand. `--locate "{forge_data_folder}" --project-name "{project_name}"` applies the rule and reads only the `-latest` copy (a timestamped file can be a halted run's partial report). Given a report path instead, the script checks and reads that file the same way and prints the same JSON, so a consumer reads a path its user gives through the script too. Both modes check the required sections and `schemaVersion`, and return `path` and `schemaVersion` for any report they read; for a `1.0` report they also return `generatedAt`, `overallVerdict`, `coveragePercentage`, `coverageMeasured`, `pairVerdicts` (from the canonical table under `## Integration Verdicts`) and `unknownTokens`. `--locate` adds `projectName`, `projectSlug` and `latestPath`. `coverageMeasured` is true only when `stepsCompleted` lists `coverage` and `coveragePercentage` is a whole percentage: the producer writes `coveragePercentage: 0` when a run starts, so a run that stopped earlier holds a 0 that was never measured. `--locate` exits 0 with `status: "ok"`, or with `status: "not-found"` when the project has no `-latest` report. Both modes exit 1 when a required section is missing or out of order, the report's `schemaVersion` is not `"1.0"`, its canonical table is missing or there twice (`duplicateVerdictTableLine` gives the second one's line), or a verdict token is unknown, and 2 when the report cannot be read. Either mode also exits 2 on a usage error, which prints no JSON: a missing `--project-name`, an empty folder, or a stray argument such as an unquoted path that holds a space.
|
|
12
14
|
|
|
13
15
|
## Frontmatter (required)
|
|
14
16
|
|
|
@@ -39,18 +41,18 @@ Exactly one of:
|
|
|
39
41
|
|
|
40
42
|
| Token | Meaning | Required evidence |
|
|
41
43
|
|---|---|---|
|
|
42
|
-
| `Verified` |
|
|
43
|
-
| `Plausible` |
|
|
44
|
-
| `Risky` | At least one check produced incompatibility that a workaround may resolve |
|
|
44
|
+
| `Verified` | Every compatibility check passes, and at least one of the two skills cites the other literally | Documentation cross-reference (Check 4) MUST pass with a literal substring/name citation in at least one direction; language + protocol + type checks all pass |
|
|
45
|
+
| `Plausible` | Every check passes except the documentation cross-reference: neither skill cites the other literally | Language + protocol + type checks pass; Check 4 weak or missing (no literal citation) |
|
|
46
|
+
| `Risky` | At least one check produced incompatibility that a workaround may resolve | The language, protocol or type check fails (a missing Check 4 citation caps at `Plausible` instead); workaround cited in recommendation |
|
|
45
47
|
| `Blocked` | Fundamental incompatibility that cannot be worked around | Language mismatch, protocol mismatch with no bridge, or type mismatch with no adapter |
|
|
46
48
|
|
|
47
49
|
## Overall verdict tokens (case-sensitive)
|
|
48
50
|
|
|
49
51
|
Exactly one of `FEASIBLE`, `CONDITIONALLY_FEASIBLE`, `NOT_FEASIBLE`.
|
|
50
52
|
|
|
51
|
-
- `FEASIBLE
|
|
52
|
-
- `NOT_FEASIBLE
|
|
53
|
-
- `CONDITIONALLY_FEASIBLE
|
|
53
|
+
- `FEASIBLE`: every live technology is Covered (100% coverage; a technology marked Replaced is not live), every integration pair is `Verified`, at least one integration pair exists when there are two or more live technologies, and, when the requirements pass ran, every requirement is Fulfilled.
|
|
54
|
+
- `NOT_FEASIBLE`: any `Blocked` pair, or zero coverage.
|
|
55
|
+
- `CONDITIONALLY_FEASIBLE`: everything else. This includes a run that found no integration pair across two or more live technologies: those integrations were never checked, so they are not known to be compatible.
|
|
54
56
|
|
|
55
57
|
## Body section headings (required, in order)
|
|
56
58
|
|
|
@@ -62,24 +64,28 @@ Exactly one of `FEASIBLE`, `CONDITIONALLY_FEASIBLE`, `NOT_FEASIBLE`.
|
|
|
62
64
|
## Evidence Sources
|
|
63
65
|
```
|
|
64
66
|
|
|
65
|
-
Consumers
|
|
67
|
+
Consumers read the pair table under `## Integration Verdicts` through the script (see Filename). The table header is fixed:
|
|
66
68
|
|
|
67
69
|
```markdown
|
|
68
70
|
| lib_a | lib_b | verdict | rationale |
|
|
69
71
|
```
|
|
70
72
|
|
|
73
|
+
Only this table carries the per-pair verdicts, and the report holds it exactly once. The script fails on a report with a second one (a filled table appended below the report template's empty one, say), skips any table in fenced code or an HTML comment, and does not read the display table with more columns that may follow for human readers.
|
|
74
|
+
|
|
71
75
|
## Producer obligations (skf-verify-stack)
|
|
72
76
|
|
|
73
77
|
- Set `schemaVersion: "1.0"` in frontmatter.
|
|
78
|
+
- Write the `-latest` copy only after the finished report passes `skf-validate-feasibility-report.py`, and write nothing but the timestamped report before that, so a run that halts leaves the previous finished copy, the one `--locate` reads, in place.
|
|
74
79
|
- Never emit a verdict token outside the defined set.
|
|
75
|
-
-
|
|
80
|
+
- Write the canonical table exactly once under `## Integration Verdicts`, with no data rows when the run found no integration pair: fill the empty table in `assets/feasibility-report-template.md` instead of appending a second one.
|
|
81
|
+
- When Check 4 (documentation cross-reference) finds no literal citation, cap the per-pair verdict at `Plausible`. Protocol and data-format tokens inferred from prose (Check 2) can flag a risk, but they neither promote a pair to `Verified` nor cap it at `Plausible`.
|
|
76
82
|
- When `coveragePercentage == 0`, force `overallVerdict: NOT_FEASIBLE` regardless of pair results.
|
|
77
83
|
|
|
78
|
-
## Consumer obligations (skf-create-stack-skill)
|
|
84
|
+
## Consumer obligations (skf-refine-architecture, skf-create-stack-skill)
|
|
79
85
|
|
|
86
|
+
- Locate and read the report with `skf-validate-feasibility-report.py --locate` (see Filename), and read a report path the user gives through the same script; never build the file name or parse the report in prose.
|
|
80
87
|
- Verify `schemaVersion == "1.0"`; halt with explicit error on mismatch.
|
|
81
|
-
- Treat any unknown verdict token as a hard error (do not silently drop or map).
|
|
82
|
-
- Use filename pattern above when referencing prior reports.
|
|
88
|
+
- Treat any unknown verdict token (`--locate` lists them in `unknownTokens`) as a hard error (do not silently drop or map).
|
|
83
89
|
|
|
84
90
|
## Versioning policy
|
|
85
91
|
|
|
@@ -9,14 +9,16 @@ Gates are user interaction points where a workflow pauses for confirmation or in
|
|
|
9
9
|
Every gate in a step file follows this pattern:
|
|
10
10
|
|
|
11
11
|
```
|
|
12
|
-
**GATE
|
|
13
|
-
If `{headless_mode}`: auto-proceed with
|
|
12
|
+
**GATE [default: <option>]**: present [options] to the user.
|
|
13
|
+
If `{headless_mode}`: auto-proceed with <option>, log: "headless: auto-<option>".
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
A gate with no safe default names its HALT instead: `**GATE [default: HALT]**`, with the HALT's exit code and `halt_reason` where it fires.
|
|
17
|
+
|
|
16
18
|
The gate always:
|
|
17
19
|
1. Prepares the same output (summary, preview, menu) regardless of mode
|
|
18
20
|
2. In interactive mode: displays the output and waits for user input
|
|
19
|
-
3. In headless mode: displays the output, logs the auto-action, and proceeds with the default
|
|
21
|
+
3. In headless mode: displays the output, logs the auto-action, records it in the run sink (see [Recording Auto-Decisions and Warnings](#recording-auto-decisions-and-warnings)), and proceeds with the default
|
|
20
22
|
|
|
21
23
|
## Resolving `{headless_mode}`
|
|
22
24
|
|
|
@@ -27,6 +29,17 @@ The gate always:
|
|
|
27
29
|
|
|
28
30
|
Each workflow's On Activation section resolves this variable alongside other config. The forger passes it through when dispatching to workflows.
|
|
29
31
|
|
|
32
|
+
## Binding Inputs at Activation
|
|
33
|
+
|
|
34
|
+
Each workflow's On Activation, or its first stage, binds and checks what the run needs, so that a headless run never waits for a reply, makes up a value or widens what it acts on, and an interactive run never asks for what the invocation already said:
|
|
35
|
+
|
|
36
|
+
1. **Parse every input once.** Bind each input and flag of the workflow's Invocation Contract to a variable, in every mode. An argument the invocation supplies answers its question in an interactive run too. List every input and flag activation parses in the contract, and parse every one the contract lists.
|
|
37
|
+
2. **Validate fail-closed.** Bind a flag's raw value whenever the flag is present (null only when it is absent), and let the script that owns the check reject a wrong value. Halt on a value outside the documented set, with the exit code and the `halt_reason` the workflow's schema gives an invalid input, such as `input-invalid` (Campaign: `invalid-input`; update-skill and setup halt `blocked` at a named phase), and never fall back to a default. Audit-skill's `tier_override` is the one exception: an invalid value falls through to the preferences tier, then the detected one.
|
|
38
|
+
3. **Resolve the emitter before the first prompt.** Resolve the result envelope's emitter, and create the run folder where the workflow keeps one, at activation or at the start of the first stage, so every HARD HALT can emit its envelope. A helper that only a later stage runs may be resolved in that stage; when it is missing, the stage halts with the workflow's `helper-missing` or `resolution-failure` reason (brief-skill's helper halts name no `halt_reason` and emit nothing, as its SKILL.md Halt Contract says).
|
|
39
|
+
4. **Give every gate a default or a coded HALT.** Name each gate's headless default in its `**GATE [default: <option>]**` annotation, and record the decision it takes in the run sink, unless the workflow's contract names where that decision goes instead: Campaign's decision log, brief-skill's log lines (its envelope has no `headless_decisions`), or a field or warning the run already writes, such as Analyze's `coexistence`. A gate with no safe default, such as an input gate whose required input is missing, halts with its exit code and the `halt_reason` the workflow's schema gives a missing input, such as `input-missing` (update-skill and setup halt `blocked` at a named phase).
|
|
40
|
+
|
|
41
|
+
The workflow's Stages table and its contract's Gates row follow the `GATE` annotations: a stage that holds a gate does not read as auto-proceeding, a stage that waits holds one, and the Gates row names the steps that hold one.
|
|
42
|
+
|
|
30
43
|
## Gate Types
|
|
31
44
|
|
|
32
45
|
### Confirm Gate (default: Continue)
|
|
@@ -55,8 +68,47 @@ For skills that require user input (skill name, target path, etc.), headless mod
|
|
|
55
68
|
|
|
56
69
|
Example: `@Ferris QS cocoindex --headless` passes `cocoindex` as the target and skips all gates.
|
|
57
70
|
|
|
71
|
+
## Recording Auto-Decisions and Warnings
|
|
72
|
+
|
|
73
|
+
Every run owns a run folder, `_bmad-output/.skf-run/<workflow>-<run_id>/` (`{run_dir}`). Its sink holds what the run decided and noticed without a person, one JSON value per line:
|
|
74
|
+
|
|
75
|
+
| File | One line per |
|
|
76
|
+
| --- | --- |
|
|
77
|
+
| `headless-decisions.jsonl` | auto-decision: a JSON object shaped like one entry of the workflow's `headless_decisions` |
|
|
78
|
+
| `warnings.jsonl` | warning: a JSON string, such as `"customization_resolver_unavailable: <reason>"` |
|
|
79
|
+
|
|
80
|
+
A gate appends its decision the moment it decides, and a step appends a warning when it raises it, through the shared emitter rather than by hand. For a decision, stage the object as a file in the run folder first:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
uv run {emitEnvelopeHelper} record --workflow <workflow> --run-dir "{run_dir}" --decision < "{run_dir}/decision.json"
|
|
84
|
+
uv run {emitEnvelopeHelper} record --run-dir "{run_dir}" --warning "<warning>"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
With `--workflow`, a decision the workflow's envelope schema rejects fails here, at the gate; without it, the emitter leaves the decision out when the run ends and adds a `headless_decision_invalid` warning. Because the sink is on disk, the trail survives context compaction, and a HARD HALT reports every decision taken before it.
|
|
88
|
+
|
|
89
|
+
When the On Activation customization resolver is missing or fails, the run applies only the skill's own `customize.toml`. Record `customization_resolver_unavailable: <reason>` as a warning, or pass the reason in the envelope payload as `customization_resolver_unavailable`, so a pipeline sees that the team and user overrides under `_bmad/custom/` were not applied. Campaign's run spans several sessions, so it logs `customization_resolver_unavailable: <reason>` as an `event` in its decision log instead, and its result envelope's `decision_log` names that file.
|
|
90
|
+
|
|
91
|
+
## Emitting the Result Envelope
|
|
92
|
+
|
|
93
|
+
A workflow with a headless contract prints one `SKF_<NAME>_RESULT_JSON: {...}` line when a run ends and at every HARD HALT. The shared emitter builds it; the model never types it. Stage the payload as a file in the run folder, then run one command:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
uv run {emitEnvelopeHelper} emit --workflow <workflow> --run-dir "{run_dir}" --result-dir "{forge_version}" < "{run_dir}/result-context.json"
|
|
97
|
+
uv run {emitEnvelopeHelper} emit-halt --workflow <workflow> --run-dir "{run_dir}" < "{run_dir}/halt.json"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
- `result-context.json` holds the envelope's fields, and optionally the `result_contract` object for the run's result files. `halt.json` holds the halt's `phase`, `reason`, `halt_reason`, `exit_code` and `path`, plus any envelope field the halt already knows, such as the skill name.
|
|
101
|
+
- The emitter stamps what the model must not type: the timestamp from the clock, the run id and the result file path. It folds the sink into `headless_decisions` and `warnings`, derives `exit_code` from `halt_reason`, checks the envelope against the workflow's schema, `shared/scripts/schemas/skf-<name>-result-envelope.v1.json`, and prints the line. Display that line verbatim.
|
|
102
|
+
- With `--result-dir` naming a folder that exists (the version folder), it also writes the run's per-run and `-latest` result files, as `output-contract-schema.md` describes. A halt before that folder exists reports through the line alone.
|
|
103
|
+
- Write the `emit-halt` command at each HARD HALT, naming its phase, `halt_reason` and exit code there, and resolve the helper once at activation, before the first halt can fire. The halt then emits the right line even when the step file that defines the run's success envelope was never loaded, or was compacted away.
|
|
104
|
+
- If the helper exits non-zero or prints no line, display the halt reason alone.
|
|
105
|
+
|
|
106
|
+
A workflow adopts the emitter by adding its schema under `src/shared/scripts/schemas/`, with the emitter's settings in its `$defs`: an entry `skf-envelope` whose `const` names the workflow, the line's prefix, the status a halt carries, the exit code of each `halt_reason` and the result file name (the emitter's docstring lists the fields). `$defs` and `const` are standard keywords, so a strict validator such as Ajv still compiles the installed schema. skf-setup calls the same helper through its `emit` and `emit-blocked` subcommands, and skf-brief-skill through `skf-emit-brief-result-envelope.py`, which stays as an alias. Like the helper it replaced, the alias refuses no payload for a key the envelope has no field for, or for a typed `exit_code`: it drops the key, derives the code, and says so in the envelope's `warnings`.
|
|
107
|
+
|
|
58
108
|
## What Headless Does NOT Skip
|
|
59
109
|
|
|
60
110
|
- Error halts (hard halts on missing files, invalid state)
|
|
61
111
|
- Progress output (summaries, status updates still display)
|
|
62
112
|
- Quality thresholds (if a step produces output below spec, it still reports the issue)
|
|
113
|
+
|
|
114
|
+
Exception: skf-setup makes its result envelope the final message of a standalone headless run, so the envelope line is all `claude -p` prints. Under `--headless`, its alias `--quiet`, or `headless_mode: true` in `{sidecar_path}/preferences.yaml`, it skips its progress output, resolves its gates without displaying them, and the health check it chains to adds nothing of its own before that envelope. Inside a forger pipeline it displays the same line and returns control to the forger. skf-setup's `references/invocation-contract.md` states this.
|
|
@@ -9,22 +9,28 @@ Every pipeline-capable skill writes a result JSON file at its final step. This e
|
|
|
9
9
|
"skill": "skf-skill-name",
|
|
10
10
|
"status": "success" | "failed" | "partial",
|
|
11
11
|
"timestamp": "ISO-8601",
|
|
12
|
+
"run_id": "<run id>",
|
|
12
13
|
"outputs": [
|
|
13
14
|
{"type": "report|skill|manifest|config", "path": "relative/path/to/file"}
|
|
14
15
|
],
|
|
15
16
|
"summary": {
|
|
16
17
|
// skill-specific summary fields
|
|
17
|
-
}
|
|
18
|
+
},
|
|
19
|
+
"headless_decisions": [ /* the run's auto-decisions */ ],
|
|
20
|
+
"warnings": [ /* the run's non-fatal warnings */ ]
|
|
18
21
|
}
|
|
19
22
|
```
|
|
20
23
|
|
|
24
|
+
The shared emitter stamps `timestamp` (UTC, from the clock), `run_id` (when the run has a run folder), `headless_decisions` and `warnings` (from the run sink, see `headless-gate-convention.md`) into the record it writes. The workflow supplies the rest.
|
|
25
|
+
|
|
21
26
|
## Filenames
|
|
22
27
|
|
|
23
28
|
Each run writes **two files** to `{output_dir}`:
|
|
24
29
|
|
|
25
30
|
1. **Per-run record** (audit trail): `{skill-name}-result-{YYYYMMDD-HHmmss}.json`
|
|
26
|
-
- Timestamp is UTC, resolution to seconds
|
|
27
|
-
-
|
|
31
|
+
- Timestamp is UTC, resolution to seconds, for example `update-skill-result-20260413-145230.json`
|
|
32
|
+
- When a run of the same workflow already took that second's name, the emitter appends `-2`, `-3` and so on (`update-skill-result-20260413-145230-2.json`), so two runs that end in the same second never share a file
|
|
33
|
+
- Never overwritten by subsequent runs, so it keeps a durable audit trail across retries, aborts, and re-runs
|
|
28
34
|
2. **Stable latest pointer** (pipeline consumption): `{skill-name}-result-latest.json`
|
|
29
35
|
- A **copy** (not a symlink) of the per-run record just written
|
|
30
36
|
- Always present at a deterministic path so CI / pipelines / the forger can read `summary.*` without enumerating timestamps
|
|
@@ -34,12 +40,17 @@ Write the per-run record first, then copy it to the `-latest.json` path. If the
|
|
|
34
40
|
|
|
35
41
|
**Consumers (forger, CI, chained workflows):** read from `{skill-name}-result-latest.json`. Do not enumerate timestamped files unless inspecting prior-run history.
|
|
36
42
|
|
|
37
|
-
##
|
|
43
|
+
## Writing the Files
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
The shared emitter, `shared/scripts/skf-emit-result-envelope.py`, writes both files when it builds the run's `SKF_<NAME>_RESULT_JSON` envelope (see `headless-gate-convention.md`). Pass the version folder as `--result-dir`:
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
```bash
|
|
48
|
+
uv run {emitEnvelopeHelper} emit --workflow <workflow> --run-dir "{run_dir}" --result-dir "{forge_version}" < "{run_dir}/result-context.json"
|
|
49
|
+
```
|
|
42
50
|
|
|
43
|
-
|
|
51
|
+
- The file name's stem comes from the workflow's envelope schema (`result_file` in the emitter settings its `$defs` holds under `skf-envelope`), and the emitter chooses the per-run name, suffix included. A workflow whose settings name no result file writes none, and ignores `--result-dir` with a `result_dir_ignored` warning.
|
|
52
|
+
- The record is the payload's `result_contract` object with the stamped fields above, and with the payload's own `status` and `summary` when the contract leaves them out, so a workflow lists its summary once. A payload without one records the envelope itself, the error variant several workflows write on a HARD HALT (`emit-halt` takes `--result-dir` too).
|
|
53
|
+
- Each file is written atomically, the per-run record first and then its `-latest.json` copy. A write that fails adds a `result_file_write_failed` warning to the envelope, and a failed per-run record also leaves its `result_path` null; the envelope line still prints.
|
|
54
|
+
- When `--result-dir` names no folder that exists, nothing is written: a halt before the version folder exists reports through the envelope line alone.
|
|
44
55
|
|
|
45
|
-
skf-quick-skill writes both the success-variant contract
|
|
56
|
+
Workflows that have not adopted the emitter yet still assemble the record in their terminal step. skf-create-skill writes each brief's record through the emitter from step 8 (`references/report.md`), and a halt's from step 7 on. skf-quick-skill writes both through the emitter: the success-variant contract from `finalize.md` §3's `result_contract`, and the error variant, its envelope, at a HARD HALT once the version folder holds `metadata.json` (`references/halt-contract.md`).
|