plugins/github-copilot-modernization/skills/analyzing-architecture/SKILL.md
Architect analysis for rewrite/migration: produces structured architecture artifacts plus global prose research views (project-structure, tech-stack, data-model) for planning, implementation, feature-inventory, and gates. This is the single architect task. Triggers: "analyze architecture", "analyze existing application", "analyze the codebase", "codebase architecture analysis", "analyze for migration", "prepare migration analysis", "produce migration artifacts", "analyze before rewrite". NOT for: greenfield projects, pure syntax/version migrations (Python2→3, Java 8→17 — no paradigm shift), runtime validation (use runtime-validation), infrastructure/deployment analysis (use analyzing-operations), feature inventory/spec writing (use feature-inventory).
npx skillsauth add microsoft/github-copilot-modernization analyzing-architectureInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Produce only artifacts that reduce a named failure mode. Anything that doesn't is excluded — it wastes agent context.
There are two artifact purposes:
Each reference contains the YAML schema, extraction rules, and self-check for its artifact. Read all before starting the workflow.
| Reference | Artifact | What it provides |
|---|---|---|
| references/unit-graph.md | unit_graph.yaml | Schema for units, exported_signature, dynamic_entrypoints, shared_refs |
| references/behavior.md | units/*/behavior.yaml | Schema for side_effects, branches, error_paths, concurrency |
| references/bindings.md | units/*/bindings.yaml | Schema for framework wiring, runtime_config |
| references/wire-contracts.md | wire_contracts.yaml | Schema for external contracts, target_contract, semantic_divergence |
| references/shared-modules.md | shared_modules.yaml | Schema for god-class registry, fields with types, shared_refs relationship |
| references/cross-unit-state.md | cross_unit_state.yaml | Schema for implicit state flows, pairing values, verification_hint |
| references/migration-boundary.md | migration_boundary.yaml | Intent interpretation, must_rewrite with reasons, strategy rules |
| references/seams.md | seams.yaml | Schema for frozen_contract, bridge_points, declared vs inferred rules |
| references/unit-decomposition.md | units/*/unit_decomposition.yaml | Schema for candidate_splits, split-driver vocabulary |
| references/project-structure.md | project-structure.md | Functional domains, layers, project type — global prose view for planning/feature-inventory |
| references/tech-stack.md | tech-stack.md | Frameworks, deps, runtime versions, migration blockers — global prose view |
| references/data-model.md | data-model.md | Entity inventory, relationships, key-entities summary — global prose view |
| references/extraction-signals.md | (all artifacts) | Signal→artifact mapping, what to look for per signal area |
| references/architecture-index.md | architecture_index.md | Implementation Guide contract, per-unit navigation template |
| references/consumption-contract.md | (downstream) | How implementation agents read the artifacts |
source_loc: path:line is the natural ID. Never invent stable IDs.must_preserve, must_appear_in_target) so the next agent needs no extra skill loaded.confidence: 0.9. Where confidence matters, report the evidence basis (static vs static+runtime), not a number nobody measured.source_anchors are discovery evidence, not rewrite targets.A unit = one externally triggerable entry point (HTTP route, scheduled job, message handler, UI page, public API surface, CLI command). Uniqueness invariant: each source file appears in at most one unit's source_anchors. Files used by ≥2 units → shared_modules.yaml.
artifacts/
├── architecture_index.md top-level implementation guide
├── project-structure.md global prose, functional domains + layers + project type
├── tech-stack.md global prose, frameworks + deps + runtime versions
├── data-model.md global prose, entity inventory + key-entities summary
├── unit_graph.yaml global index, lightweight
├── migration_boundary.yaml global, minimal runnable boundary + rewrite scope contract
├── wire_contracts.yaml global, outward contracts
├── shared_modules.yaml global, files used by ≥2 units; god-class registry
├── cross_unit_state.yaml global, implicit shared-state flows
├── seams.yaml global, partial-migration cut points + bridge design
└── units/<unit_name>/
├── behavior.yaml per-unit, heavyweight
├── bindings.yaml per-unit; may be [] + reason
└── unit_decomposition.yaml per-unit, CANDIDATES only, no commit
Base path: {artifact_root}/ (typically .github/modernize/rearchitecture/artifacts/)
Global artifacts (1 each):
unit_graph.yaml — alwaysmigration_boundary.yaml — rewrite/migration workwire_contracts.yaml — alwaysshared_modules.yaml — alwayscross_unit_state.yaml — alwaysseams.yaml — when seams exist (declared or inferred); omit file entirely if no seams foundarchitecture_index.md (top-level implementation guide) — alwaysproject-structure.md (global prose: functional domains, layers, project type) — alwaystech-stack.md (global prose: frameworks, deps, runtime versions, migration blockers) — alwaysdata-model.md (global prose: entity inventory + key-entities summary) — when project has entities/ORM/DB accessPer-unit artifacts (one set per unit in unit_graph.yaml):
units/<unit_name>/behavior.yamlunits/<unit_name>/bindings.yamlunits/<unit_name>/unit_decomposition.yamlCompleteness invariant: count(units/*/behavior.yaml) == count(units in unit_graph.yaml).
For how downstream agents consume these artifacts, load references/consumption-contract.md.
target_idiom is NOT produced here — lives in guidelines/<source>-to-<target>/.
The top-level architect artifact is an implementation index, not a prose summary. It must tell implementation agents which artifact paths to read, why each matters, how to filter global rows, and what completion evidence to report.
Load references/architecture-index.md for the required Implementation Guide contract and example shape.
Core artifacts:
unit_graph.yaml (entry-point enumeration + exported_signature + dynamic_entrypoints + per-unit shared_refs). Load references/unit-graph.md for schema and self-check.behavior.yaml (side_effects, branches, error_paths, concurrency). Load references/behavior.md for schema.bindings.yaml (framework wiring + runtime_config). Load references/bindings.md for schema.wire_contracts.yaml (rest/grpc/kafka/sql/semantic_divergence). Load references/wire-contracts.md for schema and scope boundary.shared_modules.yaml (god-class registry: kind/used_by_units/fields/split_candidate). Load references/shared-modules.md for schema and shared_refs relationship.cross_unit_state.yaml (implicit session/ThreadLocal/SSO flows; per-row must_confirm:runtime for any unpaired flow). Load references/cross-unit-state.md for schema and pairing values.migration_boundary.yaml — minimal runnable boundary + rewrite scope contractRecords the smallest runtime-reachable implementation boundary that satisfies the user's acceptance criteria. Implementation scope comes from must_rewrite, not from all source_anchors or every legacy-framework file.
Load references/migration-boundary.md for intent interpretation rules, schema, and self-check.
seams.yaml — partial-migration cut points + bridge designRecords deliberate cuts for partial migration: which side is frozen, which side migrates, and how the bridge converts protocols/idioms. declared seams are authoritative; inferred seams are advisory.
Load references/seams.md for schema, conditional frozen_contract rules, discovery signals, and self-check.
units/<unit>/unit_decomposition.yaml (per-unit)Records split candidates for design. It produces candidate_splits, not target units; the design phase owns the decision.
Load references/unit-decomposition.md for schema and split-driver vocabulary.
guidelines/<source>-to-<target>/, and any user-declared seams (cut points the user specified).
1b. Load extraction signals — read references/extraction-signals.md and map discovered signals into the structured artifacts.
1c. Produce global prose views — alongside the structured per-unit artifacts, emit project-structure.md (functional domains, layers, project type), tech-stack.md (frameworks, deps, runtime versions, migration blockers), and data-model.md (entity inventory + key-entities summary) per their reference schemas. These global views are consumed by creating-implementation-plan, feature-inventory, and the spec-quality gate; the structured YAML artifacts do not replace them.unit_graph.yaml (spine). Resolve exported_signature from public signatures only. Seed shared_modules.yaml same pass; flag god-class + reference-cliff candidates.
2b. Build migration_boundary.yaml — infer user intent, acceptance criteria, cleanup requirement, and the smallest runtime-reachable rewrite boundary. Populate must_rewrite, copy_as_is, legacy_allowed_to_remain, and defer_cleanup. Only choose full_rewrite when user intent or technical evidence requires it; do not equate source_anchors with rewrite targets.unit_graph.yaml, create units/<unit_name>/behavior.yaml, units/<unit_name>/bindings.yaml, and units/<unit_name>/unit_decomposition.yaml. Do not skip units. Do not create "representative samples". Do not defer to a later step. >~200 lines per file → re-examine the unit boundary. Populate shared_refs from subset whitelist. unit_decomposition sets commit: false.
3b. Verify per-unit completeness before proceeding. Run: count the units in unit_graph.yaml and count the units/*/behavior.yaml files. If they do not match, create the missing per-unit files NOW. Do not proceed to step 4 until every unit has all three files.wire_contracts.yaml — outward edges; cross-ref unit_graph for external interfaces.
4b. Build cross_unit_state.yaml — scan medium patterns; pair across units only; per-row must_confirm:runtime on any unpaired flow.
4c. Build seams.yaml (skip if no declared or inferred seams exist) — emit every user-declared seam first (source: declared). Then add inferred seams from discovery signals. For each seam: record frozen_side + frozen_side_rule (always), and — where protocols differ — the bridge_points conversion design (mapping_rule + edge_cases + idempotency_retry + fallback). Add frozen_contract only when the migrating agent cannot read the frozen side's behavior from source (binary/private dependency, config/data-gated semantics, name-contradicts-behavior); when the frozen source is visible and self-explanatory, omit it — don't restate what the agent reads directly. Resolve declared/inferred conflicts toward declared.
4d. Build the architecture index — top-level architect artifact with an Implementation Guide. For each unit, list exact artifact paths, purpose of each file, how to filter global rows, and required completion evidence. Do not make it a prose-only summary.unit_graph.yaml (grep -c '^\s*- name:' artifacts/unit_graph.yaml). Count per-unit behavior files (ls artifacts/units/*/behavior.yaml | wc -l). If counts do not match, list missing units and create their behavior.yaml, bindings.yaml, and unit_decomposition.yaml NOW. Do not report done until counts match. "Representative samples" or "most controllers follow identical patterns" is NOT acceptable — every unit gets all three files.unit_graph has behavior/bindings/decomposition files.migration_boundary.yaml exists for rewrite/migration work; must_rewrite is the implementation scope; source_anchors are not treated as rewrite targets.Implementation Guide for every unit, with exact artifact paths, purpose, row-filter instructions, and completion evidence requirements.TBD in wire_contracts.yaml::target_contract, seams.yaml::frozen_contract target form, or seams.yaml::bridge_points[].mapping_rule.source_anchors of multiple units.unit_decomposition.commit == false.shared_refs.used_fields ⊆ {f.name for f in shared_modules.fields}.cross_unit_state flow with pairing != matched carries must_confirm: runtime.declared seam present; every seam has a frozen_side_rule; frozen_contract present only where the frozen source is invisible/unrecoverable; every protocol_shift != null seam has ≥1 bridge_point with concrete mapping_rule (no TBD).notes: / rationale:.source_loc: path:line is the identifier.target_idiom.yaml.TBD forbidden in wire contract target_contract, seam frozen_contract target form, and seam mapping_rule.unit_decomposition.yaml MUST set commit: false.declared seam is authoritative — design may not overrule it; an inferred seam is a candidate.migration_boundary.yaml::must_rewrite, not from unit_graph.source_anchors, all files of the old framework, or inventory lists. source_anchors prove behavior exists; they do not mandate rewriting that file.| # | Failure mode | Prevented by |
|---|---|---|
| 1 | Dropped side-effect | behavior.yaml::side_effects[must_preserve] |
| 2 | Dropped framework binding | bindings.yaml::bindings[must_appear_in_target] |
| 3 | Hallucinated target API | guidelines/<source>-to-<target>/ (out of scope) |
| 4 | Broken caller (signature unsync) | unit_graph.yaml::depends_on + exported_signature |
| 5 | Dead-code removal of reflection/DI class | unit_graph.yaml::dynamic_entrypoints |
| 6 | Wire contract break | wire_contracts.yaml::stability:frozen + target_contract |
| 7 | Tx boundary lost | behavior.yaml::concurrency.tx_boundary |
| 8 | Cross-language semantic gotcha | wire_contracts.yaml::semantic_divergence |
| 9 | Missing runtime config | bindings.yaml::runtime_config[must_appear_in_target] |
| 10 | Significant branch dropped | behavior.yaml::branches[must_preserve] |
| 11 | Error contract drift | behavior.yaml::error_paths[contract + must_preserve] |
| 12 | Shared module duplicated/lost | shared_modules.yaml::migration_strategy |
| 13 | Concurrency model mismatch | behavior.yaml::concurrency.model |
| 14 | Implicit cross-unit state lost | cross_unit_state.yaml::flows[must_preserve] |
| 15 | Static pairing missed dynamic key / external writer | cross_unit_state.yaml::pairing + must_confirm:runtime |
| 16 | God-class field drift / hallucinated fields | shared_modules.yaml::god_class + shared_refs.used_fields ⊆ |
| 17 | Premature commit to target unit count | unit_decomposition.yaml::commit:false + candidate_splits |
| 18 | Split candidate without driver/rationale | unit_decomposition.yaml::candidate_splits[].drivers + rationale |
| 19 | Fabricated score/confidence misleads design | Principle 6 + self-check: no composite_score |
| 20 | Partial-migration cut breaks at the seam (an unreadable frozen-side semantic — binary dep, config-gated, or name-contradicts-behavior — never recorded) | seams.yaml::frozen_contract[must_preserve], conditional: only when source is invisible/unrecoverable |
| 21 | Frozen side refactored, breaking un-migrated peers | seams.yaml::frozen_side_rule |
| 22 | Protocol-shift conversion left to the migrating agent's guess (wrong mapping/edge cases) | seams.yaml::bridge_points[mapping_rule + edge_cases + idempotency_retry + fallback] |
| 23 | User-specified cut point silently overruled by analyze | seams.yaml::source:declared authoritative rule |
| 24 | Inventory-driven over-rewrite: every discovered framework file or source_anchor becomes an implementation task, even though a smaller runtime boundary satisfies acceptance | migration_boundary.yaml::{strategy,must_rewrite,legacy_allowed_to_remain} + rule: source_anchors are not rewrite targets |
| 25 | User asked for clean/full rewrite but analyze silently leaves legacy runtime residue | migration_boundary.yaml::{user_intent.cleanup_required,full_rewrite_reason} |
analyzing-operationsnotes / stabilityguidelines/<source>-to-<target>/exported_signature sufficesshared_modules.yaml::split_candidate.development
Scan dependency manifests against known CVEs and remediate by upgrading vulnerable dependencies to patched versions, then rebuild and re-scan to confirm. Self-contained scan→fix→verify loop for any project with a dependency manifest. Use when: a cve-remediation task is dispatched; dependency set changed (version bump, new framework); assessment flagged vulnerable or EOL dependencies; or user asked to "fix CVEs", "patch vulnerabilities", or "dependency security". Triggers: "cve", "remediate cve", "fix cves", "patch vulnerable dependencies", "vulnerability scanning", "dependency security", "vulnerable dependencies", "security advisories", "npm audit", "pnpm audit", "maven audit", "gradle audit", "dependency scan", "vulnerability remediation". NOT for: security audit of auth/input/secrets/OWASP code paths (use security-review).
development
Generate dependency map diagram from project build files
documentation
Generate data architecture and persistence layer documentation with data model diagram
documentation
Generate core business workflow documentation with sequence diagram