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
|
@@ -13,7 +13,7 @@ Compare QMD knowledge context between the original skill creation and current st
|
|
|
13
13
|
|
|
14
14
|
## Rules
|
|
15
15
|
|
|
16
|
-
-
|
|
16
|
+
- At Quick/Forge/Forge+ tier, skip the entire analysis — append the skip notice only
|
|
17
17
|
- Focus only on semantic/meaning-level changes via QMD context — do not repeat structural findings from Step 03
|
|
18
18
|
- Do not classify severity (Step 05)
|
|
19
19
|
- Use subprocess Pattern 3 when available for QMD queries; if unavailable, query in main thread
|
|
@@ -22,7 +22,7 @@ Compare QMD knowledge context between the original skill creation and current st
|
|
|
22
22
|
|
|
23
23
|
### 1. Check Forge Tier
|
|
24
24
|
|
|
25
|
-
**
|
|
25
|
+
**If forge tier is Quick, Forge, or Forge+:**
|
|
26
26
|
|
|
27
27
|
Append to {outputFile}:
|
|
28
28
|
|
|
@@ -40,7 +40,7 @@ Update frontmatter: append `'semantic-diff'` to `stepsCompleted`
|
|
|
40
40
|
|
|
41
41
|
→ Auto-proceed to {nextStepFile}
|
|
42
42
|
|
|
43
|
-
**
|
|
43
|
+
**If forge tier is Deep:**
|
|
44
44
|
|
|
45
45
|
Continue to section 2.
|
|
46
46
|
|
|
@@ -127,23 +127,5 @@ Append to {outputFile}:
|
|
|
127
127
|
|
|
128
128
|
### 5. Update Report and Auto-Proceed
|
|
129
129
|
|
|
130
|
-
Update {outputFile} frontmatter
|
|
131
|
-
- Append `'semantic-diff'` to `stepsCompleted`
|
|
132
|
-
|
|
133
|
-
### 6. Present MENU OPTIONS
|
|
134
|
-
|
|
135
|
-
Display: "**Semantic diff complete. {total} semantic drift items found. Proceeding to severity classification...**"
|
|
136
|
-
|
|
137
|
-
#### Menu Handling Logic:
|
|
138
|
-
|
|
139
|
-
- After semantic diff section is appended and frontmatter updated, immediately load, read entire file, then execute {nextStepFile}
|
|
140
|
-
|
|
141
|
-
#### EXECUTION RULES:
|
|
142
|
-
|
|
143
|
-
- This is an auto-proceed analysis step with no user choices
|
|
144
|
-
- Proceed directly to next step after completion
|
|
145
|
-
|
|
146
|
-
## CRITICAL STEP COMPLETION NOTE
|
|
147
|
-
|
|
148
|
-
ONLY WHEN the ## Semantic Drift section (or skip notice) has been appended to {outputFile} will you then load and read fully `{nextStepFile}` to execute and begin severity classification.
|
|
130
|
+
Update {outputFile} frontmatter — append `'semantic-diff'` to `stepsCompleted`. Once the ## Semantic Drift section (or skip notice) has been appended, load, read fully, and execute `{nextStepFile}` (severity classification).
|
|
149
131
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'step-doc-drift.md'
|
|
3
3
|
outputFile: '{forge_version}/drift-report-{timestamp}.md'
|
|
4
|
-
severityRulesFile: '
|
|
4
|
+
severityRulesFile: '{severityRulesPath}'
|
|
5
|
+
severityClassifyProbeOrder:
|
|
6
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-severity-classify.py'
|
|
7
|
+
- '{project-root}/src/shared/scripts/skf-severity-classify.py'
|
|
5
8
|
---
|
|
6
9
|
|
|
7
10
|
<!-- Config: communicate in {communication_language}. -->
|
|
@@ -10,82 +13,61 @@ severityRulesFile: 'references/severity-rules.md'
|
|
|
10
13
|
|
|
11
14
|
## STEP GOAL:
|
|
12
15
|
|
|
13
|
-
Grade every drift finding from Steps 03 and 04 by severity
|
|
16
|
+
Grade every drift finding from Steps 03 and 04 by severity (CRITICAL/HIGH/MEDIUM/LOW), derive the overall drift score, and produce a categorized findings table with confidence-tier labels.
|
|
14
17
|
|
|
15
18
|
## Rules
|
|
16
19
|
|
|
17
|
-
- Only classify
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
+
- Only classify existing findings — do not discover new drift items or suggest remediation
|
|
21
|
+
- Reading each change and assigning its `type` / `category` is judgment; mapping those to a severity, reducing the set to the drift score, and counting per level are deterministic and delegated to the shared helper so the classification cannot drift from {severityRulesFile} between runs
|
|
22
|
+
- The confidence tier (T1 / T1-low / T2) travels with each finding from Steps 03/04 — the helper never touches it
|
|
20
23
|
|
|
21
24
|
## MANDATORY SEQUENCE
|
|
22
25
|
|
|
23
|
-
### 1.
|
|
26
|
+
### 1. Collect and Categorize Findings
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
1. Loads {severityRulesFile}
|
|
27
|
-
2. Extracts classification criteria for each severity level
|
|
28
|
-
3. Returns structured rules to parent
|
|
28
|
+
Gather every drift item already recorded in the report:
|
|
29
29
|
|
|
30
|
-
**
|
|
30
|
+
**From ## Structural Drift (Step 03):** added, removed, changed, and moved exports (plus any Script/Asset Drift rows).
|
|
31
|
+
**From ## Semantic Drift (Step 04, Deep tier only):** new patterns, changed conventions, dependency shifts, deprecated patterns.
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
- **CRITICAL:** Removed/renamed exports, changed signatures (breaking changes)
|
|
34
|
-
- **HIGH:** New public API not in skill (>3), removed helpers used in patterns, deprecated APIs
|
|
35
|
-
- **MEDIUM:** Implementation changes behind stable API, 1-3 new exports, moved functions
|
|
36
|
-
- **LOW:** Style/convention changes, comments, whitespace, internal functions
|
|
33
|
+
For each finding, read {severityRulesFile} and assign the two interpretive fields the rules key on — this is the judgment step, where the nuance of the change lives:
|
|
37
34
|
|
|
38
|
-
|
|
35
|
+
- `type`: `removed` / `added` / `changed` / `moved` / `renamed` / `deprecated` / `semantic`
|
|
36
|
+
- `category`: what the change is about — e.g. `export`, `module`, `class`, `interface`, `signature`, `parameter_count`, `return_type`, `inheritance`, `internal_helper`, `default_value`, `required_parameter`, `implementation`, `optional_parameter`, `function` (for a move), or a LOW bucket (`style`, `convention`, `comment`, `documentation`, `whitespace`, `test`, `private`, `internal`). The category carries the interpretation: a removed helper referenced in a documented pattern is `internal_helper` (→ HIGH); a new private function is `private` (→ LOW).
|
|
39
37
|
|
|
40
|
-
|
|
38
|
+
Build one JSON array of `{type, category, detail, confidence, file, line}` objects — carry each finding's `confidence`, `file`, `line`, and human `detail` through untouched.
|
|
41
39
|
|
|
42
|
-
|
|
43
|
-
- Added exports
|
|
44
|
-
- Removed exports
|
|
45
|
-
- Changed exports
|
|
40
|
+
### 2. Classify, Score, and Count (deterministic)
|
|
46
41
|
|
|
47
|
-
|
|
48
|
-
- New patterns
|
|
49
|
-
- Changed conventions
|
|
50
|
-
- Dependency shifts
|
|
51
|
-
- Deprecated patterns
|
|
42
|
+
Mapping type/category to a severity, reducing the severities to an overall drift score, and counting per level each have exactly one correct answer for a given finding set — delegate them to the shared helper, which encodes {severityRulesFile} directly.
|
|
52
43
|
|
|
53
|
-
|
|
44
|
+
**Resolve `{severityClassifyHelper}`** from `{severityClassifyProbeOrder}`; first existing path wins.
|
|
54
45
|
|
|
55
|
-
|
|
46
|
+
Pipe the findings array from §1 to the helper on stdin:
|
|
56
47
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
- Removed export → CRITICAL (breaking: skill references something that no longer exists)
|
|
61
|
-
- Changed signature → CRITICAL (breaking: skill documents wrong parameters/return type)
|
|
62
|
-
- Renamed export → CRITICAL (breaking: skill references old name)
|
|
63
|
-
- Moved export (same signature) → MEDIUM (non-breaking but location in skill is wrong)
|
|
64
|
-
- Added export (>3 total) → HIGH (significant API surface not documented)
|
|
65
|
-
- Added export (1-3 total) → MEDIUM (minor gap in coverage)
|
|
66
|
-
|
|
67
|
-
**Semantic findings classification:**
|
|
68
|
-
- Deprecated pattern still in skill → HIGH (skill teaches outdated approach)
|
|
69
|
-
- Changed convention → MEDIUM (skill may use old style)
|
|
70
|
-
- New pattern detected → MEDIUM (skill doesn't cover new approach)
|
|
71
|
-
- Dependency shift → MEDIUM (skill may reference wrong dependencies)
|
|
48
|
+
```bash
|
|
49
|
+
echo '{findings_json}' | uv run {severityClassifyHelper} -
|
|
50
|
+
```
|
|
72
51
|
|
|
73
|
-
|
|
52
|
+
Parse the emitted JSON:
|
|
74
53
|
|
|
75
|
-
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"status": "ok",
|
|
57
|
+
"drift_score": "CLEAN|MINOR|SIGNIFICANT|CRITICAL",
|
|
58
|
+
"total_findings": N,
|
|
59
|
+
"by_severity": {"CRITICAL": N, "HIGH": N, "MEDIUM": N, "LOW": N},
|
|
60
|
+
"findings": [ {"type": "...", "category": "...", "detail": "...", "confidence": "...", "severity": "CRITICAL|HIGH|MEDIUM|LOW"} ]
|
|
61
|
+
}
|
|
62
|
+
```
|
|
76
63
|
|
|
77
|
-
|
|
64
|
+
Consume `by_severity`, `drift_score`, and each finding's assigned `severity` directly — do not recount or recompute the score in prose.
|
|
78
65
|
|
|
79
|
-
|
|
80
|
-
|-------|----------|
|
|
81
|
-
| **CLEAN** | 0 findings at any level |
|
|
82
|
-
| **MINOR** | LOW findings only, no MEDIUM+ |
|
|
83
|
-
| **SIGNIFICANT** | Any MEDIUM or HIGH findings, no CRITICAL |
|
|
84
|
-
| **CRITICAL** | Any CRITICAL findings present |
|
|
66
|
+
**If `uv`/the helper cannot execute** (e.g. claude.ai web): fall back to classifying in the main thread — apply {severityRulesFile}'s severity levels to each finding's type/category, then reduce with its Overall Drift Score table (CLEAN = no findings; MINOR = LOW only; SIGNIFICANT = any MEDIUM/HIGH, no CRITICAL; CRITICAL = any CRITICAL present).
|
|
85
67
|
|
|
86
|
-
###
|
|
68
|
+
### 3. Compile Severity Classification Section
|
|
87
69
|
|
|
88
|
-
**Rollup inherits from step 3.** If step 3 §5 collapsed ≥ 10 same-kind findings into a single rollup row (deleted source file, renamed module, entire package tree removed), carry that rollup through to the matching severity table as one row — do not re-expand it here. Keep the
|
|
70
|
+
**Rollup inherits from step 3.** If step 3 §5 collapsed ≥ 10 same-kind findings into a single rollup row (deleted source file, renamed module, entire package tree removed), carry that rollup through to the matching severity table as one row — do not re-expand it here. Keep the 6-column severity table shape; the rollup encodes root cause, count, and representative symbols **inline in the `Finding` cell** rather than adding columns, so rollup and per-item rows render cleanly in one table. Changed-signature and cross-file findings remain per-row; they were not eligible for rollup in step 3 and are not eligible here.
|
|
89
71
|
|
|
90
72
|
**Rollup row form (any severity table):**
|
|
91
73
|
|
|
@@ -93,32 +75,32 @@ Apply scoring rules from {severityRulesFile}:
|
|
|
93
75
|
|---|---------|------|--------|----------|------------|
|
|
94
76
|
| N | {root cause} (×{Count}; rep: `{sym1}`, `{sym2}`, `{sym3}`, …) | {structural/semantic} | {shared detail} | {root-cause path} | {T1/T2} |
|
|
95
77
|
|
|
96
|
-
Append to {outputFile}
|
|
78
|
+
Append to {outputFile}, filling the counts from `by_severity` and each finding's assigned `severity`:
|
|
97
79
|
|
|
98
80
|
```markdown
|
|
99
81
|
## Severity Classification
|
|
100
82
|
|
|
101
|
-
**Overall Drift Score: {
|
|
83
|
+
**Overall Drift Score: {drift_score}**
|
|
102
84
|
|
|
103
|
-
### CRITICAL ({
|
|
85
|
+
### CRITICAL ({by_severity.CRITICAL})
|
|
104
86
|
|
|
105
87
|
| # | Finding | Type | Detail | Location | Confidence |
|
|
106
88
|
|---|---------|------|--------|----------|------------|
|
|
107
89
|
| 1 | {finding} | {structural/semantic} | {detail} | {file}:{line} | {T1/T2} |
|
|
108
90
|
|
|
109
|
-
### HIGH ({
|
|
91
|
+
### HIGH ({by_severity.HIGH})
|
|
110
92
|
|
|
111
93
|
| # | Finding | Type | Detail | Location | Confidence |
|
|
112
94
|
|---|---------|------|--------|----------|------------|
|
|
113
95
|
| 1 | {finding} | {structural/semantic} | {detail} | {file}:{line} | {T1/T2} |
|
|
114
96
|
|
|
115
|
-
### MEDIUM ({
|
|
97
|
+
### MEDIUM ({by_severity.MEDIUM})
|
|
116
98
|
|
|
117
99
|
| # | Finding | Type | Detail | Location | Confidence |
|
|
118
100
|
|---|---------|------|--------|----------|------------|
|
|
119
101
|
| 1 | {finding} | {structural/semantic} | {detail} | {file}:{line} | {T1/T2} |
|
|
120
102
|
|
|
121
|
-
### LOW ({
|
|
103
|
+
### LOW ({by_severity.LOW})
|
|
122
104
|
|
|
123
105
|
| # | Finding | Type | Detail | Location | Confidence |
|
|
124
106
|
|---|---------|------|--------|----------|------------|
|
|
@@ -126,35 +108,19 @@ Append to {outputFile}:
|
|
|
126
108
|
|
|
127
109
|
### Classification Summary
|
|
128
110
|
|
|
129
|
-
| Severity | Count |
|
|
130
|
-
|
|
131
|
-
| CRITICAL | {
|
|
132
|
-
| HIGH | {
|
|
133
|
-
| MEDIUM | {
|
|
134
|
-
| LOW | {
|
|
135
|
-
| **Total** | {
|
|
111
|
+
| Severity | Count |
|
|
112
|
+
|----------|-------|
|
|
113
|
+
| CRITICAL | {by_severity.CRITICAL} |
|
|
114
|
+
| HIGH | {by_severity.HIGH} |
|
|
115
|
+
| MEDIUM | {by_severity.MEDIUM} |
|
|
116
|
+
| LOW | {by_severity.LOW} |
|
|
117
|
+
| **Total** | {total_findings} |
|
|
136
118
|
```
|
|
137
119
|
|
|
138
|
-
###
|
|
120
|
+
### 4. Update Report and Auto-Proceed
|
|
139
121
|
|
|
140
122
|
Update {outputFile} frontmatter:
|
|
141
123
|
- Append `'severity-classify'` to `stepsCompleted`
|
|
142
|
-
- Set `drift_score` to
|
|
143
|
-
|
|
144
|
-
### 7. Present MENU OPTIONS
|
|
145
|
-
|
|
146
|
-
Display: "**Severity classification complete. Overall drift score: {score}. Proceeding to report generation...**"
|
|
147
|
-
|
|
148
|
-
#### Menu Handling Logic:
|
|
149
|
-
|
|
150
|
-
- After severity classification section is appended and frontmatter updated, immediately load, read entire file, then execute {nextStepFile}
|
|
151
|
-
|
|
152
|
-
#### EXECUTION RULES:
|
|
153
|
-
|
|
154
|
-
- This is an auto-proceed analysis step with no user choices
|
|
155
|
-
- Proceed directly to next step after completion
|
|
156
|
-
|
|
157
|
-
## CRITICAL STEP COMPLETION NOTE
|
|
158
|
-
|
|
159
|
-
ONLY WHEN the ## Severity Classification section has been appended to {outputFile} with all findings classified will you then load and read fully `{nextStepFile}` to execute and begin final report generation.
|
|
124
|
+
- Set `drift_score` to `{drift_score}` from the helper
|
|
160
125
|
|
|
126
|
+
Once the ## Severity Classification section has been appended with all findings classified, load, read fully, and execute `{nextStepFile}` (documentation drift).
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'report.md'
|
|
3
3
|
outputFile: '{forge_version}/drift-report-{timestamp}.md'
|
|
4
|
+
# Resolve `{compareDocHashesHelper}` by probing `{compareDocHashesProbeOrder}`
|
|
5
|
+
# in order (installed SKF module path first, src/ dev-checkout fallback); first
|
|
6
|
+
# existing path wins. When neither resolves (uv/python absent), §2 falls back to
|
|
7
|
+
# skipping the doc-drift check with a notice — see the graceful-failure rule.
|
|
8
|
+
compareDocHashesProbeOrder:
|
|
9
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-detect-docs.py'
|
|
10
|
+
- '{project-root}/src/shared/scripts/skf-detect-docs.py'
|
|
4
11
|
---
|
|
5
12
|
|
|
6
13
|
<!-- Config: communicate in {communication_language}. -->
|
|
@@ -53,15 +60,38 @@ Set `doc_drift_summary = { total_tracked: 0, skipped_entirely: false }` in workf
|
|
|
53
60
|
|
|
54
61
|
### 2. Fetch and Hash Each Tracked Doc
|
|
55
62
|
|
|
56
|
-
|
|
63
|
+
Fetching each URL, hashing the response bytes, comparing against the stored `content_hash`, and categorizing the outcome is deterministic work — and the model cannot compute a `sha256:{hexdigest}` of fetched bytes natively (it must shell out). Delegate the whole fetch/hash/compare pass to the shared script, which hashes byte-symmetrically with how `doc_sources` hashes were written at compile time and fetches independently of whether a WebFetch tool is wired.
|
|
57
64
|
|
|
58
|
-
|
|
59
|
-
2. **If `content_hash` is `null`:** Skip this entry — there is no baseline to compare against. Record it for the report as a null-hash entry. Do not attempt to fetch the URL.
|
|
60
|
-
3. **If `content_hash` is non-null:** Attempt HTTP GET of the URL with a reasonable timeout (10s)
|
|
61
|
-
- **On success:** Compute `sha256:{hexdigest}` of the response body bytes (UTF-8 encoding). Compare against the stored `content_hash`. If they differ, record as drifted. If they match, record as unchanged.
|
|
62
|
-
- **On failure (network error, timeout, non-200 status):** Record the entry as `status: "fetch_failed"` with the failure reason. Do not report as drift.
|
|
65
|
+
**Resolve `{compareDocHashesHelper}`** from `{compareDocHashesProbeOrder}`; first existing path wins.
|
|
63
66
|
|
|
64
|
-
|
|
67
|
+
Run one deterministic comparison subprocess over the skill's `doc_sources`. The script reads the `doc_sources` array straight out of the skill's `metadata.json` (or accepts a bare `doc_sources` array, or `-` for stdin):
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
uv run {compareDocHashesHelper} compare-hashes {skill_path}/metadata.json
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
For each entry, the script:
|
|
74
|
+
- **`content_hash` is `null`** → records it under `skipped_null_hash` and does **not** fetch the URL (there is no baseline to compare against).
|
|
75
|
+
- **`content_hash` is non-null** → HTTP GETs the URL (15s timeout, same User-Agent as the compile side), computes `sha256:{hexdigest}` of the response body bytes, and compares against the stored `content_hash` (prefix-normalized so a bare-hex writer form still matches).
|
|
76
|
+
- Hashes match → `unchanged`.
|
|
77
|
+
- Hashes differ → `changed`, carrying `old_hash` and `new_hash`.
|
|
78
|
+
- Network error, timeout, or non-200 status → `fetch_failed`, carrying the failure `reason`. Not reported as drift.
|
|
79
|
+
|
|
80
|
+
Parse the emitted JSON:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"changed": [{"url": "...", "old_hash": "sha256:...", "new_hash": "sha256:..."}],
|
|
85
|
+
"unchanged": [{"url": "..."}],
|
|
86
|
+
"fetch_failed": [{"url": "...", "old_hash": "sha256:...", "reason": "..."}],
|
|
87
|
+
"skipped_null_hash": [{"url": "..."}],
|
|
88
|
+
"stats": {"total_tracked": N, "changed": N, "unchanged": N, "fetch_failed": N, "skipped_null_hash": N}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The script exits 0 on any well-formed input (even when everything drifted) and exits 2 only on malformed args/JSON — it never blocks this informational audit.
|
|
93
|
+
|
|
94
|
+
If `uv`/`python` is unavailable or the script cannot be resolved — i.e. URL fetching is unavailable in the current environment — skip the doc drift check entirely with:
|
|
65
95
|
|
|
66
96
|
```markdown
|
|
67
97
|
## Documentation Drift
|
|
@@ -73,18 +103,18 @@ Set `doc_drift_summary = { skipped_entirely: true }` and auto-proceed.
|
|
|
73
103
|
|
|
74
104
|
### 3. Build Drift Findings
|
|
75
105
|
|
|
76
|
-
|
|
77
|
-
- **changed:** entries where `content_hash` differs from newly computed hash
|
|
78
|
-
- **unchanged:** entries where hashes match
|
|
79
|
-
- **fetch_failed:** entries where the URL could not be reached
|
|
80
|
-
- **skipped_null_hash:** entries where `content_hash` was `null`
|
|
106
|
+
Read the categories and totals directly from the script's JSON — no manual counting. The four buckets are already computed:
|
|
107
|
+
- **changed:** entries where the stored `content_hash` differs from the newly computed hash (`changed[]`)
|
|
108
|
+
- **unchanged:** entries where the hashes match (`unchanged[]`)
|
|
109
|
+
- **fetch_failed:** entries where the URL could not be reached (`fetch_failed[]`)
|
|
110
|
+
- **skipped_null_hash:** entries where `content_hash` was `null` (`skipped_null_hash[]`)
|
|
81
111
|
|
|
82
|
-
|
|
83
|
-
- `total_tracked` =
|
|
84
|
-
- `changed` =
|
|
85
|
-
- `unchanged` =
|
|
86
|
-
- `fetch_failed` =
|
|
87
|
-
- `skipped_null_hash` =
|
|
112
|
+
Take the totals straight from `stats` (do not recount):
|
|
113
|
+
- `total_tracked` = `stats.total_tracked`
|
|
114
|
+
- `changed` = `stats.changed`
|
|
115
|
+
- `unchanged` = `stats.unchanged`
|
|
116
|
+
- `fetch_failed` = `stats.fetch_failed`
|
|
117
|
+
- `skipped_null_hash` = `stats.skipped_null_hash`
|
|
88
118
|
|
|
89
119
|
### 4. Append to Drift Report
|
|
90
120
|
|
|
@@ -144,4 +174,4 @@ Load, read the full file, then execute {nextStepFile}.
|
|
|
144
174
|
|
|
145
175
|
## CRITICAL STEP COMPLETION NOTE
|
|
146
176
|
|
|
147
|
-
|
|
177
|
+
Only when the ## Documentation Drift section has been appended to {outputFile} and workflow context updated do you then load and read fully `{nextStepFile}` to begin final report generation.
|
|
@@ -7,6 +7,9 @@ loadProvenanceProbeOrder:
|
|
|
7
7
|
compareFileHashesProbeOrder:
|
|
8
8
|
- '{project-root}/_bmad/skf/shared/scripts/skf-compare-file-hashes.py'
|
|
9
9
|
- '{project-root}/src/shared/scripts/skf-compare-file-hashes.py'
|
|
10
|
+
structuralDiffProbeOrder:
|
|
11
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-structural-diff.py'
|
|
12
|
+
- '{project-root}/src/shared/scripts/skf-structural-diff.py'
|
|
10
13
|
---
|
|
11
14
|
|
|
12
15
|
<!-- Config: communicate in {communication_language}. -->
|
|
@@ -25,69 +28,57 @@ Compare the original provenance map extractions from create-skill against the cu
|
|
|
25
28
|
|
|
26
29
|
## MANDATORY SEQUENCE
|
|
27
30
|
|
|
28
|
-
### 1.
|
|
31
|
+
### 1. Run the Deterministic Export Diff
|
|
29
32
|
|
|
30
|
-
|
|
33
|
+
The export comparison — canonicalization, set arithmetic (added/removed/moved), and field-level change detection — is fully deterministic and runs in one subprocess. Do **not** diff the two export lists by hand: an LLM comparing dozens or hundreds of exports can silently drop or mis-match entries, which violates this skill's zero-hallucination contract.
|
|
31
34
|
|
|
32
|
-
**
|
|
33
|
-
- Export list with names, types, signatures, file paths, line numbers
|
|
35
|
+
**Resolve `{structuralDiffHelper}`** from `{structuralDiffProbeOrder}`; first existing path wins. HALT if no candidate exists.
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
- Export list with names, types, signatures, file paths, line numbers
|
|
37
|
+
Run one comparison over the baseline provenance map (from step 1) and the current extraction snapshot (`{extractionSnapshot}`, written to disk by step 2 §3):
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
- **Module qualification of stdlib helpers.** Strip module prefixes on well-known stdlib helpers when the unqualified form is importable at the call site: `dataclasses.field(...)` → `field(...)`, `typing.Optional[...]` → `Optional[...]`, `typing.List[...]` → `List[...]`. Do not collapse user-defined namespaces.
|
|
42
|
-
- **Public-API re-export resolution.** When `{source_root}/**/__init__.py` re-exports an internal symbol under a different public name (`from .internal import _Impl as Public`, or via `__all__`), resolve both sides to the public name before key-matching — otherwise a renamed re-export in the current scan shows up as "Removed `_Impl`" + "Added `Public`" instead of matching the baseline entry. The re-export map is already in workflow context as `{reexport_map}` (produced by `skf-load-provenance.py normalize` in step 1 §4). Apply it directly without re-walking `__init__.py` files.
|
|
43
|
-
|
|
44
|
-
Record the set of transforms actually applied in workflow context — step 6 surfaces them in the Provenance section so a reviewer can tell which differences the diff collapsed and which were real.
|
|
45
|
-
|
|
46
|
-
Normalize both sets for comparison:
|
|
47
|
-
- Match by canonicalized export name (primary key)
|
|
48
|
-
- Group by file for location-aware comparison
|
|
49
|
-
|
|
50
|
-
> **Longer-term fix.** The principled remedy is to persist `skf-create-skill`'s ast-grep ruleset to `{forge_version}/extraction-rules.yaml` at create time and have step 2 replay that exact ruleset. When the file is present, step 2 extraction becomes reproducible against the baseline and the canonicalization pass above becomes a no-op. Until then, normalization is the salvage remediation for provenance maps that predate extractor pinning.
|
|
39
|
+
```bash
|
|
40
|
+
uv run {structuralDiffHelper} {provenanceMap} {extractionSnapshot}
|
|
41
|
+
```
|
|
51
42
|
|
|
52
|
-
|
|
43
|
+
The helper reads both shapes directly — the provenance map's `entries[]` (with `export_name`/`export_type`/`source_file`/`source_line`) and the snapshot's `exports[]` — and aliases the field names, so no manual projection is needed.
|
|
53
44
|
|
|
54
|
-
**
|
|
45
|
+
**Canonicalization is applied inside the helper, symmetrically to both sides**, before name-keyed matching — so cosmetic extractor differences do not surface as false-positive "Changed"/"Removed"/"Added" entries:
|
|
55
46
|
|
|
56
|
-
|
|
47
|
+
- **Quote style on string defaults** — `kind: str = "Hnsw"` ↔ `kind: str = 'Hnsw'`.
|
|
48
|
+
- **Stdlib module qualification** — `typing.Optional[...]` → `Optional[...]`, `dataclasses.field(...)` → `field(...)` (user-defined namespaces are never collapsed).
|
|
49
|
+
- **Public-API re-export resolution** — a renamed public re-export (`_Impl` → `Public`) matches the baseline entry instead of splitting into "Removed `_Impl`" + "Added `Public`". The re-export map is **auto-derived from the provenance map** (identical to the `{reexport_map}` projection `skf-load-provenance.py normalize` produced in step 1 §4). Pass `--reexport-map {file}` only to override with a custom map.
|
|
57
50
|
|
|
58
|
-
|
|
59
|
-
- Export name, type, signature
|
|
60
|
-
- File path and line number (from current scan)
|
|
61
|
-
- Confidence tier (T1 if AST-backed, T1-low if text-based)
|
|
51
|
+
Parse the emitted JSON:
|
|
62
52
|
|
|
63
|
-
|
|
53
|
+
```
|
|
54
|
+
{
|
|
55
|
+
"summary": {"added": N, "removed": N, "changed": N, "moved": N, "unchanged": N},
|
|
56
|
+
"added": [ <entry>, ... ], // in current snapshot, NOT in provenance map
|
|
57
|
+
"removed": [ <entry>, ... ], // in provenance map, NOT in current snapshot
|
|
58
|
+
"changed": [ {"name", "field", "baseline_value", "current_value"}, ... ],
|
|
59
|
+
"moved": [ {"name", "previous_file", "current_file"}, ... ],
|
|
60
|
+
"unchanged_count": N,
|
|
61
|
+
"applied_transforms": [ {"transform": "quote-style|stdlib-prefix|reexport-resolution", "count": N}, ... ]
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
Stash `applied_transforms` in workflow context — step 6 surfaces it in the Provenance section so a reviewer can tell which cosmetic differences the diff collapsed and which changes were real.
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
**If `uv` / the helper cannot execute** (e.g. claude.ai web): fall back to comparing the two lists by hand — match by canonicalized export name (apply the three transforms above to both sides), then read off added (current-only), removed (baseline-only), moved (same name, different `file`), and changed (matched name, differing type/signature/line). Compare a field only when it is present on both sides.
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
- Export name, type, signature (from provenance map)
|
|
71
|
-
- Original file path and line number
|
|
72
|
-
- Confidence tier (T1 if AST-backed, T1-low if text-based)
|
|
69
|
+
### 2. Read Added / Removed / Moved from the Diff
|
|
73
70
|
|
|
74
|
-
|
|
71
|
+
These sets come straight from the helper's JSON — no further set arithmetic:
|
|
75
72
|
|
|
76
|
-
|
|
73
|
+
- **Added** — `added[]`: exports in the current snapshot but not the provenance map. Each carries name, type, signature, file, line, confidence.
|
|
74
|
+
- **Removed** — `removed[]`: exports in the provenance map but not the current snapshot. Same fields (in provenance-map field names).
|
|
75
|
+
- **Moved** — `moved[]`: matched exports whose file path changed (`previous_file` → `current_file`). A move is **not** a removal.
|
|
77
76
|
|
|
78
|
-
|
|
77
|
+
Confidence tier for each entry is the `confidence` field the extractor recorded (T1 if AST-backed, T1-low if text-based).
|
|
79
78
|
|
|
80
|
-
|
|
81
|
-
- **Signature changes:** Parameter count, parameter types, return type
|
|
82
|
-
- **Type changes:** Function became class, const became function, etc.
|
|
83
|
-
- **Location changes:** Same name/signature but different file or line number (MOVED)
|
|
79
|
+
### 3. Read Changed Exports from the Diff
|
|
84
80
|
|
|
85
|
-
|
|
86
|
-
- Export name
|
|
87
|
-
- Original signature → Current signature
|
|
88
|
-
- Original location → Current location
|
|
89
|
-
- What changed (signature / type / location)
|
|
90
|
-
- Confidence tier
|
|
81
|
+
`changed[]` lists per-field differences for exports present in BOTH sets. Each item names the export, the `field` that changed (type / signature / line / confidence), and its `baseline_value` → `current_value`. Group items by export name when compiling the report, and pair with the export's `moved[]` entry (if any) to describe location changes.
|
|
91
82
|
|
|
92
83
|
### 4b. Detect Script/Asset Drift
|
|
93
84
|
|
|
@@ -114,7 +105,9 @@ Parse the emitted JSON:
|
|
|
114
105
|
|
|
115
106
|
Hash-prefix normalization (writer-vs-reader compatibility — `skf-create-skill` writes `content_hash` with a `"sha256:"` prefix, a bare-hex hash from `hashlib` would otherwise never match) is handled inside the script. Downstream consumers read `added`/`removed`/`changed` directly with no further normalization.
|
|
116
107
|
|
|
117
|
-
Append the three lists into the Structural Drift section
|
|
108
|
+
Append the three lists into the Structural Drift section under a `### Script/Asset Drift (added {stats.added}, removed {stats.removed}, changed {stats.changed})` heading — take each count straight from `stats`, no recount.
|
|
109
|
+
|
|
110
|
+
**If `uv`/the helper cannot execute** (e.g. claude.ai web): skip the script/asset drift check with a `### Script/Asset Drift — skipped (hashing helper unavailable)` note rather than blocking the audit. This check is supplementary to the export diff, which has its own by-hand fallback in §1.
|
|
118
111
|
|
|
119
112
|
### Stack-Specific Structural Diff
|
|
120
113
|
|
|
@@ -122,7 +115,7 @@ If `{is_stack_skill}` is true:
|
|
|
122
115
|
|
|
123
116
|
**For v2 provenance (per-export entries with `source_library`):**
|
|
124
117
|
- Group entries by `source_library`
|
|
125
|
-
- For each library,
|
|
118
|
+
- For each library, run the same deterministic diff as the single-skill path (§1) — pass the per-library baseline slice and the matching current snapshot to `{structuralDiffHelper}`
|
|
126
119
|
- Report per-library diff results
|
|
127
120
|
|
|
128
121
|
**For code-mode stacks:** Re-extract from each source repo and compare per-library entries.
|
|
@@ -135,7 +128,7 @@ If `{is_stack_skill}` is true:
|
|
|
135
128
|
|
|
136
129
|
### 5. Compile Structural Drift Section
|
|
137
130
|
|
|
138
|
-
**Rollup for high-volume uniform findings.** When ≥ 10 findings in the same table share one root cause (deleted source file, renamed module, entire package tree removed), you
|
|
131
|
+
**Rollup for high-volume uniform findings.** When ≥ 10 findings in the same table share one root cause (deleted source file, renamed module, entire package tree removed), you may collapse them into one row per root cause. Rollup rows replace the per-symbol `Export`/`Signature` columns with `Count` and `Representative symbols` (up to 3 names, `…` if more). Rollup applies to **Added Exports**, **Removed Exports**, and **Script/Asset Drift** tables — **not** to Changed Exports, which are heterogeneous by construction (signature changes and cross-file changes are inspected per-finding). Record which groupings were collapsed in workflow context for reviewer traceability.
|
|
139
132
|
|
|
140
133
|
**Rollup row form (Added / Removed Exports):**
|
|
141
134
|
|
|
@@ -181,23 +174,5 @@ Append to {outputFile}:
|
|
|
181
174
|
|
|
182
175
|
### 6. Update Report and Auto-Proceed
|
|
183
176
|
|
|
184
|
-
Update {outputFile} frontmatter
|
|
185
|
-
- Append `'structural-diff'` to `stepsCompleted`
|
|
186
|
-
|
|
187
|
-
### 7. Present MENU OPTIONS
|
|
188
|
-
|
|
189
|
-
Display: "**Structural diff complete. {total} drift items found. Proceeding to semantic diff...**"
|
|
190
|
-
|
|
191
|
-
#### Menu Handling Logic:
|
|
192
|
-
|
|
193
|
-
- After structural diff section is appended and frontmatter updated, immediately load, read entire file, then execute {nextStepFile}
|
|
194
|
-
|
|
195
|
-
#### EXECUTION RULES:
|
|
196
|
-
|
|
197
|
-
- This is an auto-proceed analysis step with no user choices
|
|
198
|
-
- Proceed directly to next step after completion
|
|
199
|
-
|
|
200
|
-
## CRITICAL STEP COMPLETION NOTE
|
|
201
|
-
|
|
202
|
-
ONLY WHEN the ## Structural Drift section has been appended to {outputFile} with all findings documented will you then load and read fully `{nextStepFile}` to execute and begin semantic diff analysis.
|
|
177
|
+
Update {outputFile} frontmatter — append `'structural-diff'` to `stepsCompleted`. Once the ## Structural Drift section has been appended, load, read fully, and execute `{nextStepFile}` (semantic diff).
|
|
203
178
|
|
|
@@ -9,11 +9,9 @@ description: Design a skill scope through guided discovery. Use when the user re
|
|
|
9
9
|
|
|
10
10
|
Helps the user define what to skill — target repo, scope, language, inclusion/exclusion patterns — and produces a `skill-brief.yaml` that drives create-skill. This is the first step in the skill creation pipeline; the brief is the input contract for create-skill, which performs the actual compilation.
|
|
11
11
|
|
|
12
|
-
A good skill brief sets a tight, cohesive boundary: one capability with 3-8 primary functions, an unambiguous public API surface, and a description short enough to fit in a registry row. Briefs that try to cover several unrelated concerns (e.g. authentication *and* data visualization) compile into skills that no agent can route to confidently — a brief covering too much is a worse failure mode than a brief covering too little, and this workflow steers toward the smaller, sharper version when scope is unclear.
|
|
12
|
+
A good skill brief sets a tight, cohesive boundary: one capability with 3-8 primary functions, an unambiguous public API surface, and a description short enough to fit in a registry row. Briefs that try to cover several unrelated concerns (e.g. authentication *and* data visualization) compile into skills that no agent can route to confidently — a brief covering too much is a worse failure mode than a brief covering too little, and this workflow steers toward the smaller, sharper version when scope is unclear. Scope on cheap signals — manifests, top-level exports, intent — not full AST extraction.
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
**Ratify path.** When the user already has a `skill-brief.yaml` produced by another workflow — typically `skf-analyze-source`'s `generate-briefs` step, where one analyze pass emits several recommended briefs — the brief can be *ratified* (reviewed and rewritten without re-deriving its fields) instead of authored from scratch. **Interactively:** invoke `/skf-brief-skill` with a path to that brief at the first prompt — gather-intent §3.1a loads the YAML, hydrates the brief context, and jumps straight to step 4 (confirm-brief) where the standard review/edit cycle still applies before step 5 writes. **Headlessly:** pass `from_brief <path>` — the step 1 §8 GATE runs the same schema validation and hydration and writes through the canonical writer (overwriting in place), enabling a fully headless analyze → brief → create pipeline that preserves the upstream-authored scope. Either path skips re-deriving fields the upstream draft already supplies and saves the 5-10 minutes a full re-run of intent + analyze + scope would cost.
|
|
14
|
+
**Ratify path.** A pre-authored `skill-brief.yaml` (typically from `skf-analyze-source`'s `generate-briefs` step) can be *ratified* — reviewed and rewritten in place — instead of re-derived from scratch. Interactively, pass its path at the first prompt; headlessly, pass `from_brief <path>`. See the `from_brief` Inputs cell in `references/invocation-contract.md` for the full ratify contract.
|
|
17
15
|
|
|
18
16
|
## Conventions
|
|
19
17
|
|
|
@@ -63,8 +61,11 @@ These rules apply to every step in this workflow:
|
|
|
63
61
|
- `{descriptionVoiceExamplesPath}` ← `workflow.description_voice_examples_path` if non-empty, else `assets/description-voice-examples.md`
|
|
64
62
|
- `{scopeTemplatesPath}` ← `workflow.scope_templates_path` if non-empty, else `assets/scope-templates.md`
|
|
65
63
|
- `{briefSchemaPath}` ← `workflow.brief_schema_path` if non-empty, else `assets/skill-brief-schema.md`
|
|
64
|
+
- `{onCompleteCommand}` ← `workflow.on_complete` if non-empty, else empty string (no-op — write-brief.md skips the hook invocation entirely)
|
|
65
|
+
|
|
66
|
+
Stash all four as workflow-context variables. Stage files reference `{descriptionVoiceExamplesPath}` / `{scopeTemplatesPath}` / `{briefSchemaPath}` / `{onCompleteCommand}` directly — no conditional at the usage site. Empty-string overrides cleanly fall through to the bundled default; non-empty values let orgs swap in house-style copies (or wire in a pipeline hook) without forking the skill.
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
Also apply the array surfaces so they are not silent no-ops: execute each entry in `workflow.activation_steps_prepend` in order now; treat every entry in `workflow.persistent_facts` as standing context for the whole run (`file:`-prefixed entries are paths or globs whose contents load as facts — the bundled default loads any `project-context.md` under `{project-root}`); then, after activation completes and before step 4 loads the first stage, execute each entry in `workflow.activation_steps_append` in order.
|
|
68
69
|
|
|
69
70
|
4. Load, read the full file, and execute `references/gather-intent.md`.
|
|
70
71
|
|
|
@@ -85,34 +86,4 @@ Stages 1a-1b are conditional — they replace stages 2-5 when BS is invoked with
|
|
|
85
86
|
|
|
86
87
|
## Invocation Contract
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|--------|--------|
|
|
90
|
-
| **Inputs** | `target_repo` [required], `skill_name` [required], `scope_hint` [optional], `language_hint` [optional], `target_version` [optional], `source_authority` [optional: official/community/internal, default community], `source_type` [optional: source/docs-only, default source], `doc_urls` [optional: list of `url[,label]` for source_type=docs-only or supplemental], `scope_type` [optional: full-library/specific-modules/public-api/component-library/reference-app/docs-only], `include` [optional: comma-separated globs], `exclude` [optional: comma-separated globs], `scripts_intent` [optional: detect/none/free-text, default detect], `assets_intent` [optional: detect/none/free-text, default detect], `intent` [optional: free-text used to derive description], `force` [optional: overwrite existing brief without prompting], `from_brief` [optional: path to a pre-authored `skill-brief.yaml` to *ratify* — when supplied it is the source of truth, `target_repo`/`skill_name` become optional/derived-from-brief, and the run mirrors the interactive §3.1a ratify path: schema-validate, skip analyze-target/scope-definition, write through the canonical writer in place], `[auto]` [optional: bracket modifier passed via pipeline context — when present, BS loads the upstream brief from `brief_path` in pipeline data, enriches it with doc detection, and writes through the canonical writer; requires `brief_path` from AN's `SKF_ANALYZE_RESULT_JSON`] |
|
|
91
|
-
| **Gates** | step 1: Input Gate [use args] | step 3: Confirm Gate [C] | step 4: Confirm Gate [C] |
|
|
92
|
-
| **Outputs** | `skill-brief.yaml` at `{forge_data_folder}/{skill-name}/skill-brief.yaml`; final `SKF_BRIEF_RESULT_JSON` line on stdout when `{headless_mode}` is true |
|
|
93
|
-
| **Headless** | All gates auto-resolve with heuristic-driven or default action when `{headless_mode}` is true; pre-supplied inputs consumed at the gates that would otherwise prompt; absent `source_authority` and `scope_type` are resolved by signal-driven detection (see `references/headless-args.md`); existing briefs are preserved unless `--force` was supplied (HALT with `overwrite-cancelled` otherwise); supplying `from_brief <path>` instead routes the step 1 GATE to a ratify path that schema-validates the pre-authored brief, skips analyze-target/scope-definition, and writes through the canonical writer (overwriting in place, no `--force` needed) rather than deriving a new brief |
|
|
94
|
-
| **Transient-failure retry** | This workflow does **not** auto-retry network or subprocess failures. A failed `gh` fetch (analyze-target.md §1, portfolio-similarity-check.md), QMD probe, or extraction script is logged and surfaced in the final result envelope as a warning, but the workflow continues with whatever signal it has. Headless pipelines that want retry semantics should wrap the invocation at their orchestrator level (e.g. CI re-runner on non-zero exit). Rationale: brief-skill is read-mostly with one terminal write (the YAML at step 5); a partial-signal retry has more failure modes than just re-running the whole workflow, which is cheap. |
|
|
95
|
-
| **Exit codes** | See "Exit Codes" below |
|
|
96
|
-
|
|
97
|
-
## Exit Codes
|
|
98
|
-
|
|
99
|
-
Every HARD HALT in this workflow exits with a stable code so headless automators can branch on the failure class without grepping message text:
|
|
100
|
-
|
|
101
|
-
| Code | Meaning | Raised by |
|
|
102
|
-
| ---- | -------------------- | ------------------------------------------------------------------------------------------ |
|
|
103
|
-
| 0 | success | step 6 (terminal) |
|
|
104
|
-
| 2 | input-missing / input-invalid | step 1 GATE — required headless arg absent (`target_repo`, `skill_name`, or `doc_urls` when `source_type=docs-only`) → `input-missing`; enum violation, malformed semver, non-kebab `skill_name`, or step 5 brief-context schema validation failure → `input-invalid` |
|
|
105
|
-
| 3 | resolution-failure | step 1 §1 (`forge-tier.yaml` missing); step 2 §1 (target inaccessible / `gh auth` fails) |
|
|
106
|
-
| 4 | write-failure | step 1 §1 pre-flight write probe (data folder unwritable: read-only mount, disk full, permissions denied); step 5 §4 (write to `{forge_data_folder}/{skill-name}/skill-brief.yaml` failed) |
|
|
107
|
-
| 5 | overwrite-cancelled | step 5 §2 (existing brief, `force` not supplied) |
|
|
108
|
-
| 6 | user-cancelled | any interactive menu in step 1/03/04 (user selected `[X]` Cancel and exit) |
|
|
109
|
-
|
|
110
|
-
## Result Contract (Headless)
|
|
111
|
-
|
|
112
|
-
When `{headless_mode}` is true, step 5 emits a single-line JSON envelope on **stdout** before chaining to step 6, and every HARD HALT emits the same envelope shape on **stderr** with `status: "error"`:
|
|
113
|
-
|
|
114
|
-
```
|
|
115
|
-
SKF_BRIEF_RESULT_JSON: {"status":"success|error","brief_path":"…|null","skill_name":"…","version":"…|null","language":"…|null","scope_type":"…|null","exit_code":0,"halt_reason":null,"mode":"auto|null"}
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
`status` is `"success"` on the terminal happy path, `"error"` on any HALT. `halt_reason` is one of: `null` (success), `"input-missing"`, `"input-invalid"`, `"forge-tier-missing"`, `"target-inaccessible"`, `"gh-auth-failed"`, `"write-failed"`, `"overwrite-cancelled"`, `"user-cancelled"`. `exit_code` matches the table above. `mode` is `"auto"` when BS was invoked with the `[auto]` flag (pipeline auto-brief generation), `null` otherwise (interactive or headless-without-auto).
|
|
89
|
+
Headless callers: the full argument set (`Inputs`), gate map, exit-code table, and `SKF_BRIEF_RESULT_JSON` result envelope live in `references/invocation-contract.md`. Interactive runs do not need it.
|
|
@@ -121,7 +121,7 @@ Auto-detect demo directories and file patterns:
|
|
|
121
121
|
- Directories: `demo/`, `demos/`, `stories/`, `examples/`, `__stories__/`, `storybook/`
|
|
122
122
|
- Files: `*.stories.*`, `*.story.*`, `*.example.*`, `*.demo.*`
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
Show detected patterns to the user for confirmation before applying them, rather than excluding files silently.
|
|
125
125
|
Prompt: "**Auto-detected {N} demo/example files** in {M} directories. Confirm exclusion? [Y/n] Or adjust patterns:"
|
|
126
126
|
|
|
127
127
|
**Phase 3 — Variant Selection (if applicable):**
|