[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M69B4PCKJQANEJXBJKCTEXRB":3,"skill-same:01M69B4PCKJQANEJXBJKCTEXRB":84},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":28,"linkOnly":29,"markdownContent":30,"markdownBody":31,"frontMatter":32,"refName":33,"commitSha":34,"skillDirectory":35,"forksCount":36,"repositoryHtmlUrl":37,"repositoryHomepageUrl":6,"ownerHtmlUrl":38,"ownerBlogUrl":39,"ownerDescription":40,"updatedAt":41,"install":42,"resources":55},"01M69B4PCKJQANEJXBJKCTEXRB","project-decomposition",null,"Single-source codebase decomposition: scans a project scope, builds the module dependency graph, counts LOC by language, computes skip patterns (caller-supplied ∪ .gitignore ∪ baseline), and (when grouping is required) produces topology groupings with L3 quality validation. One skill owns ProjectProfile JSON, grouping protocols, and quality gates.\nTriggers: \"before generating a workflow plan\", \"before topology grouping\", \"project sizing\", \"LOC counting\", \"module grouping\", \"topology splitting rules\", \"topology consumer rules\", \"scale-aware splitting\", \"large codebase decomposition\", \"module dependency graph\", \"scope measurement\".\nNOT for: semantic architecture analysis, implementation planning, running tests\u002Fbuilds\u002Flinters.","microsoft\u002Fgithub-copilot-modernization","microsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6154722?v=4","01M698VYDXZ6JW5WH3CRV650R8","Microsoft","01M69B2DAY0HTBHWQN4WF3JDBQ",55,"MIT","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fgithub-copilot-modernization\u002Fblob\u002Fmain\u002Fplugins\u002Fgithub-copilot-modernization\u002Fskills\u002Fproject-decomposition\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[24,25,26,27],"project decomposition","workflow","architecture","quality validation","2026-11-10 10:12:30",false,"---\nname: project-decomposition\ndescription: |\n  Single-source codebase decomposition: scans a project scope, builds the module dependency graph, counts LOC by language, computes skip patterns (caller-supplied ∪ .gitignore ∪ baseline), and (when grouping is required) produces topology groupings with L3 quality validation. One skill owns ProjectProfile JSON, grouping protocols, and quality gates.\n  Triggers: \"before generating a workflow plan\", \"before topology grouping\", \"project sizing\", \"LOC counting\", \"module grouping\", \"topology splitting rules\", \"topology consumer rules\", \"scale-aware splitting\", \"large codebase decomposition\", \"module dependency graph\", \"scope measurement\".\n  NOT for: semantic architecture analysis, implementation planning, running tests\u002Fbuilds\u002Flinters.\n---\n\n# Project Decomposition: Recon, Grouping & Validation\n\n## What this skill does\n\nThis is the single entry point for measuring a codebase scope and (when needed) decomposing it into topology groups. Two modes:\n\n1. **Lightweight recon (JSON)** — `scripts\u002Fdecompose.py ... --profile-json` produces a structured `ProjectProfile` JSON with LOC \u002F file counts \u002F module list \u002F dep graph summary \u002F skip patterns. Used by upstream planners to decide pipeline variant and grouping needs.\n2. **Full grouping + validation** — `scripts\u002Fdecompose.py` directly, for L0→L1→L2 grouping protocol and L3 quality validation. Used when the workflow plan declares `grouping.needed: true`.\n\nBoth modes are the same `decompose.py` engine — single source of truth for LOC counting (`--lang` defines the LOC semantic boundary; `--exclude` defines the directory boundary), graph extraction, and validation scoring.\n\n### Which mode to run\n\n| Caller intent | Use | Why |\n|---------------|-----|-----|\n| Decide whether to fan out at all (sizing, dispatch) | `--profile-json` | Returns structured ProjectProfile (LOC, module count, depth, hub-ratio, sizing hints) without grouping output. Cheap, machine-readable. |\n| Caller already decided to fan out and needs L1 numbers + L2 grouping + L3 validation | run without `--profile-json`; then again with `--validate` for L3 | Human-readable Graph Statistics + Quality Scores. |\n| Caller wants both | run twice: once with `--profile-json` for the planner, once without for human L1 | The flags are mutually exclusive in one invocation; do not combine `--profile-json` with `--validate`. |\n\n`--profile-json` and `--validate` cannot be combined in a single invocation (the script rejects this).\n\n## When to Apply\n\n**Scale threshold**: Codebase is large enough that no single agent reading the source can hold any one group's source in context, or has enough modules that dependency-aware grouping adds value. The unit being sized is **one group's codebase scope** (which many agents in the pipeline must read), not a \"one-agent workload\" — every group still runs a full plan→execute→validate pipeline with many agent sessions.\n\n**Scope check** (after scale threshold is met, applied by the caller — see Workflow § input contract for the field this maps to):\n\n1. The caller determines the **rewrite scope** from the user request and passes it via the `Scope:` dispatch field:\n   - **Full rewrite** — all modules in scope → `scope = full`\n   - **Partial rewrite** — user specifies modules\u002Flayers\u002Ffeatures → `scope = scoped`\n   - **Cross-layer rewrite** — rewrite targets a different architectural layer (e.g. Razor → Angular while backend stays) → `scope = scoped` (only the target layer is in scope; source-layer modules are `context-only`)\n\n2. Apply the scope (classify groups using the dispatched value):\n   - `full` — all groups are `in-scope`\n   - `scoped` — analyze all modules for the dependency graph, but classify each group:\n     - **`in-scope`** — being rewritten → generates DAG tasks\n     - **`context-only`** — depended on by in-scope but NOT being rewritten → no DAG tasks, dependency context only\n\n3. **Skip entirely** if all of the following hold for the in-scope set:\n   - DAG depth ≤ 2 AND module count ≤ 3, AND\n   - total in-scope LOC \u003C `ideal_group_loc` (from `topology_hints`)\n\n   Report skip rationale back to the caller (plain text reply, not the artifact); do not produce a topology artifact.\n\n## Architecture: 3 Layers\n\n| Layer | Output |\n|-------|--------|\n| **L1 Extract** (`scripts\u002Fdecompose.py \u003Cpath> --lang '\u003Clang>' --exclude '\u003Cpatterns>'`) | Modules, edges, SCCs, DAG layers, LOC, oversized flags. No grouping. |\n| **L2 Group** (caller agent) | Module groups using L1 data + topology-aware judgment. See `references\u002Fgrouping.md`. |\n| **L3 Validate** (`scripts\u002Fdecompose.py \u003Cpath> --lang '\u003Clang>' --exclude '\u003Cpatterns>' --validate '\u003Cspec>'`) | 4 raw Quality Scores (Outlier ratio, SCC integrity, Group cycles, Coverage). Definitions and judgment protocol live in `references\u002Fgrouping.md` §4 and `references\u002Ftopology-thresholds.md`. |\n\nDo NOT skip any layer. L3 is the only authoritative quality check — hand-computed metrics are not accepted.\n\n## Files (load on demand)\n\n| File | Load when |\n|------|-----------|\n| `references\u002Fgrouping.md` | L2 step — topology-aware grouping rules + L3 metric definitions (authoritative source for thresholds) |\n| `templates\u002Foutput-template.md` | Output step — project topology artifact format and fixed path |\n| `references\u002Fconsume.md` | Downstream consumer contract — how the artifact is read and accepted |\n| `references\u002Fmanual-extraction.md` | Only if L1 reports `Unsupported language` (rare — C#\u002FJava\u002FPython\u002FJS-TS supported) |\n\n**Python is mandatory for topology grouping.** `decompose.py` is the only authoritative LOC counter for grouping\u002FL3 metrics — external counters drift across runs and inflate by 5–15% on comment-heavy languages, which destabilizes outlier-ratio and SCC-integrity scoring.\n\n`scripts\u002Fdecompose.py` invocation surface:\n- `\u003Cpath> --lang '\u003Clang>' --exclude '\u003Cmerged>'` — extract mode\n- `--validate '\u003Cspec>'` — L3 quality gate\n- `--module-loc \u003CModule>` — sub-dir LOC for a specific module\n- `--json out.json` — machine-readable dump\n- `--profile-json` — `ProjectProfile` JSON to stdout (see **JSON Profile Mode** below)\n\n`--lang` and `--exclude` are required. `--lang` accepts `python|java|csharp|javascript` (or aliases: `py`, `cs`\u002F`c#`\u002F`dotnet`, `js`\u002F`ts`\u002F`node`). For mixed projects pass comma-separated, e.g. `--lang csharp,javascript`. `--exclude` takes the **merged** list (see Workflow § effective_exclude).\n\n## Workflow\n\nThe caller dispatches with a fixed input contract — these fields MUST be present, do not infer them yourself:\n\n| Field | Type | Example | Used by |\n|-------|------|---------|---------|\n| `Source path:` | absolute path to repo root | `\u002Fpath\u002Fto\u002Frepo` | every L1\u002FL3 invocation as `\u003Csource-path>` |\n| `Language(s):` | comma-separated `decompose.py --lang` value | `csharp` or `csharp,javascript` | `--lang '\u003Clang>'` |\n| `Skip patterns:` | comma-separated path segments (may be empty) | `tests,docs,samples` | exclude-merge input |\n| `Scope:` | `full` \\| `scoped` | `scoped` | Scope check classification |\n| `Mode:` | `topology` \\| `profile-json` | `topology` | output shape — `profile-json` returns `ProjectProfile` JSON to stdout instead of producing the artifact (see **JSON Profile Mode** below) |\n\nAll five fields are required. If any is missing, halt and request it from the caller — do **not** guess or default. Then build the **effective exclude list** by union-ing four sources:\n\n```\neffective_exclude = caller_skip_patterns\n                  ∪ gitignore_dirs(\u003Csource-path>\u002F.gitignore)\n                  ∪ auto_gen_dirs(\u003Csource-path>)        ← see below\n                  ∪ BASELINE\n```\n\n**`auto_gen_dirs(path)`** — pre-L1 sniff for framework-generated code that the caller cannot anticipate (EF Core `Migrations\u002F`, protobuf-generated stubs, OpenAPI\u002FGraphQL codegen, ANTLR `.g4`-output dirs, etc.). These dirs may contain tens of thousands of lines that are not authored code; they distort outlier ratio and force spurious sub-splits. Procedure:\n\n1. Walk top 2 levels under `\u003Csource-path>` (skipping anything already in BASELINE \u002F gitignore_dirs \u002F caller_skip_patterns).\n2. For each directory whose **source-file LOC** (matching `--lang` extensions) ≥ 5% of project total, sample up to 3 source files (largest first) and read the **top 100 lines** of each.\n3. If ≥ 1 sampled file contains any of these markers (case-insensitive), add the directory's segment name to `auto_gen_dirs`:\n   - `\u003Cauto-generated>`\n   - `DO NOT EDIT`\n   - `This file was generated`\n   - `@generated`\n   - `Code generated by` (Go convention)\n   - `auto-generated by`\n4. Cap at 8 directories. Log each accepted dir and the marker that triggered it; this list is reproducible across runs.\n\nDo NOT use this mechanism to skip hand-written code that happens to be large — only marker-confirmed generated code qualifies. If marker matching is ambiguous, leave the dir in and let the outlier-ratio band trigger normal remediation.\n\n**BASELINE** (language-neutral, fixed list, always applied — fallback when caller\u002Fgitignore miss something):\n```\n.git, .svn, .hg, .idea, .vscode, .vs, .DS_Store,\nnode_modules, bower_components, vendor, packages,\n__pycache__, .venv, venv, .tox, .pytest_cache, .cache,\nbin, obj, target, build, dist, out,\n.gradle, .mvn\n```\n\nBASELINE is fixed and language-neutral. Project-type-specific extras (framework directories, generated folders) are the **caller**'s responsibility and must be passed via `caller_skip_patterns`; do not extend BASELINE per project.\n\n**`gitignore_dirs(path)`** — parse repo's `.gitignore` and extract directory-shaped entries:\n- keep: lines ending in `\u002F`, or bare path segments without glob chars (e.g. `wwwroot\u002Flib\u002F`, `App_Data`)\n- drop: blanks, comments (`#…`), negations (`!…`), file-level globs (any line containing `*` `?` `[`)\n- strip leading\u002Ftrailing `\u002F`; dedupe across all three sources\n- if `.gitignore` is missing, this set is empty\n\nPass the merged list verbatim in every `decompose.py` invocation as `--exclude '\u003Cmerged>'`. Rationale: build output, vendored deps, and generated assets the repo itself ignores must not inflate LOC or group sizes — relying on the caller alone is fragile.\n\n1. **Extract (L1)** — Invoke `scripts\u002Fdecompose.py \u003Csource-path> --lang '\u003Clang>' --exclude '\u003Cmerged>'`. Treat output as source of truth; do NOT re-extract module\u002Fedge\u002FLOC data from raw source. Apply the caller's `scope` to classify modules.\n\n2. **Group (L2)** — Load `references\u002Fgrouping.md`. Use L1 data + topology rules to form groups.\n\n3. **Validate (L3, MANDATORY)** — Invoke `scripts\u002Fdecompose.py \u003Csource-path> --lang '\u003Clang>' --exclude '\u003Cmerged>' --validate 'G1:M1,M2|G2:M3,M4|...'`. Classify path (Path A vs Path B) and judge Quality Scores per `references\u002Fgrouping.md` § Scored Validation Protocol & Convergence Loop. Paste full output into Provenance.\n\n4. **Output** — Load `templates\u002Foutput-template.md`. Produce the artifact at the fixed path.\n\n5. **Consume** — Downstream consumers load `references\u002Fconsume.md`. The caller runs an additional acceptance check (see consume.md § Acceptance Check).\n\n---\n\n## JSON Profile Mode (`--profile-json`)\n\nFor upstream planners that just need a structured snapshot of the scope — no grouping, no L2\u002FL3 — invoke `decompose.py` with `--profile-json` instead of running the full L1→L2→L3 workflow.\n\n```\nscripts\u002Fdecompose.py \u003Cscope_path> --lang '\u003Clang>' --exclude '\u003Cmerged>' --profile-json\n```\n\n- `\u003Cscope_path>`: project root, module dir, or any walkable sub-folder.\n- `--lang`: required. Same canonical names + aliases as the extract mode. Multi-lang via comma.\n- `--exclude`: same semantics as extract mode (see Workflow § effective_exclude). The script ships with NO defaults beyond `.git`.\n- `--profile-json`: emits `ProjectProfile` JSON to stdout and suppresses normal text output.\n\n> **Note on `.gitignore`**: `.gitignore` uses glob\u002Fnegation\u002Fanchored semantics that don't map cleanly to the script's segment-substring exclusion. The caller assembles the merged exclude (see Workflow § effective_exclude) and passes it explicitly via `--exclude`. The script does NOT parse `.gitignore` itself.\n\nOutputs `ProjectProfile` JSON to stdout. Schema:\n\n```json\n{\n  \"scope_path\": \"\u002Fabs\u002Fpath\",\n  \"languages\": [\"csharp\"],\n  \"skip_patterns\": [\"bin\", \"obj\", \"...\"],\n  \"total_loc\": 314217,\n  \"total_files\": 4321,\n  \"module_count\": 36,\n  \"edge_count\": 40,\n  \"scc_count\": 36,\n  \"scc_nontrivial\": 0,\n  \"dag_depth\": 6,\n  \"topology_hints\": {\n    \"target_group_count\": 6,\n    \"ideal_group_loc\": 52369,\n    \"median_module_loc\": 1182,\n    \"trivial_module_test\": {\"abs_loc\": 500, \"pct_total\": 0.01, \"op\": \"or\"},\n    \"oversized_threshold\": 50000\n  },\n  \"modules\": [\n    {\"name\": \"Nop.Core\", \"loc\": 7143, \"files\": 355, \"layer\": 5, \"in_deg\": 4, \"out_deg\": 0, \"flags\": []}\n  ],\n  \"dag_layers\": [\n    {\"layer\": 0, \"module_count\": 31, \"loc\": 69913}\n  ],\n  \"warnings\": [\"LOW COVERAGE: 27% of project code is outside discovered modules.\"]\n}\n```\n\n`topology_hints` field meanings:\n- `target_group_count` — recommended number of topology groups: `ceil(total_loc \u002F 80_000)`, clamped to `[max(2, ceil(module_count \u002F 12)), max(2, ceil(module_count \u002F 4))]`. Computed by L1.\n- `ideal_group_loc` — `total_loc \u002F target_group_count`. Used by grouping rules to size merges and judge group-LOC distribution.\n- `trivial_module_test` — module is trivial iff `loc \u003C abs_loc OR loc\u002Ftotal_loc \u003C pct_total` (note: OR, not AND).\n\n**Single source of truth**: profile mode and extract\u002Fvalidate mode share the same in-memory analysis pass — LOC counting, `--lang` semantics, and `--exclude` semantics are identical by construction. If you need grouping or `--validate`, omit `--profile-json` and invoke `decompose.py` directly.\n\n---\n\n## Anti-patterns\n- ❌ Hand-computing quality scores instead of running L3 `--validate`\n- ❌ Re-extracting modules\u002Fedges\u002FLOC from raw source instead of using L1 output\n- ❌ Grouping by name or functional domain instead of dependency affinity (e.g. \"payment plugins\" — group by topology, not by what modules do)\n- ❌ Splitting or moving modules between groups to equalize LOC sizes (corrupts dependency graph — size rebalancing belongs upstream). Note: merging trivial modules per `grouping.md` §1 is topology-driven, not LOC rebalancing.\n- ❌ Skipping L3 validation because the artifact \"looks reasonable\"\n","# Project Decomposition: Recon, Grouping & Validation\n\n## What this skill does\n\nThis is the single entry point for measuring a codebase scope and (when needed) decomposing it into topology groups. Two modes:\n\n1. **Lightweight recon (JSON)** — `scripts\u002Fdecompose.py ... --profile-json` produces a structured `ProjectProfile` JSON with LOC \u002F file counts \u002F module list \u002F dep graph summary \u002F skip patterns. Used by upstream planners to decide pipeline variant and grouping needs.\n2. **Full grouping + validation** — `scripts\u002Fdecompose.py` directly, for L0→L1→L2 grouping protocol and L3 quality validation. Used when the workflow plan declares `grouping.needed: true`.\n\nBoth modes are the same `decompose.py` engine — single source of truth for LOC counting (`--lang` defines the LOC semantic boundary; `--exclude` defines the directory boundary), graph extraction, and validation scoring.\n\n### Which mode to run\n\n| Caller intent | Use | Why |\n|---------------|-----|-----|\n| Decide whether to fan out at all (sizing, dispatch) | `--profile-json` | Returns structured ProjectProfile (LOC, module count, depth, hub-ratio, sizing hints) without grouping output. Cheap, machine-readable. |\n| Caller already decided to fan out and needs L1 numbers + L2 grouping + L3 validation | run without `--profile-json`; then again with `--validate` for L3 | Human-readable Graph Statistics + Quality Scores. |\n| Caller wants both | run twice: once with `--profile-json` for the planner, once without for human L1 | The flags are mutually exclusive in one invocation; do not combine `--profile-json` with `--validate`. |\n\n`--profile-json` and `--validate` cannot be combined in a single invocation (the script rejects this).\n\n## When to Apply\n\n**Scale threshold**: Codebase is large enough that no single agent reading the source can hold any one group's source in context, or has enough modules that dependency-aware grouping adds value. The unit being sized is **one group's codebase scope** (which many agents in the pipeline must read), not a \"one-agent workload\" — every group still runs a full plan→execute→validate pipeline with many agent sessions.\n\n**Scope check** (after scale threshold is met, applied by the caller — see Workflow § input contract for the field this maps to):\n\n1. The caller determines the **rewrite scope** from the user request and passes it via the `Scope:` dispatch field:\n   - **Full rewrite** — all modules in scope → `scope = full`\n   - **Partial rewrite** — user specifies modules\u002Flayers\u002Ffeatures → `scope = scoped`\n   - **Cross-layer rewrite** — rewrite targets a different architectural layer (e.g. Razor → Angular while backend stays) → `scope = scoped` (only the target layer is in scope; source-layer modules are `context-only`)\n\n2. Apply the scope (classify groups using the dispatched value):\n   - `full` — all groups are `in-scope`\n   - `scoped` — analyze all modules for the dependency graph, but classify each group:\n     - **`in-scope`** — being rewritten → generates DAG tasks\n     - **`context-only`** — depended on by in-scope but NOT being rewritten → no DAG tasks, dependency context only\n\n3. **Skip entirely** if all of the following hold for the in-scope set:\n   - DAG depth ≤ 2 AND module count ≤ 3, AND\n   - total in-scope LOC \u003C `ideal_group_loc` (from `topology_hints`)\n\n   Report skip rationale back to the caller (plain text reply, not the artifact); do not produce a topology artifact.\n\n## Architecture: 3 Layers\n\n| Layer | Output |\n|-------|--------|\n| **L1 Extract** (`scripts\u002Fdecompose.py \u003Cpath> --lang '\u003Clang>' --exclude '\u003Cpatterns>'`) | Modules, edges, SCCs, DAG layers, LOC, oversized flags. No grouping. |\n| **L2 Group** (caller agent) | Module groups using L1 data + topology-aware judgment. See `references\u002Fgrouping.md`. |\n| **L3 Validate** (`scripts\u002Fdecompose.py \u003Cpath> --lang '\u003Clang>' --exclude '\u003Cpatterns>' --validate '\u003Cspec>'`) | 4 raw Quality Scores (Outlier ratio, SCC integrity, Group cycles, Coverage). Definitions and judgment protocol live in `references\u002Fgrouping.md` §4 and `references\u002Ftopology-thresholds.md`. |\n\nDo NOT skip any layer. L3 is the only authoritative quality check — hand-computed metrics are not accepted.\n\n## Files (load on demand)\n\n| File | Load when |\n|------|-----------|\n| `references\u002Fgrouping.md` | L2 step — topology-aware grouping rules + L3 metric definitions (authoritative source for thresholds) |\n| `templates\u002Foutput-template.md` | Output step — project topology artifact format and fixed path |\n| `references\u002Fconsume.md` | Downstream consumer contract — how the artifact is read and accepted |\n| `references\u002Fmanual-extraction.md` | Only if L1 reports `Unsupported language` (rare — C#\u002FJava\u002FPython\u002FJS-TS supported) |\n\n**Python is mandatory for topology grouping.** `decompose.py` is the only authoritative LOC counter for grouping\u002FL3 metrics — external counters drift across runs and inflate by 5–15% on comment-heavy languages, which destabilizes outlier-ratio and SCC-integrity scoring.\n\n`scripts\u002Fdecompose.py` invocation surface:\n- `\u003Cpath> --lang '\u003Clang>' --exclude '\u003Cmerged>'` — extract mode\n- `--validate '\u003Cspec>'` — L3 quality gate\n- `--module-loc \u003CModule>` — sub-dir LOC for a specific module\n- `--json out.json` — machine-readable dump\n- `--profile-json` — `ProjectProfile` JSON to stdout (see **JSON Profile Mode** below)\n\n`--lang` and `--exclude` are required. `--lang` accepts `python|java|csharp|javascript` (or aliases: `py`, `cs`\u002F`c#`\u002F`dotnet`, `js`\u002F`ts`\u002F`node`). For mixed projects pass comma-separated, e.g. `--lang csharp,javascript`. `--exclude` takes the **merged** list (see Workflow § effective_exclude).\n\n## Workflow\n\nThe caller dispatches with a fixed input contract — these fields MUST be present, do not infer them yourself:\n\n| Field | Type | Example | Used by |\n|-------|------|---------|---------|\n| `Source path:` | absolute path to repo root | `\u002Fpath\u002Fto\u002Frepo` | every L1\u002FL3 invocation as `\u003Csource-path>` |\n| `Language(s):` | comma-separated `decompose.py --lang` value | `csharp` or `csharp,javascript` | `--lang '\u003Clang>'` |\n| `Skip patterns:` | comma-separated path segments (may be empty) | `tests,docs,samples` | exclude-merge input |\n| `Scope:` | `full` \\| `scoped` | `scoped` | Scope check classification |\n| `Mode:` | `topology` \\| `profile-json` | `topology` | output shape — `profile-json` returns `ProjectProfile` JSON to stdout instead of producing the artifact (see **JSON Profile Mode** below) |\n\nAll five fields are required. If any is missing, halt and request it from the caller — do **not** guess or default. Then build the **effective exclude list** by union-ing four sources:\n\n```\neffective_exclude = caller_skip_patterns\n                  ∪ gitignore_dirs(\u003Csource-path>\u002F.gitignore)\n                  ∪ auto_gen_dirs(\u003Csource-path>)        ← see below\n                  ∪ BASELINE\n```\n\n**`auto_gen_dirs(path)`** — pre-L1 sniff for framework-generated code that the caller cannot anticipate (EF Core `Migrations\u002F`, protobuf-generated stubs, OpenAPI\u002FGraphQL codegen, ANTLR `.g4`-output dirs, etc.). These dirs may contain tens of thousands of lines that are not authored code; they distort outlier ratio and force spurious sub-splits. Procedure:\n\n1. Walk top 2 levels under `\u003Csource-path>` (skipping anything already in BASELINE \u002F gitignore_dirs \u002F caller_skip_patterns).\n2. For each directory whose **source-file LOC** (matching `--lang` extensions) ≥ 5% of project total, sample up to 3 source files (largest first) and read the **top 100 lines** of each.\n3. If ≥ 1 sampled file contains any of these markers (case-insensitive), add the directory's segment name to `auto_gen_dirs`:\n   - `\u003Cauto-generated>`\n   - `DO NOT EDIT`\n   - `This file was generated`\n   - `@generated`\n   - `Code generated by` (Go convention)\n   - `auto-generated by`\n4. Cap at 8 directories. Log each accepted dir and the marker that triggered it; this list is reproducible across runs.\n\nDo NOT use this mechanism to skip hand-written code that happens to be large — only marker-confirmed generated code qualifies. If marker matching is ambiguous, leave the dir in and let the outlier-ratio band trigger normal remediation.\n\n**BASELINE** (language-neutral, fixed list, always applied — fallback when caller\u002Fgitignore miss something):\n```\n.git, .svn, .hg, .idea, .vscode, .vs, .DS_Store,\nnode_modules, bower_components, vendor, packages,\n__pycache__, .venv, venv, .tox, .pytest_cache, .cache,\nbin, obj, target, build, dist, out,\n.gradle, .mvn\n```\n\nBASELINE is fixed and language-neutral. Project-type-specific extras (framework directories, generated folders) are the **caller**'s responsibility and must be passed via `caller_skip_patterns`; do not extend BASELINE per project.\n\n**`gitignore_dirs(path)`** — parse repo's `.gitignore` and extract directory-shaped entries:\n- keep: lines ending in `\u002F`, or bare path segments without glob chars (e.g. `wwwroot\u002Flib\u002F`, `App_Data`)\n- drop: blanks, comments (`#…`), negations (`!…`), file-level globs (any line containing `*` `?` `[`)\n- strip leading\u002Ftrailing `\u002F`; dedupe across all three sources\n- if `.gitignore` is missing, this set is empty\n\nPass the merged list verbatim in every `decompose.py` invocation as `--exclude '\u003Cmerged>'`. Rationale: build output, vendored deps, and generated assets the repo itself ignores must not inflate LOC or group sizes — relying on the caller alone is fragile.\n\n1. **Extract (L1)** — Invoke `scripts\u002Fdecompose.py \u003Csource-path> --lang '\u003Clang>' --exclude '\u003Cmerged>'`. Treat output as source of truth; do NOT re-extract module\u002Fedge\u002FLOC data from raw source. Apply the caller's `scope` to classify modules.\n\n2. **Group (L2)** — Load `references\u002Fgrouping.md`. Use L1 data + topology rules to form groups.\n\n3. **Validate (L3, MANDATORY)** — Invoke `scripts\u002Fdecompose.py \u003Csource-path> --lang '\u003Clang>' --exclude '\u003Cmerged>' --validate 'G1:M1,M2|G2:M3,M4|...'`. Classify path (Path A vs Path B) and judge Quality Scores per `references\u002Fgrouping.md` § Scored Validation Protocol & Convergence Loop. Paste full output into Provenance.\n\n4. **Output** — Load `templates\u002Foutput-template.md`. Produce the artifact at the fixed path.\n\n5. **Consume** — Downstream consumers load `references\u002Fconsume.md`. The caller runs an additional acceptance check (see consume.md § Acceptance Check).\n\n---\n\n## JSON Profile Mode (`--profile-json`)\n\nFor upstream planners that just need a structured snapshot of the scope — no grouping, no L2\u002FL3 — invoke `decompose.py` with `--profile-json` instead of running the full L1→L2→L3 workflow.\n\n```\nscripts\u002Fdecompose.py \u003Cscope_path> --lang '\u003Clang>' --exclude '\u003Cmerged>' --profile-json\n```\n\n- `\u003Cscope_path>`: project root, module dir, or any walkable sub-folder.\n- `--lang`: required. Same canonical names + aliases as the extract mode. Multi-lang via comma.\n- `--exclude`: same semantics as extract mode (see Workflow § effective_exclude). The script ships with NO defaults beyond `.git`.\n- `--profile-json`: emits `ProjectProfile` JSON to stdout and suppresses normal text output.\n\n> **Note on `.gitignore`**: `.gitignore` uses glob\u002Fnegation\u002Fanchored semantics that don't map cleanly to the script's segment-substring exclusion. The caller assembles the merged exclude (see Workflow § effective_exclude) and passes it explicitly via `--exclude`. The script does NOT parse `.gitignore` itself.\n\nOutputs `ProjectProfile` JSON to stdout. Schema:\n\n```json\n{\n  \"scope_path\": \"\u002Fabs\u002Fpath\",\n  \"languages\": [\"csharp\"],\n  \"skip_patterns\": [\"bin\", \"obj\", \"...\"],\n  \"total_loc\": 314217,\n  \"total_files\": 4321,\n  \"module_count\": 36,\n  \"edge_count\": 40,\n  \"scc_count\": 36,\n  \"scc_nontrivial\": 0,\n  \"dag_depth\": 6,\n  \"topology_hints\": {\n    \"target_group_count\": 6,\n    \"ideal_group_loc\": 52369,\n    \"median_module_loc\": 1182,\n    \"trivial_module_test\": {\"abs_loc\": 500, \"pct_total\": 0.01, \"op\": \"or\"},\n    \"oversized_threshold\": 50000\n  },\n  \"modules\": [\n    {\"name\": \"Nop.Core\", \"loc\": 7143, \"files\": 355, \"layer\": 5, \"in_deg\": 4, \"out_deg\": 0, \"flags\": []}\n  ],\n  \"dag_layers\": [\n    {\"layer\": 0, \"module_count\": 31, \"loc\": 69913}\n  ],\n  \"warnings\": [\"LOW COVERAGE: 27% of project code is outside discovered modules.\"]\n}\n```\n\n`topology_hints` field meanings:\n- `target_group_count` — recommended number of topology groups: `ceil(total_loc \u002F 80_000)`, clamped to `[max(2, ceil(module_count \u002F 12)), max(2, ceil(module_count \u002F 4))]`. Computed by L1.\n- `ideal_group_loc` — `total_loc \u002F target_group_count`. Used by grouping rules to size merges and judge group-LOC distribution.\n- `trivial_module_test` — module is trivial iff `loc \u003C abs_loc OR loc\u002Ftotal_loc \u003C pct_total` (note: OR, not AND).\n\n**Single source of truth**: profile mode and extract\u002Fvalidate mode share the same in-memory analysis pass — LOC counting, `--lang` semantics, and `--exclude` semantics are identical by construction. If you need grouping or `--validate`, omit `--profile-json` and invoke `decompose.py` directly.\n\n---\n\n## Anti-patterns\n- ❌ Hand-computing quality scores instead of running L3 `--validate`\n- ❌ Re-extracting modules\u002Fedges\u002FLOC from raw source instead of using L1 output\n- ❌ Grouping by name or functional domain instead of dependency affinity (e.g. \"payment plugins\" — group by topology, not by what modules do)\n- ❌ Splitting or moving modules between groups to equalize LOC sizes (corrupts dependency graph — size rebalancing belongs upstream). Note: merging trivial modules per `grouping.md` §1 is topology-driven, not LOC rebalancing.\n- ❌ Skipping L3 validation because the artifact \"looks reasonable\"\n",{"name":5,"description":7},"main","a9c9469d86e9dc078018e8fb391abc7744088078","plugins\u002Fgithub-copilot-modernization\u002Fskills\u002Fproject-decomposition",15,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fgithub-copilot-modernization","https:\u002F\u002Fgithub.com\u002Fmicrosoft","https:\u002F\u002Fopensource.microsoft.com","Open source projects and samples from Microsoft","2026-09-24 00:17:59",{"source":8,"skillName":5,"commands":43,"prompt":53,"zipAvailable":54},[44,47,50],{"tool":45,"command":46},"npx","npx skills add microsoft\u002Fgithub-copilot-modernization --skill project-decomposition",{"tool":48,"command":49},"bunx","bunx skills add microsoft\u002Fgithub-copilot-modernization --skill project-decomposition",{"tool":51,"command":52},"pnpm","pnpm dlx skills add microsoft\u002Fgithub-copilot-modernization --skill project-decomposition","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fgithub-copilot-modernization\u002Fblob\u002Fmain\u002Fplugins\u002Fgithub-copilot-modernization\u002Fskills\u002Fproject-decomposition\u002FSKILL.md",true,[56,62,66,70,74,80],{"path":57,"resourceType":58,"resourceTypeDesc":59,"sizeBytes":60,"sourceHtmlUrl":61},"references\u002Fconsume.md","REFERENCE","参考文档",8098,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fgithub-copilot-modernization\u002Fblob\u002Fmain\u002Fplugins\u002Fgithub-copilot-modernization\u002Fskills\u002Fproject-decomposition\u002Freferences\u002Fconsume.md",{"path":63,"resourceType":58,"resourceTypeDesc":59,"sizeBytes":64,"sourceHtmlUrl":65},"references\u002Fgrouping.md",23399,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fgithub-copilot-modernization\u002Fblob\u002Fmain\u002Fplugins\u002Fgithub-copilot-modernization\u002Fskills\u002Fproject-decomposition\u002Freferences\u002Fgrouping.md",{"path":67,"resourceType":58,"resourceTypeDesc":59,"sizeBytes":68,"sourceHtmlUrl":69},"references\u002Fmanual-extraction.md",3283,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fgithub-copilot-modernization\u002Fblob\u002Fmain\u002Fplugins\u002Fgithub-copilot-modernization\u002Fskills\u002Fproject-decomposition\u002Freferences\u002Fmanual-extraction.md",{"path":71,"resourceType":58,"resourceTypeDesc":59,"sizeBytes":72,"sourceHtmlUrl":73},"references\u002Ftopology-thresholds.md",8914,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fgithub-copilot-modernization\u002Fblob\u002Fmain\u002Fplugins\u002Fgithub-copilot-modernization\u002Fskills\u002Fproject-decomposition\u002Freferences\u002Ftopology-thresholds.md",{"path":75,"resourceType":76,"resourceTypeDesc":77,"sizeBytes":78,"sourceHtmlUrl":79},"scripts\u002Fdecompose.py","SCRIPT","脚本",90746,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fgithub-copilot-modernization\u002Fblob\u002Fmain\u002Fplugins\u002Fgithub-copilot-modernization\u002Fskills\u002Fproject-decomposition\u002Fscripts\u002Fdecompose.py",{"path":81,"resourceType":58,"resourceTypeDesc":59,"sizeBytes":82,"sourceHtmlUrl":83},"templates\u002Foutput-template.md",8468,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fgithub-copilot-modernization\u002Fblob\u002Fmain\u002Fplugins\u002Fgithub-copilot-modernization\u002Fskills\u002Fproject-decomposition\u002Ftemplates\u002Foutput-template.md",[85,97,106,114,123,131],{"skillNo":86,"name":87,"nameZh":6,"description":88,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":89,"categories":90,"keywords":94,"publishedAt":28},"01M69B5DBRA354JMQRZP3D1X3X","verify-test-baseline","Generate and run post-migration tests from the frozen baseline specification.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fgithub-copilot-modernization\u002Fblob\u002Fmain\u002Fplugins\u002Fgithub-copilot-modernization\u002Fskills\u002Fverify-test-baseline\u002FSKILL.md",[91],{"categoryNo":92,"categoryName":93,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量",[95,96],"test","verify test baseline",{"skillNo":98,"name":99,"nameZh":6,"description":100,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":101,"categories":102,"keywords":103,"publishedAt":28},"01M69B5BJWPCN41J5ZAR2XFMBR","team-request","How team members request infrastructure connection info and handle secrets in team mode","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fgithub-copilot-modernization\u002Fblob\u002Fmain\u002Fplugins\u002Fgithub-copilot-modernization\u002Fskills\u002Fteam-request\u002FSKILL.md",[],[104,105],"team request","infrastructure",{"skillNo":107,"name":108,"nameZh":6,"description":109,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":110,"categories":111,"keywords":112,"publishedAt":28},"01M69B58TZ7SNTPB6C508M5HWX","team-charters","Provides role charters (mission, ownership, core principles, quality bar) for a multi-agent coding team. Each charter defines the role's mission, ownership scope, core principle (boundary constraints), and quality bar. Most roles also include communication rules. Consumed by the coordinator during task decomposition to assign work to the correct role.\nTriggers: \"look up role charter\", \"what does the architect own\", \"check role boundaries\", \"find team roles\", \"which role handles X\", \"list agent charters\", \"role responsibilities\".\nNOT for: task decomposition (use breaking-down-tasks), implementation (use implementing-code), architecture analysis (use analyzing-architecture).","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fgithub-copilot-modernization\u002Fblob\u002Fmain\u002Fplugins\u002Fgithub-copilot-modernization\u002Fskills\u002Fteam-charters\u002FSKILL.md",[],[113,26],"team charters",{"skillNo":115,"name":116,"nameZh":6,"description":117,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":118,"categories":119,"keywords":120,"publishedAt":28},"01M69B56JVPKCS2WWVSCZXHEZJ","struts-to-spring","Migration guideline for transforming Apache Struts 2 applications to Spring Boot 3.x and Spring MVC.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fgithub-copilot-modernization\u002Fblob\u002Fmain\u002Fplugins\u002Fgithub-copilot-modernization\u002Fskills\u002Fstruts-to-spring\u002FSKILL.md",[],[121,122],"struts to spring","boot",{"skillNo":124,"name":125,"nameZh":6,"description":126,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":127,"categories":128,"keywords":129,"publishedAt":28},"01M69B54QQ6K8SDZ8MJYEKBYHJ","spring-boot-scaffolding","Reference guide for creating a new Spring Boot project during rewrite migration.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fgithub-copilot-modernization\u002Fblob\u002Fmain\u002Fplugins\u002Fgithub-copilot-modernization\u002Fskills\u002Fspring-boot-scaffolding\u002FSKILL.md",[],[122,130],"spring boot scaffolding",{"skillNo":132,"name":133,"nameZh":6,"description":134,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":135,"categories":136,"keywords":137,"publishedAt":28},"01M69B52T5G9CZWHYXWP22WEKY","sharing-learnings","How to record project learnings so that later-phase workers and future agent runs can consume them.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fgithub-copilot-modernization\u002Fblob\u002Fmain\u002Fplugins\u002Fgithub-copilot-modernization\u002Fskills\u002Fsharing-learnings\u002FSKILL.md",[],[138],"sharing learnings"]