bmad-module-skill-forge 1.9.0 → 2.0.1
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/.nvmrc +1 -1
- package/README.md +10 -5
- package/docs/_data/pinned.yaml +2 -2
- package/docs/agents.md +11 -2
- package/docs/architecture.md +5 -4
- package/docs/bmad-synergy.md +30 -7
- package/docs/campaign.md +172 -0
- package/docs/examples.md +7 -3
- package/docs/forge-auto.md +90 -0
- package/docs/getting-started.md +9 -0
- package/docs/how-it-works.md +6 -4
- package/docs/index.md +4 -3
- package/docs/skill-model.md +1 -1
- package/docs/troubleshooting.md +17 -1
- package/docs/verifying-a-skill.md +2 -2
- package/docs/why-skf.md +1 -1
- package/docs/workflows.md +64 -24
- package/package.json +2 -2
- package/src/knowledge/skill-lifecycle.md +1 -1
- package/src/module-help.csv +4 -3
- package/src/shared/data/language-corpora.json +32 -0
- package/src/shared/references/pipeline-contracts.md +6 -3
- package/src/shared/scripts/schemas/skill-brief.v1.json +6 -1
- package/src/shared/scripts/skf-comention-pairs.py +350 -0
- package/src/shared/scripts/skf-count-tokens.py +222 -0
- package/src/shared/scripts/skf-derive-assembly-shape.py +107 -0
- package/src/shared/scripts/skf-detect-docs.py +240 -4
- package/src/shared/scripts/skf-detect-language.py +82 -3
- package/src/shared/scripts/skf-detect-tools.py +105 -2
- package/src/shared/scripts/skf-emit-result-envelope.py +17 -0
- package/src/shared/scripts/skf-enumerate-stack-skills.py +111 -2
- package/src/shared/scripts/skf-extract-public-api.py +53 -0
- package/src/shared/scripts/skf-find-cycles.py +246 -0
- package/src/shared/scripts/skf-hash-content.py +487 -2
- package/src/shared/scripts/skf-language-corpora.py +100 -0
- package/src/shared/scripts/skf-manifest-ops.py +67 -1
- package/src/shared/scripts/skf-merge-doc-urls.py +244 -0
- package/src/shared/scripts/skf-preapply.py +1 -1
- package/src/shared/scripts/skf-rebuild-managed-sections.py +180 -0
- package/src/shared/scripts/skf-recommend-scope-type.py +1 -2
- package/src/shared/scripts/skf-render-metadata-stats.py +499 -0
- package/src/shared/scripts/skf-rewrite-skill-name.py +308 -0
- package/src/shared/scripts/skf-shape-detect.py +576 -25
- package/src/shared/scripts/skf-shard-body.py +461 -0
- package/src/shared/scripts/skf-skill-inventory.py +139 -3
- package/src/shared/scripts/skf-structural-diff.py +307 -67
- package/src/shared/scripts/skf-validate-brief-schema.py +41 -6
- package/src/shared/scripts/skf-validate-feasibility-report.py +234 -0
- package/src/shared/scripts/skf-validate-frontmatter.py +17 -12
- package/src/shared/scripts/skf-validate-output.py +443 -10
- package/src/shared/scripts/skf-validate-pins.py +3 -3
- package/src/shared/scripts/skf-verify-no-trace.py +214 -0
- package/src/shared/scripts/skf-verify-provenance-completeness.py +439 -0
- package/src/shared/scripts/skf-write-skill-brief.py +21 -5
- package/src/skf-analyze-source/SKILL.md +17 -32
- package/src/skf-analyze-source/assets/skill-brief-schema.md +1 -1
- package/src/skf-analyze-source/customize.toml +2 -0
- package/src/skf-analyze-source/references/auto-docs-only.md +116 -0
- package/src/skf-analyze-source/references/continue.md +8 -13
- package/src/skf-analyze-source/references/generate-briefs.md +28 -12
- package/src/skf-analyze-source/references/headless-contract.md +33 -0
- package/src/skf-analyze-source/references/health-check.md +1 -2
- package/src/skf-analyze-source/references/identify-units.md +25 -36
- package/src/skf-analyze-source/references/init.md +12 -25
- package/src/skf-analyze-source/references/map-and-detect.md +8 -20
- package/src/skf-analyze-source/references/recommend.md +4 -14
- package/src/skf-analyze-source/references/scan-project.md +3 -11
- package/src/skf-analyze-source/references/step-auto-scope.md +211 -197
- package/src/skf-analyze-source/references/step-shape-detect.md +20 -13
- package/src/skf-analyze-source/references/unit-detection-heuristics.md +2 -2
- package/src/skf-audit-skill/SKILL.md +9 -6
- package/src/skf-audit-skill/customize.toml +2 -0
- package/src/skf-audit-skill/references/init.md +58 -32
- package/src/skf-audit-skill/references/re-index.md +15 -34
- package/src/skf-audit-skill/references/report.md +11 -58
- package/src/skf-audit-skill/references/semantic-diff.md +4 -22
- package/src/skf-audit-skill/references/severity-classify.md +53 -87
- package/src/skf-audit-skill/references/step-doc-drift.md +49 -19
- package/src/skf-audit-skill/references/structural-diff.md +43 -68
- package/src/skf-brief-skill/SKILL.md +7 -36
- package/src/skf-brief-skill/assets/scope-templates.md +1 -1
- package/src/skf-brief-skill/assets/skill-brief-schema.md +1 -1
- package/src/skf-brief-skill/customize.toml +14 -0
- package/src/skf-brief-skill/references/analyze-target.md +13 -18
- package/src/skf-brief-skill/references/confirm-brief.md +2 -15
- package/src/skf-brief-skill/references/draft-checkpoint.md +8 -8
- package/src/skf-brief-skill/references/gather-intent.md +27 -24
- package/src/skf-brief-skill/references/headless-args.md +1 -1
- package/src/skf-brief-skill/references/health-check.md +1 -22
- package/src/skf-brief-skill/references/invocation-contract.md +37 -0
- package/src/skf-brief-skill/references/scope-definition.md +6 -15
- package/src/skf-brief-skill/references/step-auto-brief.md +22 -9
- package/src/skf-brief-skill/references/step-auto-validate.md +3 -7
- package/src/skf-brief-skill/references/version-resolution.md +1 -1
- package/src/skf-brief-skill/references/write-brief.md +19 -13
- package/src/skf-campaign/SKILL.md +121 -0
- package/src/skf-campaign/assets/campaign-state-schema.json +191 -0
- package/src/skf-campaign/customize.toml +75 -0
- package/src/skf-campaign/manifest.yaml +15 -0
- package/src/skf-campaign/references/campaign-contracts.md +67 -0
- package/src/skf-campaign/references/campaign-directive-spec.md +32 -0
- package/src/skf-campaign/references/health-check.md +35 -0
- package/src/skf-campaign/references/step-01-setup.md +121 -0
- package/src/skf-campaign/references/step-02-strategy.md +102 -0
- package/src/skf-campaign/references/step-03-pins.md +56 -0
- package/src/skf-campaign/references/step-04-provenance.md +63 -0
- package/src/skf-campaign/references/step-05-skill-loop.md +103 -0
- package/src/skf-campaign/references/step-06-batch.md +88 -0
- package/src/skf-campaign/references/step-07-capstone.md +63 -0
- package/src/skf-campaign/references/step-08-verify.md +75 -0
- package/src/skf-campaign/references/step-09-refine.md +83 -0
- package/src/skf-campaign/references/step-10-export.md +106 -0
- package/src/skf-campaign/references/step-11-maintenance.md +84 -0
- package/src/skf-campaign/references/step-resume.md +115 -0
- package/src/skf-campaign/scripts/.gitkeep +0 -0
- package/src/skf-campaign/scripts/campaign-deps.py +244 -0
- package/src/skf-campaign/scripts/campaign-parse-manifest.py +119 -0
- package/src/skf-campaign/scripts/campaign-provenance.py +247 -0
- package/src/skf-campaign/scripts/campaign-render-batch.py +199 -0
- package/src/skf-campaign/scripts/campaign-render-kickoff.py +158 -0
- package/src/skf-campaign/scripts/campaign-report.py +249 -0
- package/src/skf-campaign/scripts/campaign-status.py +162 -0
- package/src/skf-campaign/scripts/campaign-validate-pins.py +174 -0
- package/src/skf-campaign/scripts/campaign-validate-state.py +207 -0
- package/src/skf-campaign/templates/campaign-brief-template.yaml +34 -0
- package/src/skf-campaign/templates/campaign-report-template.md +54 -0
- package/src/skf-campaign/templates/kickoff-template.md +48 -0
- package/src/skf-create-skill/SKILL.md +15 -4
- package/src/skf-create-skill/assets/compile-assembly-rules.md +35 -34
- package/src/skf-create-skill/assets/skill-sections.md +9 -100
- package/src/skf-create-skill/assets/tessl-dismissal-rules.md +4 -13
- package/src/skf-create-skill/customize.toml +13 -0
- package/src/skf-create-skill/references/authoritative-files-protocol.md +7 -7
- package/src/skf-create-skill/references/compile.md +37 -47
- package/src/skf-create-skill/references/component-extraction.md +8 -35
- package/src/skf-create-skill/references/ecosystem-check.md +9 -25
- package/src/skf-create-skill/references/enrich.md +4 -17
- package/src/skf-create-skill/references/extract.md +20 -27
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +1 -1
- package/src/skf-create-skill/references/extraction-patterns.md +10 -8
- package/src/skf-create-skill/references/generate-artifacts.md +20 -25
- package/src/skf-create-skill/references/health-check.md +2 -2
- package/src/skf-create-skill/references/load-brief.md +16 -18
- package/src/skf-create-skill/references/report.md +27 -14
- package/src/skf-create-skill/references/source-resolution-protocols.md +4 -4
- package/src/skf-create-skill/references/step-auto-shard.md +52 -25
- package/src/skf-create-skill/references/step-doc-rot.md +33 -15
- package/src/skf-create-skill/references/step-doc-sources.md +13 -4
- package/src/skf-create-skill/references/sub/ccc-discover.md +2 -13
- package/src/skf-create-skill/references/sub/fetch-docs.md +33 -46
- package/src/skf-create-skill/references/sub/fetch-temporal.md +5 -20
- package/src/skf-create-skill/references/tier-degradation-rules.md +6 -8
- package/src/skf-create-skill/references/validate.md +69 -29
- package/src/skf-create-skill/scripts/scan-doc-rot.py +245 -0
- package/src/skf-create-stack-skill/SKILL.md +15 -9
- package/src/skf-create-stack-skill/assets/provenance-map-schema.md +1 -1
- package/src/skf-create-stack-skill/customize.toml +10 -0
- package/src/skf-create-stack-skill/references/compile-stack.md +7 -8
- package/src/skf-create-stack-skill/references/compose-mode-rules.md +2 -13
- package/src/skf-create-stack-skill/references/detect-integrations.md +49 -54
- package/src/skf-create-stack-skill/references/detect-manifests.md +37 -30
- package/src/skf-create-stack-skill/references/generate-output.md +24 -75
- package/src/skf-create-stack-skill/references/init.md +9 -81
- package/src/skf-create-stack-skill/references/manifest-patterns.md +5 -35
- package/src/skf-create-stack-skill/references/parallel-extract.md +12 -27
- package/src/skf-create-stack-skill/references/rank-and-confirm.md +6 -6
- package/src/skf-create-stack-skill/references/report.md +27 -62
- package/src/skf-create-stack-skill/references/validate.md +35 -31
- package/src/skf-drop-skill/SKILL.md +20 -23
- package/src/skf-drop-skill/customize.toml +10 -0
- package/src/skf-drop-skill/references/execute.md +67 -36
- package/src/skf-drop-skill/references/headless-contract.md +18 -0
- package/src/skf-drop-skill/references/health-check.md +1 -13
- package/src/skf-drop-skill/references/report.md +44 -10
- package/src/skf-drop-skill/references/select.md +93 -48
- package/src/skf-drop-skill/scripts/dir-sizes.py +116 -0
- package/src/skf-export-skill/SKILL.md +17 -14
- package/src/skf-export-skill/assets/managed-section-format.md +2 -5
- package/src/skf-export-skill/customize.toml +10 -6
- package/src/skf-export-skill/references/generate-snippet.md +21 -35
- package/src/skf-export-skill/references/load-skill.md +44 -42
- package/src/skf-export-skill/references/multi-skill-mode.md +1 -1
- package/src/skf-export-skill/references/orphan-context-detection.md +11 -3
- package/src/skf-export-skill/references/package.md +27 -33
- package/src/skf-export-skill/references/preflight-snippet-root-probe.md +24 -5
- package/src/skf-export-skill/references/result-envelope.md +28 -0
- package/src/skf-export-skill/references/summary.md +11 -5
- package/src/skf-export-skill/references/token-report.md +42 -24
- package/src/skf-export-skill/references/update-context.md +32 -33
- package/src/skf-forger/SKILL.md +32 -39
- package/src/skf-forger/references/pipeline-mode.md +34 -0
- package/src/skf-forger/scripts/parse-pipeline.py +270 -0
- package/src/skf-quick-skill/SKILL.md +10 -60
- package/src/skf-quick-skill/customize.toml +9 -0
- package/src/skf-quick-skill/references/batch-mode.md +6 -4
- package/src/skf-quick-skill/references/compile.md +15 -52
- package/src/skf-quick-skill/references/ecosystem-check.md +5 -20
- package/src/skf-quick-skill/references/finalize.md +12 -6
- package/src/skf-quick-skill/references/halt-contract.md +54 -0
- package/src/skf-quick-skill/references/health-check.md +3 -4
- package/src/skf-quick-skill/references/quick-extract.md +7 -18
- package/src/skf-quick-skill/references/registry-resolution.md +1 -23
- package/src/skf-quick-skill/references/resolve-target.md +27 -34
- package/src/skf-quick-skill/references/write-and-validate.md +10 -25
- package/src/skf-refine-architecture/SKILL.md +16 -8
- package/src/skf-refine-architecture/customize.toml +9 -0
- package/src/skf-refine-architecture/references/compile.md +10 -8
- package/src/skf-refine-architecture/references/gap-analysis.md +21 -50
- package/src/skf-refine-architecture/references/health-check.md +1 -1
- package/src/skf-refine-architecture/references/improvements.md +9 -25
- package/src/skf-refine-architecture/references/init.md +9 -16
- package/src/skf-refine-architecture/references/issue-detection.md +10 -25
- package/src/skf-refine-architecture/references/refinement-rules.md +4 -16
- package/src/skf-refine-architecture/references/report.md +14 -11
- package/src/skf-rename-skill/SKILL.md +11 -21
- package/src/skf-rename-skill/customize.toml +10 -0
- package/src/skf-rename-skill/references/execute.md +112 -82
- package/src/skf-rename-skill/references/exit-codes.md +12 -0
- package/src/skf-rename-skill/references/report.md +16 -8
- package/src/skf-rename-skill/references/select.md +69 -42
- package/src/skf-rename-skill/scripts/skf-validate-rename-name.py +161 -0
- package/src/skf-setup/SKILL.md +21 -13
- package/src/skf-setup/customize.toml +10 -0
- package/src/skf-setup/references/auto-index.md +11 -10
- package/src/skf-setup/references/ccc-index.md +14 -15
- package/src/skf-setup/references/detect-and-tier.md +10 -8
- package/src/skf-setup/references/report.md +26 -32
- package/src/skf-setup/references/tier-rules.md +2 -32
- package/src/skf-setup/references/write-config.md +9 -10
- package/src/skf-test-skill/SKILL.md +10 -8
- package/src/skf-test-skill/customize.toml +2 -0
- package/src/skf-test-skill/references/coherence-check.md +19 -31
- package/src/skf-test-skill/references/coverage-check.md +111 -67
- package/src/skf-test-skill/references/detect-mode.md +10 -41
- package/src/skf-test-skill/references/external-validators.md +11 -19
- package/src/skf-test-skill/references/init.md +39 -21
- package/src/skf-test-skill/references/migration-section-rules.md +4 -4
- package/src/skf-test-skill/references/report.md +60 -40
- package/src/skf-test-skill/references/score.md +32 -64
- package/src/skf-test-skill/references/scoring-rules.md +6 -62
- package/src/skf-test-skill/references/source-access-protocol.md +15 -5
- package/src/skf-test-skill/references/step-hard-gate.md +1 -3
- package/src/skf-test-skill/scripts/aggregate-coherence.py +276 -0
- package/src/skf-test-skill/scripts/check-metadata-coherence.py +359 -0
- package/src/skf-test-skill/scripts/combine-external-scores.py +190 -0
- package/src/skf-test-skill/scripts/compute-score.py +135 -4
- package/src/skf-test-skill/scripts/reconcile-coverage.py +327 -0
- package/src/skf-test-skill/scripts/validate-inventory.py +251 -0
- package/src/skf-test-skill/scripts/verify-declared-numerator.py +192 -0
- package/src/skf-update-skill/SKILL.md +17 -5
- package/src/skf-update-skill/customize.toml +11 -6
- package/src/skf-update-skill/references/detect-changes.md +48 -36
- package/src/skf-update-skill/references/health-check.md +5 -11
- package/src/skf-update-skill/references/init.md +40 -32
- package/src/skf-update-skill/references/manual-section-rules.md +1 -2
- package/src/skf-update-skill/references/merge-conflict-rules.md +1 -52
- package/src/skf-update-skill/references/merge.md +13 -57
- package/src/skf-update-skill/references/re-extract.md +27 -25
- package/src/skf-update-skill/references/report.md +14 -7
- package/src/skf-update-skill/references/validate.md +32 -30
- package/src/skf-update-skill/references/write.md +86 -51
- package/src/skf-update-skill/scripts/skf-new-file-diff.py +167 -0
- package/src/skf-verify-stack/SKILL.md +11 -21
- package/src/skf-verify-stack/customize.toml +12 -3
- package/src/skf-verify-stack/references/coverage-patterns.md +1 -29
- package/src/skf-verify-stack/references/coverage.md +21 -10
- package/src/skf-verify-stack/references/exit-codes.md +14 -0
- package/src/skf-verify-stack/references/health-check.md +1 -1
- package/src/skf-verify-stack/references/init.md +20 -25
- package/src/skf-verify-stack/references/integration-verification-rules.md +10 -19
- package/src/skf-verify-stack/references/integrations.md +44 -49
- package/src/skf-verify-stack/references/report.md +28 -34
- package/src/skf-verify-stack/references/requirements.md +3 -3
- package/src/skf-verify-stack/references/synthesize.md +36 -39
- package/src/skf-verify-stack/scripts/skf-coverage-tally.py +196 -0
- package/src/skf-verify-stack/scripts/skf-report-delta.py +256 -0
- package/src/skf-verify-stack/scripts/skf-verdict-rollup.py +258 -0
- package/tools/cli/lib/ui.js +3 -2
- package/docs/deepwiki.md +0 -89
- package/src/skf-rename-skill/references/rebuild-context.md +0 -110
|
@@ -28,7 +28,7 @@ Perform tier-aware extraction on only the changed files identified in step 02, p
|
|
|
28
28
|
- Only extract files in the change manifest — do not touch unchanged files. **Exception (gap-driven mode):** §0a's Targeted Re-Extraction Branch also scans files listed in each manifest entry's `remediation_paths[]` to resolve citation-less Critical/High gaps.
|
|
29
29
|
- For each changed file, launch a subprocess for deep AST analysis (Pattern 2); if unavailable, extract sequentially
|
|
30
30
|
|
|
31
|
-
##
|
|
31
|
+
## Steps
|
|
32
32
|
|
|
33
33
|
### 0. Check for Gap-Driven Mode
|
|
34
34
|
|
|
@@ -45,7 +45,7 @@ uv run {checkWorkspaceDriftHelper} <source-root> \
|
|
|
45
45
|
[--allow-drift]
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
Pass `--allow-drift` only when the user provided `--allow-workspace-drift` to update-skill. The helper accepts `""` and `"local"` as the "no pinned commit" sentinels; it also auto-skips when `source_root` is not a git working tree (bare checkout, tarball extract, etc.).
|
|
48
|
+
Pass `--allow-drift` only when the user provided `--allow-workspace-drift` to update-skill. The helper accepts `""` and `"local"` as the "no pinned commit" sentinels; it also auto-skips when `source_root` is not a git working tree (bare checkout, tarball extract, etc.).
|
|
49
49
|
|
|
50
50
|
The helper emits a result envelope:
|
|
51
51
|
|
|
@@ -63,7 +63,7 @@ The helper emits a result envelope:
|
|
|
63
63
|
|
|
64
64
|
- **`ok` or `skipped`** (helper exit 0): log `log_message` and continue to bullet 1.
|
|
65
65
|
- **`overridden`** (helper exit 0): log `log_message`, surface a visible warning in the final report ("**Workspace drift accepted via --allow-workspace-drift** — spot-checks read HEAD {head_short_sha}, not pinned {pinned_commit}"), and continue to bullet 1. The override does not automatically re-pin `metadata.source_commit`; re-pinning is explicit user work (run the normal-mode update-skill flow against the same HEAD, or re-create the skill).
|
|
66
|
-
- **`mismatch`** (helper exit 2): HALT immediately with
|
|
66
|
+
- **`mismatch`** (helper exit 2): HALT immediately with status `halted-for-workspace-drift`. Display the helper's `halt_message` verbatim — it already substitutes `{pinned_commit}`, `{source_ref or "unset"}`, `{source_root}`, `{head_sha}`, and the suggested `git checkout` command. Do not proceed to bullet 1. Step-04 merge has not run; no partial writes. In `{headless_mode}`, emit the halt envelope per SKILL.md §Headless (`error: {phase: "re-extract:workspace-drift", path: "{source_root}", reason: "..."}`).
|
|
67
67
|
|
|
68
68
|
1. Use the provenance map already loaded in step 1 (at `{forge_version}/provenance-map.json`) — do not re-read
|
|
69
69
|
2. **Partition by change category, then iterate the export-bearing entries.** Entries that do not name an export skip the per-export verification below — they have no symbol to resolve against source:
|
|
@@ -173,7 +173,7 @@ The helper emits a result envelope:
|
|
|
173
173
|
c) Downgrade the gap(s) to Medium/Low/Info (accepts the degraded documentation outcome).
|
|
174
174
|
```
|
|
175
175
|
|
|
176
|
-
Exit with status `halted-for-remediation-path`. Step-04 merge has not run; no partial writes.
|
|
176
|
+
Exit with status `halted-for-remediation-path`. Step-04 merge has not run; no partial writes. In `{headless_mode}`, emit the halt envelope per SKILL.md §Headless (`error: {phase: "re-extract:targeted-reextraction", reason: "..."}`).
|
|
177
177
|
|
|
178
178
|
6. **Success summary** — record `targeted_reextraction: {resolved_count, files_scanned, exports_matched, tier}` in workflow context. The evidence report (step 6 §4) surfaces this alongside the verified / moved / missing tally.
|
|
179
179
|
|
|
@@ -223,7 +223,7 @@ The helper emits a result envelope:
|
|
|
223
223
|
|
|
224
224
|
**Forge tier (AST structural extraction):**
|
|
225
225
|
|
|
226
|
-
|
|
226
|
+
Load and follow the **AST Extraction Protocol** from `{extractionPatternsData}`. Use the decision tree based on the number of changed files: prefer MCP `find_code()` for small sets, `find_code_by_rule()` with scoped YAML rules for medium sets, and CLI `--json=stream` with line-by-line streaming for large sets. Never use `ast-grep --json` (without `=stream`) — it loads the entire result set into memory and will fail on large codebases.
|
|
227
227
|
|
|
228
228
|
- Extract: function signatures, type definitions, class members, exported constants
|
|
229
229
|
- Extract: parameter types, return types, JSDoc/docstring comments
|
|
@@ -243,18 +243,26 @@ The helper emits a result envelope:
|
|
|
243
243
|
|
|
244
244
|
**Skip authoritative doc paths.** Before iterating the change manifest, build a skip set from `promoted_docs_new[]` (populated by step 2 §1b) and any existing `file_entries[]` entries with `file_type: "doc"` from the provenance map. These are documentation files tracked for drift detection only — they must not reach AST extraction, which would produce ghost entries on non-code content. If a change manifest entry matches the skip set, skip it silently and continue; doc-type drift is handled by step 2 Category D and step 4 Priority 6/7.
|
|
245
245
|
|
|
246
|
-
|
|
246
|
+
For each remaining file in the change manifest with status MODIFIED, ADDED, or RENAMED, launch a subprocess that:
|
|
247
247
|
|
|
248
248
|
1. Loads the source file
|
|
249
249
|
2. Performs tier-appropriate extraction (Quick/Forge/Forge+/Deep)
|
|
250
|
-
3.
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
250
|
+
3. Extract each export into the per-file return contract shown in bullet 4.
|
|
251
|
+
4. **Return contract.** Each extraction worker returns ONLY this per-file block — no prose, no commentary, no markdown fences (the parent strips wrapping fences before parsing). The shape is exactly the per-file record §4 aggregates (the `Per-file extractions` block, lines below), so the parent appends it verbatim rather than re-parsing free text:
|
|
252
|
+
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"file_path": "...",
|
|
256
|
+
"exports": [
|
|
257
|
+
{"name": "...", "type": "function|class|type|constant",
|
|
258
|
+
"signature": "...", "location": "{file}:{start_line}-{end_line}",
|
|
259
|
+
"confidence": "T1|T1-low|T2",
|
|
260
|
+
"parameters": [{"name": "...", "type": "..."}],
|
|
261
|
+
"return_type": "...", "docstring": "...",
|
|
262
|
+
"qmd_evidence": "<if Deep tier, else omit>"}
|
|
263
|
+
]
|
|
264
|
+
}
|
|
265
|
+
```
|
|
258
266
|
|
|
259
267
|
**For DELETED files:** No extraction needed — deletions handled in merge step.
|
|
260
268
|
|
|
@@ -277,7 +285,7 @@ This helps the merge step (section 4) prioritize which changes are most likely t
|
|
|
277
285
|
|
|
278
286
|
CCC failures: skip ranking silently, all changes treated equally.
|
|
279
287
|
|
|
280
|
-
**Note on remote sources:** If `source_root` is a workspace clone, the CCC index may already exist from a prior forge and can be reused via `ccc search --refresh`. If the source is an ephemeral fallback clone, the clone path is not indexed by CCC — the search
|
|
288
|
+
**Note on remote sources:** If `source_root` is a workspace clone, the CCC index may already exist from a prior forge and can be reused via `ccc search --refresh`. If the source is an ephemeral fallback clone, the clone path is not indexed by CCC — the search returns empty results, so semantic ranking is skipped and all changes are treated equally.
|
|
281
289
|
|
|
282
290
|
**IF `tools.ccc` is false:** Skip this section silently.
|
|
283
291
|
|
|
@@ -342,16 +350,10 @@ Extraction Results:
|
|
|
342
350
|
|
|
343
351
|
**Proceeding to merge with existing skill...**"
|
|
344
352
|
|
|
345
|
-
### 6.
|
|
346
|
-
|
|
347
|
-
- **If `dry_run_mode` is true:** display "**Dry-run mode — skipping merge/validate/write.** Loading report..." and load `report.md` (NOT `{nextStepFile}`). The report emits the dry-run envelope describing what merge+write WOULD have done.
|
|
348
|
-
- Else, display "**Proceeding to merge...**" and after extraction results are compiled, immediately load, read entire file, then execute `{nextStepFile}`.
|
|
349
|
-
- This is an auto-proceed step with no user choices.
|
|
350
|
-
|
|
351
|
-
## CRITICAL STEP COMPLETION NOTE
|
|
353
|
+
### 6. Route to Next Step
|
|
352
354
|
|
|
353
|
-
|
|
355
|
+
This step auto-proceeds — no user choices. Once all changed files are extracted and results compiled, load and fully read the next file, then execute it, per the branch that applies:
|
|
354
356
|
|
|
355
|
-
-
|
|
356
|
-
- Otherwise → load `{nextStepFile}` (merge.md) to begin the merge operation.
|
|
357
|
+
- **`dry_run_mode == true`** → display "**Dry-run mode — skipping merge/validate/write.** Loading report..." and load `report.md` (NOT `{nextStepFile}`); it emits status `dry-run` describing what merge+write would have done. No artifact is modified on disk by this run.
|
|
358
|
+
- **Otherwise** → display "**Proceeding to merge...**" and load `{nextStepFile}` (merge.md) to begin the merge operation.
|
|
357
359
|
|
|
@@ -16,7 +16,7 @@ Present a comprehensive change summary showing what was updated, [MANUAL] sectio
|
|
|
16
16
|
- Present clear, actionable summary with next step recommendations
|
|
17
17
|
- Chains to the local health-check step via `{nextStepFile}` after completion — the user-facing summary is NOT the terminal step
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## Steps
|
|
20
20
|
|
|
21
21
|
### 1. Handle No-Change Shortcut
|
|
22
22
|
|
|
@@ -89,7 +89,7 @@ The headless envelope carries `status: "dry-run"`, `files_written: []`, the `hea
|
|
|
89
89
|
|
|
90
90
|
| Metric | Value |
|
|
91
91
|
|--------|-------|
|
|
92
|
-
| **Skill** | {skill_name}
|
|
92
|
+
| **Skill** | {skill_name} |
|
|
93
93
|
| **Forge Tier** | {tier} |
|
|
94
94
|
| **Mode** | {update_mode}{mode_fallback_note} |
|
|
95
95
|
| **Duration** | {step count} steps |
|
|
@@ -169,7 +169,6 @@ These signals also appear in `warnings[]` on the headless envelope; the Mode row
|
|
|
169
169
|
| `{resolved_skill_package}/metadata.json` | Updated |
|
|
170
170
|
| `{forge_version}/provenance-map.json` | Updated |
|
|
171
171
|
| `{forge_version}/evidence-report.md` | Appended |
|
|
172
|
-
| {stack reference files if applicable} | Updated |
|
|
173
172
|
|
|
174
173
|
Where `{resolved_skill_package}` = `{skills_output_folder}/{skill_name}/{version}/{skill_name}/` and `{forge_version}` = `{forge_data_folder}/{skill_name}/{version}/` — see `knowledge/version-paths.md`."
|
|
175
174
|
|
|
@@ -199,16 +198,24 @@ Write the result contract per `shared/references/output-contract-schema.md`: the
|
|
|
199
198
|
**Headless envelope (`SKF_UPDATE_RESULT_JSON`):** when `{headless_mode}` is true, ALSO emit a single-line JSON envelope to stdout prefixed with the literal `SKF_UPDATE_RESULT_JSON: `. Schema: `src/shared/scripts/schemas/skf-update-result-envelope.v1.json`. Construct the envelope from in-context state:
|
|
200
199
|
|
|
201
200
|
```json
|
|
202
|
-
SKF_UPDATE_RESULT_JSON: {"skf_update":{"status":"success|no-changes|halted-for-*|blocked","skill_name":"<name>","version":"<v>","previous_version":"<v>","update_mode":"normal|gap-driven|degraded","files_written":[...],"headless_decisions":[...],"warnings":[...],"error":null|{...}}}
|
|
201
|
+
SKF_UPDATE_RESULT_JSON: {"skf_update":{"status":"success|no-changes|detect-only|dry-run|halted-for-*|blocked","skill_name":"<name>","version":"<v>","previous_version":"<v>","update_mode":"normal|gap-driven|degraded","files_written":[...],"headless_decisions":[...],"warnings":[...],"error":null|{...}}}
|
|
203
202
|
```
|
|
204
203
|
|
|
205
|
-
- `headless_decisions[]` — verbatim from the in-context array populated by gates (init.md §confirmation, detect-changes.md §1b/§1c/§2.2, merge.md §gate). Each entry `{gate, default_action, taken_action, reason, evidence?}`. Empty when no gates auto-resolved (e.g. no-changes path skipped detect-changes' gates).
|
|
206
|
-
- `status` — single-field outcome for pipeline branching. `"success"` when the run wrote artifacts and produced no halts; `"no-changes"` when §1 short-circuited; one of the documented `halted-for-*` codes when a halt fired; `"blocked"` as the catch-all.
|
|
204
|
+
- `headless_decisions[]` — verbatim from the in-context array populated by gates (init.md §confirmation and §4 degraded-rebuild, detect-changes.md §1b/§1c/§2.2, merge.md §gate). Each entry `{gate, default_action, taken_action, reason, evidence?}`. Empty when no gates auto-resolved (e.g. no-changes path skipped detect-changes' gates).
|
|
205
|
+
- `status` — single-field outcome for pipeline branching. `"success"` when the run wrote artifacts and produced no halts; `"no-changes"` when §1 short-circuited; `"detect-only"` / `"dry-run"` for the §1a/§1b read-only exits; one of the documented `halted-for-*` codes when a halt fired; `"blocked"` as the catch-all. The full enum lives in the schema (this step emits the value already resolved in context).
|
|
207
206
|
- `error` — null on success or no-changes. Object `{phase, path?, reason}` describing the failure when a halt or write error fired. Pipelines branch on `error !== null` for non-zero exit semantics.
|
|
208
207
|
|
|
209
208
|
The headless envelope is the structured channel; the per-run JSON written above is the audit trail. Both coexist — the envelope is one line on stdout for grep-friendly consumption, the per-run JSON is the full record on disk.
|
|
210
209
|
|
|
210
|
+
**Post-finalization hook.** If `{onCompleteCommand}` (resolved in SKILL.md On Activation §3 from `workflow.on_complete`) is non-empty, invoke it after both result-JSON writes complete:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
{onCompleteCommand} --result-path={forge_version}/update-skill-result-latest.json
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Run it with a bounded timeout (default 60s). On success, log an Info note and continue; on non-zero exit, timeout, or any failure, append the reason to `warnings[]` (surfaced on the headless envelope) and continue. The hook must never fail the workflow — it is integration glue (notify a CI router, chain audit/export/test) orthogonal to the update outcome. Empty `{onCompleteCommand}` = no-op, no log entry.
|
|
217
|
+
|
|
211
218
|
### 6. Chain to Health Check
|
|
212
219
|
|
|
213
|
-
|
|
220
|
+
Once the change summary has been presented, the files-written list displayed, and the result contract saved, load, read the full file, and execute `{nextStepFile}`. The health-check step is the true terminal step — do not stop at the report even though it reads as final.
|
|
214
221
|
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'write.md'
|
|
3
|
+
# Resolve `{hashContentHelper}` to the first existing path; HALT if neither
|
|
4
|
+
# candidate exists. Check B uses its `manual-verify` subcommand to verify the
|
|
5
|
+
# merged (on-disk) SKILL.md against the byte-exact [MANUAL] inventory captured
|
|
6
|
+
# in step 1 §5 — the deterministic replacement for the LLM byte-identity
|
|
7
|
+
# eyeball, which could silently pass a subtly truncated block.
|
|
8
|
+
hashContentProbeOrder:
|
|
9
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-hash-content.py'
|
|
10
|
+
- '{project-root}/src/shared/scripts/skf-hash-content.py'
|
|
3
11
|
---
|
|
4
12
|
|
|
5
13
|
<!-- Config: communicate in {communication_language}. -->
|
|
@@ -14,9 +22,9 @@ Validate the merged skill content against the agentskills.io specification, veri
|
|
|
14
22
|
|
|
15
23
|
- Focus only on validation — do not fix issues (that's the user's choice)
|
|
16
24
|
- Validation is read-only — do not modify merged content
|
|
17
|
-
-
|
|
25
|
+
- Run the two live structural checks (B, then C) in order; Checks A, D, E, F are deferred to step 6
|
|
18
26
|
|
|
19
|
-
##
|
|
27
|
+
## Steps
|
|
20
28
|
|
|
21
29
|
### 1. Check Tool Availability and Validation Timing
|
|
22
30
|
|
|
@@ -27,30 +35,40 @@ Run: `npx skill-check -h`
|
|
|
27
35
|
|
|
28
36
|
**Important:** Do not assume availability — empirical check required.
|
|
29
37
|
|
|
30
|
-
**Validation timing note:** Step-04 section 6b has already written SKILL.md
|
|
38
|
+
**Validation timing note:** Step-04 section 6b has already written SKILL.md to disk. External-tool checks against written files (skill-check Checks A, E, F) still run in **step 6 section 7** to co-locate external-tool validation with post-write verification. Check D (Provenance Completeness) is deterministic but needs both `metadata.json` and `provenance-map.json` on disk — neither exists yet at this step — so it is deferred to **step 6 section 6a**, which runs it via the completeness helper against the freshly-written artifacts. Structural checks (B, C) run here against the merged content — content on disk is byte-identical to the in-context copy.
|
|
31
39
|
|
|
32
|
-
### 2.
|
|
40
|
+
### 2. Run Validation Checks
|
|
33
41
|
|
|
34
|
-
|
|
42
|
+
Per the §1 timing note, only Check B (a single deterministic `manual-verify` script) and Check C (an in-prompt tier-label consistency check) run live at this step; Checks A, D, E, F are deferred to step 6. Run B then C in order — one script plus one in-prompt comparison have nothing to fan out.
|
|
35
43
|
|
|
36
44
|
**Check A — Spec Compliance (deferred to post-write):**
|
|
37
45
|
|
|
38
46
|
Skill-check requires written files on disk. This check is deferred to step 6 section 7. Perform manual structural check only: verify merged SKILL.md has required sections (exports, usage patterns, conventions), verify export entries have name/type/signature/file:line reference, flag missing sections.
|
|
39
47
|
|
|
40
48
|
**Check B — [MANUAL] Section Integrity:**
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
|
|
50
|
+
Run the deterministic [MANUAL]-integrity verifier against the step-1 §5 inventory — do not eyeball byte-identity (a subtly truncated block reads as intact to the eye):
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv run {hashContentHelper} manual-verify {skill_package}/SKILL.md \
|
|
54
|
+
--inventory {manual_inventory}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Read the verdict JSON `{"preserved":[...], "modified":[...], "missing":[...], "moved":[...], "ok":bool}` (the on-disk SKILL.md is byte-identical to the merged in-context copy per the timing note above):
|
|
58
|
+
- `ok == true` → status PASS. `preserved` blocks are byte-identical in place; any `moved` blocks are byte-identical but relocated with their logical parent section (report as informational, not a finding).
|
|
59
|
+
- `modified` non-empty → FAIL: these blocks' byte-exact interiors changed (the truncation a marker-count/eyeball check would miss). List each by name.
|
|
60
|
+
- `missing` non-empty → FAIL: these blocks lost their markers entirely. List each by name.
|
|
61
|
+
|
|
62
|
+
Populate the §3 `manual_integrity` record from this verdict (`sections_verified` = inventory count, `sections_intact` = `len(preserved) + len(moved)`). This check is advisory here (findings inform, do not block); write.md §1 enforces the same `ok` verdict as a HALT gate before any derived artifact is written.
|
|
44
63
|
|
|
45
64
|
**Check C — Confidence Tier Consistency:**
|
|
46
65
|
- Verify all re-extracted exports have confidence labels (T1/T1-low/T2)
|
|
47
66
|
- Verify tier labels match forge tier: Quick=T1-low only, Forge=T1 (T1-low for degraded), Forge+=T1 (same as Forge, CCC improves coverage not confidence), Deep=T1+T2
|
|
48
67
|
- Flag mismatched or missing tier labels
|
|
49
68
|
|
|
50
|
-
**Check D — Provenance Completeness:**
|
|
51
|
-
|
|
52
|
-
-
|
|
53
|
-
- Flag orphaned provenance entries (export removed but provenance remains)
|
|
69
|
+
**Check D — Provenance Completeness (deferred to post-write):**
|
|
70
|
+
|
|
71
|
+
The provenance map does not exist on disk until step 6 §3 writes it, and completeness is a deterministic set-diff (metadata `exports[]` vs provenance `entries[].export_name`) plus file:line citation resolution — not something to eyeball. This check is deferred to **step 6 section 6a**, which runs `skf-verify-provenance-completeness.py` against the just-written `metadata.json` and `provenance-map.json` and reads back `missing[]` / `orphaned[]` / `stale[]` findings. Do not attempt the set comparison here — there is no provenance map to compare against yet. The `Provenance` row in §5's summary is populated from §6a's result.
|
|
54
72
|
|
|
55
73
|
**Check E — Diff Comparison (via skill-check):**
|
|
56
74
|
|
|
@@ -83,16 +101,6 @@ Validation Results:
|
|
|
83
101
|
quality_score: [0-100] # from skill-check, if available
|
|
84
102
|
```
|
|
85
103
|
|
|
86
|
-
### 4. For Stack Skills — Validate Reference Files
|
|
87
|
-
|
|
88
|
-
**ONLY if skill_type == "stack":**
|
|
89
|
-
|
|
90
|
-
Repeat checks A-D for each reference file:
|
|
91
|
-
- `references/{library}.md` — spec compliance and [MANUAL] integrity
|
|
92
|
-
- `references/integrations/{pair}.md` — spec compliance and [MANUAL] integrity
|
|
93
|
-
|
|
94
|
-
**If skill_type != "stack":** Skip with notice.
|
|
95
|
-
|
|
96
104
|
### 5. Display Validation Summary
|
|
97
105
|
|
|
98
106
|
"**Validation Results:**
|
|
@@ -110,13 +118,7 @@ Repeat checks A-D for each reference file:
|
|
|
110
118
|
|
|
111
119
|
**If findings exist:** List each with severity, description, and location. Add: "Validation is advisory. Findings do not block the update."
|
|
112
120
|
|
|
113
|
-
### 6.
|
|
114
|
-
|
|
115
|
-
Display: "**Proceeding to write updated files...**"
|
|
116
|
-
|
|
117
|
-
After validation summary is displayed, immediately load, read entire file, then execute {nextStepFile}. This is an auto-proceed step — validation is advisory, not blocking.
|
|
118
|
-
|
|
119
|
-
## CRITICAL STEP COMPLETION NOTE
|
|
121
|
+
### 6. Route to Next Step
|
|
120
122
|
|
|
121
|
-
|
|
123
|
+
This step auto-proceeds — no user choices; validation is advisory and does not block, it only informs. Once all validation checks have completed and findings are displayed, display "**Proceeding to write updated files...**", then load, fully read, and execute `{nextStepFile}` to write the updated files.
|
|
122
124
|
|
|
@@ -17,6 +17,31 @@ descriptionGuardProbeOrder:
|
|
|
17
17
|
updateActiveSymlinkProbeOrder:
|
|
18
18
|
- '{project-root}/_bmad/skf/shared/scripts/skf-update-active-symlink.py'
|
|
19
19
|
- '{project-root}/src/shared/scripts/skf-update-active-symlink.py'
|
|
20
|
+
# Resolve `{verifyProvenanceCompletenessHelper}` to the first existing path.
|
|
21
|
+
# §6a runs Check D (Provenance Completeness), deferred from step 5 because it
|
|
22
|
+
# needs both metadata.json + provenance-map.json on disk: the export/provenance
|
|
23
|
+
# set-diff (missing + orphaned entries) and file:line citation resolution.
|
|
24
|
+
# Advisory — do not HALT if neither path resolves; fall back to the in-prose
|
|
25
|
+
# set comparison §6a documents (graceful degradation).
|
|
26
|
+
verifyProvenanceCompletenessProbeOrder:
|
|
27
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-verify-provenance-completeness.py'
|
|
28
|
+
- '{project-root}/src/shared/scripts/skf-verify-provenance-completeness.py'
|
|
29
|
+
# Resolve `{hashContentHelper}` to the first existing path; HALT if neither
|
|
30
|
+
# candidate exists. §1 uses its `manual-verify` subcommand to verify the
|
|
31
|
+
# post-merge file against the byte-exact [MANUAL] inventory captured in step 1
|
|
32
|
+
# §5; a marker-count comparison would pass a block whose interior was truncated
|
|
33
|
+
# without changing the marker count.
|
|
34
|
+
hashContentProbeOrder:
|
|
35
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-hash-content.py'
|
|
36
|
+
- '{project-root}/src/shared/scripts/skf-hash-content.py'
|
|
37
|
+
# Resolve `{renderMetadataStatsHelper}` by probing `{renderMetadataStatsProbeOrder}`
|
|
38
|
+
# in order (installed SKF module path first, src/ dev-checkout fallback); first
|
|
39
|
+
# existing path wins. HALT if neither resolves — §2's `stats` block and
|
|
40
|
+
# `confidence_distribution` are computed values that must not be hand-binned,
|
|
41
|
+
# and this is the same helper sibling create-skill compiles them with.
|
|
42
|
+
renderMetadataStatsProbeOrder:
|
|
43
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-render-metadata-stats.py'
|
|
44
|
+
- '{project-root}/src/shared/scripts/skf-render-metadata-stats.py'
|
|
20
45
|
---
|
|
21
46
|
|
|
22
47
|
<!-- Config: communicate in {communication_language}. -->
|
|
@@ -25,7 +50,7 @@ updateActiveSymlinkProbeOrder:
|
|
|
25
50
|
|
|
26
51
|
## STEP GOAL:
|
|
27
52
|
|
|
28
|
-
Verify the merged SKILL.md
|
|
53
|
+
Verify the merged SKILL.md that step 4 section 6b wrote to disk, then write the derived artifacts (metadata.json, provenance-map.json, evidence-report.md, context-snippet.md, and the active symlink).
|
|
29
54
|
|
|
30
55
|
## Rules
|
|
31
56
|
|
|
@@ -34,7 +59,7 @@ Verify the merged SKILL.md and stack reference files that step 4 section 6b wrot
|
|
|
34
59
|
- Do not skip provenance map update — critical for future audits
|
|
35
60
|
- HALT immediately on verification failure before writing any derived artifact — a partial-write skill package is worse than an unchanged one
|
|
36
61
|
|
|
37
|
-
##
|
|
62
|
+
## Steps
|
|
38
63
|
|
|
39
64
|
### 0. Description Guard Protocol
|
|
40
65
|
|
|
@@ -48,13 +73,19 @@ Update-skill does not run the optional post-restore frontmatter re-validation to
|
|
|
48
73
|
|
|
49
74
|
SKILL.md was written in step 4 section 6b. Verify the write landed intact before proceeding to any derived-artifact writes.
|
|
50
75
|
|
|
51
|
-
- Read `{skill_package}/SKILL.md` from disk
|
|
52
|
-
- Count `<!-- [MANUAL:*] -->` opening markers and compare against the [MANUAL] inventory captured in step 1
|
|
53
76
|
- Verify the resolved `{skill_package}` path matches the version directory step 4 wrote to (if the version changed, step 4 updated `{skill_package}` in context to point at the new path)
|
|
54
|
-
-
|
|
55
|
-
- **If [MANUAL] count does not match: HALT immediately.** Do not write `metadata.json`, `provenance-map.json`, or any other artifact — further writes would compound the inconsistency. Alert the user:
|
|
77
|
+
- Run the deterministic [MANUAL]-integrity verifier against the byte-exact inventory captured in step 1 §5:
|
|
56
78
|
|
|
57
|
-
|
|
79
|
+
```bash
|
|
80
|
+
uv run {hashContentHelper} manual-verify {skill_package}/SKILL.md \
|
|
81
|
+
--inventory {manual_inventory}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The verdict JSON is `{"preserved":[...], "modified":[...], "missing":[...], "moved":[...], "ok":bool}`. A `modified` block is one whose byte-exact interior changed (an interior truncation); a `missing` block lost its markers entirely; a `moved` block is byte-identical but relocated with its logical parent section (clean — does not fail the gate). `ok == (modified empty AND missing empty)`.
|
|
85
|
+
- If `ok == true` and the path resolves: proceed to section 2
|
|
86
|
+
- **If `ok == false`: HALT immediately** with status `halted-for-manual-mismatch`. Do not write `metadata.json`, `provenance-map.json`, or any other artifact — further writes would compound the inconsistency. In `{headless_mode}`, emit the halt envelope per SKILL.md §Headless (`error: {phase: "write:verify-manual-integrity", path: "{skill_package}/SKILL.md", reason: "..."}`). Alert the user:
|
|
87
|
+
|
|
88
|
+
"**[MANUAL] section integrity failure after write.** Blocks modified (interior changed): {modified}. Blocks missing (markers lost): {missing}. Relocated-but-intact (advisory only): {moved}. Verified against the step-1 inventory `{manual_inventory}`, on disk at `{skill_package}/SKILL.md`. The skill package is in an inconsistent state. Manual recovery required — restore the previous version from `{skill_group}/{previous_version}/` or fix the file in place, then re-run update-skill."
|
|
58
89
|
|
|
59
90
|
### 2. Write Updated metadata.json
|
|
60
91
|
|
|
@@ -64,22 +95,28 @@ Update `{skill_package}/metadata.json`:
|
|
|
64
95
|
- Update `version`: **if `update_mode == "gap-driven"`, do not bump — the skill is being repaired against the same source commit, so leave `version` unchanged and update only `generation_date` / `last_update` below.** This keeps metadata `version` consistent with the on-disk `{skill_package}` path, which step 4 §6b also leaves unchanged in gap-driven mode (see step 4 §6b's "If the source version detected during step 3 differs..." carve-out — in gap-driven mode no source version is detected, so step 4 writes into the existing version directory). Otherwise, if a source version was detected during re-extraction and differs from the current metadata version, use the source version; otherwise increment patch version
|
|
65
96
|
- Update `generation_date` timestamp to current ISO-8601 date
|
|
66
97
|
- Update `exports` array to reflect current export list
|
|
67
|
-
-
|
|
68
|
-
|
|
98
|
+
- **Compute the `stats` block and `confidence_distribution` deterministically** with `{renderMetadataStatsHelper}` (resolve from `{renderMetadataStatsProbeOrder}`; first existing path wins) — the same helper sibling create-skill compiles them with, so create and update emit byte-identical stats for identical inputs. The helper owns all the arithmetic: it bins each provenance `entries[]` row once by its `signature_source` tier into `confidence_distribution.{t1,t1_low,t2,t3}`, sets `exports_documented` = the entry count, and derives `exports_total` = `exports_public_api` + `exports_internal`, `public_api_coverage` = documented / public_api (`null` if public_api is 0), `total_coverage` = documented / total (`null` if total is 0), plus `scripts_count` / `assets_count` from the inventory arrays. Run `uv run {renderMetadataStatsHelper} --help` for the full contract. Do not hand-bin the distribution — binning T2 annotations + T3 doc items on top of the per-export tiers double-counts, which per-entry binning by `signature_source` makes structurally impossible. You supply only the judgment payload:
|
|
99
|
+
|
|
100
|
+
**Judgment payload (what you decide — passed as JSON on stdin):**
|
|
69
101
|
- `exports_public_api`: count of exports from public entry points (`__init__.py`, `index.ts`, `lib.rs`, or equivalent)
|
|
70
102
|
- `exports_internal`: count of all other non-underscore-prefixed exports
|
|
71
|
-
- `
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
103
|
+
- `scripts` / `assets`: the scripts / assets inventory arrays (or `[]` when empty) — the helper sets `scripts_count` / `assets_count` from their lengths
|
|
104
|
+
|
|
105
|
+
**Invoke** — since the helper reads `entries[]`, stage §3's `provenance-map.json` write first (§3 does not depend on these stats):
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
echo '{"exports_public_api": {N}, "exports_internal": {M}, "scripts": {scripts-inventory-or-[]}, "assets": {assets-inventory-or-[]}}' \
|
|
109
|
+
| uv run {renderMetadataStatsHelper} {forge_version}/provenance-map.json
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Write the returned `stats` and `confidence_distribution` objects into `metadata.json` **verbatim**. If the helper reports `coherence.ok: false`, some provenance entries carry a missing/unrecognized `signature_source` (§3 must write it on every entry) — fix the provenance map, do not hand-edit the stats.
|
|
78
113
|
|
|
79
114
|
### 3. Write Updated provenance-map.json
|
|
80
115
|
|
|
81
116
|
Write to `{forge_version}/provenance-map.json`:
|
|
82
117
|
|
|
118
|
+
**Every entry this step writes or rewrites carries a `signature_source` (`T1` / `T1-low` / `T2` / `T3`)** — the tier that contributed the structural signature, matching create-skill's entry contract. §2's stats helper bins each entry on this field, so a missing value trips its `coherence.ok: false` check. Preserve it byte-identical on untouched entries; set it from the contributing extraction tier on every re-extracted or new entry.
|
|
119
|
+
|
|
83
120
|
**If `no_reextraction == true` (gap-driven mode from step 3 section 0):**
|
|
84
121
|
Dispatch per-entry on the verification outcome recorded by step 3 — gap-driven runs produce a mix of `verified`, `moved`, `re-extracted`, and `unknown` outcomes, and each requires a different provenance-map write strategy:
|
|
85
122
|
|
|
@@ -122,6 +159,8 @@ Dispatch per-entry on the verification outcome recorded by step 3 — gap-driven
|
|
|
122
159
|
}
|
|
123
160
|
```
|
|
124
161
|
|
|
162
|
+
`manual_sections_preserved` = `len(preserved) + len(moved)` from the §1 `manual-verify` verdict (blocks that survived byte-identical, whether in place or relocated). Do not re-count markers by hand — the §1 verdict is the deterministic source.
|
|
163
|
+
|
|
125
164
|
### 4. Write Updated evidence-report.md
|
|
126
165
|
|
|
127
166
|
Append update operation section to `{forge_version}/evidence-report.md` (create the file with a standard header if it does not yet exist):
|
|
@@ -168,18 +207,9 @@ Append update operation section to `{forge_version}/evidence-report.md` (create
|
|
|
168
207
|
|
|
169
208
|
**Context Snippet population** (used by §5 after the staleness check runs): §4 writes the sub-block with placeholders; §5 updates the on-disk evidence report in place after deciding whether to regenerate. Set `Regenerated: true` and populate `Triggers fired` with any combination of `headline-exports`, `version`, `gotchas` when at least one trigger fired. Set `Regenerated: false` and `Triggers fired: —` when none fired (the gap-driven / internals-only outcome). Always fill `Notes` with a one-sentence reason (e.g., `"Gap-driven repair — no snippet surface changed"`, `"Version bumped 0.1.0 → 0.2.0; headline exports re-ranked"`).
|
|
170
209
|
|
|
171
|
-
### 5.
|
|
210
|
+
### 5. Regenerate context-snippet.md
|
|
172
211
|
|
|
173
|
-
**
|
|
174
|
-
|
|
175
|
-
Stack reference files were written in step 4 section 6b. Verify each affected reference file that the merge produced:
|
|
176
|
-
|
|
177
|
-
- Read each `references/{library}.md` back from disk
|
|
178
|
-
- Read each `references/integrations/{pair}.md` back from disk
|
|
179
|
-
- Verify per-file [MANUAL] section counts match the per-file inventory captured in step 1
|
|
180
|
-
- **If any verification fails: HALT** using the same recovery protocol as section 1 — do not regenerate `context-snippet.md` or write any further derived artifact
|
|
181
|
-
|
|
182
|
-
**For all skills (both single and stack) — regenerate `context-snippet.md` if stale:**
|
|
212
|
+
**Regenerate `context-snippet.md` if stale:**
|
|
183
213
|
|
|
184
214
|
`context-snippet.md` is a `{skill_package}` deliverable that goes stale whenever **headline exports**, **version**, or **gotchas** change in this run. Regenerate it only when at least one of these triggers fired; otherwise skip — a skip is the correct outcome for gap-driven repairs and other runs that touch internals below the snippet's surface, where regenerating would produce byte-identical content.
|
|
185
215
|
|
|
@@ -193,10 +223,7 @@ Stack reference files were written in step 4 section 6b. Verify each affected re
|
|
|
193
223
|
|
|
194
224
|
**If no trigger fired:** skip regeneration — do not touch `context-snippet.md` on disk. The snippet remains valid against the prior run's surface. Continue to §5b.
|
|
195
225
|
|
|
196
|
-
**If at least one trigger fired:** regenerate the snippet using the format from
|
|
197
|
-
|
|
198
|
-
- For single skills: `skf-create-skill/assets/skill-sections.md` (pipe-delimited indexed format)
|
|
199
|
-
- For stack skills: `skf-create-stack-skill/assets/stack-skill-template.md`
|
|
226
|
+
**If at least one trigger fired:** regenerate the snippet using the format from `skf-create-skill/assets/skill-sections.md` (pipe-delimited indexed format).
|
|
200
227
|
|
|
201
228
|
Use the **flat draft form** for the `root:` path in the draft snippet: `root: skills/{skill-name}/`. The per-IDE skill root (e.g., `.claude/skills/`, `.windsurf/skills/`, `.github/skills/` — see `skf-export-skill/assets/managed-section-format.md`) is applied later by `export-skill` step 3 when the skill is exported. Do not choose an IDE-specific prefix in update-skill — that is an export-time decision that depends on config.yaml.
|
|
202
229
|
|
|
@@ -204,8 +231,6 @@ Pull values for the regenerated snippet from the updated metadata.json (version,
|
|
|
204
231
|
|
|
205
232
|
Write the regenerated snippet to `{skill_package}/context-snippet.md`, preserving file permissions.
|
|
206
233
|
|
|
207
|
-
**If skill_type == "stack"**, also verify that the reference file updates from the first half of this section have been applied before writing the snippet so the stack snippet reflects the newest integration list.
|
|
208
|
-
|
|
209
234
|
### 5b. Update Active Symlink
|
|
210
235
|
|
|
211
236
|
Flip `{skill_group}/active` to point at the current `{version}` via the helper. The call is **always** run — atomic, idempotent, and verified in one shot. The helper's no-op path handles the "version did not change" case (gap-driven mode, or no source drift) without writing to disk:
|
|
@@ -225,9 +250,11 @@ The helper emits a result envelope with `status` ∈ `{ok, flipped, mismatch, mi
|
|
|
225
250
|
- **`missing-target`** (exit 2): `{skill_group}/{version}/` directory does not exist on disk. HALT — display `halt_message` verbatim. This indicates §4 §6b did not write the version directory before §5b ran (a workflow bug, not a user error).
|
|
226
251
|
- **`mismatch`** (exit 2): re-read after flip showed the symlink still points elsewhere. HALT — display `halt_message`. Should be impossible because the helper uses `os.replace` (atomic rename); a mismatch here indicates filesystem-level interference (concurrent writer, broken FUSE mount).
|
|
227
252
|
|
|
253
|
+
Both exit-2 halts carry status `halted-for-write-failure`; in `{headless_mode}`, emit the halt envelope per SKILL.md §Headless (`error: {phase: "write:active-symlink", reason: "..."}`).
|
|
254
|
+
|
|
228
255
|
### 6. Verify Derived Artifact Writes
|
|
229
256
|
|
|
230
|
-
SKILL.md was verified in section 1
|
|
257
|
+
SKILL.md was verified in section 1 (written by step 4 section 6b). This section verifies the artifacts this step wrote: `metadata.json`, `provenance-map.json`, `evidence-report.md`, `context-snippet.md`, and the `active` symlink from §5b.
|
|
231
258
|
|
|
232
259
|
For each derived artifact:
|
|
233
260
|
- Read back the file
|
|
@@ -246,12 +273,33 @@ For each derived artifact:
|
|
|
246
273
|
| evidence-report.md | {VERIFIED/FAILED} |
|
|
247
274
|
| context-snippet.md | {VERIFIED/FAILED} |
|
|
248
275
|
| {skill_group}/active symlink | {VERIFIED/FAILED} (readlink → {resolved_version}, expected {version}) |
|
|
249
|
-
| {stack reference files...} | {VERIFIED in section 5} |
|
|
250
276
|
|
|
251
|
-
**On symlink `mismatch` (helper exit 2):** HALT
|
|
277
|
+
**On symlink `mismatch` (helper exit 2):** HALT with status `halted-for-write-failure`. Do not proceed to §7 post-write validation or §8 menu. Display the helper's `halt_message` verbatim — it already includes the diverged target, the expected version, and the recovery command; in `{headless_mode}`, emit the halt envelope per SKILL.md §Headless (`error: {phase: "write:verify-active-symlink", reason: "..."}`). This matches the severity of the other four artifact checks — silent divergence here mis-routes any downstream consumer that uses the symlink fallback.
|
|
252
278
|
|
|
253
279
|
**All files written and verified.**"
|
|
254
280
|
|
|
281
|
+
### 6a. Provenance Completeness (Check D — Deferred from Step 05)
|
|
282
|
+
|
|
283
|
+
`validate.md` Check D (Provenance Completeness) is a deterministic set-diff plus citation resolution, and it needs both `metadata.json` (written in §2) and `provenance-map.json` (written in §3) on disk — neither exists at validate time, so the check is deferred here. Run it against the just-written artifacts via `{verifyProvenanceCompletenessHelper}`:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
uv run {verifyProvenanceCompletenessHelper} verify \
|
|
287
|
+
--metadata {skill_package}/metadata.json \
|
|
288
|
+
--provenance {forge_version}/provenance-map.json \
|
|
289
|
+
--source-root {source_root}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
The helper reads its `--source-root` (falling back to the provenance map's own `source_root` field when the flag is omitted); pass the resolved `{source_root}` so citation resolution runs against the same tree re-extraction read. **Read the emitted JSON — do NOT recompute the set operations by eye; an LLM set-diff can silently pass a dropped or orphaned entry:**
|
|
293
|
+
|
|
294
|
+
- `missing[]` — documented exports (metadata `exports[]`) with no provenance entry: a coverage gap.
|
|
295
|
+
- `orphaned[]` — provenance `entries[].export_name` whose export was removed but the entry remains.
|
|
296
|
+
- `stale[]` — entries whose `source_file:source_line` no longer resolves; each carries a `reason` of `file-missing`, `line-out-of-bounds`, or `line-invalid`. Internal names are canonicalized through `reexport_map` before the diff, so a barrel-renamed export does not read as missing or orphaned.
|
|
297
|
+
- `summary.stale_check` — `"checked"` when citations were resolved against the source tree, or `"skipped-no-source-root"` when no source root resolved on disk (the completeness + orphan diffs still ran; `stale` is empty by construction, not clean-by-verification).
|
|
298
|
+
|
|
299
|
+
Map `status` to the `Provenance:` line of the §4 evidence report's Validation Summary: `PASS` when `status == "pass"`, `WARN` when `status == "findings"` (this is the persistent record — step 5 §5's table was rendered before the provenance map existed, so it necessarily showed this row as deferred). Provenance findings are **advisory** — they do not block the update. Surface each `missing` / `orphaned` / `stale` entry in the evidence report's Validation Summary so the user can decide, and note when `stale_check` was `skipped-no-source-root`.
|
|
300
|
+
|
|
301
|
+
**Graceful degradation:** if neither probe path resolves (no `uv` / script available), fall back to the manual set comparison the script encapsulates — enumerate metadata `exports[]` and provenance `entries[].export_name` (canonicalizing internal names through `reexport_map`), diff the two sets for missing/orphaned entries, and spot-check that each `source_file:source_line` still points at a real line in the source tree. Prefer the script — it does this deterministically.
|
|
302
|
+
|
|
255
303
|
### 7. Run Post-Write Validation (Deferred from Step 05)
|
|
256
304
|
|
|
257
305
|
External tool checks deferred from step 5 now run against the written files.
|
|
@@ -284,20 +332,7 @@ Record findings in the evidence report (section 4), including any `description_g
|
|
|
284
332
|
|
|
285
333
|
**If skill-check unavailable:** Skip with note — structural checks from step 5 are sufficient.
|
|
286
334
|
|
|
287
|
-
### 8.
|
|
288
|
-
|
|
289
|
-
Display: "**Proceeding to report...**"
|
|
290
|
-
|
|
291
|
-
#### Menu Handling Logic:
|
|
292
|
-
|
|
293
|
-
- After all writes verified and post-write validation complete, immediately load, read entire file, then execute {nextStepFile}
|
|
294
|
-
|
|
295
|
-
#### EXECUTION RULES:
|
|
296
|
-
|
|
297
|
-
- This is an auto-proceed step with no user choices
|
|
298
|
-
- Proceed directly to report after verification
|
|
299
|
-
|
|
300
|
-
## CRITICAL STEP COMPLETION NOTE
|
|
335
|
+
### 8. Route to Next Step
|
|
301
336
|
|
|
302
|
-
|
|
337
|
+
This step auto-proceeds — no user choices. Once all files have been written and verified and post-write validation is complete, display "**Proceeding to report...**", then load, fully read, and execute `{nextStepFile}` to display the change report.
|
|
303
338
|
|