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
|
@@ -6,21 +6,21 @@ When `source_repo` is a remote URL (GitHub URL or owner/repo format) and the tie
|
|
|
6
6
|
|
|
7
7
|
- **ast-grep requires local files** — it cannot operate on remote URLs
|
|
8
8
|
|
|
9
|
-
**
|
|
9
|
+
**Private tree at the resolved commit (preferred):**
|
|
10
10
|
|
|
11
|
-
1.
|
|
12
|
-
2.
|
|
11
|
+
1. `skf-source-tree.py resolve` reads the resolved commit into a private tree of the run's own, from the workspace checkout at `{workspace_root}/repos/{host}/{owner}/{repo}/` when it holds the commit and from the remote otherwise. It then moves that workspace checkout to the same commit, cloning it first when it is missing, after the git hygiene check (it undoes the `.gitignore` edit `ccc init` made there and keeps ccc's index folder and SKF's lock file out of `git status`). See `source-resolution-protocols.md` for the full resolution algorithm.
|
|
12
|
+
2. When `git` is missing, resolve reports `git-unavailable` and reads no tree, and the run falls back to source reading (below). `git` is effectively guaranteed at Deep tier (via the `gh` dependency) but not at Forge tier.
|
|
13
13
|
3. The workspace uses a full checkout (no sparse-checkout). Brief `include_patterns` and `exclude_patterns` are applied as file-level filters at extraction time, not at the git level. This allows a single workspace checkout to serve multiple briefs with different scope filters.
|
|
14
|
-
4. For update-skill: `changed_files_from_manifest` scoping is applied as file-level filters at extraction time
|
|
15
|
-
5. If
|
|
16
|
-
6. If
|
|
14
|
+
4. For update-skill: a skill forged from a remote repository is read from a checkout of the skill's commit that update-skill prepares for each run (from the workspace clone's objects or the remote), never from the workspace clone as it stands, and `changed_files_from_manifest` scoping is applied as file-level filters at extraction time; a gap-driven repair reads the workspace clone after checking that it holds the skill's pinned commit.
|
|
15
|
+
5. If `resolve` reads the tree: use the tree for AST extraction. Each export an ast-grep rule matches is T1 with an `[AST:...]` citation; an export read by eye stays T1-low (see Source Read by Choice below).
|
|
16
|
+
6. If the remote cannot be reached, or the fetch or checkout fails, no tree is read: fall back to source reading (below). A tree that was read is removed at the end of the run.
|
|
17
17
|
7. Workspace checkouts persist across forges — CCC indexes, tool outputs, and the checkout itself are reused.
|
|
18
18
|
|
|
19
|
-
**Fallback (
|
|
19
|
+
**Fallback (no tree can be read, or `git` is unavailable):**
|
|
20
20
|
|
|
21
21
|
- The extraction step warns the user explicitly before degrading — a silent drop from AST (T1) to source reading (T1-low) would leave them trusting a lower-confidence result without knowing it changed
|
|
22
22
|
- **create-skill:** the warning includes actionable guidance — clone locally and update `source_repo` in the brief to the local path
|
|
23
|
-
- **update-skill:**
|
|
23
|
+
- **update-skill:** does not degrade to source reading for a remote skill: when it cannot get the commit to read, it stops before change detection (`init:source-tree`), since reading any other tree would compare the skill with the wrong code; when only the network is down, it reads the pinned commit from the workspace clone.
|
|
24
24
|
- Extraction proceeds using Quick tier strategy (source reading via gh_bridge — resolved as `gh api` commands or direct file I/O; see `knowledge/tool-resolution.md`)
|
|
25
25
|
- All results labeled T1-low with `[SRC:...]` citations
|
|
26
26
|
- The degradation reason is recorded in the evidence report
|
|
@@ -41,5 +41,14 @@ When ast-grep fails on an individual file (parse error, unsupported syntax):
|
|
|
41
41
|
|
|
42
42
|
- Fall back to source reading for **that file only**
|
|
43
43
|
- Other files continue with AST extraction
|
|
44
|
-
- The affected file's results are labeled T1-low
|
|
44
|
+
- The affected file's results are labeled T1-low with `[SRC:...]` citations, `extraction_method: source-read` and `ast_node_type: null`; exports ast-grep matched in other files stay T1
|
|
45
45
|
- Log a warning noting which file degraded and why
|
|
46
|
+
|
|
47
|
+
## Source Read by Choice
|
|
48
|
+
|
|
49
|
+
When ast-grep works but an export is read by eye anyway (a file read to confirm a signature, a re-export the rules did not match, a symbol found while reading a neighbouring file):
|
|
50
|
+
|
|
51
|
+
- Label the export by the tool that produced it, not by the tier: T1-low with a `[SRC:{file}:L{line}]` citation
|
|
52
|
+
- Record `extraction_method: source-read`, `ast_node_type: null` and a `signature_source` other than T1
|
|
53
|
+
- Only an export an ast-grep rule matched is T1, with an `[AST:...]` citation, `extraction_method: ast-grep` and, as `ast_node_type`, the `kind` its recipe declares in `extraction-patterns.md`, or the kind the ast-grep Patterns table in `extraction-patterns-by-hand.md` gives a `find_code` pattern
|
|
54
|
+
- This is not a degradation: no warning is needed, and other exports keep their own labels
|
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'generate-artifacts.md'
|
|
3
|
-
tesslDismissalData: 'assets/tessl-dismissal-rules.md'
|
|
4
|
-
descriptionGuardProtocol: '{project-root}/src/shared/references/description-guard-protocol.md'
|
|
5
3
|
# Resolve `{atomicWriteHelper}` by probing `{atomicWriteProbeOrder}` in order
|
|
6
4
|
# (installed SKF module path first, src/ dev-checkout fallback); first existing
|
|
7
|
-
# path wins. HALT
|
|
8
|
-
#
|
|
5
|
+
# path wins. HALT (exit code 3, helper-missing) if neither resolves: the
|
|
6
|
+
# staging-directory artifacts this step writes need atomic writes.
|
|
9
7
|
atomicWriteProbeOrder:
|
|
10
8
|
- '{project-root}/_bmad/skf/shared/scripts/skf-atomic-write.py'
|
|
11
9
|
- '{project-root}/src/shared/scripts/skf-atomic-write.py'
|
|
12
10
|
# Resolve `{descriptionGuardHelper}` by probing `{descriptionGuardProbeOrder}`
|
|
13
11
|
# in order (installed SKF module path first, src/ dev-checkout fallback);
|
|
14
|
-
# first existing path wins. HALT
|
|
15
|
-
# tool's rewrite of the description field
|
|
16
|
-
# discovery quality.
|
|
12
|
+
# first existing path wins. HALT (exit code 3, helper-missing) if neither
|
|
13
|
+
# resolves: letting an external tool's rewrite of the description field
|
|
14
|
+
# stand would silently regress discovery quality.
|
|
17
15
|
descriptionGuardProbeOrder:
|
|
18
16
|
- '{project-root}/_bmad/skf/shared/scripts/skf-description-guard.py'
|
|
19
17
|
- '{project-root}/src/shared/scripts/skf-description-guard.py'
|
|
20
18
|
# Resolve `{frontmatterValidator}` by probing `{frontmatterValidatorProbeOrder}`
|
|
21
19
|
# in order (installed SKF module path first, src/ dev-checkout fallback); first
|
|
22
|
-
# existing path wins.
|
|
23
|
-
#
|
|
20
|
+
# existing path wins.
|
|
21
|
+
# HALT (exit code 3, helper-missing) if neither resolves: §6's description
|
|
22
|
+
# check has no fallback, and §0's post-restore re-validation hook uses it
|
|
23
|
+
# too; an installed module has no src/ tree, so a bare src/ path would
|
|
24
|
+
# silently skip both.
|
|
24
25
|
frontmatterValidatorProbeOrder:
|
|
25
26
|
- '{project-root}/_bmad/skf/shared/scripts/skf-validate-frontmatter.py'
|
|
26
27
|
- '{project-root}/src/shared/scripts/skf-validate-frontmatter.py'
|
|
@@ -38,6 +39,41 @@ shardBodyProbeOrder:
|
|
|
38
39
|
renderMetadataStatsProbeOrder:
|
|
39
40
|
- '{project-root}/_bmad/skf/shared/scripts/skf-render-metadata-stats.py'
|
|
40
41
|
- '{project-root}/src/shared/scripts/skf-render-metadata-stats.py'
|
|
42
|
+
# Resolve `{verifyProvenanceCompletenessHelper}` to the first existing path.
|
|
43
|
+
# §7's relabel runs its `kind-at`, and §7a its `verify` and `fix`. Advisory:
|
|
44
|
+
# if neither path resolves, §7a records that its check did not run, and a
|
|
45
|
+
# node kind that needs `kind-at` stays a WARN.
|
|
46
|
+
verifyProvenanceCompletenessProbeOrder:
|
|
47
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-verify-provenance-completeness.py'
|
|
48
|
+
- '{project-root}/src/shared/scripts/skf-verify-provenance-completeness.py'
|
|
49
|
+
# Resolve `{tesslReviewHelper}` by probing `{tesslReviewProbeOrder}` in order
|
|
50
|
+
# (installed SKF module path first, src/ dev-checkout fallback); first existing
|
|
51
|
+
# path wins. If neither path exists, §6b records that Tessl Review did not run
|
|
52
|
+
# and continues: the review is optional and never gates the workflow.
|
|
53
|
+
tesslReviewProbeOrder:
|
|
54
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-tessl-review.py'
|
|
55
|
+
- '{project-root}/src/shared/scripts/skf-tessl-review.py'
|
|
56
|
+
# Resolve `{tesslReviewRules}` the same way. §6b loads it after a completed
|
|
57
|
+
# review to mark the suggestions SKF does not follow; without it the
|
|
58
|
+
# suggestions are listed unmarked.
|
|
59
|
+
tesslReviewRulesProbeOrder:
|
|
60
|
+
- '{project-root}/_bmad/skf/shared/references/tessl-review.md'
|
|
61
|
+
- '{project-root}/src/shared/references/tessl-review.md'
|
|
62
|
+
preferencesFile: '{sidecar_path}/preferences.yaml'
|
|
63
|
+
# Loaded only when §7 or §7a meets a provenance label or node-kind finding.
|
|
64
|
+
relabelRuleData: 'references/relabel-rule.md'
|
|
65
|
+
# Resolve `{extractionPatternsData}` to the first existing path, as step 3
|
|
66
|
+
# did: the Relabel Rule's `kind-at` reads the recipes there.
|
|
67
|
+
extractionPatternsDataProbeOrder:
|
|
68
|
+
- '{project-root}/_bmad/skf/skf-create-skill/references/extraction-patterns.md'
|
|
69
|
+
- '{project-root}/src/skf-create-skill/references/extraction-patterns.md'
|
|
70
|
+
# HARD HALT helpers (Rules).
|
|
71
|
+
sourceTreeProbeOrder:
|
|
72
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-source-tree.py'
|
|
73
|
+
- '{project-root}/src/shared/scripts/skf-source-tree.py'
|
|
74
|
+
emitEnvelopeProbeOrder:
|
|
75
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-emit-result-envelope.py'
|
|
76
|
+
- '{project-root}/src/shared/scripts/skf-emit-result-envelope.py'
|
|
41
77
|
---
|
|
42
78
|
|
|
43
79
|
<!-- Config: communicate in {communication_language}. -->
|
|
@@ -46,23 +82,31 @@ renderMetadataStatsProbeOrder:
|
|
|
46
82
|
|
|
47
83
|
## STEP GOAL:
|
|
48
84
|
|
|
49
|
-
To validate the compiled SKILL.md content against the agentskills.io specification using skill-check, auto-fix any validation failures, and confirm spec compliance before artifact generation.
|
|
85
|
+
To validate the compiled SKILL.md content against the agentskills.io specification using skill-check, auto-fix any validation failures, confirm that the frontmatter description holds no angle brackets, and confirm spec compliance before artifact generation. When the user has opted in to Tessl Review, also record Tessl's review of the skill as advice; it never gates the step.
|
|
50
86
|
|
|
51
87
|
## Rules
|
|
52
88
|
|
|
53
89
|
- Focus only on validating compiled content against spec — only fix spec compliance issues
|
|
54
90
|
- Validation and auto-fix modify files in the staging directory
|
|
55
|
-
- `<staging-skill-dir>` resolves to `_bmad-output/{skill-name}/` as created by step 5.
|
|
91
|
+
- `<staging-skill-dir>` resolves to `_bmad-output/.skf-stage/{skill-name}/` as created by step 5. Its last folder name must match the skill's frontmatter `name` field exactly — `skill-check`'s `frontmatter.name_matches_directory` rule rejects any suffix.
|
|
56
92
|
- If skill-check unavailable: skip validation, add warning to evidence report
|
|
57
93
|
- Ignore non-zero exit codes from skill-check if JSON output shows 0 errors
|
|
94
|
+
- Tessl Review (§6b) is optional and advisory: it never halts, never asks the user anything and never changes the staged files, and SKF applies none of its suggestions
|
|
95
|
+
- A HARD HALT, once step 3 §2b has bound `{source_tree}`, first runs `uv run {sourceTreeHelper} close --tree "{source_tree}"` from `{project-root}` (resolved from `{sourceTreeProbeOrder}`) and goes on whatever it prints, and emits through `{emitEnvelopeHelper}`, resolved from `{emitEnvelopeProbeOrder}` when it is not bound. After its envelope, under `--batch` it ends only this brief: return to `references/batch-mode.md` §3, even when the halt reads as the end of the run.
|
|
58
96
|
|
|
59
97
|
## MANDATORY SEQUENCE
|
|
60
98
|
|
|
99
|
+
**Helpers.** Resolve `{atomicWriteHelper}`, `{descriptionGuardHelper}` and `{frontmatterValidator}` now, each ← the first existing path of its probe order. If one has no path, **HARD HALT** (exit code 3, `helper-missing`, phase `validate`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "Cannot validate the staged skill: {the missing script} is missing. Re-install SKF, then re-run create-skill."
|
|
100
|
+
|
|
61
101
|
### 0. Description Guard Protocol
|
|
62
102
|
|
|
63
|
-
**Used by:** §2 (`skill-check check --fix`)
|
|
103
|
+
**Used by:** §2 (`skill-check check --fix`) and §4 (the body split).
|
|
104
|
+
|
|
105
|
+
The deterministic phases are executed via `{descriptionGuardHelper}`: the calling sections (§2 and §4) invoke the helper at the capture and verify-restore points.
|
|
64
106
|
|
|
65
|
-
|
|
107
|
+
**Guard outputs.** Bind `{guarded_description}` ← `description` from each `capture`, which reads the staged `<staging-skill-dir>/SKILL.md` just before the tool that may rewrite it. Bind `{guard_restored}` ← `restored` and `{guard_diff_kind}` ← `diff_kind` from each `verify-restore`. When `{guard_restored}` is true, set the in-context `description` to `{guarded_description}` so later sections do not work from the tool-mutated value, and record `description_guard_restored: true` with the tool name and `description_guard_diff_kind: {guard_diff_kind}` in workflow context for the evidence report (§8). A later `verify-restore` that exits 0 with `{guard_restored}` false leaves those records in place.
|
|
108
|
+
|
|
109
|
+
**Empty-snapshot rule.** `verify-restore` refuses an empty or whitespace-only `--captured-description` (exit 1, file untouched). Never re-run it with the empty value: writing it back would blank the field the guard protects. If the description compile §2a sanitized is still in context (an in-context copy of the description, not of the file), re-run `verify-restore` with that value. Otherwise record `description_guard_restored: false` and `description_guard_refused: empty-capture` with the tool name; the evidence report (§8) renders that as a fired guard, not as a clean run.
|
|
66
110
|
|
|
67
111
|
**This skill's post-restore re-validation hook:** after `{descriptionGuardHelper}` reports `restored: true`, resolve `{frontmatterValidator}` from `{frontmatterValidatorProbeOrder}` (first existing path wins), run `uv run {frontmatterValidator} <staging-skill-dir>/SKILL.md` and capture `schema_revalidation_result` in context. If the validator exits non-zero OR reports failure for the `description` field, flip the Schema result back to `FAIL` in the evidence report (overriding any prior PASS/WARN from §2), record `description_guard_revalidation: FAIL` with the validator's diagnostic message, and continue — do not halt (step 9 health-check and result contract still need to run so the failure is surfaced through the normal artifact path).
|
|
68
112
|
|
|
@@ -71,7 +115,7 @@ Load `{descriptionGuardProtocol}` for the full prose explanation of the four-pha
|
|
|
71
115
|
Run: `timeout 30s npx skill-check -h` — the short timeout protects against a cold `npx` download blocking the workflow indefinitely on a slow network.
|
|
72
116
|
|
|
73
117
|
- If succeeds: Continue to automated validation (section 2)
|
|
74
|
-
- If fails or times out: Perform manual fallback (section 3); add note to evidence-report: "Spec validation performed manually — skill-check tool unavailable". Also set `metadata.validation_status: 'manual-only'` in `metadata.json` (write via `python3 {atomicWriteHelper} write --target <staging-skill-dir>/metadata.json`), and in the evidence-report's `Validation Results` section mark Security
|
|
118
|
+
- If fails or times out: Perform manual fallback (section 3); add note to evidence-report: "Spec validation performed manually — skill-check tool unavailable". Also set `metadata.validation_status: 'manual-only'` in `metadata.json` (write via `python3 {atomicWriteHelper} write --target <staging-skill-dir>/metadata.json`), and in the evidence-report's `Validation Results` section mark the Security and Body rows explicitly as `skipped — skill-check unavailable` (§6 and §6b do not depend on skill-check). Downstream consumers (pipeline, forger, test-skill) check `validation_status` to decide how much weight to put on the artifact; leaving it unset would make a manual-only run look equivalent to a fully automated PASS.
|
|
75
119
|
|
|
76
120
|
**Important:** Do not assume availability — empirical check required.
|
|
77
121
|
|
|
@@ -113,7 +157,7 @@ uv run {descriptionGuardHelper} verify-restore <staging-skill-dir>/SKILL.md \
|
|
|
113
157
|
--captured-description "{guarded_description}"
|
|
114
158
|
```
|
|
115
159
|
|
|
116
|
-
If `restored: true` in the verify-restore output, apply §0's post-restore re-validation hook.
|
|
160
|
+
If `restored: true` in the verify-restore output, apply §0's post-restore re-validation hook. Step 7 promotes the staged files as they are on disk, `--fix` changes included.
|
|
117
161
|
|
|
118
162
|
**Note:** `skill-check` may return non-zero exit code even when `summary.errorCount` is 0. Always rely on parsed JSON, not the shell exit code.
|
|
119
163
|
|
|
@@ -138,45 +182,30 @@ If fails: auto-fix (deterministic), re-validate once, record result. If passes:
|
|
|
138
182
|
|
|
139
183
|
### 4. Split Oversized Body (if needed)
|
|
140
184
|
|
|
141
|
-
**If step 2 reported `body.max_lines` failure:**
|
|
142
|
-
|
|
143
|
-
**Description Guard Protocol:** Split operations may rewrite the frontmatter. Wrap the split invocation in the four-phase guard defined in §0:
|
|
185
|
+
**If step 2 reported `body.max_lines` failure:** split the body with `{shardBodyHelper}`, the splitter step 5b auto-shard runs (resolve it from `{shardBodyProbeOrder}`; first existing path wins), inside the §0 guard, since a split may rewrite the frontmatter. Never run `npx skill-check split-body --write`: it moves every `##` section to `references/`, Tier 1 included.
|
|
144
186
|
|
|
145
187
|
```bash
|
|
146
|
-
# Phase 1
|
|
188
|
+
# Phase 1: capture before the split
|
|
147
189
|
uv run {descriptionGuardHelper} capture <staging-skill-dir>/SKILL.md
|
|
148
190
|
# stash returned `description` as `guarded_description`
|
|
149
191
|
|
|
150
|
-
# Phase 2
|
|
192
|
+
# Phase 2: the split
|
|
193
|
+
uv run {shardBodyHelper} <staging-skill-dir>/SKILL.md --budget 400
|
|
151
194
|
|
|
152
|
-
# Phases 3
|
|
195
|
+
# Phases 3 and 4: verify and restore after the split
|
|
153
196
|
uv run {descriptionGuardHelper} verify-restore <staging-skill-dir>/SKILL.md \
|
|
154
197
|
--captured-description "{guarded_description}"
|
|
155
198
|
```
|
|
156
199
|
|
|
157
200
|
If `restored: true` in the verify-restore output, apply §0's post-restore re-validation hook.
|
|
158
201
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
This selective split is deterministic — run `{shardBodyHelper}` (the same splitter step 5b auto-shard uses) rather than counting and extracting by hand. **Resolve `{shardBodyHelper}`** from `{shardBodyProbeOrder}`; first existing path wins.
|
|
202
|
+
The splitter extracts the Tier 2 sections, those whose heading starts `## Full`, largest first, to `references/` until the body fits, puts a cross-reference blockquote in each one's place, and reports `sections_extracted`, `body_lines_after`, `tier1_preserved` (with any pulled heading in `tier1_missing`), `xref_ok` and `under_budget`. Act on them:
|
|
162
203
|
|
|
163
|
-
|
|
164
|
-
uv run {
|
|
165
|
-
|
|
204
|
+
- **`tier1_preserved` is false:** **HARD HALT** (exit code 5, `tier1-not-preserved`, phase `validate`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "Split reduced Tier-1 section count (missing {tier1_missing}). Tier-1 sections must remain inline. Aborting the body split: manual review required." Every Tier 1 section must remain inline, and the context snippet's `#quick-start` and `#key-types` anchors name two of them, so this one check keeps the anchors resolving too.
|
|
205
|
+
- **`xref_ok` is false:** **HARD HALT** (exit code 5, `shard-xref-broken`, phase `validate`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "The body split left a cross-reference that does not resolve. Aborting."
|
|
206
|
+
- **`under_budget` is false** (rare: Tier 1 alone runs past about 300 lines): trim `## Key API Summary` and `## Architecture at a Glance` until the body fits, never moving a Tier 1 section to `references/`, then run the split again, guard included, and take `body_lines_after` from it.
|
|
166
207
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
**Do not run `npx skill-check split-body --write` before selective extraction.** It extracts every `##` section top-to-bottom, destroying the Tier 1 inline content the two-tier design depends on — a last resort used only after selective split has been attempted and proven insufficient.
|
|
170
|
-
|
|
171
|
-
**If selective split alone does not bring body under the limit** (the splitter reports `under_budget: false` — rare, typically only when Tier 1 itself exceeds 300 lines): reduce Tier 1 Key API Summary and Architecture at a Glance sections to fit within limits. Do not fall back to automated `split-body --write` to solve a Tier 1 sizing problem.
|
|
172
|
-
|
|
173
|
-
**Tier 1 preservation check:** After any split operation, verify that all of the following Tier 1 sections remain inline in SKILL.md (not moved to references/): Overview, Quick Start, Common Workflows, Key API Summary, Migration & Deprecation Warnings (if present), Key Types, Architecture at a Glance, CLI (if present), Scripts & Assets (if present), Manual Sections. If any was moved to references/, restore it immediately and re-split targeting only Tier 2 sections.
|
|
174
|
-
|
|
175
|
-
**Post-split Tier-1 count check (mandatory):** do not recount Tier-1 headings by hand — consume the splitter's `tier1_preserved` field. `{shardBodyHelper}` compares the Tier-1 headings inline before extraction against those inline afterward and reports `tier1_preserved` (with any pulled headings in `tier1_missing`). Read it from the invocation above, or re-check any split's result with `uv run {shardBodyHelper} <staging-skill-dir>/SKILL.md --dry-run`. **HALT** if `tier1_preserved` is false with: "Split reduced Tier-1 section count (missing {tier1_missing}). Tier-1 sections must remain inline. Restoring from staging backup and aborting body split — manual review required." Do not proceed past §4 — Tier-1 preservation is a hard invariant and a `tier1_preserved: false` result means the splitter pulled an inline section into references/ regardless of the section-list check above (e.g., heading-text variation, capitalization, or the splitter's own heuristics).
|
|
176
|
-
|
|
177
|
-
**Anchor validation and remediation:** After any split, verify that context-snippet section anchors (`#quick-start`, `#key-types`) still resolve to headings in SKILL.md. If an anchor no longer resolves (section was split out), restore that section to SKILL.md inline content — the context-snippet must always reference sections that exist in the main file.
|
|
178
|
-
|
|
179
|
-
Then re-validate: `npx skill-check check <staging-skill-dir> --format json {security_scan_flag}` — use the flag cached from §2's probe. If `{skill_check_flag_fallback}` is true, skip re-validation and rely on the §3 manual check.
|
|
208
|
+
Then re-validate: `npx skill-check check <staging-skill-dir> --format json {security_scan_flag}`, with the flag cached from §2's probe. If `{skill_check_flag_fallback}` is true, skip re-validation and rely on the §3 manual check.
|
|
180
209
|
|
|
181
210
|
**If skill-check unavailable or no body size issue:** Skip.
|
|
182
211
|
|
|
@@ -200,90 +229,136 @@ Record: "Security scan skipped — SNYK_TOKEN not configured"
|
|
|
200
229
|
|
|
201
230
|
**If skill-check unavailable:** Skip with note: "Security scan skipped — skill-check tool unavailable"
|
|
202
231
|
|
|
203
|
-
### 6.
|
|
232
|
+
### 6. Description Angle-Bracket Check
|
|
204
233
|
|
|
205
|
-
|
|
234
|
+
The Claude platform does not accept a skill whose frontmatter `description` contains XML tags, and none of the validators this step runs checks for them: skill-check has no such rule and Tessl Review accepts them. Step 5 §2a replaces every `<` with `{` and every `>` with `}` before SKILL.md is written, and the §0 guard puts that description back whenever a tool rewrites it; this section checks the staged result after every tool in this step has run, whether or not skill-check was available.
|
|
206
235
|
|
|
207
|
-
|
|
236
|
+
Resolve `{frontmatterValidator}` from `{frontmatterValidatorProbeOrder}`; first existing path wins. If neither path resolves, or the command below prints no JSON object, **HARD HALT** (exit code 3, `helper-missing`, phase `validate`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "Cannot check the staged description: skf-validate-frontmatter.py is missing or did not run. Re-install SKF, then re-run create-skill." Run:
|
|
208
237
|
|
|
209
|
-
|
|
238
|
+
```bash
|
|
239
|
+
uv run {frontmatterValidator} "<staging-skill-dir>/SKILL.md" --forbid-angle-brackets
|
|
240
|
+
```
|
|
210
241
|
|
|
211
|
-
|
|
242
|
+
Rely on the parsed JSON, not the exit code: the validator also exits 1 for the frontmatter issues §2 and §3 already recorded. Bind `{description_angle_brackets}` ← `description_angle_brackets`.
|
|
212
243
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
- If `review_score < 60` or `content_score < 60`: record warnings in the evidence report, continue.
|
|
217
|
-
2. **Iterate `judge_suggestions[]`.** For each suggestion:
|
|
218
|
-
- Cross-reference against the rules in `{tesslDismissalData}` in order.
|
|
219
|
-
- If a rule matches: record `{rule_id, rationale, suggestion_text}` under "Dismissed tessl suggestions" in the evidence report. Do not apply.
|
|
220
|
-
- If no rule matches: add to the "Novel tessl suggestions" list for §6b to surface to the user.
|
|
221
|
-
3. **Short-circuit when empty.** If every suggestion was dismissed (no novel suggestions), §6b has nothing to show — auto-proceed to §7.
|
|
244
|
+
- **`{description_angle_brackets}` is `0`:** record `Description angle brackets: none` and continue to §6b.
|
|
245
|
+
- **`{description_angle_brackets}` is null** (the description is missing, blank or not a string, which §2 or §3 already recorded): record `Description angle brackets: not checked — no description` and continue to §6b.
|
|
246
|
+
- **`{description_angle_brackets}` is above `0`:** apply step 5 §2a's substitution again, in place. The guard helper rewrites only the `description` field and takes no description on the command line, so backticks and `$` in it are safe:
|
|
222
247
|
|
|
223
|
-
|
|
248
|
+
```bash
|
|
249
|
+
uv run {descriptionGuardHelper} sanitize "<staging-skill-dir>/SKILL.md"
|
|
250
|
+
```
|
|
224
251
|
|
|
225
|
-
|
|
252
|
+
Bind `{angle_bracket_substitutions}` ← `substitutions`, `{angle_brackets_sanitized}` ← `sanitized` and `{sanitized_description}` ← `description`. Then run the validator command above once more and bind `{description_angle_brackets}` ← `description_angle_brackets` again.
|
|
253
|
+
- **Recovered** (the guard helper exited 0, `{angle_brackets_sanitized}` is true and `{description_angle_brackets}` is now `0`): record `Description angle brackets: re-sanitized ({angle_bracket_substitutions} substitutions)` and continue to §6b.
|
|
254
|
+
- **Otherwise** **HARD HALT** (exit code 5, `description-angle-brackets`, phase `validate`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "Description sanitization failed: the staged SKILL.md description still holds angle brackets after step 5 §2a's substitution was applied again. The Claude platform does not accept XML tags in a skill description. Check that `<staging-skill-dir>/SKILL.md` can be written, then re-run create-skill." Nothing has been promoted yet, so the halt writes no result file.
|
|
226
255
|
|
|
227
|
-
|
|
256
|
+
### 6b. Tessl Review (optional)
|
|
228
257
|
|
|
229
|
-
|
|
258
|
+
Tessl Review (`tessl review run`, which the helper below runs on a copy of `<staging-skill-dir>`) scores the skill on Tessl's servers with validation checks and two AI judges, one for the description and one for the content. It runs only when the user opted in by setting `tessl_review_workspace` in `{preferencesFile}` to a Tessl workspace name, because it needs a Tessl account, uploads the skill's files to that workspace's review history and spends Tessl credits. The helper applies that setting and every other condition, so run it on every pass and let it decide; `{tesslReviewRules}` explains what is uploaded and what each result means. Nothing in this section halts, asks the user anything, changes the staged files or adds an auto-decision, in interactive and headless runs alike.
|
|
230
259
|
|
|
231
|
-
|
|
260
|
+
Resolve `{tesslReviewHelper}` ← first existing path in `{tesslReviewProbeOrder}`. If neither path exists, set `{tessl_summary}` to `not run — skf-tessl-review.py is missing` and `{tessl_warnings}` to the one line `Tessl Review: {tessl_summary}`, add that line to the evidence report's Remaining Warnings and continue to §7. Otherwise submit the review:
|
|
232
261
|
|
|
233
|
-
|
|
262
|
+
```bash
|
|
263
|
+
uv run {tesslReviewHelper} submit "<staging-skill-dir>" --preferences "{preferencesFile}"
|
|
264
|
+
```
|
|
234
265
|
|
|
235
|
-
|
|
266
|
+
A review takes Tessl about two minutes, so no call waits for all of it. When the review is on, `submit` sends a copy of the skill to Tessl and returns `pending` with Tessl's run id as soon as Tessl accepts it; when it is off or cannot run, `submit` returns that result instead. While `{tessl_status}` is `pending`, collect the review, at most six times, and add `--final` to the sixth call, which turns a review still running into `timeout`:
|
|
236
267
|
|
|
237
|
-
|
|
238
|
-
{
|
|
268
|
+
```bash
|
|
269
|
+
uv run {tesslReviewHelper} collect "{tessl_run_id}" --workspace "{tessl_workspace}" --tessl-version "{tessl_version}"
|
|
270
|
+
```
|
|
239
271
|
|
|
240
|
-
|
|
241
|
-
- **[S] Skip** — proceed with current content as-is (default)
|
|
242
|
-
- **[A] Apply structural fixes** — apply only structural suggestions (split sections, consolidate duplicates). No new content generated.
|
|
243
|
-
- **[R] Review all** — show each suggestion with proposed changes before applying"
|
|
272
|
+
Each call ends within two minutes (a `collect` checks the review for up to 90 seconds, then returns `pending` again or the result), so run each one with your shell tool's default time limit. If the shell tool stops a call before it prints its JSON, or it prints none, make that the last call: set `{tessl_status}` to `failed`, `{tessl_summary}` to `failed — stopped before skf-tessl-review.py reported a result` and `{tessl_warnings}` to the one line `Tessl Review: {tessl_summary}`, keep `{tessl_run_id}` and the other values the calls before it bound, add that line to the Remaining Warnings and continue to §7. Otherwise rely on the JSON, not the exit code, and bind these from the `submit` JSON and again from each `collect` JSON, whose values replace the earlier ones:
|
|
244
273
|
|
|
245
|
-
|
|
274
|
+
- `{tessl_status}` ← `status`
|
|
275
|
+
- `{tessl_summary}` ← `summary`
|
|
276
|
+
- `{tessl_warnings}` ← `warnings`
|
|
277
|
+
- `{tessl_workspace}` ← `workspace`
|
|
278
|
+
- `{tessl_version}` ← `tessl_version`
|
|
279
|
+
- `{tessl_run_id}` ← `run_id`
|
|
280
|
+
- `{tessl_review_score}` ← `review_score`
|
|
281
|
+
- `{tessl_description_score}` ← `description_score`
|
|
282
|
+
- `{tessl_content_score}` ← `content_score`
|
|
283
|
+
- `{tessl_validation}` ← `validation`
|
|
284
|
+
- `{tessl_description_suggestions}` ← `description_suggestions`
|
|
285
|
+
- `{tessl_content_suggestions}` ← `content_suggestions`
|
|
246
286
|
|
|
247
|
-
-
|
|
248
|
-
- **Semantic suggestions** (add examples, add error handling, add validation checkpoints) introduce content not verified from source code. If the user chooses to apply these:
|
|
249
|
-
- Warn: "This adds content not verified from source code."
|
|
250
|
-
- Mark applied content with `<!-- [TESSL:auto-fix] -->` markers
|
|
251
|
-
- Cite as `[TESSL:suggestion]` in the provenance map with `confidence: "TESSL"` (below T3)
|
|
252
|
-
- Record in evidence report: "TESSL-suggested content applied: {count} items (unverified)"
|
|
253
|
-
- **If user selects [S]:** Record "tessl suggestions: skipped by user" in evidence report. Proceed to section 7.
|
|
254
|
-
- **If user selects [A]:** Apply structural fixes only, re-run tessl to capture updated score, record results. Proceed to section 7.
|
|
255
|
-
- **If user selects [R]:** Show each suggestion with the proposed change. For each, user confirms or skips. Apply confirmed changes, record results. Proceed to section 7.
|
|
287
|
+
Every key is always present: the scores and `{tessl_validation}` are null and the suggestion lists are empty unless `{tessl_status}` is `reviewed`, and `{tessl_run_id}` is null until Tessl has accepted the review. After the last call, add each entry of `{tessl_warnings}` to the evidence report's Remaining Warnings: a score below 60%, validation errors or, for any status other than `reviewed` and `off`, why the review produced no score. When `{tessl_status}` is `reviewed`, resolve `{tesslReviewRules}` ← first existing path in `{tesslReviewRulesProbeOrder}`, load it, and mark each entry of `{tessl_content_suggestions}` that one of its rules matches with `(not applicable: <rule-id>)`; if neither path exists, list the suggestions unmarked. Apply no suggestion: content suggestions would add text SKF cannot cite to source, and the description comes from the brief. The staged skill holds no `scripts/` or `assets/` until step 7 copies them, so for a brief with scripts or assets, validation findings about missing `scripts/` or `assets/` paths are expected here; test-skill reviews the finished package. §8 records the result.
|
|
256
288
|
|
|
257
289
|
### 7. Validate metadata.json
|
|
258
290
|
|
|
259
|
-
**Re-derive the computed fields with `{renderMetadataStatsHelper}` in check mode** rather than re-doing the arithmetic by hand. Resolve `{renderMetadataStatsHelper}` from `{renderMetadataStatsProbeOrder}` (first existing path wins;
|
|
291
|
+
**Re-derive the computed fields with `{renderMetadataStatsHelper}` in check mode** rather than re-doing the arithmetic by hand. Resolve `{renderMetadataStatsHelper}` from `{renderMetadataStatsProbeOrder}` (first existing path wins; if neither resolves, **HARD HALT** (exit code 3, `helper-missing`, phase `validate`; stage `{run_dir}/halt.json` per the Workflow Rules and run `uv run {emitEnvelopeHelper} emit-halt --workflow skf-create-skill --run-dir "{run_dir}" --target stderr < "{run_dir}/halt.json"`): "Cannot check metadata.json: skf-render-metadata-stats.py is missing. Re-install SKF, then re-run create-skill."), then run it against the staged provenance-map and metadata.json:
|
|
260
292
|
|
|
261
293
|
```bash
|
|
262
294
|
uv run {renderMetadataStatsHelper} <staging-skill-dir>/provenance-map.json \
|
|
263
295
|
--check <staging-skill-dir>/metadata.json
|
|
264
296
|
```
|
|
265
297
|
|
|
266
|
-
The helper re-bins `entries[]` by `signature_source`, recomputes `exports_documented`, `exports_total`, and `public_api_coverage` / `total_coverage` (null when the denominator is 0), and cross-checks `stats.scripts_count` / `stats.assets_count` against the `scripts[]` / `assets[]` array lengths and the provenance-map `file_entries` counts. It takes the judgment values (`exports_public_api`, `exports_internal`, `effective_denominator`) from `metadata.json` itself and infers the shape from `scope_type` / `skill_type` (pass `--shape` to override). Parse the emitted JSON (rely on the JSON, not the exit code):
|
|
298
|
+
The helper re-bins `entries[]` by `signature_source`, recomputes `exports_documented`, `exports_total`, and `public_api_coverage` / `total_coverage` (null when the denominator is 0), and cross-checks `stats.scripts_count` / `stats.assets_count` against the `scripts[]` / `assets[]` array lengths and the provenance-map `file_entries` counts. It also checks that each T1 or T1-low provenance entry's `confidence`, `signature_source` and `ast_node_type` match its `extraction_method`, and that no entry read by eye (`source-read`) carries `signature_source: "T1"` at any confidence. It takes the judgment values (`exports_public_api`, `exports_internal`, `effective_denominator`) from `metadata.json` itself and infers the shape from `scope_type` / `skill_type` (pass `--shape` to override). Parse the emitted JSON (rely on the JSON, not the exit code):
|
|
267
299
|
|
|
268
300
|
- **`coherence.ok: true`** — the computed fields are internally consistent; record "Metadata: PASS".
|
|
269
|
-
-
|
|
301
|
+
- **A `provenance.entries[<i>].*` violation** (handle these before any other): entry `<i>` of the staged provenance map (its `export_name` is in the violation) carries a label its `extraction_method` does not allow (one compile §4 did not settle): relabel it by the Relabel Rule in `{relabelRuleData}`, resolving `{verifyProvenanceCompletenessHelper}` ← first existing path in `{verifyProvenanceCompletenessProbeOrder}` for its `kind-at` lookup. Write the relabeled map with `python3 {atomicWriteHelper} write --target <staging-skill-dir>/provenance-map.json`, then re-run the check above and act on its new result: a relabeled `signature_source` moves the distribution, so the computed-value fixes below come from the re-run, and a violation left as a WARN does not block them. Record the relabeled export names, and each WARN left, on the evidence report's `Provenance labels` line (§8).
|
|
302
|
+
- **`coherence.ok: false`**: each `violations[]` entry is `{field, expected, actual}` where `expected` is the correct value. **Auto-fix each computed-value violation** (`field` starting `stats.` or `confidence_distribution.`) by setting that field in `metadata.json` to `expected` (write via `python3 {atomicWriteHelper} write --target <staging-skill-dir>/metadata.json`), leaving every other stats field (e.g. `stats.notes` on a reference app) untouched. Record "Metadata: auto-fixed {N} computed-value discrepanc(y|ies)" listing the fields. These are computed values, so the helper is authoritative: a `confidence_distribution` violation is the per-entry mis-binning compile.md §4 describes (T2 annotations + T3 doc items counted on top of the per-export tiers); the helper's per-entry counts replace them. The carve-out is handled by `--shape`: a **reference-app** distribution sums to the per-citation count, a consistent state, not a violation. A `provenance.file_entries.*` violation is not a computed metadata field: it means the provenance-map `file_entries` and metadata counts disagree; record it as a warning for manual reconciliation rather than auto-editing the count.
|
|
270
303
|
|
|
271
304
|
Then verify the two fields the helper does not own (genuine constants/contract):
|
|
272
305
|
- `spec_version` is `"1.3"`.
|
|
273
306
|
- `scope_type` is present and equals the brief's `scope.type` verbatim.
|
|
274
307
|
|
|
308
|
+
### 7a. Verify Provenance Lines and Citation Prefixes
|
|
309
|
+
|
|
310
|
+
Check that each staged provenance entry's `source_line` is the line that defines its export (the `def` or declaration line itself, not a decorator or blank line above it), and that each `[AST:]` / `[SRC:]` citation in SKILL.md and `references/` carries the prefix its entry's `extraction_method` implies: `ast-grep` gives `[AST:]`, `source-read` gives `[SRC:]`. Also check that each ast-grep entry's `ast_node_type` is a node kind ast-grep knows for its file's language. Resolve `{verifyProvenanceCompletenessHelper}` ← first existing path in `{verifyProvenanceCompletenessProbeOrder}`. If neither path exists, record `Provenance lines: not run: verifier missing` and continue to §8. Otherwise bind `{verify_json}` ← `{project-root}/_bmad-output/.skf-stage/{skill-name}.verify.json` (beside the staging folder, never inside the skill) and, from `{project-root}`, remove the JSON an earlier run left there and run the verifier against the staged package:
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
rm -f "{verify_json}"
|
|
314
|
+
uv run {verifyProvenanceCompletenessHelper} verify \
|
|
315
|
+
--metadata <staging-skill-dir>/metadata.json \
|
|
316
|
+
--provenance <staging-skill-dir>/provenance-map.json \
|
|
317
|
+
--source-root {source_root} \
|
|
318
|
+
--skill-dir <staging-skill-dir> \
|
|
319
|
+
--check-node-kinds \
|
|
320
|
+
-o "{verify_json}"
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
`{source_root}` is the local tree step 3 extracted from. When it is null, empty or a URL, leave out the `--source-root` line (an empty flag value fails the helper's arguments). When there is no local tree (no flag), the helper checks no source line and reports `summary.stale_check: skipped-no-source-root`, and the citation check still runs. A JSON at `{verify_json}` after the call is this run's: read it, not the exit code (exit 1 means findings). When no JSON is there after the call (an input error, exit 2, `uv` failing, or a shell timeout that stopped it), record `Provenance lines: not run: verifier error`, add the helper's stderr to the evidence report's Remaining Warnings and continue to §8. When `summary.skill_citations_scanned` is above 0 and `summary.skill_citations_matched` is 0, no citation names a path and line the map records (the citations use another root), so the prefix check compared nothing: list that as a WARN. `--check-node-kinds` reports in `node_kinds[]` each `ast-grep` entry whose `ast_node_type` is `ERROR` or not shaped like a kind (judged without ast-grep), or that the ast-grep CLI does not know as a kind of its file's language; each item gives the entry's `entry_index`, `export_name`, `source_file`, `source_line` and `language`. `summary.node_kind_check` is `skipped-no-ast-grep` when no ast-grep CLI is on PATH, or `skipped-unrecognized-ast-grep` when the ast-grep found does not reject a kind no grammar has, so its answers cannot be read: either way ast-grep judged no kind. `node_kinds_unchecked[]` lists, with a `reason`, the entries whose kind ast-grep could not judge, and `summary.node_kind_check_skipped` counts the ast-grep entries in files ast-grep has no language for. Record both on the `Provenance lines` line.
|
|
324
|
+
|
|
325
|
+
Fix the findings that have one answer, in this order, then run the command above once more:
|
|
326
|
+
|
|
327
|
+
1. **Citation prefixes and source lines.** Never apply them by hand: from `{project-root}`, run the verifier's `fix` on the JSON the run above wrote:
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
uv run {verifyProvenanceCompletenessHelper} fix \
|
|
331
|
+
--verify "{verify_json}" \
|
|
332
|
+
--provenance <staging-skill-dir>/provenance-map.json \
|
|
333
|
+
--skill-dir <staging-skill-dir>
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
It gives each mismatched citation its `expected_prefix`, moves each `source_line` that has exactly one value in `definition_lines` there, with the citations of the old line in SKILL.md and `references/` (a range by both ends, each citation at most once), writes each changed file through the atomic writer, and prints `applied[]`, `left_as_warn[]` (each finding it left, with its `why`), `files_written[]` and `summary`, on exit 0 and on exit 1 (it left a WARN) alike. Exit 2 prints no JSON (its stderr line names any file it already wrote): list a WARN, `not fixed: verifier error` with that line, and go on to item 2.
|
|
337
|
+
2. **Node kinds.** For each `node_kinds[]` item (`reason` is `invalid-kind` or `error-kind`), take the entry at its `entry_index` in the staged provenance map (its `export_name` and `source_file` confirm it; item 1's `fix` may have moved its `source_line`) and set its `ast_node_type` to the node kind the Relabel Rule in `{relabelRuleData}` gives: the kind of the recipe the export's `ast_recipe` names in the extraction inventory step 3 §5 wrote, `{project-root}/_bmad-output/.skf-stage/{skill-name}.inventory.json`, else its `kind-at` lookup at the entry's current `source_line`. When the rule gives no kind, list a WARN with its reason. Never invent a kind, and never change `extraction_method` to clear the finding. Write the map with `python3 {atomicWriteHelper} write --target <staging-skill-dir>/provenance-map.json`.
|
|
338
|
+
|
|
339
|
+
If that second run leaves no JSON at `{verify_json}`, record the fixes already applied and `second run: verifier error`, and continue to §8. Fix nothing else, and triage what is left:
|
|
340
|
+
|
|
341
|
+
- A `left_as_warn[]` item whose `why` is `no-definition-line` is unverified, not gone: the rules found no definition line, which may be a shape they do not cover. List its export as unverified.
|
|
342
|
+
- Every other `left_as_warn[]` item needs a person to decide, so list each as a WARN: several definition lines (`several-definition-lines`), a `file-missing`, `line-out-of-bounds` or `line-invalid` item (`needs-decision`), a citation of a line another entry also records, which may cite that export (`shared-line`), a citation or entry `fix` could not find (`citation-not-found`, `entry-not-found`), and a citation inside a `[MANUAL]` block (`inside-manual-block`).
|
|
343
|
+
- The helper's `missing` and `orphaned` exports are not line, citation or node-kind findings: add each to the evidence report's Remaining Warnings.
|
|
344
|
+
|
|
345
|
+
Record the result on the evidence report's `Provenance lines` line (§8): `pass` when the first run found nothing, `findings` when it found something and this section fixed nothing, or what it fixed (`fix`'s `summary.source_lines_moved` and `summary.citation_prefixes_fixed`, and the node kinds item 2 set); then the unverified exports, a WARN for each `left_as_warn[]` item and each other line, citation or node-kind finding the second run still reports, `source lines not checked: no local source tree` when `stale_check` is `skipped-no-source-root`, `node kinds not checked: no ast-grep CLI` or `node kinds not checked: unrecognized ast-grep` when `node_kind_check` is `skipped-no-ast-grep` or `skipped-unrecognized-ast-grep`, each `node_kinds_unchecked[]` entry with its `reason`, and `summary.node_kind_check_skipped` when it is above 0. This section never halts.
|
|
346
|
+
|
|
275
347
|
### 8. Update Evidence Report
|
|
276
348
|
|
|
277
|
-
|
|
349
|
+
Write the validation results into the staged `<staging-skill-dir>/evidence-report.md`, in place of the `[PENDING: populated by step 6]` placeholders compile left, with `python3 {atomicWriteHelper} write --target <staging-skill-dir>/evidence-report.md`: step 7 promotes that file as it is. In the same write, add under `## Remaining Warnings` the notes steps 5a to 5c kept for the evidence report (the doc-sources note, `{temporal_feeder_notice}` when step 5c set it, because the Deep-tier temporal feeder held no files) and, once each, the skipped authoritative-files scan when the inventory's `authoritative_files_scan` records `not_scanned` (a remote source that was never cloned; the `skipped` count of candidates the user skipped is not a warning). When no split ran and the staged `references/` holds no file, the Body line says `Tier-2 kept inline (references/ empty)`, so an audit can tell inline by design from a split that failed.
|
|
278
350
|
|
|
279
351
|
```markdown
|
|
280
352
|
## Validation Results
|
|
281
353
|
- Schema: {pass/fail} (quality score: {score}/100)
|
|
282
354
|
- Frontmatter: {pass/fail}
|
|
283
|
-
- Body: {pass/fail} {
|
|
355
|
+
- Body: {pass/fail} {body split applied if applicable}
|
|
284
356
|
- Security: {pass/warn/skipped}
|
|
285
|
-
-
|
|
357
|
+
- Description angle brackets: {none | re-sanitized ({count} substitutions) | not checked — no description}
|
|
358
|
+
- Tessl Review: {tessl_summary}
|
|
286
359
|
- Metadata: {pass/fail}
|
|
360
|
+
- Provenance labels: {pass | relabeled {N} to match extraction_method: {export names}}{; WARN, no node kind found: {export names}}
|
|
361
|
+
- Provenance lines: {pass | findings | fixed {N} source lines, {M} citation prefixes and {K} node kinds | not run: verifier missing | not run: verifier error}{; second run: verifier error}{; unverified, no definition line found: {export names}}{; WARN: {each line, citation or node-kind warning §7a lists}}{; source lines not checked: no local source tree}{; node kinds not checked: no ast-grep CLI | unrecognized ast-grep}{; node kinds unchecked: {export name (reason) for each node_kinds_unchecked item}}{; node kinds skipped: {N} in files ast-grep has no language for}
|
|
287
362
|
|
|
288
363
|
## Quality Score Breakdown
|
|
289
364
|
- Frontmatter (30%): {score} | Description (30%): {score} | Body (20%): {score} | Links (10%): {score} | File (10%): {score}
|
|
@@ -297,32 +372,31 @@ Add validation results to evidence-report content in context:
|
|
|
297
372
|
## Auto-Fixed Issues
|
|
298
373
|
- {list of issues automatically corrected by --fix}
|
|
299
374
|
|
|
300
|
-
## Remaining Warnings
|
|
301
|
-
- {warnings
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
**Auto-Decisions table (reconcile from the durable sink — idempotent):** all gates have now fired — every one appended its row to the on-disk sink `{sidecar_path}/auto-decisions.jsonl` as it landed (including §6b's tessl-suggestions row), step 5 §7 rendered the step 1–3d rows into the staged `<staging-skill-dir>/evidence-report.md`, and steps 7–9 add none. Reconcile: read the sink's JSON lines (the authoritative durable record — it survives any compaction of the in-context buffer), union them with both the `## Auto-Decisions` rows already in `<staging-skill-dir>/evidence-report.md` and the in-context `headless_decisions[]` buffer, keyed on `step`+`gate` so no decision is duplicated or dropped, and re-render the section from that union. Because the rows are recovered from the sink rather than from the possibly-compacted buffer, the audit table stays complete on a long headless run. Emit one row per entry:
|
|
375
|
+
## Remaining Warnings
|
|
376
|
+
- {warnings and security results, then each entry of {tessl_warnings} — or "none"}
|
|
305
377
|
|
|
378
|
+
## Tessl Review
|
|
379
|
+
- Result: {tessl_summary}
|
|
380
|
+
- Workspace: {tessl_workspace or —} · tessl {tessl_version or —} · Run: {tessl_run_id or —}
|
|
381
|
+
- Validation findings: {each {tessl_validation} finding as `name (status): message`, or "none"}
|
|
382
|
+
- Description suggestions (to act on one, edit the description in the brief and re-run create-skill): {each of {tessl_description_suggestions}, or "none"}
|
|
383
|
+
- Content suggestions (advisory, not applied): {each of {tessl_content_suggestions} with its `(not applicable: <rule-id>)` mark, or "none"}
|
|
306
384
|
```
|
|
307
|
-
## Auto-Decisions
|
|
308
385
|
|
|
309
|
-
|
|
310
|
-
|------|------|----------|-----------|-----------|
|
|
311
|
-
| {step} | {gate} | {decision}{value?} | {rationale} | {timestamp} |
|
|
312
|
-
```
|
|
386
|
+
When `{tessl_status}` is not `reviewed`, the `## Tessl Review` section holds only its Result line and, when `{tessl_run_id}` is set, its Workspace line, so the report names the run of a review that may still finish.
|
|
313
387
|
|
|
314
|
-
|
|
388
|
+
**Auto-Decisions:** keep the `## Auto-Decisions` section step 5 §7 rendered from the run sink as it is: every gate decided before step 5, and no step records a decision after it, so its rows already match `summary.auto_decision_count`.
|
|
315
389
|
|
|
316
|
-
**Description Guard population:** if the §0 protocol fired during §2 (`skill-check --fix`) or §4 (
|
|
390
|
+
**Description Guard population:** if the §0 protocol fired during §2 (`skill-check --fix`) or §4 (the body split), fill the four Description Guard fields from context:
|
|
317
391
|
|
|
318
392
|
- `Restored: true` when `description_guard_restored == true`, otherwise `false`.
|
|
319
|
-
- `Triggering tool`: the tool name recorded by §0 (`skill-check --fix
|
|
393
|
+
- `Triggering tool`: the tool name recorded by §0 (`skill-check --fix` in §2, `skf-shard-body.py` in §4), or the template's no-fire dash if the guard did not fire.
|
|
320
394
|
- `Original description preserved`: `true` if the restore succeeded (on-disk now matches the pre-tool snapshot), `false` if restoration itself failed (rare — treat as a halt condition in a future version).
|
|
321
|
-
- `Notes`: a one-sentence description of what the tool had changed. Typical values: `"replaced with generic summary"`, `"truncated at N chars"`, `"angle-bracket tokens re-introduced"`, `"field deleted entirely"`. If `Restored: false`, use `—`.
|
|
395
|
+
- `Notes`: a one-sentence description of what the tool had changed, based on the recorded `description_guard_diff_kind` (`replaced`, `truncated` or `deleted`). Typical values: `"replaced with generic summary"`, `"truncated at N chars"`, `"angle-bracket tokens re-introduced"`, `"field deleted entirely"`. If `Restored: false`, use `—`.
|
|
322
396
|
|
|
323
|
-
When `Restored: false`, the three follow-up fields are all `—` — this is the clean-run expected state — with one exception: when `description_guard_refused == "empty-capture"` (
|
|
397
|
+
When `Restored: false`, the three follow-up fields are all `—` — this is the clean-run expected state — with one exception: when `description_guard_refused == "empty-capture"` (§0's empty-snapshot rule — `verify-restore` exited 1 and no in-context copy allowed a re-run), the guard did fire and must not render as a clean run. Set `Restored: false`, `Triggering tool` to the recorded tool name, `Original description preserved: false`, and `Notes: guard refused — empty captured snapshot (empty-capture)`.
|
|
324
398
|
|
|
325
399
|
### 9. Auto-Proceed
|
|
326
400
|
|
|
327
|
-
|
|
401
|
+
No user interaction: this step has no gate. After validation completes, load `{nextStepFile}`, read it fully, then execute it. Tool unavailability, validation failures and every Tessl Review result are recorded as skips and warnings; the step halts only where a section above says HALT: a helper whose probe order says HALT and that no path resolves, the §4 Tier-1 preservation and cross-reference checks, and the §6 description check.
|
|
328
402
|
|