bmad-module-skill-forge 2.2.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +49 -49
- package/docs/404.md +10 -8
- package/docs/_data/pinned.yaml +22 -13
- package/docs/_internal/STABILITY.md +58 -35
- package/docs/agents.md +39 -53
- package/docs/architecture.md +65 -51
- package/docs/bmad-synergy.md +53 -51
- package/docs/campaign.md +127 -75
- package/docs/concepts.md +34 -28
- package/docs/examples.md +70 -68
- package/docs/forge-auto.md +34 -31
- package/docs/getting-started.md +118 -57
- package/docs/how-it-works.md +25 -21
- package/docs/index.md +15 -15
- package/docs/skill-model.md +70 -59
- package/docs/troubleshooting.md +135 -18
- package/docs/verifying-a-skill.md +83 -57
- package/docs/why-skf.md +24 -22
- package/docs/workflows.md +274 -110
- package/package.json +18 -10
- package/src/forger/preferences.yaml +8 -1
- package/src/knowledge/agentskills-spec.md +2 -0
- package/src/knowledge/ccc-bridge.md +40 -24
- package/src/knowledge/confidence-tiers.md +9 -5
- package/src/knowledge/overview.md +3 -3
- package/src/knowledge/progressive-capability.md +8 -8
- package/src/knowledge/provenance-tracking.md +9 -5
- package/src/knowledge/qmd-registry.md +2 -2
- package/src/knowledge/skf-knowledge-index.csv +2 -2
- package/src/knowledge/skill-lifecycle.md +18 -11
- package/src/knowledge/split-body-strategy.md +0 -3
- package/src/knowledge/tool-resolution.md +4 -2
- package/src/knowledge/version-paths.md +101 -15
- package/src/module-help.csv +3 -3
- package/src/module.yaml +10 -0
- package/src/shared/data/ast-grep-recipes.yaml +608 -0
- package/src/shared/data/ide-context-files.json +30 -0
- package/src/shared/health-check.md +32 -12
- package/src/shared/references/description-guard-protocol.md +12 -9
- package/src/shared/references/feasibility-report-schema.md +19 -13
- package/src/shared/references/headless-gate-convention.md +55 -3
- package/src/shared/references/output-contract-schema.md +19 -8
- package/src/shared/references/pipeline-contracts.md +94 -29
- package/src/shared/references/tessl-review.md +77 -0
- package/src/shared/scripts/schemas/skf-analyze-result-envelope.v1.json +194 -0
- package/src/shared/scripts/schemas/skf-audit-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-brief-result-envelope.v1.json +32 -4
- package/src/shared/scripts/schemas/skf-campaign-result-envelope.v1.json +174 -0
- package/src/shared/scripts/schemas/skf-create-skill-result-envelope.v1.json +284 -0
- package/src/shared/scripts/schemas/skf-drop-skill-result-envelope.v1.json +164 -0
- package/src/shared/scripts/schemas/skf-export-result-envelope.v1.json +160 -0
- package/src/shared/scripts/schemas/skf-quick-skill-result-envelope.v1.json +261 -0
- package/src/shared/scripts/schemas/skf-refine-architecture-result-envelope.v1.json +192 -0
- package/src/shared/scripts/schemas/skf-rename-skill-result-envelope.v1.json +179 -0
- package/src/shared/scripts/schemas/skf-setup-result-envelope.v1.json +27 -11
- package/src/shared/scripts/schemas/skf-stack-result-envelope.v1.json +176 -0
- package/src/shared/scripts/schemas/skf-test-result-envelope.v1.json +173 -0
- package/src/shared/scripts/schemas/skf-update-result-envelope.v1.json +19 -5
- package/src/shared/scripts/schemas/skf-verify-stack-result-envelope.v1.json +180 -0
- package/src/shared/scripts/schemas/skill-brief.v1.json +34 -0
- package/src/shared/scripts/schemas/workspace-detection.v1.json +1 -1
- package/src/shared/scripts/skf-atomic-write.py +30 -14
- package/src/shared/scripts/skf-build-change-manifest.py +2203 -24
- package/src/shared/scripts/skf-ccc-git-hygiene.py +532 -0
- package/src/shared/scripts/skf-check-unit-records.py +184 -0
- package/src/shared/scripts/skf-check-workspace-drift.py +538 -9
- package/src/shared/scripts/skf-classify-changed-files.py +694 -0
- package/src/shared/scripts/skf-comention-pairs.py +1333 -123
- package/src/shared/scripts/skf-compare-file-hashes.py +1 -1
- package/src/shared/scripts/skf-count-imports.py +1867 -0
- package/src/shared/scripts/skf-count-tokens.py +1 -1
- package/src/shared/scripts/skf-derive-assembly-shape.py +3 -2
- package/src/shared/scripts/skf-description-guard.py +99 -11
- package/src/shared/scripts/skf-detect-docs.py +694 -2
- package/src/shared/scripts/skf-detect-language.py +486 -107
- package/src/shared/scripts/skf-detect-registry.py +887 -0
- package/src/shared/scripts/skf-detect-scripts-assets.py +1 -1
- package/src/shared/scripts/skf-detect-tools.py +209 -27
- package/src/shared/scripts/skf-detect-workspaces.py +506 -30
- package/src/shared/scripts/skf-disqualify-candidates.py +821 -182
- package/src/shared/scripts/skf-emit-brief-result-envelope.py +69 -191
- package/src/shared/scripts/skf-emit-result-envelope.py +1604 -106
- package/src/shared/scripts/skf-enumerate-stack-skills.py +986 -117
- package/src/shared/scripts/skf-extract-public-api.py +4084 -85
- package/src/shared/scripts/skf-extraction-inventory.py +746 -0
- package/src/shared/scripts/skf-extraction-snapshot.py +539 -0
- package/src/shared/scripts/skf-fetch-temporal.py +674 -0
- package/src/shared/scripts/skf-find-cycles.py +97 -29
- package/src/shared/scripts/skf-find-test-report.py +476 -0
- package/src/shared/scripts/skf-forge-tier-rw.py +444 -203
- package/src/shared/scripts/skf-github-fetch.py +365 -0
- package/src/shared/scripts/skf-github-probe.py +661 -0
- package/src/shared/scripts/skf-hash-content.py +166 -12
- package/src/shared/scripts/skf-language-corpora.py +1 -1
- package/src/shared/scripts/skf-load-provenance.py +159 -27
- package/src/shared/scripts/skf-manifest-ops.py +1 -1
- package/src/shared/scripts/skf-merge-ccc-exclusions.py +2307 -223
- package/src/shared/scripts/skf-merge-doc-urls.py +1 -1
- package/src/shared/scripts/skf-names-present.py +221 -0
- package/src/shared/scripts/skf-pair-intersect.py +119 -28
- package/src/shared/scripts/skf-parse-gaps.py +1384 -0
- package/src/shared/scripts/skf-preapply.py +1 -1
- package/src/shared/scripts/skf-preflight.py +161 -27
- package/src/shared/scripts/skf-promote-staged.py +430 -0
- package/src/shared/scripts/skf-provenance-gap-dispatch.py +39 -7
- package/src/shared/scripts/skf-qmd-classify-collections.py +229 -45
- package/src/shared/scripts/skf-quick-batch.py +774 -0
- package/src/shared/scripts/skf-rebuild-managed-sections.py +972 -88
- package/src/shared/scripts/skf-recommend-scope-type.py +323 -156
- package/src/shared/scripts/skf-render-metadata-stats.py +156 -12
- package/src/shared/scripts/skf-render-quick-metadata.py +132 -28
- package/src/shared/scripts/skf-render-stack-metadata.py +976 -0
- package/src/shared/scripts/skf-resolve-authoritative-files.py +128 -13
- package/src/shared/scripts/skf-resolve-package.py +523 -106
- package/src/shared/scripts/skf-rewrite-skill-name.py +433 -47
- package/src/shared/scripts/skf-run-lock.py +577 -0
- package/src/shared/scripts/skf-scan-manifests.py +998 -57
- package/src/shared/scripts/skf-scan-skill-md-structure.py +1341 -37
- package/src/shared/scripts/skf-severity-classify.py +712 -108
- package/src/shared/scripts/skf-shape-detect.py +298 -204
- package/src/shared/scripts/skf-shard-body.py +9 -8
- package/src/shared/scripts/skf-skill-inventory.py +2412 -89
- package/src/shared/scripts/skf-skills-module.py +472 -0
- package/src/shared/scripts/skf-source-tree.py +1796 -0
- package/src/shared/scripts/skf-structural-diff.py +670 -119
- package/src/shared/scripts/skf-tessl-review.py +706 -0
- package/src/shared/scripts/skf-update-active-symlink.py +5 -5
- package/src/shared/scripts/skf-update-run-state.py +624 -0
- package/src/shared/scripts/skf-validate-brief-inputs.py +92 -29
- package/src/shared/scripts/skf-validate-brief-schema.py +4 -1
- package/src/shared/scripts/skf-validate-feasibility-report.py +577 -66
- package/src/shared/scripts/skf-validate-frontmatter.py +103 -26
- package/src/shared/scripts/skf-validate-output.py +712 -64
- package/src/shared/scripts/skf-validate-pins.py +1 -1
- package/src/shared/scripts/skf-verify-no-trace.py +116 -10
- package/src/shared/scripts/skf-verify-provenance-completeness.py +2919 -54
- package/src/shared/scripts/skf-write-skill-brief.py +367 -19
- package/src/shared/tool-requirements.yaml +201 -0
- package/src/skf-analyze-source/SKILL.md +41 -36
- package/src/skf-analyze-source/assets/skill-brief-schema.md +7 -8
- package/src/skf-analyze-source/customize.toml +36 -24
- package/src/skf-analyze-source/references/auto-docs-only.md +58 -20
- package/src/skf-analyze-source/references/continue.md +2 -13
- package/src/skf-analyze-source/references/discover-additional-source.md +147 -0
- package/src/skf-analyze-source/references/generate-briefs.md +121 -55
- package/src/skf-analyze-source/references/headless-contract.md +42 -15
- package/src/skf-analyze-source/references/identify-units.md +96 -110
- package/src/skf-analyze-source/references/init.md +73 -71
- package/src/skf-analyze-source/references/map-and-detect.md +123 -105
- package/src/skf-analyze-source/references/map-unit-exports.md +68 -0
- package/src/skf-analyze-source/references/recommend.md +51 -70
- package/src/skf-analyze-source/references/scan-project.md +60 -84
- package/src/skf-analyze-source/references/scan-root.md +39 -0
- package/src/skf-analyze-source/references/step-auto-scope-coexistence.md +47 -0
- package/src/skf-analyze-source/references/step-auto-scope-corpora.md +53 -0
- package/src/skf-analyze-source/references/step-auto-scope-split.md +91 -0
- package/src/skf-analyze-source/references/step-auto-scope.md +208 -293
- package/src/skf-analyze-source/references/step-shape-detect.md +14 -12
- package/src/skf-analyze-source/references/unit-detection-heuristics.md +37 -42
- package/src/skf-audit-skill/SKILL.md +43 -51
- package/src/skf-audit-skill/assets/drift-report-template.md +27 -3
- package/src/skf-audit-skill/customize.toml +41 -20
- package/src/skf-audit-skill/references/constituent-freshness.md +91 -0
- package/src/skf-audit-skill/references/doc-drift.md +141 -0
- package/src/skf-audit-skill/references/headless-contract.md +29 -0
- package/src/skf-audit-skill/references/init.md +148 -210
- package/src/skf-audit-skill/references/re-index.md +96 -108
- package/src/skf-audit-skill/references/report.md +96 -33
- package/src/skf-audit-skill/references/semantic-diff.md +27 -18
- package/src/skf-audit-skill/references/severity-classify.md +79 -65
- package/src/skf-audit-skill/references/severity-rules.md +15 -6
- package/src/skf-audit-skill/references/structural-diff.md +75 -90
- package/src/skf-audit-skill/references/upstream-checkout.md +77 -0
- package/src/skf-audit-skill/scripts/render-drift-tables.py +685 -0
- package/src/skf-brief-skill/SKILL.md +36 -25
- package/src/skf-brief-skill/assets/description-voice-examples.md +1 -1
- package/src/skf-brief-skill/assets/scope-templates.md +17 -24
- package/src/skf-brief-skill/assets/skill-brief-schema.md +29 -15
- package/src/skf-brief-skill/customize.toml +48 -20
- package/src/skf-brief-skill/references/analyze-target.md +142 -125
- package/src/skf-brief-skill/references/confirm-brief.md +10 -8
- package/src/skf-brief-skill/references/draft-checkpoint.md +36 -17
- package/src/skf-brief-skill/references/gather-intent-ratify.md +68 -0
- package/src/skf-brief-skill/references/gather-intent.md +87 -182
- package/src/skf-brief-skill/references/headless-args.md +84 -16
- package/src/skf-brief-skill/references/health-check.md +1 -1
- package/src/skf-brief-skill/references/invocation-contract.md +18 -13
- package/src/skf-brief-skill/references/portfolio-similarity-check.md +1 -1
- package/src/skf-brief-skill/references/qmd-collection-registration.md +7 -10
- package/src/skf-brief-skill/references/scope-definition.md +123 -47
- package/src/skf-brief-skill/references/step-auto-brief.md +24 -80
- package/src/skf-brief-skill/references/step-auto-validate.md +20 -121
- package/src/skf-brief-skill/references/version-resolution.md +3 -2
- package/src/skf-brief-skill/references/write-brief.md +66 -57
- package/src/skf-campaign/SKILL.md +31 -34
- package/src/skf-campaign/assets/campaign-state-schema.json +25 -4
- package/src/skf-campaign/customize.toml +47 -16
- package/src/skf-campaign/references/campaign-contracts.md +39 -29
- package/src/skf-campaign/references/campaign-directive-spec.md +4 -2
- package/src/skf-campaign/references/health-check.md +7 -16
- package/src/skf-campaign/references/step-01-setup.md +46 -84
- package/src/skf-campaign/references/step-02-strategy.md +31 -30
- package/src/skf-campaign/references/step-03-pins.md +26 -18
- package/src/skf-campaign/references/step-04-provenance.md +24 -23
- package/src/skf-campaign/references/step-05-skill-loop.md +67 -48
- package/src/skf-campaign/references/step-06-batch.md +41 -34
- package/src/skf-campaign/references/step-07-capstone.md +40 -25
- package/src/skf-campaign/references/step-08-verify.md +28 -29
- package/src/skf-campaign/references/step-09-refine.md +29 -30
- package/src/skf-campaign/references/step-10-export.md +48 -36
- package/src/skf-campaign/references/step-11-maintenance.md +31 -34
- package/src/skf-campaign/references/step-resume.md +37 -68
- package/src/skf-campaign/scripts/campaign-deps.py +57 -18
- package/src/skf-campaign/scripts/campaign-parse-manifest.py +361 -54
- package/src/skf-campaign/scripts/campaign-provenance.py +96 -53
- package/src/skf-campaign/scripts/campaign-quality-gate.py +592 -0
- package/src/skf-campaign/scripts/campaign-render-batch.py +257 -49
- package/src/skf-campaign/scripts/campaign-render-kickoff.py +343 -50
- package/src/skf-campaign/scripts/campaign-report.py +204 -37
- package/src/skf-campaign/scripts/campaign-state.py +1128 -0
- package/src/skf-campaign/scripts/campaign-status.py +10 -74
- package/src/skf-campaign/scripts/campaign-validate-pins.py +30 -3
- package/src/skf-campaign/scripts/campaign-validate-state.py +34 -4
- package/src/skf-campaign/templates/campaign-brief-template.yaml +4 -5
- package/src/skf-campaign/templates/campaign-report-template.md +5 -1
- package/src/skf-campaign/templates/kickoff-template.md +0 -14
- package/src/skf-create-skill/SKILL.md +27 -20
- package/src/skf-create-skill/assets/compile-assembly-rules.md +6 -5
- package/src/skf-create-skill/assets/skill-sections.md +15 -5
- package/src/skf-create-skill/customize.toml +20 -8
- package/src/skf-create-skill/references/authoritative-files-protocol.md +41 -42
- package/src/skf-create-skill/references/batch-mode.md +81 -0
- package/src/skf-create-skill/references/ccc-index-check.md +27 -0
- package/src/skf-create-skill/references/compile.md +107 -29
- package/src/skf-create-skill/references/component-extraction.md +113 -91
- package/src/skf-create-skill/references/enrich.md +41 -23
- package/src/skf-create-skill/references/entry-points-by-hand.md +20 -0
- package/src/skf-create-skill/references/extract.md +200 -161
- package/src/skf-create-skill/references/extraction-patterns-by-hand.md +141 -0
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +2 -2
- package/src/skf-create-skill/references/extraction-patterns.md +584 -196
- package/src/skf-create-skill/references/generate-artifacts.md +145 -93
- package/src/skf-create-skill/references/health-check.md +1 -1
- package/src/skf-create-skill/references/load-brief.md +53 -36
- package/src/skf-create-skill/references/relabel-rule.md +12 -0
- package/src/skf-create-skill/references/report.md +28 -59
- package/src/skf-create-skill/references/source-resolution-protocols.md +49 -155
- package/src/skf-create-skill/references/step-auto-shard.md +20 -93
- package/src/skf-create-skill/references/step-doc-rot.md +44 -60
- package/src/skf-create-skill/references/step-doc-sources.md +28 -19
- package/src/skf-create-skill/references/sub/ccc-discover.md +18 -7
- package/src/skf-create-skill/references/sub/fetch-docs.md +106 -59
- package/src/skf-create-skill/references/sub/fetch-temporal.md +53 -166
- package/src/skf-create-skill/references/tier-degradation-rules.md +18 -9
- package/src/skf-create-skill/references/validate.md +173 -99
- package/src/skf-create-skill/scripts/scan-doc-rot.py +232 -99
- package/src/skf-create-stack-skill/SKILL.md +29 -56
- package/src/skf-create-stack-skill/assets/metadata-contract.md +51 -0
- package/src/skf-create-stack-skill/assets/provenance-map-schema.md +15 -15
- package/src/skf-create-stack-skill/assets/stack-skill-template.md +23 -57
- package/src/skf-create-stack-skill/customize.toml +23 -12
- package/src/skf-create-stack-skill/references/compile-stack.md +57 -66
- package/src/skf-create-stack-skill/references/compose-mode-rules.md +24 -44
- package/src/skf-create-stack-skill/references/detect-integrations.md +92 -95
- package/src/skf-create-stack-skill/references/detect-manifests.md +46 -71
- package/src/skf-create-stack-skill/references/generate-output.md +138 -128
- package/src/skf-create-stack-skill/references/init.md +90 -32
- package/src/skf-create-stack-skill/references/integration-patterns.md +1 -17
- package/src/skf-create-stack-skill/references/invocation-contract.md +34 -0
- package/src/skf-create-stack-skill/references/manifest-patterns.md +32 -20
- package/src/skf-create-stack-skill/references/parallel-extract.md +112 -38
- package/src/skf-create-stack-skill/references/rank-and-confirm.md +57 -75
- package/src/skf-create-stack-skill/references/report.md +39 -33
- package/src/skf-create-stack-skill/references/validate.md +20 -39
- package/src/skf-drop-skill/SKILL.md +28 -51
- package/src/skf-drop-skill/customize.toml +44 -30
- package/src/skf-drop-skill/references/execute.md +79 -146
- package/src/skf-drop-skill/references/invocation-contract.md +64 -0
- package/src/skf-drop-skill/references/report.md +46 -30
- package/src/skf-drop-skill/references/select.md +118 -124
- package/src/skf-drop-skill/scripts/dir-sizes.py +54 -26
- package/src/skf-drop-skill/scripts/drop-roster.py +322 -0
- package/src/skf-export-skill/SKILL.md +40 -62
- package/src/skf-export-skill/assets/managed-section-format.md +14 -50
- package/src/skf-export-skill/assets/snippet-format.md +3 -1
- package/src/skf-export-skill/customize.toml +42 -13
- package/src/skf-export-skill/references/generate-snippet.md +54 -46
- package/src/skf-export-skill/references/health-check.md +2 -0
- package/src/skf-export-skill/references/invocation-contract.md +15 -0
- package/src/skf-export-skill/references/load-skill.md +88 -62
- package/src/skf-export-skill/references/manifest-rebuild.md +9 -10
- package/src/skf-export-skill/references/multi-skill-mode.md +4 -4
- package/src/skf-export-skill/references/orphan-context-detection.md +13 -5
- package/src/skf-export-skill/references/orphan-row-detection.md +31 -22
- package/src/skf-export-skill/references/package.md +15 -73
- package/src/skf-export-skill/references/preflight-snippet-root-probe.md +51 -70
- package/src/skf-export-skill/references/result-envelope.md +31 -16
- package/src/skf-export-skill/references/summary.md +41 -17
- package/src/skf-export-skill/references/token-report.md +4 -12
- package/src/skf-export-skill/references/update-context.md +118 -237
- package/src/skf-forger/SKILL.md +61 -37
- package/src/skf-forger/bmad-skill-manifest.yaml +4 -1
- package/src/skf-forger/customize.toml +43 -0
- package/src/skf-forger/references/pipeline-mode.md +73 -18
- package/src/skf-forger/scripts/forge-status.py +299 -0
- package/src/skf-forger/scripts/parse-pipeline.py +322 -54
- package/src/skf-forger/scripts/pipeline-gate.py +428 -0
- package/src/skf-forger/scripts/pipeline-journal.py +1052 -0
- package/src/skf-quick-skill/SKILL.md +54 -53
- package/src/skf-quick-skill/assets/skill-template.md +4 -2
- package/src/skf-quick-skill/customize.toml +51 -20
- package/src/skf-quick-skill/references/batch-mode.md +74 -21
- package/src/skf-quick-skill/references/compile.md +30 -31
- package/src/skf-quick-skill/references/ecosystem-check.md +7 -57
- package/src/skf-quick-skill/references/finalize.md +69 -18
- package/src/skf-quick-skill/references/halt-contract.md +41 -29
- package/src/skf-quick-skill/references/health-check.md +5 -3
- package/src/skf-quick-skill/references/quick-extract.md +114 -45
- package/src/skf-quick-skill/references/registry-resolution.md +9 -64
- package/src/skf-quick-skill/references/resolve-target.md +116 -66
- package/src/skf-quick-skill/references/write-and-validate.md +79 -40
- package/src/skf-refine-architecture/SKILL.md +43 -53
- package/src/skf-refine-architecture/customize.toml +49 -20
- package/src/skf-refine-architecture/references/compile.md +97 -54
- package/src/skf-refine-architecture/references/exit-codes.md +30 -0
- package/src/skf-refine-architecture/references/finding-storage.md +21 -0
- package/src/skf-refine-architecture/references/gap-analysis.md +101 -38
- package/src/skf-refine-architecture/references/improvements.md +14 -20
- package/src/skf-refine-architecture/references/init.md +98 -57
- package/src/skf-refine-architecture/references/issue-detection.md +32 -39
- package/src/skf-refine-architecture/references/refinement-rules.md +37 -48
- package/src/skf-refine-architecture/references/report.md +65 -54
- package/src/skf-refine-architecture/scripts/skf-check-preservation.py +1619 -0
- package/src/skf-rename-skill/SKILL.md +19 -54
- package/src/skf-rename-skill/customize.toml +32 -26
- package/src/skf-rename-skill/references/execute.md +230 -184
- package/src/skf-rename-skill/references/exit-codes.md +7 -7
- package/src/skf-rename-skill/references/health-check.md +1 -7
- package/src/skf-rename-skill/references/invocation-contract.md +25 -0
- package/src/skf-rename-skill/references/report.md +63 -52
- package/src/skf-rename-skill/references/select.md +197 -115
- package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -21
- package/src/skf-setup/SKILL.md +26 -26
- package/src/skf-setup/customize.toml +14 -10
- package/src/skf-setup/references/auto-index.md +50 -63
- package/src/skf-setup/references/ccc-index.md +29 -90
- package/src/skf-setup/references/detect-and-tier.md +58 -67
- package/src/skf-setup/references/health-check.md +2 -0
- package/src/skf-setup/references/invocation-contract.md +14 -0
- package/src/skf-setup/references/report.md +43 -166
- package/src/skf-setup/references/tier-rules.md +5 -5
- package/src/skf-setup/references/write-config.md +34 -57
- package/src/skf-test-skill/SKILL.md +17 -57
- package/src/skf-test-skill/assets/output-section-formats.md +33 -34
- package/src/skf-test-skill/customize.toml +27 -13
- package/src/skf-test-skill/references/coherence-check.md +134 -62
- package/src/skf-test-skill/references/coverage-check-tiers.md +35 -0
- package/src/skf-test-skill/references/coverage-check.md +217 -254
- package/src/skf-test-skill/references/detect-mode.md +5 -5
- package/src/skf-test-skill/references/external-validators.md +94 -82
- package/src/skf-test-skill/references/health-check.md +6 -7
- package/src/skf-test-skill/references/init.md +163 -88
- package/src/skf-test-skill/references/invocation-contract.md +66 -0
- package/src/skf-test-skill/references/migration-section-rules.md +5 -2
- package/src/skf-test-skill/references/report.md +162 -142
- package/src/skf-test-skill/references/score.md +80 -107
- package/src/skf-test-skill/references/scoring-rules.md +41 -155
- package/src/skf-test-skill/references/source-access-protocol.md +19 -92
- package/src/skf-test-skill/references/step-hard-gate.md +51 -33
- package/src/skf-test-skill/scripts/aggregate-coherence.py +218 -30
- package/src/skf-test-skill/scripts/build-result-context.py +287 -0
- package/src/skf-test-skill/scripts/check-metadata-coherence.py +37 -4
- package/src/skf-test-skill/scripts/combine-external-scores.py +23 -6
- package/src/skf-test-skill/scripts/compute-score.py +223 -45
- package/src/skf-test-skill/scripts/gap-ledger.py +1381 -0
- package/src/skf-test-skill/scripts/hard-gate.py +203 -0
- package/src/skf-test-skill/scripts/load-coverage-inputs.py +760 -0
- package/src/skf-test-skill/scripts/locate-export-segments.py +835 -0
- package/src/skf-test-skill/scripts/reconcile-coverage.py +273 -79
- package/src/skf-test-skill/scripts/score-signatures.py +459 -0
- package/src/skf-test-skill/scripts/stage-helper-payload.py +148 -0
- package/src/skf-test-skill/scripts/validate-inventory.py +311 -16
- package/src/skf-test-skill/scripts/verify-declared-numerator.py +127 -52
- package/src/skf-test-skill/templates/test-report-template.md +21 -15
- package/src/skf-update-skill/SKILL.md +38 -25
- package/src/skf-update-skill/customize.toml +27 -12
- package/src/skf-update-skill/references/detect-changes.md +233 -222
- package/src/skf-update-skill/references/gap-driven.md +336 -0
- package/src/skf-update-skill/references/health-check.md +31 -5
- package/src/skf-update-skill/references/init.md +250 -84
- package/src/skf-update-skill/references/invocation-contract.md +12 -0
- package/src/skf-update-skill/references/manual-section-rules.md +6 -23
- package/src/skf-update-skill/references/merge.md +180 -47
- package/src/skf-update-skill/references/re-extract.md +53 -262
- package/src/skf-update-skill/references/report.md +100 -35
- package/src/skf-update-skill/references/write.md +331 -149
- package/src/skf-update-skill/scripts/skf-new-file-diff.py +29 -7
- package/src/skf-verify-stack/SKILL.md +23 -42
- package/src/skf-verify-stack/assets/feasibility-report-template.md +11 -5
- package/src/skf-verify-stack/customize.toml +55 -22
- package/src/skf-verify-stack/references/coverage-patterns.md +17 -8
- package/src/skf-verify-stack/references/coverage.md +67 -64
- package/src/skf-verify-stack/references/exit-codes.md +21 -8
- package/src/skf-verify-stack/references/init.md +107 -62
- package/src/skf-verify-stack/references/integration-verification-rules.md +12 -13
- package/src/skf-verify-stack/references/integrations.md +106 -65
- package/src/skf-verify-stack/references/report.md +59 -42
- package/src/skf-verify-stack/references/requirements.md +32 -9
- package/src/skf-verify-stack/references/synthesize.md +53 -39
- package/src/skf-verify-stack/scripts/skf-coverage-tally.py +398 -52
- package/src/skf-verify-stack/scripts/skf-previous-report.py +330 -0
- package/src/skf-verify-stack/scripts/skf-report-delta.py +453 -49
- package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +240 -27
- package/tools/cli/commands/install.js +11 -4
- package/tools/cli/commands/status.js +15 -3
- package/tools/cli/commands/update.js +11 -4
- package/tools/cli/lib/tool-check.js +320 -0
- package/tools/cli/lib/version-check.js +22 -9
- package/tools/cli/skf-cli.js +4 -1
- package/.gitattributes +0 -16
- package/.nvmrc +0 -1
- package/docs/_internal/RELEASING.md +0 -679
- package/release-audits/v1.0.0-launch-audit.md +0 -728
- package/src/skf-audit-skill/references/step-doc-drift.md +0 -177
- package/src/skf-brief-skill/references/headless-source-authority-detection.md +0 -26
- package/src/skf-campaign/manifest.yaml +0 -15
- package/src/skf-create-skill/assets/tessl-dismissal-rules.md +0 -106
- package/src/skf-create-skill/references/ecosystem-check.md +0 -74
- package/src/skf-drop-skill/references/headless-contract.md +0 -18
- package/src/skf-update-skill/references/merge-conflict-rules.md +0 -15
- package/src/skf-update-skill/references/remote-source-resolution.md +0 -98
- package/src/skf-update-skill/references/validate.md +0 -124
- package/tools/validate-docs-drift.js +0 -233
- package/tools/validate-docs-links.js +0 -665
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'structural-diff.md'
|
|
3
|
+
extractionPatternsData: 'skf-create-skill/references/extraction-patterns.md'
|
|
4
|
+
tierDegradationRulesData: 'skf-create-skill/references/tier-degradation-rules.md'
|
|
3
5
|
outputFile: '{forge_version}/drift-report-{timestamp}.md'
|
|
6
|
+
# This run's stage data folder: the scan list, the recipe runner's JSON and
|
|
7
|
+
# the files of exports read by eye, which the snapshot is built from.
|
|
8
|
+
auditDataFolder: '{forge_version}/.skf-audit/{timestamp}'
|
|
9
|
+
extractPublicApiProbeOrder:
|
|
10
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-extract-public-api.py'
|
|
11
|
+
- '{project-root}/src/shared/scripts/skf-extract-public-api.py'
|
|
12
|
+
extractionSnapshotProbeOrder:
|
|
13
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-extraction-snapshot.py'
|
|
14
|
+
- '{project-root}/src/shared/scripts/skf-extraction-snapshot.py'
|
|
15
|
+
# Every HALT after the [C] of upstream-checkout.md closes the private tree with it.
|
|
16
|
+
sourceTreeProbeOrder:
|
|
17
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-source-tree.py'
|
|
18
|
+
- '{project-root}/src/shared/scripts/skf-source-tree.py'
|
|
4
19
|
---
|
|
5
20
|
|
|
6
21
|
<!-- Config: communicate in {communication_language}. -->
|
|
@@ -14,164 +29,137 @@ Re-scan the source code using the current forge tier tools to build a fresh extr
|
|
|
14
29
|
## Rules
|
|
15
30
|
|
|
16
31
|
- Focus only on extracting current source state — do not compare yet (that's Step 03)
|
|
17
|
-
- Extract every file in the bounded scan list
|
|
18
|
-
-
|
|
32
|
+
- Extract every file in the bounded scan list: a file skipped here makes step 3 flag its exports as false "removed" drift. The snapshot helper gives each file a status and says whether the snapshot is complete (§3), so never judge completeness by eye
|
|
33
|
+
- At Forge, Forge+ and Deep the recipe runner extracts; read by eye only what it leaves (§3), using subprocess Pattern 2 (per-file deep analysis) when available to read those files; if unavailable, read them in the main thread file by file
|
|
19
34
|
|
|
20
35
|
## MANDATORY SEQUENCE
|
|
21
36
|
|
|
37
|
+
**Halt envelope.** Every HALT in this step names its exit code, `halt_reason` and phase. When `{source_tree}` is set (the [C] of `upstream-checkout.md`), first run `uv run {sourceTreeHelper} close --tree "{source_tree}"` from `{project-root}` and go on whatever it prints. In headless mode, stage `{run_dir}/halt.json` as `{"phase": "<phase>", "reason": "<the halt message>", "halt_reason": "<halt_reason>", "skill_name": "{skill_name}", "report_path": "{outputFile}"}`, adding `"path"` when the halt names one, then run:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
uv run {emitEnvelopeHelper} emit-halt --workflow skf-audit-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Display the line it prints, then stop with the halt's exit code. If the emitter exits non-zero or prints no line, display the halt message alone. An interactive HALT displays its message and emits nothing.
|
|
44
|
+
|
|
22
45
|
### 1. Determine Extraction Strategy
|
|
23
46
|
|
|
47
|
+
Label every export by the tool that produced it, never by the tier: an export an ast-grep rule matched is T1 with `extraction_method: ast-grep` and, as `ast_node_type`, the `kind` the matching pattern or recipe declares in `{extractionPatternsData}` (ast-grep's output does not report it); an export read by eye is T1-low with `extraction_method: source-read` and `ast_node_type: null`.
|
|
48
|
+
|
|
24
49
|
Based on forge tier detected in Step 01:
|
|
25
50
|
|
|
26
51
|
**Quick tier (no AST tools):**
|
|
27
52
|
- Read source files via gh_bridge or direct file I/O
|
|
28
53
|
- Extract export names by text pattern matching (function/class/type declarations)
|
|
29
|
-
-
|
|
54
|
+
- Label every export T1-low (read by eye, not matched by ast-grep) with `extraction_method: source-read` and `ast_node_type: null`
|
|
30
55
|
|
|
31
56
|
**Forge tier (ast-grep available):**
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
57
|
+
- The recipe runner extracts, as the **AST Extraction Protocol** in `{extractionPatternsData}` says: one `skf-extract-public-api.py --mode full` call over the bounded scan list from §2 (§3 gives the command) runs every recipe for the language in one process, reads only the files on the list, and keeps every match (`--head-cap 0`: a match past a cap would read as a removed export in step 3). While it can run, never run the recipes one at a time, batch them, or merge and dedupe their matches by hand
|
|
58
|
+
- Each export it returns is T1 as it stands: its name (`$NAME`), type, file, line (`$NAME`'s line, as create-skill records it, not the match's first line, which a decorator or an `export` line can hold), `ast_node_type` and `signature`, the declaration on one line even when a formatter split its parameters over several
|
|
59
|
+
- Read by eye only what the runner leaves (§3): the forms the recipes leave out (Known Limitation #11 in `{extractionPatternsData}`) when a file uses them, the names an entry point exports that no recipe found, and the files it could not parse or read. Label each export by the tool that produced it: T1 with `extraction_method: ast-grep` for a runner export, T1-low with `extraction_method: source-read` and `ast_node_type: null` for an export read by eye
|
|
60
|
+
|
|
61
|
+
**Tier degradation handling (Forge/Forge+/Deep):** If the runner cannot run and ast-grep is unavailable, follow `{tierDegradationRulesData}` (AST Tool Unavailable, Per-File AST Failure) for the fallback and the user notification. A file ast-grep cannot parse falls back to reading that file only: its exports are T1-low with `extraction_method: source-read` and `ast_node_type: null`, and exports the runner matched in other files stay T1. Silent degradation is forbidden: the snapshot names each file's status, and the run names each file read after an ast-grep failure, and why (§3, §4); when ast-grep is unavailable for the whole run, every export is T1-low.
|
|
35
62
|
|
|
36
63
|
**Forge+ tier (ast-grep + ccc available):**
|
|
37
|
-
- Identical extraction to Forge tier
|
|
38
|
-
-
|
|
39
|
-
- CCC rename detection
|
|
64
|
+
- Identical extraction to Forge tier (the AST Extraction Protocol, above)
|
|
65
|
+
- Label each export by tool, as at Forge tier
|
|
66
|
+
- CCC rename detection runs in step 3 (`structural-diff.md` §1b), over the exports the diff reports removed
|
|
40
67
|
|
|
41
68
|
**Deep tier (ast-grep + QMD available):**
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
- Confidence labels: T1 for structural, T2 for temporal context
|
|
69
|
+
- Identical extraction to Forge tier, labeled by tool as at Forge tier
|
|
70
|
+
- No QMD query at this step: step 4 (semantic diff) queries QMD itself
|
|
45
71
|
|
|
46
|
-
**Tool resolution:** `gh_bridge` → `gh api` commands or direct file I/O if local. `ast_bridge
|
|
72
|
+
**Tool resolution:** `gh_bridge` → `gh api` commands or direct file I/O if local. `ast_bridge`, only when the runner cannot run (the protocol's **When the Runner Cannot Run**): the ast-grep MCP tool `find_code_by_rule` with a recipe and `output_format="json"`, or the protocol's CLI streaming template (`ast-grep scan -r {recipe_file} --json=stream`); `find_code` only as the fallback of Known Limitation #4. See `knowledge/tool-resolution.md`.
|
|
47
73
|
|
|
48
74
|
### 2. Build Bounded Scan List
|
|
49
75
|
|
|
50
|
-
Audit-skill detects drift on files that were in scope during create-skill. The authoritative record of "what was in scope" is the provenance map loaded in step 1. Scan only those files
|
|
76
|
+
Audit-skill detects drift on files that were in scope during create-skill. The authoritative record of "what was in scope" is the provenance map loaded in step 1. Scan only those files: **audit-skill does NOT discover new files**. New-file detection is the responsibility of `skf-update-skill`, which maintains its own change manifest; public API a package's entry points export from files outside that list reaches the drift report through the runner's entry-point diff (§3), for update-skill's scope reconciliation. To audit a project that has grown new files since creation, run update-skill first, then audit-skill.
|
|
51
77
|
|
|
52
78
|
**Why bounded:** without this constraint, files that were deliberately excluded by the original brief's scope patterns (test fixtures, vendored code, generated artifacts, demo code, unrelated modules) get scanned on every audit and their exports are flagged by step 3 structural diff as "added" — false-positive drift that obscures real structural changes.
|
|
53
79
|
|
|
54
|
-
|
|
80
|
+
Every skill that reaches this step has a provenance map: step 1 stops a skill without one, and sends a compose-mode stack and a docs-only skill around this step.
|
|
55
81
|
|
|
56
|
-
1. The **bounded scan list** is `{bounded_scan_files}
|
|
57
|
-
2. Verify each path under `{source_root}`. Files that existed at creation time but are now missing are **not** errors at this stage — keep them in the list so step 3 can classify them as DELETED. Handling missing files is step 3's job, not step 2's.
|
|
58
|
-
3. Record `bounded_scan: true` and `bounded_scan_source: "provenance-map"` in context for the evidence report.
|
|
59
|
-
4. Report:
|
|
82
|
+
1. The **bounded scan list** is `{bounded_scan_files}`, the union of `entries[].source_file` and `file_entries[].source_file` that step 1 §4's `skf-load-provenance.py normalize` call returned. Do **not** re-walk the provenance map to rebuild it. Resolve `{extractionSnapshotHelper}` ← first existing path in `{extractionSnapshotProbeOrder}` (if none exists, HALT with **exit 3**, `halt_reason: "helper-missing"`, phase `re-index:scan-list`) and write the list where the runner reads it, from `{project-root}`:
|
|
60
83
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
1. Fall back to a source-tree scan: list all source files under `{source_root}` matching the project's primary language extensions (derive from `metadata.json.language` — e.g., `*.ts` / `*.tsx` for typescript, `*.py` for python, `*.rs` for rust, `*.go` for go).
|
|
66
|
-
2. Apply generic exclusions: `**/tests/**`, `**/test/**`, `**/__tests__/**`, `*.test.*`, `*.spec.*`, `node_modules/**`, `dist/**`, `build/**`, `target/**`, `__pycache__/**`, `.venv/**`, `vendor/**`.
|
|
67
|
-
3. Record `bounded_scan: false` and `bounded_scan_source: "source-tree-fallback"` in context.
|
|
68
|
-
4. Report:
|
|
84
|
+
```bash
|
|
85
|
+
mkdir -p "{auditDataFolder}"
|
|
86
|
+
uv run {extractionSnapshotHelper} scan-list "{provenanceMap}" -o "{auditDataFolder}/scan-files.json"
|
|
87
|
+
```
|
|
69
88
|
|
|
70
|
-
|
|
89
|
+
It writes the same list as a JSON list of paths, the form the runner's `--files-from` reads: never retype it. If the folder or the file cannot be written (`status: "error"`), HALT with **exit 4**, `halt_reason: "write-failed"`, phase `re-index:scan-list`, `"path": "{auditDataFolder}"`.
|
|
90
|
+
2. Files that existed at creation time but are now missing under `{source_root}` are **not** errors at this stage: keep them in the list. The snapshot marks them `missing`, and step 3 classifies their exports as DELETED.
|
|
91
|
+
3. Report:
|
|
71
92
|
|
|
72
|
-
**
|
|
93
|
+
"**Bounded scan:** {count} files from provenance map ({provenance_date})."
|
|
73
94
|
|
|
74
95
|
### 3. Extract Current Exports
|
|
75
96
|
|
|
76
|
-
**
|
|
77
|
-
1. Loads the source file
|
|
78
|
-
2. Extracts all public exports using tier-appropriate method
|
|
79
|
-
3. Records: export name, type, signature, file path, line number, confidence tier
|
|
80
|
-
4. Returns structured findings to parent
|
|
81
|
-
|
|
82
|
-
**If a file from the bounded scan list is missing on disk:** record `{file, exports: [], status: "missing"}` and continue — step 3 structural diff will classify exports previously at this path as DELETED.
|
|
97
|
+
**1. The recipe runner** (Forge, Forge+ and Deep). Resolve `{extractPublicApiHelper}` ← first existing path in `{extractPublicApiProbeOrder}` and, from `{project-root}`, remove the JSON an earlier run left and run the runner over the scan list, so that a JSON at `-o` after the call is this call's:
|
|
83
98
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
{
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
"files_scanned": {count},
|
|
93
|
-
"bounded_scan": true|false,
|
|
94
|
-
"bounded_scan_source": "provenance-map|source-tree-fallback",
|
|
95
|
-
"exports": [
|
|
96
|
-
{
|
|
97
|
-
"name": "{export_name}",
|
|
98
|
-
"type": "function|class|type|const|interface",
|
|
99
|
-
"signature": "{full signature}",
|
|
100
|
-
"file": "{relative_path}",
|
|
101
|
-
"line": {line_number},
|
|
102
|
-
"confidence": "T1|T1-low|T2"
|
|
103
|
-
}
|
|
104
|
-
]
|
|
105
|
-
}
|
|
99
|
+
```bash
|
|
100
|
+
rm -f "{auditDataFolder}/extraction.json"
|
|
101
|
+
uv run {extractPublicApiHelper} --mode full \
|
|
102
|
+
--source-root "{source_root}" \
|
|
103
|
+
--files-from "{auditDataFolder}/scan-files.json" \
|
|
104
|
+
--head-cap 0 \
|
|
105
|
+
[--timeout "{runner_timeout}"] \
|
|
106
|
+
-o "{auditDataFolder}/extraction.json"
|
|
106
107
|
```
|
|
107
108
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
### 4. Deep Tier Enhancement (Deep Only)
|
|
111
|
-
|
|
112
|
-
**If forge tier is Deep:**
|
|
113
|
-
|
|
114
|
-
Read the `qmd_collections` registry from `{sidecar_path}/forge-tier.yaml`.
|
|
109
|
+
The runner stops its ast-grep runs after 540 seconds and still writes its JSON (status `incomplete`), so give the command your shell tool's longest timeout; when that is under 10 minutes, pass `--timeout` as `{runner_timeout}`, a little under it (`100` under a two-minute limit). Never open the JSON: item 2's helper reads it and prints what this step acts on, its `status` included (never the exit code). At Quick tier no runner runs.
|
|
115
110
|
|
|
116
|
-
|
|
111
|
+
**2. Build the snapshot.** Resolve `{extractionSnapshotHelper}` ← first existing path in `{extractionSnapshotProbeOrder}` (if none exists, HALT with **exit 3**, `halt_reason: "helper-missing"`, phase `re-index:snapshot`) and, from `{project-root}`, run:
|
|
117
112
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
**If a matching extraction collection is found but empty** (pre-query probe reports `Files: 0 (updated never)` or an empty listing):
|
|
130
|
-
Log: "QMD collection `{collection_name}` is registered but empty. Run `qmd update` to (re-)index `{collection.path}`, then re-audit. Temporal enrichment skipped for this run."
|
|
131
|
-
Continue without T2 enrichment — the unpopulated collection is a setup gap, not an extraction failure. Step-04 will fall through to its direct-content fallback for semantic diff.
|
|
132
|
-
|
|
133
|
-
**If no matching collection found in registry:**
|
|
134
|
-
Log: "No QMD extraction collection found for {skill_name}. Temporal enrichment skipped. Re-run [CS] Create Skill to generate the collection."
|
|
135
|
-
Continue without T2 enrichment — this is not an error.
|
|
113
|
+
```bash
|
|
114
|
+
uv run {extractionSnapshotHelper} build \
|
|
115
|
+
--source-root "{source_root}" \
|
|
116
|
+
--source-path "{source_path}" \
|
|
117
|
+
--tier "{tier}" \
|
|
118
|
+
--date "{timestamp}" \
|
|
119
|
+
--provenance-map "{provenanceMap}" \
|
|
120
|
+
[--extraction "{auditDataFolder}/extraction.json"] \
|
|
121
|
+
[--details "{auditDataFolder}/export-details-{n}.json"]... \
|
|
122
|
+
-o "{forge_version}/extraction-snapshot.json"
|
|
123
|
+
```
|
|
136
124
|
|
|
137
|
-
|
|
138
|
-
Skip this section. Temporal context requires Deep tier.
|
|
125
|
+
Pass `--extraction` when the runner wrote its JSON, and one `--details` for each file item 3 wrote (none on the first build). The helper merges the runner's exports with the ones read by eye, gives every file on the list one status (`extracted`, `read-by-eye`, `hash-tracked` for a script, asset or doc only `file_entries[]` names, which step 3 compares by content hash, `missing`, `parse-failed` or `unread`) and prints one line. Act on its fields:
|
|
139
126
|
|
|
140
|
-
|
|
127
|
+
- **`runner_status` is `incomplete`** on the first build (an ast-grep run failed, or the time limit ran out): run item 1 once more, then this command again.
|
|
128
|
+
- **`runner_status` is `no-ast-grep`, or null at Forge tier and above** (no JSON at `-o` after the call, or no runner candidate): the runner cannot run. Follow **When the Runner Cannot Run** in `{extractionPatternsData}` over the files in `to_read`, with this audit's parameters in place of create-skill's: the files in scope are those `to_read` lists, and their count is the Decision Tree's input (not create-skill's step 3 count). Keep every match, in every directory batch and every retry: pass `find_code_by_rule` a `max_results` that no recipe can reach (100000), and a Known Limitation #4 `find_code` retry the same, and drop the `| head -{HEAD_CAP}` from the CLI streaming template, in each batch, since a match past a cap reads as a removed export in step 3. Record each export as item 3 does, T1 with `ast-grep` for one the recipes match.
|
|
129
|
+
- **`to_read` or `extraction_gaps` is not empty**, or a file uses the forms the recipes leave out: item 3 reads them, then run this command again with its details. When `complete` is still false, the files `to_read` lists could not be read: HALT with **exit 3**, `halt_reason: "source-unreadable"`, phase `re-index:snapshot`, naming them. Step 3 never reads an incomplete snapshot.
|
|
130
|
+
- **`complete` is true** and nothing is left to read: go on to §4.
|
|
131
|
+
- **`status: "error"`:** an `error` that starts `cannot write` is a failed write: HALT with **exit 4**, `halt_reason: "write-failed"`, phase `re-index:snapshot`, `"path": "{forge_version}/extraction-snapshot.json"`. Any other names a file this step wrote: fix it and run the command again.
|
|
132
|
+
- **The command fails otherwise, or prints no JSON:** HALT with **exit 3**, `halt_reason: "helper-missing"`, phase `re-index:snapshot`, showing the first stderr line.
|
|
141
133
|
|
|
142
|
-
**
|
|
134
|
+
**3. What the runner leaves.** Read by eye (T1-low, `extraction_method: source-read`, `ast_node_type: null`) only:
|
|
143
135
|
|
|
144
|
-
|
|
136
|
+
- each file in `to_read`: a `parse-failed` one (its `issue`: a syntax error, where a recipe can miss an export; not UTF-8; unreadable), with the warning "**AST fallback:** ast-grep could not parse {file} ({issue}); its exports were read from source and labeled T1-low.", and an `unread` one (an incomplete run, or no runner: then every file, by text pattern matching at Quick tier);
|
|
137
|
+
- each name in `extraction_gaps`, in its `file` (an entry point exports it, no recipe found it);
|
|
138
|
+
- the forms the recipes leave out (Known Limitation #11 in `{extractionPatternsData}`) in a file that uses them.
|
|
145
139
|
|
|
146
|
-
|
|
147
|
-
2. If CCC returns files containing the export name:
|
|
148
|
-
- Run ast-grep verification on each candidate file
|
|
149
|
-
- If verified at a new location: reclassify from "deleted" to "moved" with the new file:line reference
|
|
150
|
-
- This reduces false-positive structural drift findings where exports were relocated, not removed
|
|
151
|
-
3. If CCC returns no results or verification fails: keep the "deleted" classification
|
|
140
|
+
For each file to read, launch a subprocess (Pattern 2) that loads it and returns ONLY `{"files": [...], "exports": [...]}`, with no prose and no fences: `files` lists the file when the worker read the whole of it (also when it holds no export), and each export gives `name`, `type`, `signature` (the declaration on one line), `file` (relative to `{source_root}`, with forward slashes), `line` (`$NAME`'s line), `confidence: "T1-low"`, `extraction_method: "source-read"` and `ast_node_type: null`. Save each worker's JSON as it returned it, as `{auditDataFolder}/export-details-{n}.json` (`{n}` counting from 1), never merged by hand; without subprocesses, read the files in the main thread, one by one, and save one such file. A stack's export needs no library: the snapshot helper gives each one its file's `source_library` from the provenance map (the map `normalize` returns as `source_library_by_file`).
|
|
152
141
|
|
|
153
|
-
|
|
142
|
+
**The snapshot.** The command writes `{forge_version}/extraction-snapshot.json`, which step 3 (`structural-diff.md`) reads directly: `exports[]` (for a stack, each with its file's `source_library`), `files[]` with each file's status, `files_by_status`, `counts` and `cap_hits` (§4) and `outside_scope` (step 6's Out-of-Scope New Public API table); `skf-extraction-snapshot.py --help` gives the full shape. Record the written path as `{extractionSnapshot}` in workflow context: step 3 passes it to the structural-diff helper.
|
|
154
143
|
|
|
155
|
-
|
|
144
|
+
### 4. Validate Extraction Completeness
|
|
156
145
|
|
|
157
|
-
|
|
146
|
+
Take every value from the snapshot (`files_by_status`, `counts`, `cap_hits`) and the build's line (`ast_fallback_files`), never a recount:
|
|
158
147
|
|
|
159
148
|
"**Extraction complete.**
|
|
160
149
|
|
|
161
150
|
| Metric | Value |
|
|
162
151
|
|--------|-------|
|
|
163
|
-
|
|
|
164
|
-
|
|
|
165
|
-
|
|
|
166
|
-
|
|
|
167
|
-
|
|
|
168
|
-
|
|
|
169
|
-
| Constants | {const_count} |
|
|
170
|
-
| Confidence | {T1/T1-low/T2} |
|
|
152
|
+
| Files scanned | {files_scanned}: {extracted} extracted, {read-by-eye} read by eye, {hash-tracked} tracked by hash, {missing} missing |
|
|
153
|
+
| Exports found | {counts.exports} |
|
|
154
|
+
| By type | {each counts.by_type entry as `{type}` ×{count}} |
|
|
155
|
+
| Labels | {t1_count} T1 (`ast-grep`), {t1_low_count} T1-low (`source-read`) |
|
|
156
|
+
| AST fallback files | {count and names from `ast_fallback_files`, or none; n/a at Quick} |
|
|
157
|
+
| Cap hits | {cap_hits, or none} |
|
|
171
158
|
|
|
172
159
|
**Proceeding to structural comparison...**"
|
|
173
160
|
|
|
174
|
-
|
|
161
|
+
`ast_fallback_files` names the files read by eye after the runner could not parse or read them, not one read again for a gap or a Known Limitation #11 form (`all files (ast-grep unavailable)` when the runner could not run, none at Quick tier).
|
|
175
162
|
|
|
176
|
-
|
|
163
|
+
### 5. Update Report and Auto-Proceed
|
|
177
164
|
|
|
165
|
+
Update {outputFile} frontmatter: append `'re-index'` to `stepsCompleted` and set `ast_fallback_files` to the last build's `ast_fallback_files`. Once the snapshot helper reports `complete: true`, load, read fully, and execute `{nextStepFile}` (structural diff).
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
outputFile: '{forge_version}/drift-report-{timestamp}.md'
|
|
3
3
|
nextStepFile: 'health-check.md'
|
|
4
|
+
# This run's stage data folder, where step 5 saved the findings and their
|
|
5
|
+
# classification.
|
|
6
|
+
auditDataFolder: '{forge_version}/.skf-audit/{timestamp}'
|
|
7
|
+
# Resolve `{sourceTreeHelper}` to the first existing path. The Result
|
|
8
|
+
# Contract removes the private tree the [C] of upstream-checkout.md read
|
|
9
|
+
# the source in.
|
|
10
|
+
sourceTreeProbeOrder:
|
|
11
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-source-tree.py'
|
|
12
|
+
- '{project-root}/src/shared/scripts/skf-source-tree.py'
|
|
13
|
+
# §2: this skill's renderer of the Out-of-Scope New Public API table, from the skill root.
|
|
14
|
+
renderDriftTablesScript: 'scripts/render-drift-tables.py'
|
|
4
15
|
---
|
|
5
16
|
|
|
6
17
|
<!-- Config: communicate in {communication_language}. Drift report prose in {document_output_language}. -->
|
|
@@ -20,21 +31,38 @@ Finalize the drift report by completing the Audit Summary with calculated metric
|
|
|
20
31
|
|
|
21
32
|
## MANDATORY SEQUENCE
|
|
22
33
|
|
|
34
|
+
**Halt envelope.** Every HALT in this step names its exit code, `halt_reason` and phase. When `{source_tree}` is set (the [C] of `upstream-checkout.md`), first run `uv run {sourceTreeHelper} close --tree "{source_tree}"` from `{project-root}` and go on whatever it prints. In headless mode, stage `{run_dir}/halt.json` as `{"phase": "<phase>", "reason": "<the halt message>", "halt_reason": "<halt_reason>", "skill_name": "{skill_name}", "report_path": "{outputFile}", "drift_score": "<the saved classification's drift_score>"}`, adding `"path"` when the halt names one, then run:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
uv run {emitEnvelopeHelper} emit-halt --workflow skf-audit-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Display the line it prints, then stop with the halt's exit code. If the emitter exits non-zero or prints no line, display the halt message alone. An interactive HALT displays its message and emits nothing.
|
|
41
|
+
|
|
23
42
|
### 1. Complete Audit Summary
|
|
24
43
|
|
|
25
44
|
Update the ## Audit Summary section at the top of {outputFile} with final calculated values:
|
|
26
45
|
|
|
27
|
-
- Fill in severity count table from
|
|
28
|
-
- Set overall drift score
|
|
29
|
-
- Add total findings count
|
|
46
|
+
- Fill in the severity count table from `{auditDataFolder}/severity.json`, the classification step 5 saved: `by_severity` for each level and `total_items` for **Total**
|
|
47
|
+
- Set the overall drift score (its `drift_score`)
|
|
30
48
|
- Include doc drift summary from `doc_drift_summary` context (set by step 5a):
|
|
31
|
-
- If `changed > 0`: "**Doc Drift:** {changed} of {total_tracked} tracked doc(s) have changed since compile. Consider re-running CS to update doc_sources."
|
|
49
|
+
- If `changed > 0`: "**Doc Drift:** {changed} of {total_tracked} tracked doc(s) have changed since compile." Then, for a docs-only skill (whose score these changes set): "Run `[US] Update Skill` to bring the skill up to them."; otherwise: "Consider re-running CS to update doc_sources."
|
|
32
50
|
- If `fetch_failed > 0`: "{fetch_failed} doc URL(s) could not be reached during audit."
|
|
33
51
|
- If `skipped_entirely`: no mention in summary (already noted in the doc drift section)
|
|
34
52
|
|
|
35
53
|
### 2. Generate Remediation Suggestions
|
|
36
54
|
|
|
37
|
-
For each classified drift finding, write one concrete remediation derived from the finding itself: **what** to change in the audited **SKILL.md** (or its `references/`)
|
|
55
|
+
For each classified drift finding (`findings[]` of `{auditDataFolder}/severity.json`; one remediation may cover a rollup row of step 5's tables), write one concrete remediation derived from the finding itself: **what** to change in the audited **SKILL.md** (or its `references/`), not the source code; **where** (the section plus the source `{file}:{line}` the finding cites); and **why**. Set effort (`low`/`medium`/`high`) by how much of the skill doc the change touches. A reviewer should be able to act on each row without re-deriving the finding.
|
|
56
|
+
|
|
57
|
+
Rows of step 3's **Provenance label differences (not drift)** table are not findings: they get no remediation row and do not count toward the Workflow Recommendation.
|
|
58
|
+
|
|
59
|
+
**Public API outside the skill's scope.** Step 2's snapshot lists in `outside_scope` the files the skill does not cover whose public API a package entry point exports: the recipe runner's entry-point diff found them, so nothing here is judged by eye. Render their subsection from the snapshot, never by hand. `{renderDriftTablesScript}` resolves relative to the skill root; from `{project-root}`, run:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
uv run {renderDriftTablesScript} outside-scope "{forge_version}/extraction-snapshot.json"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Paste its output unchanged under Remediation Suggestions, where the template below shows it (nothing when it prints nothing: `outside_scope` is empty, as at Quick tier). update-skill's scope reconciliation (`skf-provenance-gap-dispatch.py`) reads that subsection from the newest drift report and asks whether to bring each path into scope. A compose-mode stack and a docs-only skill have no snapshot: skip the command. When the command exits non-zero, its JSON `error`, else its first stderr line, says what it could not read: write `Out-of-Scope New Public API not rendered: {error}` in place of its output and go on.
|
|
38
66
|
|
|
39
67
|
Append to {outputFile}:
|
|
40
68
|
|
|
@@ -59,49 +87,61 @@ Append to {outputFile}:
|
|
|
59
87
|
|---|---------|-------------|
|
|
60
88
|
| 1 | {finding} | {specific action} |
|
|
61
89
|
|
|
90
|
+
{what the outside-scope command printed, unchanged}
|
|
91
|
+
|
|
62
92
|
### Workflow Recommendation
|
|
63
93
|
|
|
64
94
|
{IF any CRITICAL or HIGH findings:}
|
|
65
95
|
**Recommended:** Run `[US] Update Skill` workflow to apply priority remediations automatically.
|
|
66
96
|
|
|
67
|
-
{IF
|
|
68
|
-
**
|
|
97
|
+
{IF the frontmatter's `upstream_moved` is true:}
|
|
98
|
+
**Upstream moved.** The skill is built from `{baseline_ref}` and upstream is now at `{upstream_ref}`{; this audit read `{upstream_ref}`, when `audit_ref_source` is `checkout-latest`; this audit read the baseline, otherwise}. Run `[US] Update Skill` with `--target-ref {upstream_ref}`, so the update compares the ref upstream moved to rather than the one the skill is pinned to.
|
|
99
|
+
|
|
100
|
+
{IF the frontmatter's `audit_ref_source` is `checkout-latest` (the [C] of `upstream-checkout.md` audited a newer upstream ref than the baseline) or its `upstream_moved` is true:}
|
|
101
|
+
**Version preservation (non-destructive).** `update-skill` keeps the audited version (`{audited_version}`) unchanged, writes the new version in a folder of its own beside it (see `skf-update-skill/references/merge.md` §6b, which leaves the previous version on disk) and repoints the skill's `active` link at it (see `skf-update-skill/references/write.md` §5b). On the next export, the prior version's export-manifest entry transitions to `status: archived`, its files kept for rollback (see `skf-export-skill/references/update-context.md`). Do **not** recommend `skf-drop-skill` + `skf-create-skill` for a version bump: that destroys the prior version's artifacts.
|
|
69
102
|
|
|
70
|
-
|
|
103
|
+
{IF the Out-of-Scope New Public API table above has rows:}
|
|
104
|
+
**New public API outside the scope.** update-skill's scope reconciliation (detect-changes §1c) offers each path to bring into the brief's scope; review them there, or refine the scope with `skf-brief-skill` before running update-skill.
|
|
71
105
|
|
|
72
106
|
{IF only MEDIUM or LOW findings:}
|
|
73
107
|
**Optional:** Minor drift detected. Manual updates sufficient, or run `[US] Update Skill` for automated remediation.
|
|
74
108
|
|
|
75
109
|
{IF CLEAN:}
|
|
76
|
-
**No
|
|
110
|
+
**No drift against `{audit_ref}`.** The skill matches the source at `{audit_ref}` (`{audit_commit_short}`){; upstream has not moved past `{baseline_ref}`, when `upstream_moved` is false; upstream was not checked ({upstream_fetch}), when it is null; and when it is true, the Upstream moved recommendation above applies}.
|
|
77
111
|
```
|
|
78
112
|
|
|
79
113
|
### 3. Add Provenance Section
|
|
80
114
|
|
|
81
|
-
Append to {outputFile}:
|
|
115
|
+
Build the section from the frontmatter of {outputFile}, where step 1 §6, step 2 §5 and step 3 §6 recorded each value as it was known, not from values held in the conversation. Append to {outputFile}:
|
|
82
116
|
|
|
83
117
|
```markdown
|
|
84
118
|
## Provenance
|
|
85
119
|
|
|
86
120
|
| Field | Value |
|
|
87
121
|
|-------|-------|
|
|
88
|
-
| **Audit Date** | {
|
|
122
|
+
| **Audit Date** | {date} |
|
|
89
123
|
| **Audited By** | Ferris (Audit mode) |
|
|
90
|
-
| **Forge Tier** | {
|
|
91
|
-
| **Tools Used** | {tool_list based on
|
|
92
|
-
| **Source Path** | {source_path} |
|
|
124
|
+
| **Forge Tier** | {forge_tier} |
|
|
125
|
+
| **Tools Used** | {tool_list based on forge_tier} |
|
|
126
|
+
| **Source Path** | {source_path}{; read from the private tree `{source_tree}`, when set} |
|
|
93
127
|
| **Skill Path** | {skill_path} |
|
|
94
|
-
| **
|
|
95
|
-
| **Provenance
|
|
96
|
-
| **
|
|
128
|
+
| **Audited Version** | `{audited_version}` ({audited_version_reason}){; the export manifest names `{manifest_version}`, when set} |
|
|
129
|
+
| **Provenance Map** | {provenance_map} |
|
|
130
|
+
| **Provenance Age** | {provenance_age_days} days (generated {provenance_generated_at}) |
|
|
131
|
+
| **AST fallback files** | {`ast_fallback_files`, or none; n/a at Quick} |
|
|
132
|
+
| **Applied Transforms** | {each `applied_transforms` entry as `{transform}` ×{count}, or none} |
|
|
97
133
|
| **Baseline Ref / Commit** | `{baseline_ref}` @ `{baseline_commit_short}` |
|
|
98
134
|
| **Audit Ref / Commit** | `{audit_ref}` @ `{audit_commit_short}` ({audit_ref_source}) |
|
|
99
|
-
| **Upstream Latest** | `{latest_tag or remote_head or "(not fetched)"}` |
|
|
135
|
+
| **Upstream Latest** | `{latest_tag or remote_head or "(not fetched)"}` (fetch: {upstream_fetch}) |
|
|
136
|
+
| **Upstream Moved** | {upstream_moved}{: to `{upstream_ref}`, when true} |
|
|
137
|
+
| **Stage Data** | `{auditDataFolder}/`: the JSON this run saved and classified (the structural diff, the constituents' freshness or the documents' comparison, the findings and their classification) |
|
|
100
138
|
|
|
101
139
|
**Confidence Legend:**
|
|
102
|
-
- **T1:**
|
|
103
|
-
- **T1-low:**
|
|
104
|
-
- **
|
|
140
|
+
- **T1:** an ast-grep match (`extraction_method: ast-grep`) at any tier: high reliability, structural truth
|
|
141
|
+
- **T1-low:** read by eye (`extraction_method: source-read`) at any tier: moderate reliability
|
|
142
|
+
- **T1-low-fallback:** Deep-tier semantic diff read directly from the skill's docs and the current source because the QMD collection was empty: moderate reliability
|
|
143
|
+
- **T2:** Deep-tier semantic diff: a claim the skill's QMD collection holds, checked against the current source line it cites: evidence-backed semantic analysis
|
|
144
|
+
- **T3:** external documentation reference: variable reliability, secondary source
|
|
105
145
|
```
|
|
106
146
|
|
|
107
147
|
### 4. Update Report Frontmatter
|
|
@@ -109,43 +149,66 @@ Append to {outputFile}:
|
|
|
109
149
|
Update {outputFile} frontmatter:
|
|
110
150
|
- Append `'report'` to `stepsCompleted`
|
|
111
151
|
- Set `drift_score` to the score from step 5's classification helper
|
|
112
|
-
- Set `nextWorkflow` to `'update-skill'`
|
|
152
|
+
- Set `nextWorkflow` to `'update-skill'` when the saved classification's `by_severity.CRITICAL` or `by_severity.HIGH` is above 0, or when the frontmatter's `upstream_moved` is true, otherwise leave it empty
|
|
113
153
|
|
|
114
|
-
If finalizing the report
|
|
154
|
+
If finalizing the report fails (read-only mount, disk full, permissions denied) → HALT with **exit 4**, `halt_reason: "write-failed"`, phase `report:write`, `"path": "{outputFile}"`, and no `report_path` in the payload.
|
|
115
155
|
|
|
116
156
|
### 5. Present Final Report Summary
|
|
117
157
|
|
|
118
158
|
Present a concise completion summary to the user conveying: the skill name, the **overall drift score** (CLEAN / MINOR / SIGNIFICANT / CRITICAL), the severity-count table (CRITICAL / HIGH / MEDIUM / LOW / Total), and the saved report path (`{outputFile}`). Close with the next-action recommendation matching the drift level:
|
|
119
159
|
|
|
120
160
|
- **CRITICAL or HIGH findings** → action required: recommend running the `[US] Update Skill` workflow to apply the priority remediations; manual review at `{outputFile}` is the alternative.
|
|
161
|
+
- **The frontmatter's `upstream_moved` is true**, whatever the drift score → recommend `[US] Update Skill` with `--target-ref {upstream_ref}`, naming `{baseline_ref}` and `{upstream_ref}`: update-skill otherwise compares the ref the skill is pinned to, not the one upstream moved to. `{upstream_ref}` is the newer tag when upstream released one (`--target-ref {latest_tag}`), and for a skill built from the default branch it is `HEAD` (`--target-ref HEAD`).
|
|
121
162
|
- **MEDIUM or LOW only** → minor drift: manual updates suffice, or run `[US] Update Skill` for automated remediation.
|
|
122
|
-
- **CLEAN** → no action needed
|
|
163
|
+
- **CLEAN, and `upstream_moved` is not true** → no action needed: the skill matches `{audit_ref}` and is ready for `[EX] Export Skill`.
|
|
123
164
|
|
|
124
165
|
This summary reads as final but is **not** the terminal step — proceed to §6.
|
|
125
166
|
|
|
126
167
|
### Result Contract
|
|
127
168
|
|
|
128
|
-
|
|
169
|
+
**Remove the private source tree first.** When `{source_tree}` is set (the [C] of `upstream-checkout.md` read the source there), no later step reads the source: resolve `{sourceTreeHelper}` ← first existing path in `{sourceTreeProbeOrder}` and, from `{project-root}`, run `uv run {sourceTreeHelper} close --tree "{source_tree}"`. Go on whatever it prints. On `left` or `refused`, a command that fails or prints no JSON, or no candidate, record `uv run {emitEnvelopeHelper} record --run-dir "{run_dir}" --warning "source_tree_not_removed: {source_tree}"` (a later SKF run removes it once it is seven days old). Then set `{source_tree}` to null.
|
|
170
|
+
|
|
171
|
+
The shared emitter writes the result contract (per `shared/references/output-contract-schema.md`, which resolves relative to the SKF module root: `{project-root}/_bmad/skf/` when installed, `{project-root}/src/` during development) and prints the `SKF_AUDIT_RESULT_JSON` envelope; this step stages their content, every value from the drift report's frontmatter and the classification step 5 saved. Write `{run_dir}/result-context.json`:
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"status": "success",
|
|
176
|
+
"skill_name": "{skill_name}",
|
|
177
|
+
"drift_score": "<drift_score>",
|
|
178
|
+
"report_path": "{outputFile}",
|
|
179
|
+
"next_workflow": <next_workflow>,
|
|
180
|
+
"audit_ref": "<audit_ref>",
|
|
181
|
+
"upstream_moved": <upstream_moved>,
|
|
182
|
+
"upstream_ref": <upstream_ref>,
|
|
183
|
+
"result_contract": {
|
|
184
|
+
"skill": "skf-audit-skill",
|
|
185
|
+
"status": "success",
|
|
186
|
+
"outputs": [{"type": "report", "path": "{outputFile}"}],
|
|
187
|
+
"summary": {"drift_count": <total_findings>, "severity": "<drift_score>", "next_workflow": <next_workflow>,
|
|
188
|
+
"audit_ref": "<audit_ref>", "upstream_moved": <upstream_moved>, "upstream_ref": <upstream_ref>}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
129
192
|
|
|
130
|
-
|
|
193
|
+
When On Activation step 3 fell back to the bundled `customize.toml`, add `"customization_resolver_unavailable": "<the reason>"`, the one-line reason On Activation kept with each `"` and `\` escaped: the emitter turns it into a warning. `<drift_score>` and `<total_findings>` are the `drift_score` and `total_findings` of `{auditDataFolder}/severity.json`: `drift_count` (the saved classification's `total_findings`: one per finding, never a label difference) and `severity` (its `drift_score`: CLEAN/MINOR/SIGNIFICANT/CRITICAL). `<next_workflow>` is `"update-skill"` exactly when §4 set the frontmatter's `nextWorkflow` (CRITICAL or HIGH findings, or `upstream_moved` true), else JSON `null`. `audit_ref`, `upstream_moved` and `upstream_ref` are the frontmatter's, resolved at step 1 §5b and, when upstream moved, by `upstream-checkout.md` (`audit_ref` is `baseline_ref` when the audit stayed on the baseline, `upstream_ref` when the operator chose `[C]`): `<upstream_moved>` is JSON `true` when upstream moved, `false` when the check found it unchanged and `null` when the check was skipped or failed, and `<upstream_ref>` is the ref upstream moved to, as a JSON string, when `upstream_moved` is true, else `null`. Then run, in every mode:
|
|
131
194
|
|
|
132
|
-
```
|
|
133
|
-
|
|
195
|
+
```bash
|
|
196
|
+
uv run {emitEnvelopeHelper} emit --workflow skf-audit-skill --run-dir "{run_dir}" --result-dir "{forge_version}" < "{run_dir}/result-context.json"
|
|
134
197
|
```
|
|
135
198
|
|
|
136
|
-
|
|
199
|
+
It writes `{forge_version}/audit-skill-result-{YYYYMMDD-HHmmss}.json` (UTC; it picks the name) and its `audit-skill-result-latest.json` copy (stable path for pipeline consumers: a copy, not a symlink), stamps the timestamp, `run_id`, `headless_decisions` and `warnings` into both, and prints the `SKF_AUDIT_RESULT_JSON:` line on stdout. When `{headless_mode}` is true, display the line verbatim: chaining workflows read `drift_score`, `report_path`, `next_workflow`, `upstream_moved` and `upstream_ref` from it without polling the filesystem. A result file that could not be written leaves `result_path` null and a `result_file_write_failed` warning in the line, and the run still finishes. If the emitter exits non-zero, correct `result-context.json` from the message on its stderr and run it once more; if it fails again, HALT with **exit 4**, `halt_reason: "write-failed"`, phase `report:result-contract`: the run's result contract could not be written.
|
|
137
200
|
|
|
138
|
-
**Hard-halt envelope (headless only).** Every hard halt
|
|
201
|
+
**Hard-halt envelope (headless only).** Every hard halt prints its envelope through the emitter on **stderr** with `status: "error"` and the `exit_code` / `halt_reason` for its failure class, as each step's **Halt envelope** paragraph shows: it is the only failure signal a wrapping pipeline receives. `drift_score` carries its last known value (`null` if classification never ran); `report_path` is `null` when the report write failed.
|
|
139
202
|
|
|
140
|
-
**Post-audit hook (optional).** If `{onCompleteCommand}` is non-empty (resolved at SKILL.md On Activation §3 from `workflow.on_complete`), invoke it as:
|
|
203
|
+
**Post-audit hook (optional).** If `{onCompleteCommand}` is non-empty (resolved at SKILL.md On Activation §3 from `workflow.on_complete`), invoke it from `{project-root}` as:
|
|
141
204
|
|
|
142
205
|
```bash
|
|
143
206
|
{onCompleteCommand} --result-path={result_json_path}
|
|
144
207
|
```
|
|
145
208
|
|
|
146
|
-
where `{result_json_path}` is the per-run record
|
|
209
|
+
where `{result_json_path}` is the envelope's `result_path`, the per-run record the emitter wrote (skip the hook when it is null). When the hook fails, tell the user it failed and why, and go on: never fail the workflow on a hook error. The hook runs after the result contract is finalized so notifiers, ticket-tracker integrations, or downstream pipelines see a complete record. When `{onCompleteCommand}` is empty (bundled default), skip the invocation entirely.
|
|
147
210
|
|
|
148
211
|
### 6. Chain to Health Check
|
|
149
212
|
|
|
150
|
-
Only when the report has been written, presented, and the result contract saved
|
|
213
|
+
Only when the report has been written, presented, and the result contract saved, delete the run folder, whose decisions, warnings and payloads the run no longer needs: `rm -rf "{run_dir}"`. Then load, read the full file, and execute `{nextStepFile}`. The health-check step is the true terminal step: do not stop here even though the user-facing summary reads as final.
|
|
151
214
|
|