{
  "version": "act 2.1.1",
  "slug": "migration-assessment",
  "name": "migration-assessment",
  "description": "Use when assessing migration readiness, planning a port to another language, understanding what makes this codebase hard to rewrite, or requesting \"how ready is this for porting?\". Depth 2 \u2014 investigate. Produces per-module readiness cards, recommended migration order, hard/soft blocker list, and platform dependency assessment. Optionally enriches the plan with security and history evidence (taint flow, secret surface, unsafe constructs, coverage, churn, ownership) so blockers reflect real porting risk, not structure alone. Replaces the migration-readiness-plus skill.",
  "url": "https://act101.ai/docs/skills/migration-assessment",
  "body_md": "# Migration Assessment\n\n**Depth:** Level 2 (Investigate).\n\nSee `../analysis-protocol/references/protocol.md` for: artifact directory structure,\nthe investigation loop, depth levels, summary format, token budget rules, and project\nmap structure. Read that document before proceeding.\n\n## Phase 1: Parallel Tool Dispatch\n\nDispatch all available tools in a **single parallel batch**.\nEach subagent runs one tool, saves raw JSON to `raw/<tool-name>.json`, returns a\nstructured summary.\n\n**Must-have tools:**\n\n| Tool | Purpose | MCP call |\n|------|---------|----------|\n| `analyze_readiness` | Composite migration score (M1) | `analyze_readiness` |\n\nIf `analyze_readiness` is unavailable, report that and stop \u2014 no useful migration\nassessment is possible without it.\n\n**Extended tools (use if available, skip and note in manifest if not):**\n\n| Tool | Purpose | MCP call |\n|------|---------|----------|\n| `analyze_features` | Language feature inventory (M3) | `analyze_features` |\n| `analyze_platform_deps` | Platform/runtime dependencies (M5) | `analyze_platform_deps` |\n| `analyze_interfaces` | Cross-module contracts (M4) | `analyze_interfaces` |\n| `analyze_type_completeness` | Type boundary holes (M7) | `analyze_type_completeness` |\n| `analyze_fan_balance` | Migration ordering \u2014 fan-in/fan-out (M6) | `analyze_fan_balance` |\n| `analyze_depth` | Dependency chain depth (S4) | `analyze_depth` |\n| `analyze_inheritance` | Tangled inheritance hierarchies (H6) | `analyze_inheritance` |\n| `analyze_patterns` | Hard porting blockers | `analyze_patterns` (use `--pattern porting_blockers` if available, else `--tier all`) |\n\n## Phase 2: Investigation\n\nFor each file or module scored \"hard\" in readiness, or flagged as a hard blocker:\n\n**Platform dependency hypothesis example:**\n> **Hypothesis N:** The `<module>` module is migration-ready despite `<N>` platform\n> deps because they're isolated behind a `<WrapperClass>` abstraction.\n> **Evidence:** `analyze_readiness` scored it \"needs-work\"; `analyze_platform_deps`\n> shows N imports of `<platform-api>`.\n> **Confirming query:** `skeleton` on the wrapper file + `references`\n> on the platform import symbol.\n> **Confirms if:** Only the wrapper file imports the platform module directly.\n> **Refutes if:** Multiple files import the platform module directly.\n\n**Complexity blocker hypothesis example:**\n> **Hypothesis N:** `<file>` is a hard blocker due to dynamic dispatch, not complexity.\n> **Evidence:** `analyze_readiness` scored it \"hard\"; patterns flagged reflection/eval use.\n> **Confirming query:** `skeleton` on the file to count dynamic call sites.\n> **Confirms if:** Multiple reflection/eval call sites with no static alternative.\n> **Refutes if:** Single call site that can be wrapped or replaced.\n\nSave investigation notes to `investigation/hypothesis-N.md`.\n\n## Report Structure\n\n```markdown\n# Migration Assessment: <project name>\n\n## Readiness Summary\nReady / Needs work / Hard counts with percentages.\nOverall verdict: **Ready** / **Needs work** / **Hard** \u2014 with confidence note.\n\n## Recommended Migration Order\nFoundation modules first (high fan-in, low fan-out \u2014 ported early, depended upon).\nOrchestrators last (low fan-in, high fan-out \u2014 ported after their dependencies).\nNumbered list with rationale per module.\n\n## Porting Blockers\nPer-file list with context from investigation.\nDistinguish clearly:\n- **Hard blockers:** eval, reflection, FFI, dynamic dispatch \u2014 no mechanical equivalent\n- **Soft blockers:** high complexity, tight coupling \u2014 require refactor before porting\n\n## Platform Dependencies\nBy category (filesystem, network, OS, process, browser, FFI).\nFor each dependency:\n- Which files use it\n- Wrapped vs. direct (direct = higher porting cost)\n- Adaptation strategy for the target language\n\n## Type Boundary Gaps\nModules with low type completeness.\nPer-gap: module path, missing type annotations, impact on mechanical translation.\n\n## Language Feature Concerns\nFeatures with no direct equivalent in the target language.\nPer-feature: count, affected files, suggested adaptation approach.\n\n## Inheritance Complexity\nDeep hierarchies and diamond inheritance patterns that complicate porting.\nPer-finding: chain depth, members, recommended simplification before porting.\n\n## Dependency Depth\nDeepest dependency chains (leaf modules to port first).\nPer-chain: length, root, leaf, recommended port order.\n\n## Per-Module Readiness Cards\nFor each top-level module:\n- Readiness score: ready / needs-work / hard\n- Blocker count (hard / soft)\n- Platform dep count\n- Recommended action\n```\n\n## Project Map Updates\n\nAppends or updates the **\"Migration Readiness\"** section. Appends to the Analysis\nHistory table.\n\n## Optional Enrichment: Security & History Evidence\n\nThe readiness scores above are structural/heuristic. When the workspace has the\nrelevant evidence, enrich the plan so the recommended migration order reflects real\nporting risk \u2014 code that is hard to port AND dangerous AND historically volatile \u2014\nnot just structural readiness. This is optional: skip any dimension whose evidence\nor tier is unavailable and mark it UNASSESSED (never a clean bill).\n\n**Tier:** composed tools enforce their own tiers \u2014 `unsafe_surface` Free,\n`secret_surface` Engineer, `taint_flow`/`coverage_overlay`/`ownership_map` Architecture,\n`churn_hotspots` Free for a single file / Architecture in workspace mode. If a tool is\ntier-blocked, its dimension is UNASSESSED \u2014 say so.\n\n**Honesty caveat:** `taint_flow`/`secret_surface`/`unsafe_surface` report\n`modeled_kinds` \u2014 read it per call. A non-empty mask means the dimension *was*\nmodeled for that grammar (an empty finding is then genuine); an empty/absent mask\nmeans it was *not* modeled \u2014 \"no evidence,\" not \"clean.\" `coverage_overlay`/\n`churn_hotspots`/`ownership_map` reflect one coverage run and the git history\npresent; state the window and `unmapped`.\n\n| Tool | Enriches the plan with |\n|---|---|\n| `taint_flow` | Source\u2192sink data-flow paths a port must preserve exactly \u2014 a hard porting hazard. |\n| `secret_surface` | Secret-touching code needing careful handling / rotation during the move. |\n| `unsafe_surface` | Unsafe blocks, eval, raw SQL, FFI, reflection, unsafe deserialization \u2014 rarely port 1:1. |\n| `coverage_overlay` | Which modules have a test safety net for the port vs. which are flying blind. |\n| `churn_hotspots` | Volatile modules \u2014 porting a still-changing target is a moving-target risk. |\n| `ownership_map` | Bus factor \u2014 low ownership on a hard module concentrates the knowledge to port it. |\n\n**Enrichment workflow (after the structural plan):**\n\n1. Run `unsafe_surface` and `secret_surface` per module; run `taint_flow` on entry\n   functions. Any unsafe construct, secret surface, or live taint path raises that\n   module's effective difficulty above its structural score.\n2. `coverage_overlay` (lcov `report`) \u2014 a low-coverage module cannot be safely\n   verified after porting; front-load test work or reorder.\n3. `churn_hotspots` (workspace) and `ownership_map` \u2014 a high-churn or low-bus-factor\n   module is a scheduling risk: stabilize or pair-port it.\n4. Recompute the order: structurally-ready AND well-tested AND low-risk first; hard +\n   dangerous + volatile last (or split first). Reclassify any soft blocker that an\n   unsafe/taint/secret finding promotes to a hard blocker.\n\nWhen enrichment runs, each readiness card adds: taint paths, secret/unsafe hits,\ncoverage %, churn rank, and bus factor \u2014 and each blocker cites which evidence\ndimension fired.\n\n## Monorepos: frame readiness cards by package, not directory\n\nWhen the repo is a workspace with package manifests, run the structural pass at\n**package granularity** so readiness cards map to the team's real packages\n(workspace members), not arbitrary directories:\n\n- `analyze_clusters` and `analyze_layers` with `granularity: package` cluster and\n  layer the package dependency graph (`DependsOn` edges parsed from manifests),\n  giving the true cross-package porting order \u2014 port a package only after the\n  packages it depends on.\n- `analyze_conformance` with `granularity: package` evaluates deny rules against\n  package names, so a \"don't let package X depend on Y\" boundary is checked at\n  the level the team actually reasons about.\n\nWhich manifest kinds were modeled is reported from the graph's package nodes\n(empty when none) \u2014 never assume an ecosystem is covered; read what was modeled.\nFall back to file/directory granularity when no workspace manifest is present."
}