bmad-module-skill-forge 0.7.2 → 0.7.4

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.
Files changed (23) hide show
  1. package/package.json +1 -1
  2. package/src/knowledge/ccc-bridge.md +32 -0
  3. package/src/knowledge/qmd-registry.md +1 -1
  4. package/src/workflows/analyze-source/data/skill-brief-schema.md +3 -1
  5. package/src/workflows/analyze-source/steps-c/step-05-recommend.md +4 -4
  6. package/src/workflows/brief-skill/data/skill-brief-schema.md +3 -1
  7. package/src/workflows/brief-skill/steps-c/step-02-analyze-target.md +8 -0
  8. package/src/workflows/brief-skill/steps-c/step-03-scope-definition.md +6 -6
  9. package/src/workflows/brief-skill/steps-c/step-04-confirm-brief.md +4 -4
  10. package/src/workflows/create-skill/data/compile-assembly-rules.md +1 -0
  11. package/src/workflows/create-skill/data/extraction-patterns.md +45 -2
  12. package/src/workflows/create-skill/data/skill-sections.md +2 -1
  13. package/src/workflows/create-skill/steps-c/step-02b-ccc-discover.md +6 -2
  14. package/src/workflows/create-skill/steps-c/step-03-extract.md +22 -1
  15. package/src/workflows/create-skill/steps-c/step-03b-fetch-temporal.md +2 -2
  16. package/src/workflows/create-skill/steps-c/step-03c-fetch-docs.md +2 -2
  17. package/src/workflows/create-skill/steps-c/step-05-compile.md +13 -2
  18. package/src/workflows/create-skill/steps-c/step-06-validate.md +10 -6
  19. package/src/workflows/setup-forge/steps-c/step-01b-ccc-index.md +65 -13
  20. package/src/workflows/setup-forge/steps-c/step-02-write-config.md +5 -3
  21. package/src/workflows/test-skill/data/source-access-protocol.md +8 -2
  22. package/src/workflows/test-skill/steps-c/step-03-coverage-check.md +2 -0
  23. package/src/workflows/update-skill/steps-c/step-03-re-extract.md +2 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "bmad-module-skill-forge",
4
- "version": "0.7.2",
4
+ "version": "0.7.4",
5
5
  "description": "BMAD module — Turn code and docs into instructions AI agents can actually follow. Progressive capability tiers (Quick/Forge/Forge+/Deep).",
