bmad-module-skill-forge 2.0.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/docs/_data/pinned.yaml +1 -1
- package/package.json +2 -2
- package/src/knowledge/skill-lifecycle.md +1 -1
- package/src/module-help.csv +2 -2
- 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-detect-docs.py +232 -1
- package/src/shared/scripts/skf-detect-language.py +77 -0
- package/src/shared/scripts/skf-detect-tools.py +105 -2
- package/src/shared/scripts/skf-enumerate-stack-skills.py +111 -2
- 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-manifest-ops.py +67 -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-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 +39 -1
- 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 +1 -1
- package/src/shared/scripts/skf-verify-no-trace.py +214 -0
- package/src/shared/scripts/skf-verify-provenance-completeness.py +439 -0
- package/src/skf-analyze-source/SKILL.md +17 -32
- 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 +42 -180
- 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/customize.toml +14 -0
- package/src/skf-brief-skill/references/analyze-target.md +6 -14
- package/src/skf-brief-skill/references/confirm-brief.md +2 -14
- package/src/skf-brief-skill/references/draft-checkpoint.md +8 -8
- package/src/skf-brief-skill/references/gather-intent.md +19 -22
- 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 +4 -14
- package/src/skf-brief-skill/references/step-auto-brief.md +1 -5
- package/src/skf-brief-skill/references/step-auto-validate.md +1 -5
- package/src/skf-brief-skill/references/version-resolution.md +1 -1
- package/src/skf-brief-skill/references/write-brief.md +17 -10
- package/src/skf-campaign/SKILL.md +15 -84
- package/src/skf-campaign/customize.toml +2 -0
- package/src/skf-campaign/manifest.yaml +4 -0
- package/src/skf-campaign/references/campaign-contracts.md +67 -0
- package/src/skf-campaign/references/campaign-directive-spec.md +14 -103
- package/src/skf-campaign/references/step-01-setup.md +4 -5
- package/src/skf-campaign/references/step-02-strategy.md +8 -3
- package/src/skf-campaign/references/step-03-pins.md +1 -1
- package/src/skf-campaign/references/step-04-provenance.md +1 -1
- package/src/skf-campaign/references/step-05-skill-loop.md +1 -1
- package/src/skf-campaign/references/step-06-batch.md +7 -6
- package/src/skf-campaign/references/step-11-maintenance.md +2 -2
- package/src/skf-campaign/references/step-resume.md +9 -8
- package/src/skf-campaign/scripts/campaign-deps.py +10 -1
- package/src/skf-campaign/scripts/campaign-render-batch.py +199 -0
- package/src/skf-campaign/scripts/campaign-status.py +162 -0
- package/src/skf-campaign/templates/campaign-brief-template.yaml +1 -1
- package/src/skf-create-skill/SKILL.md +14 -3
- package/src/skf-create-skill/assets/compile-assembly-rules.md +17 -38
- 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 +34 -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 +14 -29
- package/src/skf-create-skill/references/extraction-patterns-tracing.md +1 -1
- package/src/skf-create-skill/references/extraction-patterns.md +7 -7
- package/src/skf-create-skill/references/generate-artifacts.md +9 -23
- package/src/skf-create-skill/references/health-check.md +1 -1
- package/src/skf-create-skill/references/load-brief.md +16 -18
- package/src/skf-create-skill/references/report.md +12 -15
- package/src/skf-create-skill/references/source-resolution-protocols.md +3 -3
- package/src/skf-create-skill/references/step-auto-shard.md +52 -25
- package/src/skf-create-skill/references/step-doc-rot.md +30 -12
- package/src/skf-create-skill/references/step-doc-sources.md +2 -2
- package/src/skf-create-skill/references/sub/ccc-discover.md +2 -13
- package/src/skf-create-skill/references/sub/fetch-docs.md +8 -50
- 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 +59 -28
- 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 +51 -31
- 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 +42 -10
- package/src/skf-drop-skill/references/select.md +88 -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 +27 -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 +14 -7
- package/src/skf-refine-architecture/customize.toml +9 -0
- package/src/skf-refine-architecture/references/compile.md +9 -7
- 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 +13 -10
- 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 +107 -78
- 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 +20 -12
- package/src/skf-setup/customize.toml +10 -0
- package/src/skf-setup/references/auto-index.md +9 -10
- package/src/skf-setup/references/ccc-index.md +14 -15
- package/src/skf-setup/references/detect-and-tier.md +6 -8
- package/src/skf-setup/references/report.md +22 -31
- 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 +109 -75
- 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 +38 -20
- 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 +6 -6
- 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 +131 -1
- 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 +14 -0
- package/src/skf-update-skill/references/detect-changes.md +19 -37
- package/src/skf-update-skill/references/health-check.md +3 -9
- package/src/skf-update-skill/references/init.md +39 -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 +12 -24
- 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/src/skf-rename-skill/references/rebuild-context.md +0 -110
|
@@ -22,32 +22,4 @@ Parse document section headers for technology groupings:
|
|
|
22
22
|
- `## Backend Core` → technologies in backend layer
|
|
23
23
|
- `## AI Layer` → AI-related technologies
|
|
24
24
|
|
|
25
|
-
**Mermaid Diagram Handling:** Do
|
|
26
|
-
|
|
27
|
-
### Coverage Verdict
|
|
28
|
-
|
|
29
|
-
The coverage matrix renders two verdict tokens per referenced technology: **Covered** and **Missing**. Extra skills (skills present in the inventory but NOT referenced by the architecture document) are tracked in a separate informational subdivision — they are not coverage verdicts and do not appear in the primary `Technology → Skill Match → Verdict` column. See step 2 §4 for the Extra-skill subdivision output.
|
|
30
|
-
|
|
31
|
-
| Verdict | Meaning |
|
|
32
|
-
|-------------|------------------------------------------------------------------|
|
|
33
|
-
| **Covered** | A generated skill exists in `skills/` for this technology |
|
|
34
|
-
| **Missing** | Technology is referenced in architecture doc but no skill exists |
|
|
35
|
-
|
|
36
|
-
**Informational — Extra skills subdivision (not a verdict; rendered in a separate section per step 2 §4):**
|
|
37
|
-
|
|
38
|
-
| Label | Meaning |
|
|
39
|
-
|----------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|
|
|
40
|
-
| **Extra (unreferenced)** | Skill exists with a resolvable `source_repo` / `source_root`, but no architecture tech token matches it |
|
|
41
|
-
| **Orphan (source_repo unresolvable)** | Skill's `source_repo` is empty, malformed, or its basename cannot be extracted — cross-reference against architecture impossible |
|
|
42
|
-
|
|
43
|
-
## Output Format
|
|
44
|
-
|
|
45
|
-
When presenting coverage results, use the following structure:
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
| Technology | Source Section | Skill Match | Verdict |
|
|
49
|
-
|------------|---------------|-------------|---------|
|
|
50
|
-
| {tech_name} | {section_heading} | {skill_name or '—'} | Covered / Missing |
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Include a summary line: `Coverage: {covered_count}/{total_count} ({percentage}%)`
|
|
25
|
+
**Mermaid Diagram Handling:** Do not parse Mermaid diagram syntax (`graph`, `flowchart`, `sequenceDiagram`, etc.) for technology detection — use only prose text (headings, paragraphs, lists, tables). If the architecture document appears to list technologies exclusively inside Mermaid diagrams, note this in the coverage results as a detection limitation and recommend the user add prose-based technology listings.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
nextStepFile: 'integrations.md'
|
|
3
3
|
coveragePatternsData: '{coveragePatternsPath}'
|
|
4
|
+
coverageTallyScript: 'scripts/skf-coverage-tally.py'
|
|
4
5
|
feasibilitySchemaProbeOrder:
|
|
5
6
|
- '{project-root}/_bmad/skf/shared/references/feasibility-report-schema.md'
|
|
6
7
|
- '{project-root}/src/shared/references/feasibility-report-schema.md'
|
|
@@ -66,7 +67,7 @@ For each referenced technology in the list:
|
|
|
66
67
|
4. Compare the resulting basenames/segments against the tech tokens via case-insensitive equality (no substring/fuzzy matching)
|
|
67
68
|
5. A match on either `source_repo` basename or `source_root` last segment counts as a hit
|
|
68
69
|
|
|
69
|
-
**Detect a deliberate-removal signal (from the architecture document):** Before assigning Covered/Missing, check whether the referenced technology is explicitly marked for removal or replacement in the architecture document itself. Be conservative — recognize a removal signal
|
|
70
|
+
**Detect a deliberate-removal signal (from the architecture document):** Before assigning Covered/Missing, check whether the referenced technology is explicitly marked for removal or replacement in the architecture document itself. Be conservative — recognize a removal signal only when one of these is present, and when in doubt leave it as a normal reference (a false removal signal silently drops a real coverage gap):
|
|
70
71
|
- The technology is listed under a section whose heading matches (case-insensitive) one of: "deprecated", "removed", "legacy", "migrating away", "being replaced", "to be removed", "sunset", "retiring".
|
|
71
72
|
- The technology's own mention carries an inline removal annotation, e.g. "(deprecated)", "(being replaced by …)", "(removing)", "(to be removed)", "(legacy)".
|
|
72
73
|
|
|
@@ -77,13 +78,19 @@ Record the cited section heading or annotation text as evidence for every techno
|
|
|
77
78
|
- **Replaced** — no matching skill exists AND a deliberate-removal signal (above) was found; the technology is intentionally being removed/replaced, so no skill should exist for it
|
|
78
79
|
- **Missing** — no matching skill found and no removal signal
|
|
79
80
|
|
|
80
|
-
**Replaced** technologies are EXCLUDED from the coverage denominator — they are not a gap to close. The denominator (`live_count`) is the count of referenced technologies that are **Covered** or **Missing**; **Replaced** technologies do not count toward it.
|
|
81
|
-
|
|
82
81
|
Build the coverage matrix as a structured table.
|
|
83
82
|
|
|
83
|
+
**Tally the matrix deterministically.** Assigning each verdict is judgment; counting the classes and computing the percentage has one correct answer, so delegate it. Serialize the matrix as `{"rows": [{"technology": "…", "verdict": "Covered|Missing|Replaced"}, …]}` and run:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
echo '<rows JSON>' | uv run {coverageTallyScript} --stdin
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The script (run `uv run {coverageTallyScript} --help` for the contract) returns `covered_count`, `missing_count`, `replaced_count`, `live_count` (the denominator — Covered + Missing, with Replaced excluded because a technology being removed is not a gap to close), `total_referenced`, and `coverage_percentage` (Replaced excluded from the denominator, half-up rounding pinned so the same matrix always yields the same integer). Consume these values in §5 and §6 rather than recomputing them. If `uv` is unavailable (e.g. claude.ai web), compute the same values inline per the `--help` contract: `live_count = covered + missing`; `coverage_percentage = round-half-up(covered / live_count * 100)`, or `0` when `live_count` is `0`.
|
|
90
|
+
|
|
84
91
|
### 4. Detect Extra Skills
|
|
85
92
|
|
|
86
|
-
Check if any skills in the inventory are
|
|
93
|
+
Check if any skills in the inventory are not referenced in the architecture document.
|
|
87
94
|
|
|
88
95
|
**Subdivide into two categories (both informational — not errors):**
|
|
89
96
|
- **Extra (unreferenced)** — The skill's `source_repo` / `source_root` resolves cleanly (both non-empty and well-formed), but no architecture document tech token matches it.
|
|
@@ -103,7 +110,7 @@ Extra and Orphan skills are informational only. They do not affect the coverage
|
|
|
103
110
|
|------------|---------------|-------------|---------|
|
|
104
111
|
| {tech_name} | {section_heading} | {skill_name or '—'} | {Covered / Missing / Replaced} |
|
|
105
112
|
|
|
106
|
-
**Coverage: {covered_count}/{live_count} ({
|
|
113
|
+
**Coverage: {covered_count}/{live_count} ({coverage_percentage}%)** (from the §3 tally; `live_count` excludes **Replaced** technologies)
|
|
107
114
|
|
|
108
115
|
{IF 100% coverage AND no Extra skills:}
|
|
109
116
|
**All referenced technologies have a matching skill. No extra skills detected.**
|
|
@@ -125,7 +132,7 @@ Extra and Orphan skills are informational only. They do not affect the coverage
|
|
|
125
132
|
|
|
126
133
|
### 6. Append to Report
|
|
127
134
|
|
|
128
|
-
**Resolve `{atomicWriteHelper}`** from `{atomicWriteProbeOrder}`; first existing path wins.
|
|
135
|
+
**Resolve `{atomicWriteHelper}`** from `{atomicWriteProbeOrder}`; first existing path wins. If no candidate exists: HALT (exit code 3, `halt_reason: "resolution-failure"`); in headless, emit the error envelope.
|
|
129
136
|
|
|
130
137
|
**Resolve `{feasibilitySchemaRef}`** from `{feasibilitySchemaProbeOrder}`; first existing path wins (installed SKF module path first, dev-checkout `src/` fallback).
|
|
131
138
|
|
|
@@ -133,9 +140,9 @@ Write the **Coverage Analysis** section to `{outputFile}` (see `{feasibilitySche
|
|
|
133
140
|
- Include the full coverage table
|
|
134
141
|
- Include coverage percentage
|
|
135
142
|
- Include missing skill recommendations
|
|
136
|
-
- Include the Replaced (being removed/replaced) subdivision from section 3, with the cited removal evidence — these are
|
|
143
|
+
- Include the Replaced (being removed/replaced) subdivision from section 3, with the cited removal evidence — these are not gaps and carry no [CS]/[QS] recommendation
|
|
137
144
|
- Include the Extra (unreferenced) and Orphan (source_repo unresolvable) subdivisions from section 4
|
|
138
|
-
- Update frontmatter: append `'coverage'` to `stepsCompleted`; set `coveragePercentage`
|
|
145
|
+
- Update frontmatter: append `'coverage'` to `stepsCompleted`; set `coveragePercentage` to the `coverage_percentage` value from the §3 tally (integer 0..100)
|
|
139
146
|
- Pipe the updated full content through `python3 {atomicWriteHelper} write --target {outputFile}` and again with `--target {outputFileLatest}`
|
|
140
147
|
|
|
141
148
|
### 7. Auto-Proceed to Next Step
|
|
@@ -147,7 +154,9 @@ Write the **Coverage Analysis** section to `{outputFile}` (see `{feasibilitySche
|
|
|
147
154
|
|
|
148
155
|
**Select:** [X] Halt workflow (recommended) | [C] Continue anyway"
|
|
149
156
|
|
|
150
|
-
-
|
|
157
|
+
**GATE [default: C]** — Interactive-only guard. If `{headless_mode}`: auto-proceed with [C] Continue, log: "headless: continuing past all-Replaced coverage gate (nothing live to verify)". Headless never takes [X], so step 6 still emits the result contract — the run resolves to `NOT_FEASIBLE` via the synthesize zero-coverage short-circuit.
|
|
158
|
+
|
|
159
|
+
- IF X: "**Workflow halted.** Coverage Analysis saved to `{outputFile}`. Update the architecture document and re-run [VS] when ready." HALT (exit code 8, `halt_reason: "analysis-halted"`).
|
|
151
160
|
- IF C: "**Continuing — the analysis covers only technologies marked for removal and will be limited.**" Load, read the full file and then execute `{nextStepFile}`.
|
|
152
161
|
|
|
153
162
|
{IF coveragePercentage is 0% AND live_count > 0:}
|
|
@@ -157,7 +166,9 @@ Write the **Coverage Analysis** section to `{outputFile}` (see `{feasibilitySche
|
|
|
157
166
|
|
|
158
167
|
**Select:** [X] Halt workflow (recommended) | [C] Continue anyway"
|
|
159
168
|
|
|
160
|
-
|
|
169
|
+
**GATE [default: C]** — Interactive-only guard. If `{headless_mode}`: auto-proceed with [C] Continue, log: "headless: continuing past 0%-coverage gate". Headless never takes [X], so step 6 still emits the result contract — the run resolves to `NOT_FEASIBLE` via the synthesize zero-coverage short-circuit.
|
|
170
|
+
|
|
171
|
+
- IF X: "**Workflow halted.** Coverage Analysis saved to `{outputFile}`. Generate skills and re-run [VS] when ready." HALT (exit code 8, `halt_reason: "analysis-halted"`).
|
|
161
172
|
- IF C: "**Continuing with 0% coverage — results will be limited.**"
|
|
162
173
|
|
|
163
174
|
Load, read the full file and then execute `{nextStepFile}`.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Exit Codes
|
|
2
|
+
|
|
3
|
+
Every hard halt in this workflow exits with a stable code so headless automators can branch on the failure class without grepping message text. Each code pairs with a `halt_reason` string carried in the headless result envelope.
|
|
4
|
+
|
|
5
|
+
| Code | Meaning | Raised by |
|
|
6
|
+
| ---- | -------------------- | -------------------------------------------------------------------------------------------- |
|
|
7
|
+
| 0 | success | step 7 (terminal) |
|
|
8
|
+
| 2 | input-missing / input-invalid | step 1 §1 (headless missing `architecture-doc` arg, or invalid path) → `input-missing`; non-existent file → `input-invalid` |
|
|
9
|
+
| 3 | resolution-failure | step 1 §2 (`{skills_output_folder}` does not exist or is empty → `skills-folder-missing`); step 1 §3 (forge_data_folder unconfigured → `forge-folder-unconfigured`); any stage that cannot resolve a required shared helper (atomic-write, schema ref, validate-feasibility-report) from its probe order → `resolution-failure` |
|
|
10
|
+
| 4 | write-failure | On-Activation §5 pre-flight write probe; step 1 §4 (atomic write of report skeleton failed); step 6 §4b (result-contract write failed) |
|
|
11
|
+
| 5 | state-conflict | step 1 §3 (fewer than 2 valid skills found — stack requires ≥2 → `insufficient-skills`); step 1 §1 (`previousReport` resolves to same inode as `{outputFile}` → `previous-report-collision`); step 6 §1 (report section order or schemaVersion mismatch → `schema-violation`) |
|
|
12
|
+
| 6 | user-cancelled | step 1 §1 prompt cancelled; any prompt that accepted `cancel`/`exit`/`:q`; step 6 menu cancelled |
|
|
13
|
+
| 7 | inventory-unreliable | step 1 §2 (>20% subagent failures or enumerate-stack-skills warnings exceed budget); step 3 §3 (>20% API-surface subagents return malformed JSON) |
|
|
14
|
+
| 8 | analysis-halted | coverage.md §7 & integrations.md §7 — user picks [X] at an elective vacuous-analysis gate. These gates are interactive-only; in headless they auto-continue, so exit 8 never fires headlessly and `analysis-halted` never appears in the result envelope. |
|
|
@@ -24,4 +24,4 @@ Chain to the shared workflow self-improvement health check at `{nextStepFile}`.
|
|
|
24
24
|
Attempt to load `{nextStepFile}`.
|
|
25
25
|
|
|
26
26
|
- **If `{nextStepFile}` loads successfully:** Read it fully, then execute it.
|
|
27
|
-
- **If `{nextStepFile}` cannot be resolved or loaded** (e.g., running against a partial installation, module root not resolvable, or the file has been removed): log exactly `health-check unavailable at {path}` (substitute the attempted resolved path) to the user-visible output and exit the workflow cleanly.
|
|
27
|
+
- **If `{nextStepFile}` cannot be resolved or loaded** (e.g., running against a partial installation, module root not resolvable, or the file has been removed): log exactly `health-check unavailable at {path}` (substitute the attempted resolved path) to the user-visible output and exit the workflow cleanly. This is not an error halt — the health check is an optional self-improvement hook, and the feasibility report (written in step 6) is the authoritative workflow output. Exiting cleanly keeps CI and headless runs from failing on a missing optional hook.
|
|
@@ -6,20 +6,15 @@ feasibilitySchemaProbeOrder:
|
|
|
6
6
|
atomicWriteProbeOrder:
|
|
7
7
|
- '{project-root}/_bmad/skf/shared/scripts/skf-atomic-write.py'
|
|
8
8
|
- '{project-root}/src/shared/scripts/skf-atomic-write.py'
|
|
9
|
-
# {outputFile} and {outputFileLatest} resolve from the activation-stored
|
|
10
|
-
# {project_slug}, {timestamp}, and {outputFolderPath} variables (set in
|
|
11
|
-
# SKILL.md On Activation §2 + §4). The activation-stored values are
|
|
12
|
-
# fixed for the entire run, so every later reference sees the same
|
|
13
|
-
# filename — no order-of-operations bug.
|
|
14
9
|
outputFile: '{outputFolderPath}/feasibility-report-{project_slug}-{timestamp}.md'
|
|
15
10
|
outputFileLatest: '{outputFolderPath}/feasibility-report-{project_slug}-latest.md'
|
|
16
11
|
# Resolve `{enumerateStackSkillsHelper}` by probing
|
|
17
12
|
# `{enumerateStackSkillsProbeOrder}` in order (installed SKF module path
|
|
18
13
|
# first, src/ dev-checkout fallback); first existing path wins. §2 calls
|
|
19
14
|
# it for the deterministic skills inventory (cascade-resolved exports,
|
|
20
|
-
# metadata-hash for change-detection, confidence-tier mapping).
|
|
21
|
-
#
|
|
22
|
-
#
|
|
15
|
+
# metadata-hash for change-detection, confidence-tier mapping). If neither
|
|
16
|
+
# candidate exists, §2 does NOT halt — it falls through to the LLM-driven
|
|
17
|
+
# subagent fan-out as graceful degradation (see §2).
|
|
23
18
|
enumerateStackSkillsProbeOrder:
|
|
24
19
|
- '{project-root}/_bmad/skf/shared/scripts/skf-enumerate-stack-skills.py'
|
|
25
20
|
- '{project-root}/src/shared/scripts/skf-enumerate-stack-skills.py'
|
|
@@ -67,10 +62,16 @@ Wait for user input. **GATE [default: use args]** — If `{headless_mode}` and `
|
|
|
67
62
|
|
|
68
63
|
**Validate previous report (if provided):**
|
|
69
64
|
- Confirm the file exists and is readable
|
|
70
|
-
- **Collision check:** Resolve `{outputFile}` from the activation-stored `{outputFolderPath}`, `{project_slug}`, and `{timestamp}
|
|
65
|
+
- **Collision check:** Resolve `{outputFile}` from the activation-stored `{outputFolderPath}`, `{project_slug}`, and `{timestamp}`. Then compare both the provided path and `{outputFile}` via `(st_dev, st_ino)` tuples obtained from `stat(2)` on each path (do not rely on absolute-path string equality — symlinks, bind mounts, and case-insensitive filesystems can defeat string comparison). If `{outputFile}` does not yet exist, resolve its parent via `realpath`, stat that directory, and combine `(st_dev, parent_ino, basename)` for comparison. If the two paths resolve to the same inode, warn: "The previous report path points to the same inode as the new report. This file will be overwritten during this run. Provide a path to a backup copy, or leave empty to skip delta comparison." HALT (exit code 5, `halt_reason: "previous-report-collision"`) until resolved. In headless, emit the error envelope.
|
|
71
66
|
- If missing → "Previous report not found at `{path}`. Proceeding without delta comparison."
|
|
72
67
|
- Store as `previousReport: {path}` (or empty string if not provided)
|
|
73
68
|
|
|
69
|
+
**Auto-discover a prior report (only when none was provided above):** If neither `--previous-report` nor an interactive previous-report path was given, glob `{outputFolderPath}` for `feasibility-report-{project_slug}-*.md`, excluding this run's `{timestamp}` file and `feasibility-report-{project_slug}-latest.md`. Every run writes a new timestamped report, so a usable prior usually already persists on disk with no manual backup. If one or more matches remain, pick the most recent by the embedded `YYYYMMDD-HHmmss` timestamp:
|
|
70
|
+
- Interactive: offer "Found a prior report from `{date}` — compare against it? **[Y]** use it / paste a different path / **[skip]**". On [Y], set `previousReport` to that path; on a pasted path, use it; on `skip`, leave `previousReport` empty.
|
|
71
|
+
- **GATE [default: Y]** — If `{headless_mode}`: auto-select the most recent match, set `previousReport` to it, log: "headless: delta comparison against `{path}`".
|
|
72
|
+
- Excluding this run's `{timestamp}` and `-latest` files guarantees the auto-selected path is a distinct inode from `{outputFile}`, so it can never trip the collision check above.
|
|
73
|
+
- If no match remains, leave `previousReport` empty — first run, no delta.
|
|
74
|
+
|
|
74
75
|
### 2. Scan Skills Folder
|
|
75
76
|
|
|
76
77
|
**Pre-flight — skills folder existence:**
|
|
@@ -82,18 +83,20 @@ Wait for user input. **GATE [default: use args]** — If `{headless_mode}` and `
|
|
|
82
83
|
**Primary path — deterministic enumeration via shared helper:**
|
|
83
84
|
|
|
84
85
|
```bash
|
|
85
|
-
python3 {enumerateStackSkillsHelper} enumerate {skills_output_folder}
|
|
86
|
+
python3 {enumerateStackSkillsHelper} enumerate {skills_output_folder} --reliability
|
|
86
87
|
```
|
|
87
88
|
|
|
88
89
|
The helper walks `{skills_output_folder}`, reads each `metadata.json`, applies the exports cascade (metadata → references/ → SKILL.md prose), maps `confidence_tier` (T1/T2/T1-low), captures stack-skill cycles via `composes:`, and emits structured JSON with one entry per skill plus a top-level `warnings[]` array. Cache the result as `skill_inventory` (used by §3, §4, §5, and the integrations + coverage stages).
|
|
89
90
|
|
|
90
91
|
Each helper-emitted entry includes: `skill_name`, `version`, `language`, `confidence_tier`, `exports` (cascade-resolved), `source_repo`, `source_root`, plus a `metadata_hash` for change-detection across runs. The helper's `warnings[]` carries per-skill skip reasons (missing manifest, malformed JSON, non-symlink `active`, orphan-versions, schema-version violations).
|
|
91
92
|
|
|
92
|
-
|
|
93
|
+
`--reliability` additionally attaches the inventory reliability verdict: `inventory_reliable` (bool), `unreliable_ratio` (float), `skill_count`, and `warning_count`.
|
|
94
|
+
|
|
95
|
+
**Failure-budget guard:** Read `inventory_reliable` from the helper JSON. If it is `false`, HALT (exit code 7, `halt_reason: "inventory-unreliable"`) with: "Inventory scan unreliable — {warning_count}/{skill_count + warning_count} skills returned malformed metadata or skip warnings. Re-run [VS] after skills stabilize." (substitute `warning_count` and `skill_count + warning_count` from the helper JSON). In headless, emit the error envelope. The helper's threshold is chosen so a single malformed skill in a small 3-5 skill inventory does not trip the halt.
|
|
93
96
|
|
|
94
97
|
**Capture mtime:** For each accepted skill in `skill_inventory`, also record `metadata.json`'s mtime via `stat` into the entry as `metadata_mtime`. Step-03 will re-verify this to detect mid-run modifications.
|
|
95
98
|
|
|
96
|
-
**Fallback path — graceful degradation when the helper is unavailable:** If `{enumerateStackSkillsHelper}` has no existing candidate (e.g. partial installation), fall through to the LLM-driven subagent fan-out: launch up to **8 subagents concurrently**, each reading one resolved skill package's `metadata.json` and returning the same JSON shape the helper would emit.
|
|
99
|
+
**Fallback path — graceful degradation when the helper is unavailable:** If `{enumerateStackSkillsHelper}` has no existing candidate (e.g. partial installation), fall through to the LLM-driven subagent fan-out: launch up to **8 subagents concurrently**, each reading one resolved skill package's `metadata.json` and returning the same JSON shape the helper would emit. In this branch `inventory_reliable` is unavailable, so compute the failure-budget guard inline: when `warning_count / (skill_count + warning_count) > 0.20`, HALT (exit code 7, `halt_reason: "inventory-unreliable"`) with the same message as the primary path. In headless, emit the error envelope.
|
|
97
100
|
|
|
98
101
|
### 3. Validate Minimum Requirements
|
|
99
102
|
|
|
@@ -107,23 +110,15 @@ Each helper-emitted entry includes: `skill_name`, `version`, `language`, `confid
|
|
|
107
110
|
- If undefined or empty → "**Cannot proceed.** `forge_data_folder` is not configured in config.yaml. Re-run [SF] Setup Forge to initialize."
|
|
108
111
|
- HALT (exit code 3, `halt_reason: "forge-folder-unconfigured"`). In headless, emit the error envelope.
|
|
109
112
|
|
|
110
|
-
**Check architecture document:**
|
|
111
|
-
- Confirm it was loaded successfully in section 1
|
|
112
|
-
- If not → HALT with error (should not reach here if section 1 validation passed)
|
|
113
|
-
|
|
114
113
|
### 4. Create Feasibility Report
|
|
115
114
|
|
|
116
|
-
**Resolve `{atomicWriteHelper}`** from `{atomicWriteProbeOrder}`; first existing path wins.
|
|
115
|
+
**Resolve `{atomicWriteHelper}`** from `{atomicWriteProbeOrder}`; first existing path wins. If no candidate exists: HALT (exit code 3, `halt_reason: "resolution-failure"`); in headless, emit the error envelope.
|
|
117
116
|
|
|
118
|
-
**Resolve `{feasibilitySchemaRef}`** from `{feasibilitySchemaProbeOrder}`; first existing path wins (installed SKF module path first, dev-checkout `src/` fallback).
|
|
117
|
+
**Resolve `{feasibilitySchemaRef}`** from `{feasibilitySchemaProbeOrder}`; first existing path wins (installed SKF module path first, dev-checkout `src/` fallback). If no candidate exists: HALT (exit code 3, `halt_reason: "resolution-failure"`); in headless, emit the error envelope.
|
|
119
118
|
|
|
120
|
-
This skill
|
|
119
|
+
This skill produces the feasibility report schema defined in `{feasibilitySchemaRef}`; every output conforms to that schema — `schemaVersion: "1.0"`, the verdict token set (`Verified|Plausible|Risky|Blocked`; overall `FEASIBLE|CONDITIONALLY_FEASIBLE|NOT_FEASIBLE`), the filename pattern, and the section-heading order.
|
|
121
120
|
|
|
122
|
-
**Filename variables
|
|
123
|
-
- `project_slug`: set in SKILL.md On Activation §2 from `project_name`
|
|
124
|
-
- `timestamp`: set in SKILL.md On Activation §2 (UTC `YYYYMMDD-HHmmss`, fixed for the run)
|
|
125
|
-
- `outputFile` resolves to `{outputFolderPath}/feasibility-report-{project_slug}-{timestamp}.md` per the stage frontmatter template
|
|
126
|
-
- `outputFileLatest` resolves to `{outputFolderPath}/feasibility-report-{project_slug}-latest.md` (a copy, not a symlink — per schema)
|
|
121
|
+
**Filename variables:** `project_slug` and `timestamp` were fixed at activation per SKILL.md On Activation §2; reuse them, do not re-derive. `{outputFile}` and `{outputFileLatest}` resolve from them per the stage frontmatter template — the latter a copy, not a symlink (per schema).
|
|
127
122
|
|
|
128
123
|
**Load** `{reportTemplatePath}` (the customize-aware template path resolved in SKILL.md On Activation §4) and stage the initial content. Substitute the template's `Schema contract:` line `{feasibilitySchemaRef}` placeholder with the resolved schema path so every emitted report cites a path that exists on the running machine.
|
|
129
124
|
|
|
@@ -145,7 +140,7 @@ This skill is the PRODUCER of the feasibility report schema defined in `{feasibi
|
|
|
145
140
|
- `skillsAnalyzed: {count}`
|
|
146
141
|
- `stepsCompleted: ['init']`
|
|
147
142
|
|
|
148
|
-
**Atomic write:** Pipe the staged content through `python3 {atomicWriteHelper} write --target {outputFile}` and then again with `--target {outputFileLatest}`. Both writes use the same staged content
|
|
143
|
+
**Atomic write:** Pipe the staged content through `python3 {atomicWriteHelper} write --target {outputFile}` and then again with `--target {outputFileLatest}`. Both writes use the same staged content through the atomic helper — a plain `rm`+rewrite risks a partial write corrupting the report, and the `-latest` file is a copy, not a symlink (per the shared schema).
|
|
149
144
|
|
|
150
145
|
On any non-zero exit from either write: HALT (exit code 4, `halt_reason: "write-failed"`) and emit the error envelope per SKILL.md "Result Contract (Headless)" with `report_path: null`, `report_latest_path: null`, `overall_verdict: null`.
|
|
151
146
|
|
|
@@ -12,9 +12,9 @@ Token set is defined canonically in the SKF shared feasibility report schema (`_
|
|
|
12
12
|
|
|
13
13
|
| Verdict | Meaning | Required Evidence |
|
|
14
14
|
|---------------|------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
15
|
-
| **Verified** | APIs demonstrably connect
|
|
15
|
+
| **Verified** | APIs demonstrably connect and docs cross-reference each other | Check 1 (language) passes with declared evidence; Check 3 (types) passes from cited `exports` signatures; **Check 4 (docs cross-reference) passes with a literal substring/name citation** — without Check 4 evidence, cap at `Plausible`. Check 2 is best-effort only and cannot by itself promote to `Verified`. |
|
|
16
16
|
| **Plausible** | Checks pass but rely on inferred or indirect evidence | Language + type checks pass; Check 2 uses inferred `protocols_inferred`/`data_formats_inferred` (prose scan); Check 4 is weak or missing (no literal cross-reference). This is the mandatory cap whenever Check 4 does not surface a literal citation. |
|
|
17
|
-
| **Risky** | Type mismatch, protocol gap, or language boundary requiring a bridge | A clear gap exists (e.g., TypeScript↔Rust FFI needed) but a workaround is architecturally feasible — a named workaround
|
|
17
|
+
| **Risky** | Type mismatch, protocol gap, or language boundary requiring a bridge | A clear gap exists (e.g., TypeScript↔Rust FFI needed) but a workaround is architecturally feasible — cite a named workaround in the recommendation |
|
|
18
18
|
| **Blocked** | Fundamental incompatibility — no feasible integration path even with a bridge or adapter layer | The two libraries cannot exchange data in any documented way; requires replacing one of the libraries |
|
|
19
19
|
|
|
20
20
|
**Promotion rule:** `Verified` requires Check 4 evidence. If Checks 1 and 3 pass but Check 4 fails (no literal substring/name citation from either skill's SKILL.md), the verdict is capped at `Plausible`. This rule is enforced by step 3 §4 and is the producer obligation declared in the shared schema.
|
|
@@ -27,22 +27,13 @@ For each integration pair (Library A ↔ Library B):
|
|
|
27
27
|
|
|
28
28
|
### 1. Language Boundary Check
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
| Same language | Same language | No boundary — direct API calls possible |
|
|
33
|
-
| TypeScript ↔ Rust | Requires FFI, IPC, or WebSocket bridge | Check if a bridge library exists in the stack (e.g., Tauri provides JS↔Rust IPC) |
|
|
34
|
-
| TypeScript ↔ Python | Requires REST/gRPC/WebSocket bridge | Typically not direct |
|
|
35
|
-
| Any ↔ C/C++ | FFI available in most languages | Check for bindings |
|
|
30
|
+
- Same language on both sides → no boundary, direct API calls. Different languages → the integration needs a bridge (FFI, IPC, or a network protocol; the mechanism follows from the pair — e.g. C/C++ exposes FFI most languages can bind).
|
|
31
|
+
- The load-bearing nudge: **check whether a bridge library already exists in the stack** before assuming one must be built (e.g., Tauri provides JS↔Rust IPC).
|
|
36
32
|
|
|
37
33
|
### 2. Protocol Compatibility Check
|
|
38
34
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
| In-process (same runtime) | In-process | Direct — function calls |
|
|
42
|
-
| HTTP/REST | HTTP/REST | Network bridge — compatible if API endpoints match |
|
|
43
|
-
| WebSocket | WebSocket | Real-time bridge — check message format compatibility |
|
|
44
|
-
| Shared filesystem | Shared filesystem | Async — check format compatibility |
|
|
45
|
-
| Embedded database | Embedded database | May conflict on lock files — check for multi-writer support |
|
|
35
|
+
- Matching transports are compatible modulo format alignment: both in-process → direct calls; both HTTP/REST → compatible if endpoints match; both WebSocket → check message-format compatibility; both shared-filesystem → async, check format.
|
|
36
|
+
- The load-bearing nudge: **two embedded databases may conflict on lock files — check for multi-writer support** before treating them as compatible.
|
|
46
37
|
|
|
47
38
|
### 3. Type Compatibility Check
|
|
48
39
|
|
|
@@ -54,15 +45,15 @@ For each integration pair (Library A ↔ Library B):
|
|
|
54
45
|
|
|
55
46
|
- Search Skill A's SKILL.md for a literal substring/name citation of Library B
|
|
56
47
|
- Search Skill B's SKILL.md for the reciprocal citation
|
|
57
|
-
- Accept literal names or aliases declared in that skill's metadata;
|
|
58
|
-
- A pass requires at least one literal citation in at least one direction; the exact substring and location
|
|
59
|
-
- If neither skill literally cites the other, Check 4
|
|
48
|
+
- Accept literal names or aliases declared in that skill's metadata; a paraphrase or fuzzy match does not satisfy Check 4
|
|
49
|
+
- A pass requires at least one literal citation in at least one direction; record the exact substring and location in the evidence block
|
|
50
|
+
- If neither skill literally cites the other, Check 4 fails and the per-pair verdict caps at `Plausible` (not `Verified`)
|
|
60
51
|
|
|
61
52
|
---
|
|
62
53
|
|
|
63
54
|
## Verdict Evidence Format
|
|
64
55
|
|
|
65
|
-
Each verdict
|
|
56
|
+
Each verdict includes:
|
|
66
57
|
|
|
67
58
|
```
|
|
68
59
|
**{Library A} ↔ {Library B}: {VERDICT}**
|
|
@@ -8,6 +8,9 @@ feasibilitySchemaProbeOrder:
|
|
|
8
8
|
atomicWriteProbeOrder:
|
|
9
9
|
- '{project-root}/_bmad/skf/shared/scripts/skf-atomic-write.py'
|
|
10
10
|
- '{project-root}/src/shared/scripts/skf-atomic-write.py'
|
|
11
|
+
cycleFinderProbeOrder:
|
|
12
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-find-cycles.py'
|
|
13
|
+
- '{project-root}/src/shared/scripts/skf-find-cycles.py'
|
|
11
14
|
outputFile: '{outputFolderPath}/feasibility-report-{project_slug}-{timestamp}.md'
|
|
12
15
|
outputFileLatest: '{outputFolderPath}/feasibility-report-{project_slug}-latest.md'
|
|
13
16
|
---
|
|
@@ -48,7 +51,7 @@ Parse the architecture document for statements describing two or more technologi
|
|
|
48
51
|
- Look for data flow descriptions: "{A} sends data to {B}", "{A} results are consumed by {B}"
|
|
49
52
|
- Look for layer boundary descriptions: "{A} at the API layer connects to {B} at the data layer"
|
|
50
53
|
|
|
51
|
-
**
|
|
54
|
+
**Mermaid Diagram Handling:** See `{coveragePatternsData}` → "Mermaid Diagram Handling" for the canonical rule (single source of truth). Summary: do not parse Mermaid diagram syntax for co-mention detection; use only prose text.
|
|
52
55
|
|
|
53
56
|
**Build integration pairs list:**
|
|
54
57
|
- Each pair: `{library_a, library_b, architectural_context}`
|
|
@@ -60,10 +63,10 @@ Parse the architecture document for statements describing two or more technologi
|
|
|
60
63
|
|
|
61
64
|
<!-- Subagent delegation: read SKILL.md files in parallel, return compact JSON -->
|
|
62
65
|
|
|
63
|
-
For each library in an integration pair, delegate SKILL.md reading to a parallel subagent. Launch up to **8 subagents concurrently** (batch if needed — same 8-way cap as step 1 §2; keeps aggregate token window manageable while still parallelizing typical stack sizes). Each subagent receives one skill's SKILL.md path and
|
|
64
|
-
1.
|
|
65
|
-
2.
|
|
66
|
-
3.
|
|
66
|
+
For each library in an integration pair, delegate SKILL.md reading to a parallel subagent. Launch up to **8 subagents concurrently** (batch if needed — same 8-way cap as step 1 §2; keeps aggregate token window manageable while still parallelizing typical stack sizes). Each subagent receives one skill's SKILL.md path and:
|
|
67
|
+
1. Reads the SKILL.md file
|
|
68
|
+
2. Extracts the API surface
|
|
69
|
+
3. Returns only this compact JSON — no prose, no extra commentary:
|
|
67
70
|
|
|
68
71
|
```json
|
|
69
72
|
{
|
|
@@ -78,13 +81,13 @@ For each library in an integration pair, delegate SKILL.md reading to a parallel
|
|
|
78
81
|
**Extraction rules for subagents:**
|
|
79
82
|
- `skill_name`, `language`: mirror the skill's metadata fields
|
|
80
83
|
- `exports`: exported functions with signatures, exported types/interfaces/classes (extracted from SKILL.md prose)
|
|
81
|
-
- `protocols_inferred`: best-effort prose scan — protocol tokens mentioned in SKILL.md descriptions/examples
|
|
82
|
-
- `data_formats_inferred`: best-effort prose scan — format tokens mentioned in SKILL.md descriptions/examples
|
|
84
|
+
- `protocols_inferred`: best-effort prose scan — protocol tokens mentioned in SKILL.md descriptions/examples; not a declared field in `metadata.json`
|
|
85
|
+
- `data_formats_inferred`: best-effort prose scan — format tokens mentioned in SKILL.md descriptions/examples; not a declared field in `metadata.json`
|
|
83
86
|
- If a field has no matches, return an empty array `[]`
|
|
84
87
|
|
|
85
|
-
**
|
|
88
|
+
**These fields are inferred, not declared.** `protocols` and `data_formats` do not exist in any skill's `metadata.json` — treat them as weak evidence from prose scanning only. When either list is used to justify compatibility in Check 2, cap the per-pair verdict at `Plausible` (see the schema's producer obligations — `{feasibilitySchemaRef}`).
|
|
86
89
|
|
|
87
|
-
**Schema validation (parent):** Each subagent response must contain the required keys (`skill_name`, `language`, `exports`). Reject responses missing required keys and exclude that skill from pair evaluation;
|
|
90
|
+
**Schema validation (parent):** Each subagent response must contain the required keys (`skill_name`, `language`, `exports`). Reject responses missing required keys and exclude that skill from pair evaluation; if more than **20%** (same failure-budget threshold as step 1 §2; see the justification there) of subagent calls return malformed JSON, HALT (exit code 7, `halt_reason: "inventory-unreliable"`) with "API-surface extraction unreliable — more than 20% of subagent reads returned malformed JSON. Re-run [VS] after skills stabilize." In headless, emit the error envelope.
|
|
88
91
|
|
|
89
92
|
**Parent collects all subagent JSON summaries.** Do not load full SKILL.md content into parent context.
|
|
90
93
|
|
|
@@ -98,48 +101,35 @@ For each library in an integration pair, delegate SKILL.md reading to a parallel
|
|
|
98
101
|
|
|
99
102
|
Store collected API surface summaries for cross-referencing.
|
|
100
103
|
|
|
101
|
-
**Integration-evidence source preference:** If the stack was assembled by `skf-create-stack-skill` and a stack manifest (e.g., `integration_patterns` block in the stack skill's `bmad-skill-manifest.yaml` or `metadata.json`) is present in the inventory, use that as the authoritative integration source and cite `source: stack manifest` in each verdict. Fall back to prose co-mention only when no manifest is available, and cite `source: prose co-mention`.
|
|
102
|
-
|
|
103
104
|
### 4. Cross-Reference Each Integration Pair
|
|
104
105
|
|
|
105
|
-
For each integration pair `{library_a, library_b}`,
|
|
106
|
-
|
|
107
|
-
**Check
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
- If no bridge mechanism documented → flag as risk
|
|
111
|
-
|
|
112
|
-
**Check 2 — Protocol Compatibility (best-effort prose scan):**
|
|
113
|
-
- Uses only the `protocols_inferred` / `data_formats_inferred` lists surfaced by the subagent prose scan — these are NOT declared metadata fields
|
|
114
|
-
- Both prose-scanned lists share a protocol token → treat as inferred compatibility (cap verdict at `Plausible`)
|
|
115
|
-
- Complementary tokens (e.g., "HTTP client" in one, "HTTP server" in the other) → inferred compatibility (cap at `Plausible`)
|
|
116
|
-
- Neither skill surfaces any protocol token, or tokens appear to conflict with no adapter mentioned → flag as risk
|
|
117
|
-
- Do NOT assert that protocols come from a declared schema field; when prose evidence is all that's available, the per-pair verdict MUST cap at `Plausible`
|
|
118
|
-
|
|
119
|
-
**Check 3 — Type Compatibility:**
|
|
120
|
-
- Shared types or compatible serialization formats (cited from `exports` signatures) → compatible
|
|
121
|
-
- Incompatible type systems with no conversion layer → flag as risk
|
|
122
|
-
|
|
123
|
-
**Check 4 — Documentation Cross-Reference (REQUIRED for `Verified`):**
|
|
124
|
-
- Search Skill A's SKILL.md for a literal substring/name citation of Skill B's library name (or an explicit alias declared in that skill's metadata)
|
|
125
|
-
- Search Skill B's SKILL.md for the reciprocal citation
|
|
126
|
-
- If a literal citation is found in at least one direction → Check 4 PASSES; record the exact cited substring and its location as evidence
|
|
127
|
-
- If neither skill literally cites the other → Check 4 FAILS (weak/missing evidence); per-pair verdict MUST be capped at `Plausible` regardless of Checks 1–3 outcomes
|
|
128
|
-
|
|
129
|
-
**Assign verdict per pair (per `{feasibilitySchemaRef}`):**
|
|
130
|
-
- **Verified** — Checks 1, 3 pass with declared evidence AND Check 4 passes with a literal substring/name citation recorded in the evidence block. Check 2 is best-effort only; it cannot by itself promote a pair to `Verified`.
|
|
131
|
-
- **Plausible** — Checks pass, but at least one relies on inferred evidence (e.g., Check 2 prose scan) OR Check 4 is weak/missing. This is the cap whenever Check 4 fails.
|
|
132
|
-
- **Risky** — At least one check flags an incompatibility that a workaround may resolve (bridge layer, adapter, serialization shim).
|
|
133
|
-
- **Blocked** — Fundamental incompatibility: language barrier with no bridge documented anywhere in the inventory, or type/protocol mismatch with no adapter mentioned.
|
|
134
|
-
|
|
135
|
-
**Each verdict MUST include:**
|
|
106
|
+
For each integration pair `{library_a, library_b}`, run the four-check protocol and assign the per-pair verdict per `{integrationRulesData}` (loaded in §1): the Cross-Reference Protocol defines Check 1 (language boundary), Check 2 (protocol compatibility), Check 3 (type compatibility), and Check 4 (documentation cross-reference, required for `Verified`); the Verdict Definitions table and promotion rule define the `Verified` / `Plausible` / `Risky` / `Blocked` thresholds and the cap-at-`Plausible` rule that applies whenever Check 4 surfaces no literal citation. Do not restate those mechanics here.
|
|
107
|
+
|
|
108
|
+
**Step-specific input for Check 2:** Check 2 draws only on the `protocols_inferred` / `data_formats_inferred` lists surfaced by the §3 subagent prose scan. A shared or complementary token (e.g., "HTTP client" ↔ "HTTP server") reads as inferred compatibility; no token on either side, or conflicting tokens with no adapter, flags a risk. Any pair whose compatibility rests on this inferred evidence caps at `Plausible` per §3.
|
|
109
|
+
|
|
110
|
+
**Each verdict includes:**
|
|
136
111
|
- Which checks passed and which flagged
|
|
137
112
|
- Evidence citations: specific exports, types, or literal substrings from the skills
|
|
138
|
-
- `source: stack manifest` or `source: prose co-mention` tag (per section
|
|
113
|
+
- `source: stack manifest` or `source: prose co-mention` tag (per section 2)
|
|
139
114
|
- For `Verified`: the exact Check 4 literal citation (e.g., `"see also: {lib_b}"` quoted from Skill A's SKILL.md, line N)
|
|
140
115
|
- **Tier annotation:** For each contributing skill, append `(evidence from Tier {n} skill)` citing that skill's `confidence_tier` (e.g., `(evidence from Tier 1 skill)`). This lets reviewers weigh evidence strength by extraction confidence.
|
|
141
116
|
|
|
142
|
-
**Cycle detection (after all pairs evaluated):**
|
|
117
|
+
**Cycle detection (after all pairs evaluated):** Deciding the edge set is a Check-4 judgment and stays here; the traversal is deterministic and is delegated to the shared helper (the in-prose DFS misses real multi-hop cycles or invents spurious ones as the pair count grows).
|
|
118
|
+
|
|
119
|
+
1. **Build the directed pair graph in the prompt:** an edge `A → B` exists when skill A literally cites skill B via Check 4. Serialize the edges as JSON: `{"edges": [["A", "B"], ["B", "C"], ...]}` (each `[from, to]` pair is one Check-4 citation direction).
|
|
120
|
+
2. **Resolve `{cycleFinderHelper}`** from `{cycleFinderProbeOrder}`; first existing path wins. Enumerate cycles deterministically (run `uv run {cycleFinderHelper} find --help` for the contract):
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
uv run {cycleFinderHelper} find --edges -
|
|
124
|
+
```
|
|
125
|
+
piping the edges JSON on stdin (use a temp file under `{forge_data_folder}/` if stdin piping is unavailable). The script emits:
|
|
126
|
+
```json
|
|
127
|
+
{"cycles": [["A", "B", "C", "A"], ...], "cycle_count": N}
|
|
128
|
+
```
|
|
129
|
+
Each `cycles[]` entry is a closed node path (first node repeated at the end); every simple directed cycle appears exactly once, de-duplicated across rotations.
|
|
130
|
+
|
|
131
|
+
**Graceful degradation:** if no `{cycleFinderProbeOrder}` candidate exists (e.g. `uv` unavailable on claude.ai web), run the equivalent DFS (visited set + recursion stack) directly per the `--help` contract and proceed with the same cycle set.
|
|
132
|
+
3. **For each cycle** in `cycles[]`, append a synthetic row to the verdict table with verdict `Risky` and rationale "circular integration dependency detected: `{A → B → C → A}`" (render the arrow chain from the cycle's node path). Do not otherwise modify the individual pair verdicts.
|
|
143
133
|
|
|
144
134
|
### 5. Display Integration Results
|
|
145
135
|
|
|
@@ -166,18 +156,23 @@ For each integration pair `{library_a, library_b}`, apply the verification proto
|
|
|
166
156
|
|
|
167
157
|
### 6. Append to Report
|
|
168
158
|
|
|
169
|
-
**Resolve `{atomicWriteHelper}`** from `{atomicWriteProbeOrder}`; first existing path wins.
|
|
159
|
+
**Resolve `{atomicWriteHelper}`** from `{atomicWriteProbeOrder}`; first existing path wins. If no candidate exists: HALT (exit code 3, `halt_reason: "resolution-failure"`); in headless, emit the error envelope.
|
|
170
160
|
|
|
171
|
-
Write the **Integration Verdicts** section to `{outputFile}` (heading is fixed — consumers grep for `## Integration Verdicts`; the table header
|
|
172
|
-
- Emit the canonical `| lib_a | lib_b | verdict | rationale |` table first (verdict tokens
|
|
161
|
+
Write the **Integration Verdicts** section to `{outputFile}` (heading is fixed — consumers grep for `## Integration Verdicts`; the table header is the canonical `| lib_a | lib_b | verdict | rationale |` per `{feasibilitySchemaRef}`, and consumers parse that exact header, so a different one breaks them; the skill-local display table with the extra Context/Source/Evidence columns can be rendered beneath it for human readers):
|
|
162
|
+
- Emit the canonical `| lib_a | lib_b | verdict | rationale |` table first (verdict tokens are exactly one of `Verified`, `Plausible`, `Risky`, `Blocked`, case-sensitive — any other token is a schema violation consumers reject)
|
|
173
163
|
- Include the extended table with Context, Source, and Evidence columns below it
|
|
174
|
-
- Include recommendations for Risky and Blocked pairs (Blocked
|
|
164
|
+
- Include recommendations for Risky and Blocked pairs (each Blocked recommendation cites a named candidate per step 5 H6, or the explicit no-candidate notice)
|
|
175
165
|
- Update frontmatter: append `'integrations'` to `stepsCompleted`; set `pairsVerified`, `pairsPlausible`, `pairsRisky`, `pairsBlocked` counts
|
|
176
166
|
- Pipe the updated full content through `python3 {atomicWriteHelper} write --target {outputFile}` and again with `--target {outputFileLatest}`
|
|
177
167
|
|
|
178
168
|
### 7. Auto-Proceed to Next Step
|
|
179
169
|
|
|
180
|
-
**Early halt guard:** If ALL integration pairs are Blocked, present: "**All integrations are Blocked** — fundamental incompatibilities detected across all library pairs. Remaining analysis will produce limited value. **[X] Halt workflow (recommended)** | **[C] Continue anyway**" — wait for user input.
|
|
170
|
+
**Early halt guard:** If ALL integration pairs are Blocked, present: "**All integrations are Blocked** — fundamental incompatibilities detected across all library pairs. Remaining analysis will produce limited value. **[X] Halt workflow (recommended)** | **[C] Continue anyway**" — wait for user input.
|
|
171
|
+
|
|
172
|
+
**GATE [default: C]** — Interactive-only guard. If `{headless_mode}`: auto-proceed with [C] Continue, log: "headless: continuing past all-Blocked integration gate". Headless never takes [X], so step 6 still emits the result contract — any Blocked pair resolves the run to `NOT_FEASIBLE` in synthesize.
|
|
173
|
+
|
|
174
|
+
- If X: halt with: "**Workflow halted — all integrations blocked.** Integration Verdicts saved to `{outputFile}`. Run **[VS]** after applying architectural changes. **Blocked integrations:** {list each blocked pair with reason}." HALT (exit code 8, `halt_reason: "analysis-halted"`).
|
|
175
|
+
- If C: continue.
|
|
181
176
|
|
|
182
177
|
{IF NOT halted (user selected C, or early halt guard did not trigger):}
|
|
183
178
|
|