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
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
nextStepFile: 'step-doc-sources.md'
|
|
3
3
|
skillSectionsData: 'assets/skill-sections.md'
|
|
4
4
|
assemblyRulesData: 'assets/compile-assembly-rules.md'
|
|
5
|
+
# Resolve `{renderMetadataStatsHelper}` by probing `{renderMetadataStatsProbeOrder}`
|
|
6
|
+
# in order (installed SKF module path first, src/ dev-checkout fallback); first
|
|
7
|
+
# existing path wins. HALT if neither resolves — the metadata `stats` block and
|
|
8
|
+
# `confidence_distribution` are computed values that must not be hand-binned
|
|
9
|
+
# (the historical 147 ≠ 59 miscount lived exactly here).
|
|
10
|
+
renderMetadataStatsProbeOrder:
|
|
11
|
+
- '{project-root}/_bmad/skf/shared/scripts/skf-render-metadata-stats.py'
|
|
12
|
+
- '{project-root}/src/shared/scripts/skf-render-metadata-stats.py'
|
|
5
13
|
---
|
|
6
14
|
|
|
7
15
|
<!-- Config: communicate in {communication_language}. -->
|
|
@@ -44,33 +52,29 @@ This is the `<staging-skill-dir>` referenced by step 6 (`npx skill-check check`,
|
|
|
44
52
|
**When assembling function signatures, parameter lists, and return types in any SKILL.md section or reference file:**
|
|
45
53
|
|
|
46
54
|
- **T1 provenance-map entries (AST-extracted) are authoritative** for: function name, parameter names, parameter types, parameter order, return type, and optionality markers (e.g., `?`, `Optional`, `= default`).
|
|
47
|
-
- **T2 (QMD-enriched) and T3 (doc-derived) sources may
|
|
55
|
+
- **T2 (QMD-enriched) and T3 (doc-derived) sources may add** contextual descriptions, usage notes, behavioral documentation, and examples to function entries, but must not replace structural signature data from T1 entries.
|
|
48
56
|
- **On conflict:** If a T2/T3 source provides a different signature than the T1 extraction for the same export (e.g., different parameter count, different types, missing `Partial<>` wrapper), keep the T1 signature and log a warning in the evidence report: "Signature conflict for `{export_name}`: T1 shows `{t1_signature}`, T2/T3 shows `{other_signature}`. T1 used as authoritative."
|
|
49
57
|
- **`signature_source` field:** Record `signature_source: "T1" | "T1-low" | "T2" | "T3"` in each provenance-map entry to indicate the highest-confidence tier that contributed the structural signature data (params, return_type). This enables test-skill to verify signature provenance.
|
|
50
58
|
|
|
51
|
-
This rule applies to
|
|
59
|
+
This rule applies to every section including Tier 1 Key API Summary, Tier 2 Full API Reference, and Section 4b Migration & Deprecation Warnings.
|
|
52
60
|
|
|
53
61
|
### 2. Build SKILL.md Content
|
|
54
62
|
|
|
55
63
|
Assemble each section in order using the assembly rules data file (`{assemblyRulesData}`). The data file specifies frontmatter format, Tier 1 section details (Sections 1-8, including conditional Section 7b for scripts/assets), Tier 2 section details (Sections 9-11), and assembly ordering rules. Follow it exactly. Assemble Section 7b (Scripts & Assets) only if `scripts_inventory` or `assets_inventory` is non-empty.
|
|
56
64
|
|
|
65
|
+
**Shape-specific overrides:** the assembly-rules file defines gated override blocks for `component-library`, `reference-app`, and **whole-language reference** skills. Apply the override whose gate matches this brief. A whole-language reference is gated on `assembly_shape: "whole-language-reference"` (a `doc_urls` entry with `source: language-registry`, as step 3c §1 determined and as `skf-derive-assembly-shape.py` reports) and uses the `language_guide[]` artifact step 3c §4a retained — it foregrounds the Language Guide and demotes compiler internals. When no override gate matches, assemble the standard library-export layout unchanged.
|
|
66
|
+
|
|
57
67
|
### 2a. Description Sanitization Pass
|
|
58
68
|
|
|
59
69
|
**Before writing SKILL.md frontmatter to disk**, sanitize the assembled `description` string by replacing every `<` with `{` and every `>` with `}`. Apply this pass unconditionally to the final assembled description in context, then write the result to `SKILL.md`.
|
|
60
70
|
|
|
61
71
|
**Why unconditional?** Both `skill-check`'s `description_field` validator and `tessl`'s deterministic description check parse the frontmatter `description` as a raw string — they reject any `<` or `>` regardless of whether the content is inside a backtick span or a generic expression. The previous rule exempted backticked content on the assumption that backticks protect from XML-tag parsing, but that assumption is false for these validators: a backticked TypeScript generic like `` `Meta<typeof X>` `` still fails tessl's check because tessl reads the raw string before markdown parsing. Unconditional replacement guarantees no angle brackets reach either validator.
|
|
62
72
|
|
|
63
|
-
**Coverage examples** (all handled by the same `<`/`>` → `{`/`}` replacement):
|
|
64
|
-
|
|
65
|
-
- Standalone placeholders: `<name>` → `{name}`, `<component-id>` → `{component-id}` — curly braces are the standard placeholder notation in prose and render cleanly.
|
|
66
|
-
- Backticked TypeScript / C++ / Rust generics: `` `Meta<typeof X>` `` → `` `Meta{typeof X}` ``, `` `Array<T>` `` → `` `Array{T}` ``, `` `Vec<u8>` `` → `` `Vec{u8}` `` — readable approximations that preserve the author's intent for code-ish fragments.
|
|
67
|
-
- Any other angle-bracket content, whether inside backticks or bare, is also rewritten.
|
|
68
|
-
|
|
69
73
|
**Scope:** This rule applies **only** to the frontmatter `description` field. Body content, code examples, reference files, and assembly-rule documents retain their original angle brackets — they are parsed through the markdown AST where backticks do protect content.
|
|
70
74
|
|
|
71
75
|
Record the count of substitutions in context as `description_sanitizations: {count}` for the evidence report.
|
|
72
76
|
|
|
73
|
-
|
|
77
|
+
If a downstream tool re-introduces angle brackets into the description, step 6 §6 recovers via `description-xml-tags-guarded-upstream` in `assets/tessl-dismissal-rules.md`.
|
|
74
78
|
|
|
75
79
|
### 3. Build context-snippet.md Content
|
|
76
80
|
|
|
@@ -100,22 +104,30 @@ Following the structure from the skill-sections data file:
|
|
|
100
104
|
- Set `generation_date` to current ISO-8601 timestamp
|
|
101
105
|
- Set `source_commit` from resolved source (if available)
|
|
102
106
|
- Set `source_ref` from resolved source ref (tag name, branch, or `HEAD`; null if unavailable)
|
|
103
|
-
- Set `scope_type` from the brief's `scope.type` value verbatim (`full-library`, `specific-modules`, `public-api`, `component-library`, `reference-app`, or `docs-only`). **Always emit this field.** `skf-test-skill` keys reference-app handling on `metadata.json.scope_type == "reference-app"` — both the scoring redistribution (Signature Accuracy / Type Coverage marked N/A) and the coverage-check §4b count-coherence skip. Omitting it silently mis-scores a reference-app skill as a library (zero-export barrel HALT or false metadata-drift findings)
|
|
104
|
-
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
- Set `scope_type` from the brief's `scope.type` value verbatim (`full-library`, `specific-modules`, `public-api`, `component-library`, `reference-app`, or `docs-only`). **Always emit this field.** `skf-test-skill` keys reference-app handling on `metadata.json.scope_type == "reference-app"` — both the scoring redistribution (Signature Accuracy / Type Coverage marked N/A) and the coverage-check §4b count-coherence skip. Omitting it silently mis-scores a reference-app skill as a library (zero-export barrel HALT or false metadata-drift findings). The value is informational for the other scope types (consumers only branch on `reference-app`), but emit it for all so the producer/consumer contract holds.
|
|
108
|
+
- **Compute the `stats` block and `confidence_distribution` deterministically** with `{renderMetadataStatsHelper}` (resolve from `{renderMetadataStatsProbeOrder}`; first existing path wins). The helper owns all the arithmetic — binning each provenance entry once by its `signature_source` tier, summing the bins, and computing every coverage ratio — and returns the finished `stats` + `confidence_distribution` objects to write into `metadata.json` verbatim. Run `uv run {renderMetadataStatsHelper} --help` for the full contract. You supply only the judgment payload below.
|
|
109
|
+
|
|
110
|
+
**Judgment payload (what you decide — passed as JSON on stdin):**
|
|
111
|
+
- `exports_public_api`: count of exports from public entry points (`__init__.py`, `index.ts`, `lib.rs`, or equivalent) — derive this from step 3's entry-point validation (section 4b), not from the provenance-map entry count (which may be incomplete if extraction patterns missed some export types)
|
|
107
112
|
- `exports_internal`: count of all other non-underscore-prefixed exports (internal modules, helpers, adapters)
|
|
108
|
-
- `
|
|
109
|
-
- `
|
|
110
|
-
- `total_coverage`: `exports_documented / exports_total` (may be low for large codebases — this is expected; `null` if `exports_total` is 0)
|
|
111
|
-
- `effective_denominator` (**optional** — emit only for stratified-scope monorepo packages): the count of public exports from files matched by the brief's authoring-surface globs, filtered by `scope.exclude`, resolved against `source_path`. **Prefer `scope.tier_a_include` when the brief supplies it** — that narrow list represents the authoring surface the brief intends to document; resolve its globs across `source_path` and count the union of **named exports** — items reachable from the language's public entry-point barrel (`lib.rs` `pub use`, `index.ts` / `index.js` re-exports, `__init__.py` exports), where a type counts **once** with its methods and impl-block members rolling up under it (count a `pub fn` only when it is a free function reachable from the barrel, never a method on an already-counted type). **Otherwise use `scope.include`** — the coarse list. This counting unit matches what `skf-test-skill` re-derives on the consumer side (`coverage-check.md` §2c excludes `kind: "method"` from `documented_set`), so the producer- and test-side denominators stay aligned; without it, a type-heavy API (a few handle types carrying hundreds of methods) inflates the denominator by an order of magnitude and auto-fails the coverage gate. This is the coverage denominator `skf-test-skill` uses when the package is a curated subset of a multi-package repository, so it must match the brief's authoring intent. Compute when ALL of the following hold:
|
|
113
|
+
- `scripts` / `assets`: the `scripts_inventory` / `assets_inventory` arrays (or `[]` when empty) — the helper sets `stats.scripts_count` / `stats.assets_count` from their lengths
|
|
114
|
+
- `effective_denominator` (**optional** — include in the helper's judgment payload only for stratified-scope monorepo packages): the count of public exports from files matched by the brief's authoring-surface globs, filtered by `scope.exclude`, resolved against `source_path`. **Prefer `scope.tier_a_include` when the brief supplies it** — that narrow list represents the authoring surface the brief intends to document; resolve its globs across `source_path` and count the union of **named exports** — items reachable from the language's public entry-point barrel (`lib.rs` `pub use`, `index.ts` / `index.js` re-exports, `__init__.py` exports), where a type counts **once** with its methods and impl-block members rolling up under it (count a `pub fn` only when it is a free function reachable from the barrel, never a method on an already-counted type). **Otherwise use `scope.include`** — the coarse list. This counting unit matches what `skf-test-skill` re-derives on the consumer side (`coverage-check.md` §2c excludes `kind: "method"` from `documented_set`), so the producer- and test-side denominators stay aligned; without it, a type-heavy API (a few handle types carrying hundreds of methods) inflates the denominator by an order of magnitude and auto-fails the coverage gate. This is the coverage denominator `skf-test-skill` uses when the package is a curated subset of a multi-package repository, so it must match the brief's authoring intent. Compute when ALL of the following hold:
|
|
112
115
|
1. The source is a monorepo (detected via `packages/` layout, `workspaces` field in root `package.json`, `lerna.json`, `rush.json`, `nx.json`, or Cargo `[workspace]`).
|
|
113
116
|
2. `scope.type` is not `full-library` (and not `reference-app` — see carve-out below), AND the resolved include list (`tier_a_include` if present, else `scope.include`) lists a curated file/directory subset rather than the full workspace.
|
|
114
117
|
3. `scope.notes` is present and documents the stratification strategy (e.g., a tiered A/B/C plan) — this serves as the intent marker confirming the subset is by design.
|
|
115
118
|
|
|
116
|
-
Otherwise omit the
|
|
119
|
+
Otherwise omit it from the payload entirely — when absent, `skf-test-skill` falls back to `exports_public_api`. See `skf-test-skill` `references/source-access-protocol.md` §Source API Surface Definition ("Stratified-scope monorepo packages") for the test-side consumption rules.
|
|
117
120
|
|
|
118
|
-
**Reference-app carve-out:** never emit `effective_denominator` for `scope.type: "reference-app"`, even when the three conditions above are literally satisfied (a reference-app-in-monorepo matches all of them). A reference app's coverage basis is `pattern_surfaces_documented`, not library exports — see the Reference-App stats semantics in `
|
|
121
|
+
**Reference-app carve-out:** never emit `effective_denominator` for `scope.type: "reference-app"`, even when the three conditions above are literally satisfied (a reference-app-in-monorepo matches all of them). A reference app's coverage basis is `pattern_surfaces_documented`, not library exports — see the Reference-App stats semantics in `assets/compile-assembly-rules.md`.
|
|
122
|
+
- **Shape:** pass `--shape reference-app` or `--shape stack` when the matching assembly-rules override applies (default `library`). For a reference app, also put `pattern_surfaces_documented` (the Pattern Surface row count) in the payload — the helper uses it as `exports_documented`, emits `stats.pattern_surfaces_documented`, and refuses to emit `effective_denominator`; the distribution then sums to the per-citation count, not to `exports_documented`. For a stack, put the own-barrel `exports_documented` (usually `0`) in the payload; the distribution sums to the cited-constituent count.
|
|
123
|
+
- **Invoke** — stage `provenance-map.json` (§6) first, since the helper reads its `entries[]`:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
echo '{"exports_public_api": {N}, "exports_internal": {M}, "scripts": {scripts_inventory-or-[]}, "assets": {assets_inventory-or-[]}}' \
|
|
127
|
+
| uv run {renderMetadataStatsHelper} <staging-skill-dir>/provenance-map.json
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Write the returned `stats` and `confidence_distribution` verbatim. The helper derives `exports_documented` (the documented-export count = provenance `entries[]` count), `exports_total` = `exports_public_api` + `exports_internal`, `public_api_coverage` = documented / public_api (`null` if public_api is 0), `total_coverage` = documented / total (`null` if total is 0), and bins `confidence_distribution.{t1, t1_low, t2, t3}` by each entry's `signature_source` — **each entry counted exactly once**, so the four bins provably sum to the documented-export count. This structurally prevents the recurring miscount where binning ~8 T2 annotations + ~80 T3 doc items on top of 59 exports produced a distribution summing to 147 ≠ 59 (`skf-test-skill` coverage-check §4b flags that sum as an internal-consistency defect). If the helper reports `coherence.ok: false`, some provenance entries carry a missing/unrecognized `signature_source` (or a file-entry count disagrees) — fix the provenance map, do not hand-edit the stats.
|
|
119
131
|
- Set `description` from the SKILL.md frontmatter `description` field (already assembled in section 2)
|
|
120
132
|
- Set `language` from source analysis (e.g., `"typescript"`, `"python"`) — use the primary language of the entry point file
|
|
121
133
|
- Set `ast_node_count` from extraction stats if ast-grep was used (Forge/Deep tier), otherwise omit
|
|
@@ -135,7 +147,7 @@ Following the structure from the skill-sections data file:
|
|
|
135
147
|
3. `"unknown"` (final fallback — add a warning to the evidence report)
|
|
136
148
|
Note: QMD is a Bun/Node package (`@tobilu/qmd`). Install via `bun install -g @tobilu/qmd`.
|
|
137
149
|
- Store `commit_short` = first 8 characters of `source_commit` (or `"unknown"` if unavailable) for use in step 8 report.
|
|
138
|
-
- If `scripts_inventory` is non-empty, populate `scripts[]` array
|
|
150
|
+
- If `scripts_inventory` is non-empty, populate the `scripts[]` array (per-file `{file, purpose, source_file, confidence}` rows). If `assets_inventory` is non-empty, populate the `assets[]` array. Omit the `scripts[]` / `assets[]` arrays entirely when their inventory is empty — `stats.scripts_count` / `stats.assets_count` were already set by `{renderMetadataStatsHelper}` from the `scripts` / `assets` payload you passed it (0 when empty).
|
|
139
151
|
|
|
140
152
|
### 5. Build references/ Content
|
|
141
153
|
|
|
@@ -155,7 +167,7 @@ One entry per extracted export: export_name, export_type, params[] (typed string
|
|
|
155
167
|
|
|
156
168
|
- `scripts_inventory` → `file_type: "script"`, `extraction_method: "file-copy"`, stored in `{skill_package}/scripts/` by step 7
|
|
157
169
|
- `assets_inventory` → `file_type: "asset"`, `extraction_method: "file-copy"`, stored in `{skill_package}/assets/` by step 7
|
|
158
|
-
- `promoted_docs` (from step 3 §2a) → `file_type: "doc"`, `extraction_method: "promoted-authoritative"`, **
|
|
170
|
+
- `promoted_docs` (from step 3 §2a) → `file_type: "doc"`, `extraction_method: "promoted-authoritative"`, **not** copied into the skill package by step 7. The source file stays at its original path; only the provenance tracking entry is written. `content_hash` was pre-computed by §2a.
|
|
159
171
|
|
|
160
172
|
Each `file_entries[]` row has the same shape regardless of `file_type`: `{file_name, file_type, source_file, content_hash, confidence, extraction_method}`. See `{skillSectionsData}` for full schema and the canonical list of `file_type` values.
|
|
161
173
|
|
|
@@ -163,33 +175,11 @@ Each `file_entries[]` row has the same shape regardless of `file_type`: `{file_n
|
|
|
163
175
|
|
|
164
176
|
Compilation audit trail: generation date, forge tier, source info, tool versions, extraction summary (files/exports/confidence), warnings. For validation-specific fields (Schema, Body, Security, Content Quality, tessl, Metadata), insert the placeholder text `[PENDING — populated by step 6]`. Step-06 will replace these placeholders with actual results. See `{skillSectionsData}` for full template. Use the same `{skf_version}` value resolved in section 4 when populating the Tool Versions block.
|
|
165
177
|
|
|
166
|
-
**Frontmatter — pinned fields
|
|
167
|
-
|
|
168
|
-
**Auto-Decisions section (headless buffer flush):** read the in-context `headless_decisions[]` list (populated by step 1 tier-override handling, step 2 ecosystem gate, and any future step that auto-resolves a gate under `{headless_mode}`). Emit an `## Auto-Decisions` section with one row per entry:
|
|
169
|
-
|
|
170
|
-
```
|
|
171
|
-
## Auto-Decisions
|
|
172
|
-
|
|
173
|
-
| Step | Gate | Decision | Rationale | Timestamp |
|
|
174
|
-
|------|------|----------|-----------|-----------|
|
|
175
|
-
| {step} | {gate} | {decision}{value?} | {rationale} | {timestamp} |
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
If `headless_decisions[]` is empty, emit the section header with a single line: `No auto-decisions — workflow ran interactively (or all gates had no match to auto-resolve).` This guarantees the section is always present so reviewers can tell "zero auto-decisions" apart from "section missing".
|
|
179
|
-
|
|
180
|
-
### 8. Menu Handling Logic
|
|
181
|
-
|
|
182
|
-
**Auto-proceed step — no user interaction.**
|
|
183
|
-
|
|
184
|
-
After all content is assembled in context and written to the staging directory, immediately load, read entire file, then execute `{nextStepFile}`.
|
|
185
|
-
|
|
186
|
-
#### EXECUTION RULES:
|
|
178
|
+
**Frontmatter — pinned fields:** emit YAML frontmatter at the top of `evidence-report.md` with at minimum `skill_name`, `generated`, `forge_tier`, and `t2_future_count`. Compute `t2_future_count` as the count of forward-looking (T2-future) temporal annotations in the enrichment data produced by step 4 (`qmd query` + temporal classification). **Emit `t2_future_count: 0` when no T2-future annotations exist** — omission is indistinguishable from "no data" for downstream consumers and would silently flip the skf-test-skill §2b/§5b migration-section gate into Case 2/3 for a Case-1 skill. This frontmatter is the authoritative detection contract — `migration-section-rules.md` Case Rules parse it deterministically rather than grepping prose.
|
|
187
179
|
|
|
188
|
-
- This is
|
|
189
|
-
- All content must be both in context and in `_bmad-output/{skill-name}/` — no final files in `skills/` or `forge-data/` yet
|
|
190
|
-
- Proceed directly to validation after assembly is complete
|
|
180
|
+
**Auto-Decisions section (render from the durable sink):** render the `## Auto-Decisions` section into `evidence-report.md` from the **union of the on-disk auto-decision sink** (`{sidecar_path}/auto-decisions.jsonl`, established at step 1 §3 and appended to on every gate landing) **and the in-context `headless_decisions[]` buffer** — read the sink's JSON lines, union them with the buffer keyed on `step`+`gate` so nothing is duplicated or dropped, and emit one row per entry in the table format documented in step 6 §8. The sink is authoritative: on a long component-library run the in-context buffer may have compacted across the token-heavy step 3→5 extraction window, but the sink carries every decision written as it landed (step 1 tier-override, step 2 ecosystem gate, step 3 zero-exports, step 3d component-extraction gates). This step is the first point `evidence-report.md` is written to disk (staging dir, §8 below). Exactly one gate can still fire after this step — step 6 §6b (the tessl-suggestions gate) — and step 6 §8 re-reconciles idempotently. If the union is empty (no decision has fired), emit the section with the single line `No auto-decisions — workflow ran interactively (or all gates had no match to auto-resolve).` — step 6 §8 replaces that line if a later decision lands.
|
|
191
181
|
|
|
192
|
-
|
|
182
|
+
### 8. Auto-Proceed
|
|
193
183
|
|
|
194
|
-
|
|
184
|
+
No user interaction. Once all content is assembled in context and written to the staging directory `_bmad-output/{skill-name}/` (no final files in `skills/` or `forge-data/` yet), load `{nextStepFile}`, read it fully, then execute it. `extraction-rules.yaml` is generated by step 7 from extraction data — do not create it here.
|
|
195
185
|
|
|
@@ -19,7 +19,7 @@ When `scope.type: "component-library"`, perform specialized extraction that trea
|
|
|
19
19
|
|
|
20
20
|
## MANDATORY SEQUENCE
|
|
21
21
|
|
|
22
|
-
**Prerequisite — §2a already ran.** Step-03 executes `§2a Discovered Authoritative Files Protocol` before delegating to this file. Any promoted authoritative files (`llms.txt`, `AGENTS.md`, etc.) are tracked in the `promoted_docs[]` context list and will be written to `file_entries[]` with `file_type: "doc"` by step 5 §6 — they do
|
|
22
|
+
**Prerequisite — §2a already ran.** Step-03 executes `§2a Discovered Authoritative Files Protocol` before delegating to this file. Any promoted authoritative files (`llms.txt`, `AGENTS.md`, etc.) are tracked in the `promoted_docs[]` context list and will be written to `file_entries[]` with `file_type: "doc"` by step 5 §6 — they do not appear in the filtered file list that was passed into this step, so Phase 1 demo exclusion below only operates on code files. No special handling is required in this file for promoted docs. See step 3 §2a for the full flow.
|
|
23
23
|
|
|
24
24
|
### Phase 1: Demo/Example Exclusion
|
|
25
25
|
|
|
@@ -42,7 +42,7 @@ Before extraction, identify and exclude demo/example files to avoid inflating ex
|
|
|
42
42
|
|
|
43
43
|
Confirm exclusion? [Y/n] Or adjust patterns:"
|
|
44
44
|
|
|
45
|
-
**GATE [default: Y]** — if `{headless_mode}` is true: auto-confirm the auto-detected exclusion patterns, log "headless: auto-confirm demo/example exclusion ({N} files, {M} directories)", and append `{step: "component-extraction", gate: "demo-exclusion", decision: "Y", value: "{N} files / {M} dirs", rationale: "headless mode — auto-detected demo patterns accepted", timestamp: {ISO}}` to `headless_decisions[]`
|
|
45
|
+
**GATE [default: Y]** — if `{headless_mode}` is true: auto-confirm the auto-detected exclusion patterns, log "headless: auto-confirm demo/example exclusion ({N} files, {M} directories)", and append `{step: "component-extraction", gate: "demo-exclusion", decision: "Y", value: "{N} files / {M} dirs", rationale: "headless mode — auto-detected demo patterns accepted", timestamp: {ISO}}` to `headless_decisions[]` and, the moment it lands, append the same object as a JSON line to the durable audit sink `{sidecar_path}/auto-decisions.jsonl` (the on-landing append established at step 1 §3) — the sink feeds the evidence-report `## Auto-Decisions` table at step 5 §7 and step 6 §8. Then proceed without waiting.
|
|
46
46
|
|
|
47
47
|
Wait for user response (interactive only). Apply confirmed patterns to the exclude list. Record `demo_files_excluded: {count}` in context.
|
|
48
48
|
|
|
@@ -85,7 +85,7 @@ Sample entries:
|
|
|
85
85
|
|
|
86
86
|
Is this the component registry? [Y/n] Or provide the correct path:"
|
|
87
87
|
|
|
88
|
-
**GATE [default: Y]** — if `{headless_mode}` is true AND `score >= 7` (high-confidence candidate): auto-confirm the registry candidate, log "headless: auto-confirm registry candidate `{path}` (score {score}/9)", and append `{step: "component-extraction", gate: "registry-confirm", decision: "Y", value: "{path} score={score}/9", rationale: "headless mode — high-confidence registry candidate auto-accepted", timestamp: {ISO}}` to `headless_decisions[]
|
|
88
|
+
**GATE [default: Y]** — if `{headless_mode}` is true AND `score >= 7` (high-confidence candidate): auto-confirm the registry candidate, log "headless: auto-confirm registry candidate `{path}` (score {score}/9)", and append `{step: "component-extraction", gate: "registry-confirm", decision: "Y", value: "{path} score={score}/9", rationale: "headless mode — high-confidence registry candidate auto-accepted", timestamp: {ISO}}` to `headless_decisions[]` and, the moment it lands, append the same object as a JSON line to the durable audit sink `{sidecar_path}/auto-decisions.jsonl` (the on-landing append established at step 1 §3). If `score < 7` in headless mode, auto-reject the candidate (treat as "no registry found"), log "headless: auto-reject low-confidence registry candidate (score {score}/9) — below auto-accept threshold 7", record the decision the same way (buffer + sink, `decision: "reject-low-score"`), and fall through to the "no registry found" branch below. Confidence threshold 7 matches the minimum score the heuristic considers "probable enough to risk" without human eyes.
|
|
89
89
|
|
|
90
90
|
Wait for user response (interactive only).
|
|
91
91
|
|
|
@@ -95,7 +95,7 @@ Wait for user response (interactive only).
|
|
|
95
95
|
- **[P]** Provide the registry file path
|
|
96
96
|
- **[S]** Skip registry — proceed with standard props-first extraction only"
|
|
97
97
|
|
|
98
|
-
**GATE [default: S]** — if `{headless_mode}` is true: auto-select [S] Skip (props-first extraction without registry), log "headless: no registry detected, auto-skip to props-first extraction (no path was provided in brief.scope.registry_path)", and append `{step: "component-extraction", gate: "provide-or-skip-registry", decision: "S", rationale: "headless mode — no human to provide registry path", timestamp: {ISO}}` to `headless_decisions[]
|
|
98
|
+
**GATE [default: S]** — if `{headless_mode}` is true: auto-select [S] Skip (props-first extraction without registry), log "headless: no registry detected, auto-skip to props-first extraction (no path was provided in brief.scope.registry_path)", and append `{step: "component-extraction", gate: "provide-or-skip-registry", decision: "S", rationale: "headless mode — no human to provide registry path", timestamp: {ISO}}` to `headless_decisions[]` and, the moment it lands, append the same object as a JSON line to the durable audit sink `{sidecar_path}/auto-decisions.jsonl` (the on-landing append established at step 1 §3). The default is `[S]` rather than `[P]` because providing a path requires user input that headless cannot supply; skipping degrades gracefully to a smaller but valid extraction.
|
|
99
99
|
|
|
100
100
|
Wait for user response (interactive only).
|
|
101
101
|
|
|
@@ -160,7 +160,7 @@ constraints:
|
|
|
160
160
|
|
|
161
161
|
Also run `export const $NAME` patterns for arrow function components.
|
|
162
162
|
|
|
163
|
-
For each component export: record name, source file, line number. Do
|
|
163
|
+
For each component export: record name, source file, line number. Do not document the function signature in detail (it's always `(props: XProps) => JSX.Element`).
|
|
164
164
|
|
|
165
165
|
**Step 3 — Link Props to Components:**
|
|
166
166
|
|
|
@@ -185,7 +185,7 @@ Extract non-Props type exports using standard AST patterns (same as Forge tier):
|
|
|
185
185
|
|
|
186
186
|
When multiple design system variants exist:
|
|
187
187
|
|
|
188
|
-
1. **Group components by registry `id`** (
|
|
188
|
+
1. **Group components by registry `id`** (not by filename — registry is source of truth):
|
|
189
189
|
- For each `id` in `component_catalog[]`, collect all variant paths from `available_in[]` and `code_paths[]`
|
|
190
190
|
|
|
191
191
|
2. **Select canonical props definition:**
|
|
@@ -243,33 +243,6 @@ Display: "**Component extraction complete.** Returning to main extraction flow."
|
|
|
243
243
|
|
|
244
244
|
## RETURN PROTOCOL
|
|
245
245
|
|
|
246
|
-
After Phase 6 completes, return control to step 3 section 5 (Build Extraction Inventory). The extraction results from this step are merged into the standard extraction inventory format. Step-03 continues with its normal Gate 2 summary and
|
|
246
|
+
After Phase 6 completes, return control to step 3 section 5 (Build Extraction Inventory). The extraction results from this step are merged into the standard extraction inventory format. Step-03 continues with its normal Gate 2 summary and confirmation.
|
|
247
247
|
|
|
248
|
-
Do
|
|
249
|
-
|
|
250
|
-
---
|
|
251
|
-
|
|
252
|
-
## SYSTEM SUCCESS/FAILURE METRICS
|
|
253
|
-
|
|
254
|
-
### SUCCESS:
|
|
255
|
-
|
|
256
|
-
- Demo/example files detected and excluded with user confirmation
|
|
257
|
-
- Registry detected (or user provided path) and parsed into component_catalog
|
|
258
|
-
- Props interfaces extracted as primary API contracts
|
|
259
|
-
- Components linked to Props via 3-level fallback chain
|
|
260
|
-
- Variant consolidation produced deduplicated counts (if applicable)
|
|
261
|
-
- All extracted items have provenance citations
|
|
262
|
-
- Results compatible with step 3 section 5 inventory format
|
|
263
|
-
- component_catalog stored in context for step 5
|
|
264
|
-
|
|
265
|
-
### FAILURE:
|
|
266
|
-
|
|
267
|
-
- Excluding demo files without user confirmation
|
|
268
|
-
- Accepting a registry candidate without user confirmation
|
|
269
|
-
- Not extracting Props interfaces as primary API surface
|
|
270
|
-
- Documenting component function signatures instead of Props
|
|
271
|
-
- Including hallucinated component data not in source
|
|
272
|
-
- Variant deduplication based on filenames instead of registry IDs
|
|
273
|
-
- Not returning control to step 3 after completion
|
|
274
|
-
|
|
275
|
-
**Master Rule:** Zero hallucination — every extraction must trace to source code. The component registry is the source of truth for the API surface.
|
|
248
|
+
Do not load `{returnToStep}` — the calling step (step 3) continues from where it delegated.
|
|
@@ -29,7 +29,7 @@ Query the ecosystem using the skill name from the brief:
|
|
|
29
29
|
- Enforce 5-second timeout — if the query does not return within 5 seconds, treat as no match. Rationale: ecosystem check is an opportunistic advisory; a slow or degraded registry must not stall the compilation pipeline, and 5s is well beyond any healthy registry's p99 latency.
|
|
30
30
|
- Cache results for 24 hours (if re-running same skill). Rationale: the agentskills.io registry publishes new official skills in daily batches; a 24-hour TTL balances freshness against redundant network calls during iterative brief refinement.
|
|
31
31
|
|
|
32
|
-
**If registry API is
|
|
32
|
+
**If registry API is not available (current default):**
|
|
33
33
|
|
|
34
34
|
Skip completely and silently. Do not output any message about API unavailability or the ecosystem check being skipped. Emit zero text to the console. Proceed exactly as if no match was found.
|
|
35
35
|
|
|
@@ -59,32 +59,16 @@ Auto-proceed silently to next step. Do not display any message about the ecosyst
|
|
|
59
59
|
|
|
60
60
|
Auto-proceed silently. Log a note in context: "Ecosystem check skipped (timeout/error) — proceeding with compilation."
|
|
61
61
|
|
|
62
|
-
### 3.
|
|
62
|
+
### 3. Gate — Ecosystem Match (conditional)
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
This gate fires only when §2 found a match; on no match, timeout, or unavailable tool the step already auto-proceeded to `{nextStepFile}` with no menu.
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
**GATE [default: P]** — under `{headless_mode}` with a match, auto-proceed as [P], log "headless: ecosystem match found, auto-proceeding", and append `{step: "ecosystem-check", gate: "ecosystem-match", decision: "P", rationale: "headless mode — match found, auto-proceed with user's own compilation", timestamp: {ISO}}` to `headless_decisions[]` and, the moment it lands, append the same object as a JSON line to the durable audit sink `{sidecar_path}/auto-decisions.jsonl` (the on-landing append established at step 1 §3) — the sink feeds the evidence-report `## Auto-Decisions` table at step 5 §7 and step 6 §8.
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
Interactively, halt and wait for the user's choice on the §2 menu:
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
- This menu ONLY appears when an ecosystem match is found
|
|
75
|
-
- If no match, timeout, or tool unavailable — auto-proceed with no menu
|
|
76
|
-
|
|
77
|
-
#### Menu Handling Logic:
|
|
78
|
-
|
|
79
|
-
- IF P: Note user's decision to proceed despite existing skill. Immediately load, read entire file, then execute `{nextStepFile}`
|
|
80
|
-
- IF I: Display: "Install the existing skill using: `[SF] Setup Forge → install {matched_skill_name}`" then halt workflow. Do not proceed to extraction.
|
|
81
|
-
- IF A: Display: "Compilation aborted. Return to Ferris menu to select another action." then halt workflow.
|
|
82
|
-
- IF no match/timeout/error: Auto-proceed — immediately load, read entire file, then execute `{nextStepFile}`
|
|
83
|
-
- IF Any other comments or queries: help user respond then redisplay the menu
|
|
84
|
-
|
|
85
|
-
## CRITICAL STEP COMPLETION NOTE
|
|
86
|
-
|
|
87
|
-
ONLY WHEN the ecosystem check is complete (match evaluated, user decision made if applicable) will you proceed to load `{nextStepFile}` for source extraction.
|
|
88
|
-
|
|
89
|
-
If no match is found, this step auto-proceeds with no user interaction.
|
|
70
|
+
- **P** — proceed despite the existing skill; load `{nextStepFile}`, read it fully, then execute it.
|
|
71
|
+
- **I** — display "Install the existing skill using: `[SF] Setup Forge → install {matched_skill_name}`", then halt (no extraction).
|
|
72
|
+
- **A** — display "Compilation aborted. Return to Ferris menu to select another action.", then halt.
|
|
73
|
+
- Any other question — answer it, then redisplay the menu.
|
|
90
74
|
|
|
@@ -34,7 +34,7 @@ Continue to step 2.
|
|
|
34
34
|
Before searching, check which QMD collections are available:
|
|
35
35
|
|
|
36
36
|
1. Read the sidecar `forge-tier.yaml` to get registered `qmd_collections` entries
|
|
37
|
-
2. Identify which collections contain enrichment context — collections with `type` equal to `"temporal"` (issues, PRs, changelogs) or `"docs"` (fetched external documentation). Do
|
|
37
|
+
2. Identify which collections contain enrichment context — collections with `type` equal to `"temporal"` (issues, PRs, changelogs) or `"docs"` (fetched external documentation). Do not include `"extraction"` or `"brief"` type collections.
|
|
38
38
|
3. **If no enrichment collections exist** (no `"temporal"` or `"docs"` type collections): report this and auto-proceed. Display:
|
|
39
39
|
|
|
40
40
|
"**Enrichment: no enrichment collections available.**
|
|
@@ -66,7 +66,7 @@ For each function, derive the **module context** from the extraction inventory's
|
|
|
66
66
|
|
|
67
67
|
**Tool resolution for qmd_bridge:** QMD MCP exposes a single `query` tool that accepts a `searches[]` array. Each entry has a `type` field — `'lex'` for BM25 keyword search, `'vec'` for semantic vector search, `'hyde'` for hypothetical-document retrieval — plus `query` and `intent` fields. Claude Code: `mcp__plugin_qmd-plugin_qmd__query`. Cursor: qmd MCP server. CLI: `qmd search "{query}"` (BM25) / `qmd vector-search "{query}"` (semantic). See `knowledge/tool-resolution.md`.
|
|
68
68
|
|
|
69
|
-
**Tool probe (graceful degradation):** If any tool-not-found error surfaces while invoking `query` (e.g., legacy `vector_search` still expected by an older client, or a bridge returns "tool not registered"), treat it as a non-fatal failure for that function's enrichment and continue with the remaining functions. Do
|
|
69
|
+
**Tool probe (graceful degradation):** If any tool-not-found error surfaces while invoking `query` (e.g., legacy `vector_search` still expected by an older client, or a bridge returns "tool not registered"), treat it as a non-fatal failure for that function's enrichment and continue with the remaining functions. Do not retry against the stale `vector_search` tool name — that name was removed from the QMD MCP server. Record the degradation in context for the evidence report.
|
|
70
70
|
|
|
71
71
|
**For each QMD result:**
|
|
72
72
|
|
|
@@ -108,20 +108,7 @@ Display brief enrichment summary:
|
|
|
108
108
|
|
|
109
109
|
Proceeding to compilation..."
|
|
110
110
|
|
|
111
|
-
### 6.
|
|
111
|
+
### 6. Auto-Proceed
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
After enrichment is complete (or skipped for non-Deep tiers), immediately load, read entire file, then execute `{nextStepFile}`.
|
|
116
|
-
|
|
117
|
-
#### EXECUTION RULES:
|
|
118
|
-
|
|
119
|
-
- This is an auto-proceed step with no user choices
|
|
120
|
-
- Quick/Forge/Forge+ tiers skip directly to next step with no output
|
|
121
|
-
- Deep tier displays brief enrichment summary then auto-proceeds
|
|
122
|
-
- QMD failures do not halt — degrade and proceed
|
|
123
|
-
|
|
124
|
-
## CRITICAL STEP COMPLETION NOTE
|
|
125
|
-
|
|
126
|
-
ONLY WHEN enrichment is complete (Deep tier) or the step is skipped (Quick/Forge/Forge+) will you proceed to load `{nextStepFile}` for SKILL.md compilation.
|
|
113
|
+
No user interaction. After enrichment completes (or is skipped for non-Deep tiers), load `{nextStepFile}`, read it fully, then execute it.
|
|
127
114
|
|
|
@@ -55,7 +55,7 @@ Load `{extractionPatternsData}` completely. Identify the strategy for the curren
|
|
|
55
55
|
|
|
56
56
|
From the brief, apply scope and pattern filters:
|
|
57
57
|
|
|
58
|
-
- `scope.type` — determines what to extract (e.g., `full-library`, `specific-modules`, `public-api`, `component-library`, `reference-app`, `docs-only`). Use `reference-app` when the source is a whole app and the skill's value is wiring patterns rather than public exports (embedded-sidecar reference apps, CLI-demo repos, integration-pattern demonstrators). `reference-app` triggers the compile-assembly overrides in `
|
|
58
|
+
- `scope.type` — determines what to extract (e.g., `full-library`, `specific-modules`, `public-api`, `component-library`, `reference-app`, `docs-only`). Use `reference-app` when the source is a whole app and the skill's value is wiring patterns rather than public exports (embedded-sidecar reference apps, CLI-demo repos, integration-pattern demonstrators). `reference-app` triggers the compile-assembly overrides in `assets/compile-assembly-rules.md` that replace "Key API Summary" with a "Pattern Surface" section and make `stats.exports_documented` semantics pattern-oriented. Do not pick `full-library` for reference apps — downstream assembly will remap wiring onto export slots, producing fuzzy counts and an awkward SKILL.md.
|
|
59
59
|
- `scope.include` — file globs to include
|
|
60
60
|
- `scope.exclude` — file globs to exclude
|
|
61
61
|
|
|
@@ -65,7 +65,7 @@ Build the filtered file list from the source tree resolved in step 1. Record the
|
|
|
65
65
|
|
|
66
66
|
**Skip this section entirely if `source_type: "docs-only"`** — there is no source tree to scan.
|
|
67
67
|
|
|
68
|
-
Load `{authoritativeFilesProtocol}` and execute it. The full protocol (heuristic scan list, helper invocation, classification dispatch, prompt flow, P/S/U decision-apply, summary, provenance-map handoff, downstream consumption) lives there.
|
|
68
|
+
Load `{authoritativeFilesProtocol}` and execute it. The full protocol (heuristic scan list, helper invocation, classification dispatch, prompt flow, P/S/U decision-apply, summary, provenance-map handoff, downstream consumption) lives there.
|
|
69
69
|
|
|
70
70
|
Briefly: scan the source tree for authoritative AI documentation files (`llms.txt`, `AGENTS.md`, `.cursorrules`, etc.) that the brief's scope filters may have excluded. The `{resolveAuthoritativeFilesHelper}` helper does the deterministic work (walk, scope diff, amendment reconcile, preview load, hashing); the LLM applies the resulting `unresolved[]` prompt loop. Promoted decisions are persisted to the brief immediately so re-runs replay deterministically.
|
|
71
71
|
|
|
@@ -95,7 +95,7 @@ Then run CCC indexing and discovery on the resolved clone (workspace or ephemera
|
|
|
95
95
|
|
|
96
96
|
2. **Initialize index (first time only):** Run `cd {remote_clone_path} && ccc init`. If init exits non-zero with `A parent directory has a project marker` — the common case when the clone is nested under a ccc-indexed project (e.g. a `.forge-sources/` checkout inside this repo) — re-run as `cd {remote_clone_path} && ccc init -f` to initialize at the subtree anyway (same handling as step 7 §6b). If init fails for any other reason, or the `-f` retry also fails, set `{ccc_discovery: []}` and continue — this is not an error.
|
|
97
97
|
|
|
98
|
-
**Apply standard exclusions:** After `ccc init`, apply generic build/dependency exclusions to `{remote_clone_path}/.cocoindex_code/settings.yml`. These are standard artifact patterns,
|
|
98
|
+
**Apply standard exclusions:** After `ccc init`, apply generic build/dependency exclusions to `{remote_clone_path}/.cocoindex_code/settings.yml`. These are standard artifact patterns, not SKF-specific paths (the workspace checkout is a source repo, not an SKF project):
|
|
99
99
|
|
|
100
100
|
```
|
|
101
101
|
node_modules/, dist/, build/, .git/, vendor/, __pycache__/, .cache/, .next/, .nuxt/, target/, out/, .venv/, .tox/
|
|
@@ -103,7 +103,7 @@ Then run CCC indexing and discovery on the resolved clone (workspace or ephemera
|
|
|
103
103
|
|
|
104
104
|
Read `settings.yml`, append any patterns not already present to the `exclude_patterns` array, write back. **Reuse check:** if an existing `.cocoindex_code/settings.yml` was already present (workspace hit), read its `exclude_patterns` first and diff against the standard-exclusion list above. If ANY standard entry is missing from the existing list, append only the missing entries (preserving any user-added patterns) AND force a re-index by running `ccc index --force` (or the equivalent rebuild flag). If every standard entry is already present, skip the write and skip the forced re-index — the existing index is valid. Record `ccc_exclusions_augmented: {count}` in context for the evidence report.
|
|
105
105
|
|
|
106
|
-
**Note:** Brief-specific `include_patterns` and `exclude_patterns` are
|
|
106
|
+
**Note:** Brief-specific `include_patterns` and `exclude_patterns` are not written to `settings.yml`. The CCC index is general-purpose — it indexes everything (minus standard artifacts). Brief-specific filtering happens at search result time, not index time. This allows a single workspace CCC index to serve multiple briefs with different scope filters.
|
|
107
107
|
|
|
108
108
|
3. **Index the clone:** Run `cd {remote_clone_path} && ccc index` with an extended timeout or in background mode. Indexing can take several minutes on large codebases (1000+ files). Verify completion with `ccc status`, then **verify integrity**: a non-zero `Chunks`/`Files` total is not sufficient — read the `Languages:` breakdown and confirm the source's primary language (`{brief.language}`) reports a non-trivial chunk count. An index dominated by `markdown`/config chunks with the source language absent or near-zero means `ccc index` ran against degraded settings (a stale `.cocoindex_code/` inherited from a parent, or a no-op init over a prior partial index) and the source code was never indexed — searches over it return nothing useful. When the source language is absent, rebuild from a clean init: `cd {remote_clone_path} && ccc init -f` then `ccc index`, and re-check the `Languages:` breakdown. If indexing fails, or the source language is still missing after a forced re-init, set `{ccc_discovery: []}` and continue — this is not an error.
|
|
109
109
|
|
|
@@ -118,13 +118,13 @@ Then run CCC indexing and discovery on the resolved clone (workspace or ephemera
|
|
|
118
118
|
|
|
119
119
|
If `remote_clone_type == "workspace"` and an existing index was reused, append: "(reused workspace index)"
|
|
120
120
|
|
|
121
|
-
7. **On failure:** Set `{ccc_discovery: []}`. Display: "CCC discovery unavailable — proceeding with standard extraction." Do
|
|
121
|
+
7. **On failure:** Set `{ccc_discovery: []}`. Display: "CCC discovery unavailable — proceeding with standard extraction." Do not halt.
|
|
122
122
|
|
|
123
123
|
**CCC Discovery Integration (Forge+ and Deep with ccc only):**
|
|
124
124
|
|
|
125
125
|
If `{ccc_discovery}` is in context and non-empty (populated by step 2b or deferred discovery above):
|
|
126
126
|
- Sort the filtered file list by CCC relevance score: files appearing in `{ccc_discovery}` results move to the front of the extraction queue, sorted by their relevance score descending
|
|
127
|
-
- Files
|
|
127
|
+
- Files not in CCC results remain in the queue after ranked files — they are not excluded, only deprioritized
|
|
128
128
|
- Display: "**CCC discovery: {N} files pre-ranked by semantic relevance** — extraction will prioritize these first."
|
|
129
129
|
|
|
130
130
|
If `{ccc_discovery}` is empty or not in context: proceed with existing file ordering (no change to current behavior).
|
|
@@ -168,13 +168,13 @@ Source resolution, version reconciliation, and CCC discovery were completed in s
|
|
|
168
168
|
|
|
169
169
|
**Forge/Forge+/Deep Tier (AST available):**
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
Before executing AST extraction, load the **AST Extraction Protocol** section from `{extractionPatternsData}`. Follow the decision tree based on the file count from step 1's file tree — it determines whether to use the MCP tool, scoped YAML rules, or CLI streaming. Do not use `ast-grep --json` (without `=stream`) — it loads the entire result set into memory and fails on large codebases; use the explicit `run` subcommand with streaming: `ast-grep run -p '{pattern}' --json=stream`.
|
|
172
172
|
|
|
173
173
|
1. Detect language from brief or file extensions
|
|
174
174
|
2. Follow the AST Extraction Protocol decision tree from `{extractionPatternsData}`:
|
|
175
175
|
- ≤100 files: use `find_code()` MCP tool with `max_results` and `output_format="text"`
|
|
176
176
|
- ≤500 files: use `find_code_by_rule()` MCP tool with scoped YAML rules
|
|
177
|
-
- >500 files: use CLI `--json=stream` with line-by-line streaming Python —
|
|
177
|
+
- >500 files: use CLI `--json=stream` with line-by-line streaming Python — inject the brief's `scope.exclude` patterns into the Python filter's `EXCLUDES` list (use `[]` if absent) so excluded files are discarded before consuming `head -N` slots (see template in extraction patterns data)
|
|
178
178
|
3. For each export: extract function name, full signature, parameter types, return type, line number
|
|
179
179
|
4. Use `ast_bridge.detect_co_imports(path, libraries[])` to find integration points
|
|
180
180
|
5. Build extraction rules YAML data for reproducibility
|
|
@@ -274,6 +274,14 @@ Compile all extracted data into a structured inventory:
|
|
|
274
274
|
|
|
275
275
|
**Docs-only note:** If `docs_only_mode` is active (`extraction_mode: "docs-only"`), display a brief note explaining that T3 content will be added by the doc-fetcher step (step 3c), then auto-proceed past this gate. Example: "Docs-only mode: extraction inventory is empty. Documentation content will be fetched from `doc_urls` in step 3c. Auto-proceeding."
|
|
276
276
|
|
|
277
|
+
**Zero-export sanity check (source mode):** If `extraction_mode != "docs-only"` AND `export_count == 0` AND the brief declares no `doc_urls`, an empty extraction is almost always an error — a wrong branch/tag, an over-narrow `scope.include`, or a failed AST run — not a valid empty surface. Do not let this sail through to a green report. Surface a distinct warning at the gate:
|
|
278
|
+
|
|
279
|
+
"**⚠️ Zero public exports extracted.** A source-type brief produced no documented surface and declares no `doc_urls`. This usually means a scope/branch/tag mismatch (wrong `target_version`, over-narrow `scope.include`) or a failed AST run — the compiled skill would document nothing. Verify the brief's source ref and scope before continuing.
|
|
280
|
+
|
|
281
|
+
**[C] Continue anyway** — compile an empty surface (default)"
|
|
282
|
+
|
|
283
|
+
Under `{headless_mode}`, do not auto-pass silently: set `status: "partial"` and `summary.warning: "zero-exports"` on the result contract (carried to step 8's record), log `"headless: zero public exports extracted — likely scope/branch/tag mismatch, continuing"`, append a `headless_decisions[]` entry `{step: "extract", gate: "zero-exports", decision: "C", rationale: "headless mode — zero exports, no human to confirm scope/ref", timestamp: {ISO}}` and, the moment it lands, append the same object as a JSON line to the durable audit sink `{sidecar_path}/auto-decisions.jsonl` (the on-landing append established at step 1 §3), and proceed. The distinct warning string surfaces the worst kind of failure (looks green, isn't) where a human or automator can act on it.
|
|
284
|
+
|
|
277
285
|
Display the extraction findings for user confirmation:
|
|
278
286
|
|
|
279
287
|
"**Extraction complete.**
|
|
@@ -291,26 +299,11 @@ Display the extraction findings for user confirmation:
|
|
|
291
299
|
|
|
292
300
|
{warnings if any files skipped or degraded}
|
|
293
301
|
|
|
294
|
-
Review the extraction summary above
|
|
295
|
-
|
|
296
|
-
### 7. Present MENU OPTIONS
|
|
297
|
-
|
|
298
|
-
Display: "**Extraction Summary — Select an Option:** [C] Continue to compilation"
|
|
299
|
-
|
|
300
|
-
#### EXECUTION RULES:
|
|
301
|
-
|
|
302
|
-
- IF docs-only mode (`extraction_mode: "docs-only"`): Auto-proceed immediately to `{nextStepFile}` — no user interaction required
|
|
303
|
-
- OTHERWISE: ALWAYS halt and wait for user input after presenting the extraction summary
|
|
304
|
-
- **GATE [default: C]** — If `{headless_mode}`: auto-proceed with [C] Continue, log: "headless: auto-approve extraction summary"
|
|
305
|
-
- This is Gate 2 — user must confirm before compilation proceeds (except docs-only mode)
|
|
306
|
-
- User may ask questions about the extraction results before continuing
|
|
307
|
-
|
|
308
|
-
#### Menu Handling Logic:
|
|
302
|
+
Review the extraction summary above, then confirm to continue."
|
|
309
303
|
|
|
310
|
-
|
|
311
|
-
- IF Any other comments or queries: answer questions about the extraction results, then redisplay the menu
|
|
304
|
+
### 7. Gate 2 — Confirm Extraction
|
|
312
305
|
|
|
313
|
-
|
|
306
|
+
Docs-only mode (`extraction_mode: "docs-only"`) needs no confirmation — auto-proceed to `{nextStepFile}`.
|
|
314
307
|
|
|
315
|
-
|
|
308
|
+
Otherwise this is a confirmation gate: halt after the §6 summary and wait for the user to continue (they may ask about the results first). **GATE [default: continue]** — under `{headless_mode}`, auto-proceed and log "headless: auto-approve extraction summary". On continue, load `{nextStepFile}`, read it fully, then execute it.
|
|
316
309
|
|
|
@@ -13,7 +13,7 @@ After initial AST extraction, some top-level exports may resolve to **module imp
|
|
|
13
13
|
**Tracing protocol:**
|
|
14
14
|
|
|
15
15
|
1. Read the entry point file (e.g., `{package}/__init__.py`) and extract all `from .X import Y` statements
|
|
16
|
-
2. For each import where Y was
|
|
16
|
+
2. For each import where Y was not found by the initial AST scan:
|
|
17
17
|
- Check if the import path resolves to a directory (e.g., `{package}/api/v1/delete/` exists with `__init__.py`)
|
|
18
18
|
- If directory: read its `__init__.py` to find the actual re-exported symbol
|
|
19
19
|
- **Handle aliases:** Check for `from .module import A as B` patterns in the intermediate `__init__.py`. If the parent imports `B`, trace through to `A` in `.module`. If the parent imports `A` but the `__init__.py` only exports it as `B` (via `from .module import A as B`), match by original name `A` and note the alias
|
|
@@ -76,7 +76,7 @@ The discovery step stores `{ccc_discovery: [{file, score, snippet}]}` in context
|
|
|
76
76
|
When `{ccc_discovery}` is present and non-empty:
|
|
77
77
|
|
|
78
78
|
1. Files appearing in `{ccc_discovery}` results move to the front of the extraction queue, sorted by relevance score descending
|
|
79
|
-
2. Files
|
|
79
|
+
2. Files not in CCC results remain in the queue — they are not excluded, only deprioritized
|
|
80
80
|
3. If the CCC intersection with scoped files produces <10 files: include all scoped files (CCC results too narrow)
|
|
81
81
|
4. Proceed with the AST Extraction Protocol on the pre-ranked list
|
|
82
82
|
|
|
@@ -113,7 +113,7 @@ Same extraction as Forge tier. Deep tier adds enrichment in step 4, not extracti
|
|
|
113
113
|
|
|
114
114
|
When AST tools are available (Forge/Deep tier), follow this deterministic protocol to prevent output overflow on large codebases.
|
|
115
115
|
|
|
116
|
-
**"Files in scope"** = files remaining after applying `include_patterns` and `exclude_patterns` from the brief, filtered by the target language extension. This is
|
|
116
|
+
**"Files in scope"** = files remaining after applying `include_patterns` and `exclude_patterns` from the brief, filtered by the target language extension. This is not the total repository file count from step 1's tree listing. Use the filtered count from step 3 section 2 as the decision tree input.
|
|
117
117
|
|
|
118
118
|
### Decision Tree
|
|
119
119
|
|
|
@@ -166,7 +166,7 @@ find_code_by_rule(
|
|
|
166
166
|
|
|
167
167
|
### CLI Streaming Fallback
|
|
168
168
|
|
|
169
|
-
When MCP tools are unavailable or the repo exceeds 500 files in scope, use `--json=stream` (
|
|
169
|
+
When MCP tools are unavailable or the repo exceeds 500 files in scope, use `--json=stream` (not `--json` or `--json=pretty`, which load the whole result set into memory) with line-by-line Python processing:
|
|
170
170
|
|
|
171
171
|
**Head cap selection:** The `| head -N` cap at the end of the pipeline controls how many exports are captured. Select `N` based on scope and tier:
|
|
172
172
|
- **Default (Quick/Forge, any scope):** `N = 200`
|
|
@@ -205,11 +205,11 @@ for line in sys.stdin:
|
|
|
205
205
|
" | head -{HEAD_CAP}
|
|
206
206
|
```
|
|
207
207
|
|
|
208
|
-
**
|
|
208
|
+
**Streaming constraints (these prevent OOM on large result sets):**
|
|
209
209
|
|
|
210
|
-
-
|
|
211
|
-
-
|
|
212
|
-
-
|
|
210
|
+
- Use `--json=stream`, not `--json` — the latter loads the entire array into memory
|
|
211
|
+
- Process line-by-line (`for line in sys.stdin`), not `json.load(sys.stdin)`
|
|
212
|
+
- Cap output with `| head -N` as a safety valve
|
|
213
213
|
- For repos > 500 files, process in directory batches of 20-50 files each: split by top-level source directory, run the CLI streaming template per batch with the same head cap, then merge results and deduplicate by export name (keep the first occurrence if duplicates exist across batches)
|
|
214
214
|
|
|
215
215
|
### YAML Rule Recipes by Language
|
|
@@ -287,7 +287,7 @@ rule:
|
|
|
287
287
|
pattern: 'export class $NAME { $$$ }'
|
|
288
288
|
```
|
|
289
289
|
|
|
290
|
-
> **Important:** The body (`{ $$$ }`) is required on ast-grep 0.42.x. The bare `export class $NAME` pattern returns zero matches — and emits a `Pattern contains an ERROR node` warning — through **both** `find_code()` and the CLI, because an incomplete class declaration does not parse as a complete statement (see Known Limitation #9). With the body present, the simple `find_code()` pattern detects class exports reliably; `find_code_by_rule` would additionally require an explicit AST `kind` rule.
|
|
290
|
+
> **Important:** The body (`{ $$$ }`) is required on ast-grep 0.42.x. The bare `export class $NAME` pattern returns zero matches — and emits a `Pattern contains an ERROR node` warning — through **both** `find_code()` and the CLI, because an incomplete class declaration does not parse as a complete statement (see Known Limitation #9). With the body present, the simple `find_code()` pattern detects class exports reliably — it matches non-generic classes only; generic (`export class $NAME<T>`) and generic-extends (`export class $NAME<T> extends $BASE`) forms are skipped, so source-read them via `^export (abstract )?class` and merge by name+file (see Known Limitation #10). `find_code_by_rule` would additionally require an explicit AST `kind` rule.
|
|
291
291
|
|
|
292
292
|
**JavaScript/TypeScript — re-export detection (use `find_code`):**
|
|
293
293
|
|
|
@@ -411,6 +411,8 @@ When using ast-grep for extraction, be aware of these documented limitations:
|
|
|
411
411
|
|
|
412
412
|
Never silently accept zero results for a declaration form the source language commonly uses.
|
|
413
413
|
|
|
414
|
+
10. **Generic class declarations do not match non-generic class patterns (ast-grep 0.42.x):** The non-generic patterns `export class $NAME { $$$ }` and `export class $NAME extends $BASE { $$$ }` silently skip every generic form on ast-grep 0.42.2 — verified via both the CLI (`ast-grep run -p ... -l typescript`) and `find_code()`, the first matched only a plain `Plain` and the second only a plain `PlainExtends` on a fixture of `Plain` / `Generic<T>` / `GenericExtends<T> extends Base<T>` / `abstract AbstractGeneric<T>` / `PlainExtends`. The per-shape generic patterns `export class $NAME<$$$P> { $$$ }`, `export class $NAME<$$$P> extends $BASE { $$$ }`, and `export abstract class $NAME<$$$P> { $$$ }` each match exactly **one** shape — no single pattern covers all of them. **Workaround:** Always run a source-read fallback `^export (abstract )?class` over the in-scope `.ts` sources (T1-low) and merge by name+file with the AST results, mirroring the `export function` guidance in #9. The bare `class $NAME` pattern catches every form but over-captures non-exported classes, so it still needs the source-read pass to re-impose the exported-only filter — this is the opposite trade from the Python #7 `^[^_]` re-filter, since TS has no name-prefix convention for exports. Never accept a class inventory that omits generic classes when the source uses them.
|
|
415
|
+
|
|
414
416
|
### Component Library Demo/Example Auto-Exclusion
|
|
415
417
|
|
|
416
418
|
When `scope.type: "component-library"`, auto-detect and propose demo/example exclusions before extraction begins. **User confirmation is required before applying** — some `examples/` directories contain API-level code.
|