6
6
  "keywords": [
7
7
  "bmad",
@@ -77,6 +77,36 @@ The ccc search is invisible in the output artifact. A Forge+ skill's citations a
77
77
  - A stale index still produces useful results — the workflow proceeds with the stale index and notes the staleness
78
78
  - setup-forge is the designated refresh authority
79
79
 
80
+ ### Exclusion Patterns
81
+
82
+ CCC stores its configuration at `{project-root}/.cocoindex_code/settings.yml`. This file contains `exclude_patterns` and `include_patterns` arrays in glob format. `ccc init` creates the file with sensible defaults (excludes `node_modules`, `__pycache__`, hidden dirs, etc.).
83
+
84
+ **SKF infrastructure exclusions:** setup-forge step-01b appends SKF-specific exclusion patterns after `ccc init` creates the default config. These patterns prevent indexing of framework and output directories that have zero value for source extraction:
85
+
86
+ | Pattern | Purpose |
87
+ |---------|---------|
88
+ | `**/_bmad` | SKF framework module (workflow instructions, agents, knowledge) |
89
+ | `**/_bmad-output` | Build output artifacts (TODO files, reports) |
90
+ | `**/.claude` | Claude Code configuration |
91
+ | `**/_skf-learn` | SKF learning materials |
92
+ | `**/{skills_output_folder}` | Generated skill files (from manifest, default: `skills`) |
93
+ | `**/{forge_data_folder}` | Compilation workspace (from manifest, default: `forge-data`) |
94
+
95
+ The `skills_output_folder` and `forge_data_folder` values are read from `_bmad/_config/skf-manifest.yaml` when available, falling back to the defaults `skills` and `forge-data`. Patterns are appended only if not already present — user customizations to `settings.yml` are preserved.
96
+
97
+ The configured exclusion patterns are stored in `ccc_index.exclude_patterns` in forge-tier.yaml for reference.
98
+
99
+ ### Deferred Discovery (Remote Sources)
100
+
101
+ For remote repository sources (GitHub URLs), CCC cannot operate during step-02b because no local code exists yet. The ephemeral clone happens in step-03. To provide CCC pre-ranking for remote sources:
102
+
103
+ 1. **step-02b:** Detects remote source, sets `{ccc_discovery: []}`, displays deferred message
104
+ 2. **step-03:** After ephemeral clone succeeds, detects the deferred scenario (`tools.ccc == true AND {ccc_discovery} is empty AND ephemeral_clone_active == true AND tier is Forge+/Deep`)
105
+ 3. **step-03:** Runs `ccc init {temp_path}` + `ccc index` on the ephemeral clone (extended timeout or background mode, verified via `ccc status`)
106
+ 4. **step-03:** Executes CCC search and populates `{ccc_discovery}` before AST extraction begins
107
+
108
+ The ephemeral clone index is not registered in `ccc_index_registry` — the clone is deleted after extraction and the CCC daemon's own GC handles orphaned indexes.
109
+
80
110
  ### Relationship to QMD Registry
81
111
 
82
112
  ccc_index and qmd_collections are **orthogonal**:
@@ -100,6 +130,8 @@ To prevent excessive daemon calls, workflow steps cap ccc queries:
100
130
  - Running ccc_bridge.ensure_index() without checking ccc_index.status first — unnecessary re-indexing
101
131
  - Passing ccc results directly to the extraction inventory — they are candidates, not extractions
102
132
  - Listing ccc as "unavailable" in reports for Quick/Forge tiers — ccc is a Forge+ capability, not something Quick/Forge tiers are missing
133
+ - Indexing without configuring SKF exclusions — framework and output directories pollute search results
134
+ - Skipping CCC discovery for remote sources without deferring to step-03 — remote repos deserve the same pre-ranking as local sources
103
135
 
104
136
  ## Related Fragments
105
137
 
@@ -127,7 +127,7 @@ These registries are orthogonal — they never reference each other, and their j
127
127
 
128
128
  ```
129
129
  qmd collection remove {name}-extraction (if exists)
130
- qmd collection add skills/{name} --name {name}-extraction --mask "**/*"
130
+ qmd collection add {project-root}/skills/{name} --name {name}-extraction --mask "**/*"
131
131
  qmd embed
132
132
  ```
133
133
 
@@ -9,7 +9,7 @@ Defines the output contract for skill-brief.yaml files generated by analyze-sour
9
9
  | Field | Type | Constraint | Description |
10
10
  |-------|------|------------|-------------|
11
11
  | name | string | kebab-case `[a-z0-9-]+` | Unique skill identifier |
12
- | version | string | Semantic `X.Y.Z` | Auto-detect from source (see Version Detection below), fall back to `1.0.0` |
12
+ | version | string | Semantic version (`X.Y.Z` or `X.Y.Z-prerelease`) | Auto-detect from source (see Version Detection below), fall back to `1.0.0` |
13
13
  | source_repo | string | GitHub URL or local path | Repository or project root (optional when `source_type: "docs-only"`) |
14
14
  | language | string | Recognized language | Primary programming language |
15
15
  | scope | object | See Scope Object below | Boundary definition |
@@ -49,6 +49,8 @@ If detection succeeds, use the detected version. If it fails or returns a non-se
49
49
 
50
50
  The create-skill workflow (step-03-extract) also performs version reconciliation at extraction time — if the source version has changed since the brief was created, the extraction step warns and uses the source version.
51
51
 
52
+ **Pre-release handling:** If the detected version contains a pre-release tag (e.g., `1.0.0-beta.0`, `2.0.0-rc.1`), preserve it as-is. Pre-release tags are valid semver and must not be stripped. When comparing versions during reconciliation, use semver-aware comparison that respects pre-release ordering.
53
+
52
54
  ## Scope Object
53
55
 
54
56
  ```yaml
@@ -5,8 +5,8 @@ description: 'Present unit recommendations with rationale for user confirmation
5
5
  nextStepFile: './step-06-generate-briefs.md'
6
6
  outputFile: '{forge_data_folder}/analyze-source-report-{project_name}.md'
7
7
  schemaFile: '../data/skill-brief-schema.md'
8
- advancedElicitationTask: '{project-root}/_bmad/core/workflows/advanced-elicitation/workflow.xml'
9
- partyModeWorkflow: '{project-root}/_bmad/core/workflows/party-mode/workflow.md'
8
+ advancedElicitationSkill: '/bmad-advanced-elicitation'
9
+ partyModeSkill: '/bmad-party-mode'
10
10
  ---
11
11
 
12
12
  # Step 5: Recommend
@@ -193,8 +193,8 @@ Display: "**Select an Option:** [A] Advanced Elicitation [P] Party Mode [D] Disc
193
193
 
194
194
  #### Menu Handling Logic:
195
195
 
196
- - IF A: Execute {advancedElicitationTask}, and when finished redisplay the menu
197
- - IF P: Execute {partyModeWorkflow}, and when finished redisplay the menu
196
+ - IF A: Invoke {advancedElicitationSkill}, and when finished redisplay the menu
197
+ - IF P: Invoke {partyModeSkill}, and when finished redisplay the menu
198
198
  - IF D: Accept a new repo path/URL from the user. Run a lightweight scan + classify (subset of steps 02-03) for the new source only. Merge new units into the existing report and update `project_paths[]` in frontmatter. Run export mapping for the new units (same logic as step 04 section 2). Generate recommendation cards for the new units and present them for confirmation. Then redisplay this menu.
199
199
  - IF C: Save recommendations to {outputFile}, update frontmatter, then load, read entire file, then execute {nextStepFile}
200
200
  - IF Any other comments or queries: help user respond then [Redisplay Menu Options](#8-present-menu-options)
@@ -5,7 +5,7 @@
5
5
  | Field | Type | Constraint | Description |
6
6
  |-------|------|------------|-------------|
7
7
  | name | string | kebab-case `[a-z0-9-]+` | Unique skill identifier |
8
- | version | string | Semantic `X.Y.Z` | Auto-detect from source (see Version Detection below), fall back to `1.0.0` |
8
+ | version | string | Semantic version (`X.Y.Z` or `X.Y.Z-prerelease`) | Auto-detect from source (see Version Detection below), fall back to `1.0.0` |
9
9
  | source_repo | string | GitHub URL or local path | Repository or project root (optional when `source_type: "docs-only"`) |
10
10
  | language | string | Recognized language | Primary programming language |
11
11
  | scope | object | See Scope Object below | Boundary definition |
@@ -45,6 +45,8 @@ If detection succeeds, use the detected version. If it fails or returns a non-se
45
45
 
46
46
  The create-skill workflow (step-03-extract) also performs version reconciliation at extraction time — if the source version has changed since the brief was created, the extraction step warns and uses the source version.
47
47
 
48
+ **Pre-release handling:** If the detected version contains a pre-release tag (e.g., `1.0.0-beta.0`, `2.0.0-rc.1`), preserve it as-is. Pre-release tags are valid semver and must not be stripped. When comparing versions during reconciliation, use semver-aware comparison that respects pre-release ordering.
49
+
48
50
  ## Scope Object Structure
49
51
 
50
52
  ```yaml
@@ -60,6 +60,12 @@ To analyze the target repository by resolving its location, reading its structur
60
60
  **For GitHub URLs:**
61
61
  - Use `gh api repos/{owner}/{repo}` to verify the repository exists
62
62
  - Use `gh api repos/{owner}/{repo}/git/trees/HEAD?recursive=1` to get the file tree
63
+
64
+ **Truncation detection:** After receiving the tree response, check the `truncated` field in the JSON output. If `truncated: true`:
65
+ - Display: "Note: GitHub API returned a truncated tree response ({count} items). Full analysis may require a local clone."
66
+ - Record in analysis summary: "Tree listing is partial — some files may not appear in the analysis."
67
+ - For very large repos (>1000 files in tree response): suggest local clone for complete analysis.
68
+
63
69
  - If inaccessible: **HALT** — "**Error:** Cannot access repository at {url}. Please verify the URL is correct and you have access. If private, ensure `gh auth` is configured."
64
70
 
65
71
  **For local paths:**
@@ -133,6 +139,8 @@ Based on detected language, identify public API surface:
133
139
 
134
140
  **Semantic Signals (Forge+ and Deep with ccc only):**
135
141
 
142
+ **Remote source guard:** If the target source was resolved via GitHub API (remote URL, not a local file path), skip this CCC subsection — CCC requires a local source index and cannot operate on remote-only sources. Note: "CCC semantic discovery skipped — target is remote. CCC discovery will run automatically during create-skill after the source is cloned."
143
+
136
144
  If `tools.ccc` is true in forge-tier.yaml, supplement the module listing with a semantic discovery pass:
137
145
 
138
146
  **CCC Semantic Discovery:**
@@ -4,8 +4,8 @@ description: 'Collaboratively define skill scope boundaries using analysis findi
4
4
 
5
5
  nextStepFile: './step-04-confirm-brief.md'
6
6
  scopeTemplatesFile: '../data/scope-templates.md'
7
- advancedElicitationTask: '{project-root}/_bmad/core/workflows/advanced-elicitation/workflow.xml'
8
- partyModeWorkflow: '{project-root}/_bmad/core/workflows/party-mode/workflow.md'
7
+ advancedElicitationSkill: '/bmad-advanced-elicitation'
8
+ partyModeSkill: '/bmad-party-mode'
9
9
  ---
10
10
 
11
11
  # Step 3: Scope Definition
@@ -90,7 +90,7 @@ Wait for confirmation. Then skip to section 5 (Summarize Scope Decisions) with:
90
90
 
91
91
  **If `source_type: "source"` (default):** Continue to scope templates below.
92
92
 
93
- ### 2c. Confirm Supplemental Documentation (if doc_urls collected)
93
+ ### 2b. Confirm Supplemental Documentation (if doc_urls collected)
94
94
 
95
95
  **If `source_type: "source"` AND supplemental `doc_urls` were collected in step 01:**
96
96
 
@@ -104,7 +104,7 @@ Wait for confirmation. Record any changes to `doc_urls`.
104
104
 
105
105
  **If no supplemental doc_urls were collected:** Skip this subsection.
106
106
 
107
- ### 2b. Offer Scope Templates
107
+ ### 2c. Offer Scope Templates
108
108
 
109
109
  Load `{scopeTemplatesFile}` for the scope type options ([F], [M], [P]) and their descriptions.
110
110
 
@@ -167,8 +167,8 @@ Display: **Select an Option:** [A] Advanced Elicitation [P] Party Mode [C] Conti
167
167
 
168
168
  #### Menu Handling Logic:
169
169
 
170
- - IF A: Execute {advancedElicitationTask}, and when finished redisplay the menu
171
- - IF P: Execute {partyModeWorkflow}, and when finished redisplay the menu
170
+ - IF A: Invoke {advancedElicitationSkill}, and when finished redisplay the menu
171
+ - IF P: Invoke {partyModeSkill}, and when finished redisplay the menu
172
172
  - IF C: Load, read entire file, then execute {nextStepFile}
173
173
  - IF Any other comments or queries: help user respond then [Redisplay Menu Options](#6-present-menu-options)
174
174
 
@@ -5,8 +5,8 @@ description: 'Present complete skill brief for user review and confirmation befo
5
5
  nextStepFile: './step-05-write-brief.md'
6
6
  reviseStepFile: './step-03-scope-definition.md'
7
7
  briefSchemaFile: '../data/skill-brief-schema.md'
8
- advancedElicitationTask: '{project-root}/_bmad/core/workflows/advanced-elicitation/workflow.xml'
9
- partyModeWorkflow: '{project-root}/_bmad/core/workflows/party-mode/workflow.md'
8
+ advancedElicitationSkill: '/bmad-advanced-elicitation'
9
+ partyModeSkill: '/bmad-party-mode'
10
10
  ---
11
11
 
12
12
  # Step 4: Confirm Brief
@@ -165,8 +165,8 @@ Display: **Select an Option:** [R] Revise Scope [A] Advanced Elicitation [P] Par
165
165
  #### Menu Handling Logic:
166
166
 
167
167
  - IF R: Load, read entire file, then execute {reviseStepFile} to re-enter scope definition
168
- - IF A: Execute {advancedElicitationTask}, and when finished redisplay the menu
169
- - IF P: Execute {partyModeWorkflow}, and when finished redisplay the menu
168
+ - IF A: Invoke {advancedElicitationSkill}, and when finished redisplay the menu
169
+ - IF P: Invoke {partyModeSkill}, and when finished redisplay the menu
170
170
  - IF C: Load, read entire file, then execute {nextStepFile}
171
171
  - IF Any other comments or queries: help user respond, apply any field adjustments, re-present brief if changed, then [Redisplay Menu Options](#6-present-menu-options)
172
172
 
@@ -116,6 +116,7 @@ Do NOT repeat Tier 1's name/purpose/key-params table format in Tier 2. Tier 2 is
116
116
  4. If Tier 1 alone exceeds 300 lines, reduce Key API Summary and Architecture at a Glance
117
117
  5. Tier 1 sections are kept short enough that `split-body` targets the larger Tier 2 sections (`## Full ...` headings) instead
118
118
  6. After split-body, SKILL.md must still contain all Tier 1 sections with actionable content
119
+ 7. **Signature fidelity:** When populating function entries from the extraction inventory, always use the `params` and `return_type` fields from the provenance-map entry (T1/AST-backed). Do not substitute parameter names, types, or return types from documentation, README examples, or enrichment annotations. T2/T3 sources may enrich descriptions and add usage notes, but structural signature data from AST extraction is authoritative.
119
120
 
120
121
  ### Reference File Rules
121
122
 
@@ -51,7 +51,7 @@ Structural extraction via ast-grep — verified exports with line-level citation
51
51
  - Internal/private functions: excluded (not part of public API)
52
52
 
53
53
  ### ast-grep Patterns
54
- - JS/TS: `export function $NAME($$$PARAMS): $RET` / `export const $NAME`
54
+ - JS/TS: `export function $NAME($$$PARAMS): $RET` / `export const $NAME = ($$$PARAMS) => $BODY` / `export const $NAME` / `export class $NAME`
55
55
  - Rust: `pub fn $NAME($$$PARAMS) -> $RET`
56
56
  - Python: function definitions within `__all__` list
57
57
  - Go: capitalized function definitions
@@ -260,6 +260,32 @@ rule:
260
260
  pattern: 'export const $NAME = $VALUE'
261
261
  ```
262
262
 
263
+ **JavaScript/TypeScript — exported arrow functions:**
264
+
265
+ ```yaml
266
+ id: js-exported-arrow-functions
267
+ language: typescript
268
+ rule:
269
+ pattern: 'export const $NAME = ($$$PARAMS) => $BODY'
270
+ ```
271
+
272
+ > **JS/TS Pattern Merging:** Modern TypeScript codebases often use `export const` exclusively for all exports (arrow functions, objects, constants). Run ALL four JS/TS patterns (functions, arrow functions, constants, classes) and merge results by `$NAME`. Priority when deduplicating: arrow function match > function declaration match > constant match. Arrow function matches capture parameters directly; constant matches require inspecting `$VALUE` to extract signatures.
273
+
274
+ **JavaScript/TypeScript — exported classes (use `find_code`, not `find_code_by_rule`):**
275
+
276
+ ```yaml
277
+ id: js-exported-classes
278
+ language: typescript
279
+ rule:
280
+ pattern: 'export class $NAME'
281
+ ```
282
+
283
+ > **Important:** For class patterns, use `find_code()` rather than `find_code_by_rule()`. The `find_code_by_rule` API requires explicit AST `kind` rules for class exports, which adds complexity. The simpler `find_code()` pattern approach works reliably for class detection.
284
+
285
+ **JavaScript/TypeScript — re-export detection (use `find_code`):**
286
+
287
+ Use `find_code()` with pattern `export { $$$NAMES } from $SOURCE` for re-export detection. Note: this pattern may produce multiple AST node matches. Post-process results to split comma-separated names from `$$$NAMES`. For complex re-export chains (aliased exports, default re-exports, namespace re-exports), fall back to the Re-Export Tracing protocol in `extraction-patterns-tracing.md`.
288
+
263
289
  **Rust — public functions:**
264
290
 
265
291
  ```yaml
@@ -277,12 +303,29 @@ rule:
277
303
  id: go-exported-functions
278
304
  language: go
279
305
  rule:
280
- pattern: 'func $NAME($$$PARAMS) $RET'
306
+ any:
307
+ - pattern: 'func $NAME($$$PARAMS) $RET'
308
+ - pattern: 'func $NAME($$$PARAMS)'
281
309
  constraints:
282
310
  NAME:
283
311
  regex: '^[A-Z]'
284
312
  ```
285
313
 
314
+ ### Known ast-grep Limitations
315
+
316
+ When using ast-grep for extraction, be aware of these documented limitations:
317
+
318
+ 1. **`find_code_by_rule` requires explicit `kind` for class exports:** The `export class $NAME` pattern needs a `kind` rule specifying the tree-sitter node type when used with `find_code_by_rule`. Use the simpler `find_code()` API instead for class detection.
319
+
320
+ 2. **Re-export patterns produce multiple AST nodes:** `export { A, B, C } from './module'` decomposes into multiple metavariable bindings for `$$$NAMES`. Results require post-processing to split comma-separated names.
321
+
322
+ 3. **Default anonymous exports capture no name:** `export default function $NAME` works, but `export default $EXPR` (anonymous default export) captures no name in `$NAME`. Fall back to source reading (T1-low) for anonymous defaults.
323
+
324
+ 4. **Fallback protocol:** If an ast-grep pattern returns errors or zero results when results are expected:
325
+ - First: retry with `find_code()` using a simpler pattern (drop type annotations, use broader match)
326
+ - Second: if `find_code()` also fails, fall back to source reading for that pattern category (T1-low confidence)
327
+ - Never silently accept zero results for a pattern category that the source language commonly uses
328
+
286
329
  ### Re-Export Tracing and Script/Asset Extraction
287
330
 
288
331
  See `extraction-patterns-tracing.md` for:
@@ -199,7 +199,8 @@ Each reference file includes:
199
199
  "source_line": 42,
200
200
  "confidence": "T1",
201
201
  "extraction_method": "ast-grep",
202
- "ast_node_type": "export_function_declaration"
202
+ "ast_node_type": "export_function_declaration",
203
+ "signature_source": "T1"
203
204
  }
204
205
  ],
205
206
  "file_entries": [
@@ -47,7 +47,7 @@ For Quick and Forge tiers, or when ccc is unavailable, skip silently and proceed
47
47
 
48
48
  - Available: tier, tools.ccc, ccc_index from forge-tier.yaml (loaded in step-01)
49
49
  - Available: brief_data (name, scope, description) from step-01
50
- - Available: source_root (resolved source path) from step-01
50
+ - Available: source_root (resolved source path) from step-01 — note: for remote sources, `source_root` may not be a local path until step-03 performs the ephemeral clone
51
51
  - Focus: Semantic discovery only — no extraction, no compilation
52
52
  - Dependencies: step-02 must have completed
53
53
 
@@ -65,7 +65,11 @@ Set `{ccc_discovery: []}` in context. Auto-proceed silently. Display no message.
65
65
 
66
66
  Check `tools.ccc` from forge-tier.yaml. If `tools.ccc` is false, set `{ccc_discovery: []}` in context and auto-proceed to section 5.
67
67
 
68
- If `tools.ccc` is true, continue to section 2.
68
+ If `tools.ccc` is true, check the remote source guard **before** proceeding to section 2:
69
+
70
+ **Remote source guard:** If `source_root` is a remote URL (GitHub repository not yet cloned locally — ephemeral clone happens in step-03), CCC cannot operate yet. Set `{ccc_discovery: []}` and display: "CCC discovery deferred — remote source will be indexed after ephemeral clone in step-03." Auto-proceed to section 5 (step completion). Step-03 will detect the deferred scenario and run CCC discovery on the ephemeral clone before AST extraction begins.
71
+
72
+ If `source_root` is a local path, continue to section 2.
69
73
 
70
74
  ### 2. Check CCC Index State
71
75
 
@@ -96,9 +96,30 @@ Load `{sourceResolutionData}` completely. Follow the **Remote Source Resolution*
96
96
 
97
97
  **Forge/Forge+/Deep Tier (AST available):**
98
98
 
99
+ **Deferred CCC Discovery (Forge+ and Deep — remote sources only):**
100
+
101
+ If ALL of these conditions are true:
102
+ - `tools.ccc` is true in forge-tier.yaml
103
+ - `{ccc_discovery}` is empty (step-02b deferred because source was remote)
104
+ - `ephemeral_clone_active` is true (clone succeeded in source resolution above)
105
+ - Tier is Forge+ or Deep
106
+
107
+ Then run CCC indexing and discovery on the ephemeral clone:
108
+
109
+ 1. **Index the clone:** Run `ccc init {temp_path}` then `ccc index` with an extended timeout or in background mode — indexing can take several minutes on large codebases (1000+ files). Use `ccc status` to verify completion — check that `Chunks` and `Files` counts are non-zero. If init fails or indexing fails, set `{ccc_discovery: []}` and continue — this is not an error.
110
+
111
+ 2. **Construct semantic query:** Build from brief data: `"{brief.name} {brief.scope}"`. Truncate to 80 characters — keep the full skill name and trim `brief.scope` from the end. If `brief.scope` is very short (< 10 chars), append terms from `brief.description` to fill the remaining space.
112
+
113
+ 3. **Execute search:** Run `ccc_bridge.search(query, temp_path, top_k=20)`:
114
+ - **Tool resolution:** Use `/ccc` skill search (Claude Code), ccc MCP server (Cursor), or `ccc search "{query}" --path {temp_path} --top 20` (CLI). See [knowledge/tool-resolution.md](../../../knowledge/tool-resolution.md).
115
+
116
+ 4. **Store results:** If search succeeds, store as `{ccc_discovery: [{file, score, snippet}]}`. Display: "**CCC semantic discovery (post-clone): {N} relevant regions identified across {M} unique files.**"
117
+
118
+ 5. **On failure:** Set `{ccc_discovery: []}`. Display: "CCC post-clone discovery unavailable — proceeding with standard extraction." Do NOT halt.
119
+
99
120
  **CCC Discovery Integration (Forge+ and Deep with ccc only):**
100
121
 
101
- If `{ccc_discovery}` is in context and non-empty (populated by step-02b):
122
+ If `{ccc_discovery}` is in context and non-empty (populated by step-02b or deferred discovery above):
102
123
  - 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
103
124
  - Files NOT in CCC results remain in the queue after ranked files — they are not excluded, only deprioritized
104
125
  - Display: "**CCC discovery: {N} files pre-ranked by semantic relevance** — extraction will prioritize these first."
@@ -172,7 +172,7 @@ If a `{skill-name}-temporal` collection already exists, remove and recreate for
172
172
 
173
173
  ```bash
174
174
  qmd collection remove {skill-name}-temporal
175
- qmd collection add _bmad-output/{skill-name}-temporal/ --name {skill-name}-temporal --mask "*.md"
175
+ qmd collection add {project-root}/_bmad-output/{skill-name}-temporal/ --name {skill-name}-temporal --mask "*.md"
176
176
  qmd embed
177
177
  ```
178
178
 
@@ -193,7 +193,7 @@ If an entry with `name: "{skill-name}-temporal"` already exists in `qmd_collecti
193
193
  **Clean up** the staging directory after successful indexing:
194
194
 
195
195
  ```bash
196
- rm -rf _bmad-output/{skill-name}-temporal/
196
+ rm -rf {project-root}/_bmad-output/{skill-name}-temporal/
197
197
  ```
198
198
 
199
199
  **Error handling:**
@@ -153,7 +153,7 @@ Parse the successfully fetched markdown for:
153
153
  **If tier is Deep and at least one URL was fetched successfully:**
154
154
 
155
155
  1. Write fetched markdown files to a staging directory: `_bmad-output/{skill-name}-docs/`
156
- 2. Index into QMD: `qmd collection add _bmad-output/{skill-name}-docs/ --name {skill-name}-docs --mask "*.md"`
156
+ 2. Index into QMD: `qmd collection add {project-root}/_bmad-output/{skill-name}-docs/ --name {skill-name}-docs --mask "*.md"`
157
157
  3. Generate embeddings: `qmd embed` (required for `vector_search` and `deep_search`)
158
158
  4. Register in forge-tier.yaml `qmd_collections` array:
159
159
 
@@ -165,7 +165,7 @@ Parse the successfully fetched markdown for:
165
165
  created_at: "{current ISO date}"
166
166
  ```
167
167
 
168
- 5. Clean up staging directory after indexing: `rm -rf _bmad-output/{skill-name}-docs/`
168
+ 5. Clean up staging directory after indexing: `rm -rf {project-root}/_bmad-output/{skill-name}-docs/`
169
169
 
170
170
  **If QMD indexing fails:** Warn: "QMD indexing of fetched docs failed. T3 items are still in the extraction inventory — enrichment will proceed without QMD-indexed docs." Continue.
171
171
 
@@ -59,6 +59,17 @@ To assemble the complete skill content from the extraction inventory and enrichm
59
59
 
60
60
  Load `{skillSectionsData}` and `{assemblyRulesData}` completely. These define the agentskills.io-compliant format and detailed assembly rules for all output artifacts.
61
61
 
62
+ ### 1b. Signature Fidelity Rule
63
+
64
+ **When assembling function signatures, parameter lists, and return types in any SKILL.md section or reference file:**
65
+
66
+ - **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`).
67
+ - **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.
68
+ - **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."
69
+ - **`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.
70
+
71
+ This rule applies to ALL sections including Tier 1 Key API Summary, Tier 2 Full API Reference, and Section 4b Migration & Deprecation Warnings.
72
+
62
73
  ### 2. Build SKILL.md Content
63
74
 
64
75
  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.
@@ -92,7 +103,7 @@ Following the structure from the skill-sections data file:
92
103
  - Set `source_commit` from resolved source (if available)
93
104
  - Set `stats` from extraction aggregate counts:
94
105
  - `exports_documented`: count of exports with documentation in the assembled SKILL.md
95
- - `exports_public_api`: count of exports from public entry points (`__init__.py`, `index.ts`, `lib.rs`, or equivalent)
106
+ - `exports_public_api`: count of exports from public entry points (`__init__.py`, `index.ts`, `lib.rs`, or equivalent) — derive this from step-03's entry-point validation (section 4b), NOT from the provenance-map entry count (which may be incomplete if extraction patterns missed some export types)
96
107
  - `exports_internal`: count of all other non-underscore-prefixed exports (internal modules, helpers, adapters)
97
108
  - `exports_total`: `exports_public_api` + `exports_internal`
98
109
  - `public_api_coverage`: `exports_documented / exports_public_api` (1.0 when all public API exports are documented; `null` if `exports_public_api` is 0)
@@ -121,7 +132,7 @@ Group functions logically by module, file, or functional area.
121
132
 
122
133
  ### 6. Build provenance-map.json Content
123
134
 
124
- One entry per extracted export: export_name, export_type, params[] (typed strings), return_type, source_file, source_line, confidence tier (T1/T1-low/T2), extraction_method, ast_node_type. If `scripts_inventory` or `assets_inventory` is non-empty, add `file_entries[]` with file_name, file_type, source_file, content_hash, confidence, extraction_method. See `{skillSectionsData}` for full schema.
135
+ One entry per extracted export: export_name, export_type, params[] (typed strings), return_type, source_file, source_line, confidence tier (T1/T1-low/T2), extraction_method, ast_node_type, signature_source ("T1"|"T1-low"|"T2"|"T3" — indicates which tier contributed the structural signature). If `scripts_inventory` or `assets_inventory` is non-empty, add `file_entries[]` with file_name, file_type, source_file, content_hash, confidence, extraction_method. See `{skillSectionsData}` for full schema.
125
136
 
126
137
  ### 7. Build evidence-report.md Content
127
138
 
@@ -76,6 +76,8 @@ This performs frontmatter validation, description quality checks, body limit enf
76
76
 
77
77
  **Context sync after --fix:** If `fixed[]` is non-empty (i.e., `--fix` modified files on disk), re-read the modified SKILL.md to update the in-context copy. Verify the re-read content matches expectations before proceeding. This prevents silent divergence between the in-context SKILL.md and the on-disk version that step-07 will use for artifact generation.
78
78
 
79
+ **Description preservation after --fix:** After re-reading the modified SKILL.md, compare the frontmatter `description` field against the original step-05 compiled description. If `--fix` replaced the description with a generic or truncated version, restore the original description to the on-disk file and update the in-context copy. The step-05 compiled description is authoritative — auto-fix tools must not replace trigger-optimized descriptions.
80
+
79
81
  **Note:** `skill-check` may return non-zero exit code even when `errorCount` is 0. Always rely on parsed JSON, not the shell exit code.
80
82
 
81
83
  - **Score ≥ 70:** Record "Schema: PASS (score: {score}/100)" in evidence-report
@@ -101,15 +103,17 @@ If fails: auto-fix (deterministic), re-validate once, record result. If passes:
101
103
 
102
104
  **If step 2 reported `body.max_lines` failure:**
103
105
 
104
- **Preferred approach — selective split:** Rather than a full `split-body`, identify which Tier 2 section(s) are largest (usually `## Full API Reference`) and manually extract only those to `references/`. Keep all Tier 1 content and smaller Tier 2 sections inline. This preserves agent accuracy inline passive context achieves 100% task accuracy vs 79% for on-demand retrieval (per Vercel research). The rationale: inline passive context achieves 100% task accuracy vs 79% for on-demand retrieval (per Vercel research).
106
+ **Description preservation:** Before any split operation, capture the current SKILL.md frontmatter `description` field. After the split completes, verify the `description` was not modified. If it was replaced with a generic placeholder, restore the original immediately.
105
107
 
106
- **If manual selective split is not feasible**, fall back to the automated full split:
108
+ **Mandatory approach selective split:** Identify Tier 2 sections by their `## Full` heading prefix (e.g., `## Full API Reference`, `## Full Type Definitions`, `## Full Integration Patterns`). Extract ONLY those sections to `references/`, starting with the largest. Keep ALL Tier 1 content and any smaller sections inline. Inline passive context achieves 100% task accuracy vs 79% for on-demand retrieval (per Vercel research).
107
109
 
108
- ```bash
109
- npx skill-check split-body <staging-skill-dir> --write
110
- ```
110
+ **FORBIDDEN:** Running `npx skill-check split-body --write` without prior selective extraction. The `split-body --write` command extracts ALL `##` sections top-to-bottom, destroying Tier 1 inline content that the two-tier design depends on. This command is a LAST RESORT only after selective split has been attempted and proven insufficient.
111
+
112
+ **If selective split alone does not bring body under the limit** (rare — typically only occurs when Tier 1 itself exceeds 300 lines): reduce Tier 1 Key API Summary and Architecture at a Glance sections to fit within limits. Do NOT fall back to automated `split-body --write` to solve a Tier 1 sizing problem.
113
+
114
+ **Tier 1 preservation check:** After ANY split operation, verify that ALL of the following sections remain inline in SKILL.md (not moved to references/): Overview, Quick Start, Common Workflows, Key API Summary, Migration & Deprecation Warnings (if present), Key Types, Architecture at a Glance, CLI (if present), Scripts & Assets (if present), Manual Sections. If any Tier 1 section was moved to references/, restore it immediately and re-split targeting only Tier 2 sections.
111
115
 
112
- After any split (selective or full), verify that context snippet section anchors (`#quick-start`, `#key-types`) still resolve to headings in SKILL.md.
116
+ **Anchor validation and remediation:** After any split, verify that context-snippet section anchors (`#quick-start`, `#key-types`) still resolve to headings in SKILL.md. If an anchor no longer resolves (section was split out), restore that section to SKILL.md inline content — the context-snippet must always reference sections that exist in the main file.
113
117
 
114
118
  Then re-validate: `npx skill-check check <staging-skill-dir> --format json --no-security-scan`
115
119
 
@@ -9,7 +9,7 @@ nextStepFile: './step-02-write-config.md'
9
9
 
10
10
  ## STEP GOAL:
11
11
 
12
- If ccc is available (`{ccc: true}` from step-01), verify that the ccc index exists for the project root. If no index exists, create it. Store index state in context for step-02 to write into forge-tier.yaml.
12
+ If ccc is available (`{ccc: true}` from step-01), configure CCC exclusion patterns for SKF infrastructure directories, verify that the ccc index exists for the project root, and create or refresh it if needed. Store index state and exclusion patterns in context for step-02 to write into forge-tier.yaml.
13
13
 
14
14
  For Quick and Forge tiers, or when ccc is unavailable, skip silently and proceed.
15
15
 
@@ -32,7 +32,7 @@ For Quick and Forge tiers, or when ccc is unavailable, skip silently and proceed
32
32
  - 🎯 Focus only on ccc index verification and creation
33
33
  - 🚫 FORBIDDEN to display skip messages for Quick/Forge tiers
34
34
  - 🚫 FORBIDDEN to fail the workflow if ccc indexing fails
35
- - 🚫 FORBIDDEN to re-index if ccc index already exists and is fresh (< staleness threshold)
35
+ - 🚫 FORBIDDEN to re-index if ccc index already exists and is fresh (< staleness threshold) UNLESS new exclusion patterns were applied to settings.yml
36
36
 
37
37
  ## EXECUTION PROTOCOLS:
38
38
 
@@ -56,7 +56,7 @@ For Quick and Forge tiers, or when ccc is unavailable, skip silently and proceed
56
56
 
57
57
  Read `{ccc}` from step-01 context.
58
58
 
59
- **If `{ccc}` is false:** Set `{ccc_index_result: "none", ccc_indexed_path: null, ccc_last_indexed: null}`. Proceed directly to section 4 (Auto-Proceed) — no output, no messaging.
59
+ **If `{ccc}` is false:** Set `{ccc_index_result: "none", ccc_indexed_path: null, ccc_last_indexed: null, ccc_exclude_patterns: []}`. Proceed directly to section 4 (Auto-Proceed) — no output, no messaging.
60
60
 
61
61
  **If `{ccc}` is true:** Continue to section 2.
62
62
 
@@ -64,17 +64,58 @@ Read `{ccc}` from step-01 context.
64
64
 
65
65
  Read existing forge-tier.yaml at `{project-root}/_bmad/_memory/forger-sidecar/forge-tier.yaml` (if it exists from a previous run).
66
66
 
67
+ Read `staleness_threshold_hours` from `ccc_index.staleness_threshold_hours` in the existing forge-tier.yaml (default: 24 if not present or not a number). Use this value for the freshness check below.
68
+
67
69
  Check the `ccc_index` section:
68
- - If `ccc_index.indexed_path` matches `{project-root}` AND `ccc_index.status` is `"fresh"`:
69
- - Check freshness: if `ccc_index.last_indexed` is within `staleness_threshold_hours` (default 24h) of now → index is fresh
70
+ - If `ccc_index.indexed_path` matches `{project-root}` AND `ccc_index.status` is `"fresh"` or `"created"`:
71
+ - Check freshness: if `ccc_index.last_indexed` is within `staleness_threshold_hours` of now → index is fresh
70
72
  - Store `{ccc_index_result: "fresh", ccc_indexed_path: {project-root}, ccc_last_indexed: {existing timestamp}}`
71
- - Proceed to section 4
73
+ - Set `{needs_reindex: false}` — proceed to section 2b (exclusions must still be configured)
72
74
 
73
75
  - If `ccc_index.indexed_path` matches `{project-root}` but timestamp is older than threshold:
74
- - Note index is stale — proceed to section 3 for re-index (section 3 will overwrite `ccc_index_result` to `"created"` or `"failed"`)
76
+ - Set `{needs_reindex: true}` — proceed to section 2b then section 3
75
77
 
76
78
  - If `ccc_index` is missing, has null values, or path doesn't match:
77
- - Proceed to section 3 for initial index
79
+ - Set `{needs_reindex: true}` — proceed to section 2b then section 3
80
+
81
+ ### 2b. Configure CCC Exclusions
82
+
83
+ SKF infrastructure and output directories must be excluded from the CCC index — they contain workflow instructions, build artifacts, and generated skills that pollute semantic search results with zero extraction value.
84
+
85
+ **Build the SKF exclusion list:**
86
+
87
+ 1. Read `{project-root}/_bmad/_config/skf-manifest.yaml` to resolve configurable paths:
88
+ - `skills_output_folder` (default: `skills` if manifest is missing or field is absent)
89
+ - `forge_data_folder` (default: `forge-data` if manifest is missing or field is absent)
90
+
91
+ 2. Assemble the exclusion patterns using `**/` prefix format (matching `.cocoindex_code/settings.yml` convention — e.g., `**/node_modules`):
92
+ - `**/_bmad` — SKF framework module (workflows, agents, knowledge files)
93
+ - `**/_bmad-output` — Build output artifacts
94
+ - `**/.claude` — Claude Code configuration
95
+ - `**/_skf-learn` — SKF learning materials
96
+ - `**/{skills_output_folder}` — Generated skill files (resolved from manifest)
97
+ - `**/{forge_data_folder}` — Compilation workspace (resolved from manifest)
98
+
99
+ 3. Store `{ccc_exclude_patterns}` in context for step-02 to write into forge-tier.yaml.
100
+
101
+ **Apply exclusions to settings.yml:**
102
+
103
+ Check if `{project-root}/.cocoindex_code/settings.yml` exists. Set `{settings_yml_existed: true}` if it does, `{settings_yml_existed: false}` if not.
104
+
105
+ If `{settings_yml_existed}` is true (from a previous `ccc init` run):
106
+
107
+ 1. Read `settings.yml`
108
+ 2. For each pattern in `{ccc_exclude_patterns}`: if the pattern is NOT already present in `exclude_patterns`, append it and set `{exclusions_changed: true}`
109
+ 3. If `{exclusions_changed}`: write the updated `settings.yml` back, set `{needs_reindex: true}` (new exclusions require re-indexing), display: "**CCC exclusions configured:** {count} SKF patterns applied to .cocoindex_code/settings.yml"
110
+ 4. If no new patterns needed: display nothing (exclusions already configured)
111
+
112
+ This preserves any existing user customizations and default exclusions while ensuring SKF directories are filtered out.
113
+
114
+ If `{settings_yml_existed}` is false: the exclusions will be applied after `ccc init` in section 3.
115
+
116
+ **Flow decision:**
117
+ - If `{needs_reindex}` is true: proceed to section 3
118
+ - If `{needs_reindex}` is false: proceed to section 4 (Auto-Proceed)
78
119
 
79
120
  ### 3. Create or Refresh CCC Index
80
121
 
@@ -93,6 +134,15 @@ ccc init
93
134
 
94
135
  **If init fails** (project may already be initialized): continue — this is not an error.
95
136
 
137
+ **Apply SKF exclusion patterns (if not already applied in section 2b):**
138
+
139
+ If `{settings_yml_existed}` is false (first-time setup — `ccc init` just created it), apply exclusions now:
140
+
141
+ 1. Read `{project-root}/.cocoindex_code/settings.yml` (created by `ccc init`)
142
+ 2. For each pattern in `{ccc_exclude_patterns}`: if the pattern is NOT already present in `exclude_patterns`, append it
143
+ 3. Write the updated `settings.yml` back
144
+ 4. Display: "**CCC exclusions configured:** {count} SKF patterns applied to .cocoindex_code/settings.yml"
145
+
96
146
  Then run:
97
147
  ```bash
98
148
  ccc index
@@ -102,8 +152,8 @@ ccc index
102
152
 
103
153
  **If succeeds:**
104
154
  - Run `ccc status` to get file count
105
- - Store `{ccc_index_result: "created", ccc_indexed_path: {project-root}, ccc_last_indexed: {current ISO timestamp}, ccc_file_count: {count from status}}`
106
- - Display: "**CCC index created.** {file_count} files indexed for semantic discovery."
155
+ - Store `{ccc_index_result: "created", ccc_indexed_path: {project-root}, ccc_last_indexed: {current ISO timestamp}, ccc_file_count: {count from ccc status}}`
156
+ - Display: "**CCC index created.** {ccc_file_count} files indexed for semantic discovery."
107
157
 
108
158
  **If fails:**
109
159
  - Store `{ccc_index_result: "failed", ccc_indexed_path: null, ccc_last_indexed: null}`
@@ -134,8 +184,8 @@ ONLY WHEN ccc index verification is complete (or step is skipped for ccc unavail
134
184
  ### ✅ SUCCESS:
135
185
 
136
186
  - ccc unavailable: skipped silently with no output, context variables set to null/none
137
- - ccc available with fresh index: verified freshness, skipped re-index, context variables set
138
- - ccc available with stale/missing index: index created, context variables set with fresh timestamp
187
+ - ccc available with fresh index: verified freshness, exclusions configured, skipped re-index, context variables set
188
+ - ccc available with stale/missing index: exclusions configured, index created, context variables set with fresh timestamp
139
189
  - ccc indexing fails: logged gracefully, workflow continues, context variables set to failed/null
140
190
  - Auto-proceeded to step-02
141
191
 
@@ -143,8 +193,10 @@ ONLY WHEN ccc index verification is complete (or step is skipped for ccc unavail
143
193
 
144
194
  - Displaying skip messages when ccc is unavailable
145
195
  - Halting the workflow on ccc index failure
146
- - Re-indexing when index is already fresh and path matches
196
+ - Re-indexing when index is already fresh and path matches (unless exclusion patterns changed)
147
197
  - Writing forge-tier.yaml (that is step-02's responsibility)
148
198
  - Not storing ccc index context variables for step-02
199
+ - Indexing without configuring SKF exclusion patterns in `.cocoindex_code/settings.yml`
200
+ - Overwriting user customizations in `.cocoindex_code/settings.yml` instead of appending
149
201
 
150
202
  **Master Rule:** CCC indexing is always best-effort. Failures degrade gracefully. The workflow never halts over ccc issues.
@@ -41,7 +41,7 @@ Write the detected tool availability and calculated tier to forge-tier.yaml, cre
41
41
 
42
42
  ## CONTEXT BOUNDARIES:
43
43
 
44
- - Available: {detected_tools}, {calculated_tier}, {previous_tier} from step-01; {ccc_index_result}, {ccc_indexed_path}, {ccc_last_indexed} from step-01b
44
+ - Available: {detected_tools}, {calculated_tier}, {previous_tier} from step-01; {ccc_index_result}, {ccc_indexed_path}, {ccc_last_indexed}, {ccc_file_count}, {ccc_exclude_patterns} from step-01b
45
45
  - Focus: file I/O operations only
46
46
  - Limits: do not modify preferences.yaml if it exists
47
47
  - Dependencies: step-01 and step-01b must have completed with tool detection and CCC index results
@@ -78,6 +78,8 @@ ccc_index:
78
78
  last_indexed: {ccc_last_indexed from step-01b, or ~}
79
79
  status: {ccc_index_result from step-01b: "fresh"|"created"|"none"|"failed"}
80
80
  staleness_threshold_hours: 24
81
+ file_count: {ccc_file_count from step-01b, or ~}
82
+ exclude_patterns: {ccc_exclude_patterns from step-01b, or []}
81
83
 
82
84
  # CCC index registry (tracks which source paths have been indexed for skill workflows)
83
85
  # PRESERVE existing entries on re-runs — see Note below
@@ -88,7 +90,7 @@ ccc_index_registry: {preserved from existing forge-tier.yaml, or [] if first run
88
90
  qmd_collections: {preserved from existing forge-tier.yaml, or [] if first run}
89
91
  ```
90
92
 
91
- **Note on re-runs:** The `qmd_collections`, `ccc_index_registry` arrays, and `staleness_threshold_hours` value must be preserved across re-runs. Before overwriting forge-tier.yaml, read these existing values and re-inject them into the new write. These values are populated by create-skill workflows or customized by users and must not be reset.
93
+ **Note on re-runs:** The `qmd_collections`, `ccc_index_registry` arrays, and `staleness_threshold_hours` value must be preserved across re-runs. Before overwriting forge-tier.yaml, read these existing values and re-inject them into the new write. These values are populated by create-skill workflows or customized by users and must not be reset. Note: `exclude_patterns` is NOT preserved — it is always written fresh from `{ccc_exclude_patterns}` computed by step-01b.
92
94
 
93
95
  **This file is ALWAYS overwritten** on every run — it reflects current tool state.
94
96
 
@@ -150,7 +152,7 @@ ONLY WHEN forge-tier.yaml has been written successfully and preferences.yaml exi
150
152
 
151
153
  ### ✅ SUCCESS:
152
154
 
153
- - forge-tier.yaml written with accurate tool booleans (including ccc), tier, timestamp, ccc_index state, and preserved qmd_collections/ccc_index_registry arrays
155
+ - forge-tier.yaml written with accurate tool booleans (including ccc), tier, timestamp, ccc_index state (including exclude_patterns), and preserved qmd_collections/ccc_index_registry arrays
154
156
  - preferences.yaml exists (created with defaults on first run, preserved on re-run)
155
157
  - forge-data/ directory exists (created or pre-existing)
156
158
  - Auto-proceeded to step-03
@@ -21,9 +21,15 @@ Before analysis, determine source access level. Walk through these states in ord
21
21
  Check if `{source_path}` (from metadata.json `source_root`) exists on disk. If yes → full analysis at detected tier (AST + signatures). Set `analysis_confidence: full`.
22
22
 
23
23
  **State 2 — Local absent, provenance-map exists:**
24
- Check `{forge_data_folder}/{skill_name}/provenance-map.json`. If present, use it as the baseline export inventory — each entry contains structured fields: `export_name`, `export_type`, `params[]`, `return_type`, `source_file`, `source_line`, `confidence`, and `ast_node_type`. Cross-reference against SKILL.md documented exports for name-matching and param-by-param coverage. Signature verification compares SKILL.md's documented params/return types against provenance-map entries directly. If remote reading tools are available (zread, deepwiki, gh API, or similar), supplement by reading the entry point file for live signature verification. Set `analysis_confidence: provenance-map`.
24
+ Check `{forge_data_folder}/{skill_name}/provenance-map.json`. If present AND contains at least 1 entry, use it as the baseline export inventory — each entry contains structured fields: `export_name`, `export_type`, `params[]`, `return_type`, `source_file`, `source_line`, `confidence`, and `ast_node_type`. Cross-reference against SKILL.md documented exports for name-matching and param-by-param coverage. Signature verification compares SKILL.md's documented params/return types against provenance-map entries directly.
25
25
 
26
- **State 2 limitations:** Signature verification at State 2 is **string comparison only**, not semantic. Provenance-map stores parameters as flat string arrays (e.g., `["data: Union[BinaryIO, list, str]"]`), so `str` vs `String` or `list` vs `List[Any]` would be treated as mismatches even when semantically equivalent. For full type-aware verification (handling type aliases, generic equivalence), State 1 (local source) with AST re-parsing is required. When the SKILL.md was compiled from the same provenance-map (typical for create-then-test flows), strings match exactly and this limitation has no practical effect.
26
+ **Cross-reference with metadata.json:** After loading provenance-map entries, compare the entry count against `metadata.json`'s `exports[]` array length and `stats.exports_public_api` count. If metadata reports more exports than provenance-map entries:
27
+ - Compute `gap = metadata.exports.length - provenance_map.entries.length`
28
+ - Report: "Provenance-map contains {pmap_count} entries but metadata.json lists {meta_count} exports ({gap} gap). Coverage denominator uses the union."
29
+ - Build the coverage denominator from the **union** of provenance-map entry names and metadata.json `exports[]` names. Exports present in metadata but absent from provenance-map are counted as "missing documentation" in the coverage calculation.
30
+ - If metadata.json is unavailable or has no `exports[]` array, use provenance-map count alone with a note: "Coverage denominator is provenance-map only — may undercount if extraction was incomplete." If remote reading tools are available (zread, deepwiki, gh API, or similar), supplement by reading the entry point file for live signature verification. Set `analysis_confidence: provenance-map`.
31
+
32
+ **State 2 limitations:** Signature verification at State 2 is **string comparison only**, not semantic. Provenance-map stores parameters as flat string arrays (e.g., `["data: Union[BinaryIO, list, str]"]`), so `str` vs `String` or `list` vs `List[Any]` would be treated as mismatches even when semantically equivalent. For full type-aware verification (handling type aliases, generic equivalence), State 1 (local source) with AST re-parsing is required. When the SKILL.md was compiled from the same provenance-map (typical for create-then-test flows), most strings will match. However, enrichment (step-04) and doc-fetching (step-03c) during compilation may alter parameter descriptions, add type annotations, or normalize signatures, causing mismatches even in create-then-test flows. Expect some string-level mismatches and treat them as compilation artifacts, not source drift signals, until signature fidelity is enforced by step-05's Signature Fidelity Rule (see `signature_source` field in provenance-map entries).
27
33
 
28
34
  **State 3 — No provenance-map, metadata exports exist (quick-skill path):**
29
35
  If no provenance-map.json exists (typical for quick-skill output), fall back to `metadata.json`'s `exports[]` array for the export name list. Coverage check becomes a self-consistency comparison: are all names in `exports[]` documented in SKILL.md with description, parameters, and return type? Signatures cannot be verified. If remote reading tools are available, supplement by reading the entry point for live export comparison. Set `analysis_confidence: metadata-only`.
@@ -185,6 +185,8 @@ Load `{scoringRulesFile}` to determine category scores:
185
185
  - **Signature Accuracy:** (matching_signatures / total_documented) * 100 (Forge/Deep only, "N/A" for Quick)
186
186
  - **Type Coverage:** (documented_types / total_types) * 100 (Forge/Deep only, "N/A" for Quick)
187
187
 
188
+ **State 2 denominator validation:** When using provenance-map as the baseline (State 2), cross-reference the provenance-map entry count against `metadata.json`'s `exports[]` array before computing Export Coverage. If they diverge, use the union as the denominator per the source-access-protocol rules. Log the gap size if any.
189
+
188
190
  ### 5. Append Coverage Analysis to Output
189
191
 
190
192
  Append the **Coverage Analysis** section to `{outputFile}`:
@@ -139,6 +139,8 @@ This helps the merge step (section 4) prioritize which changes are most likely t
139
139
 
140
140
  CCC failures: skip ranking silently, all changes treated equally.
141
141
 
142
+ **Note on remote sources:** If `source_root` is an ephemeral clone (remote source), the clone path is not indexed by CCC. The search will return empty results and semantic ranking will be skipped. This is expected — deferred CCC indexing is implemented in create-skill step-03 but not in update-skill. All changes are treated equally for remote sources.
143
+
142
144
  **IF `tools.ccc` is false:** Skip this section silently.
143
145
 
144
146
  ### 3. Deep Tier QMD Enrichment (Conditional)