KMP-IMPACT

Phase 2 — Static analysis

The second phase identifies the Kotlin files affected by the bump — both directly (they import a symbol from the bumped library) and transitively (they import a directly-affected file) — and tags every impacted file with its source set.

Inputs

Outputs

phase2/
├── impact_graph.json
└── symbol_index.json

What happens

  1. Parse every .kt under src/ with Tree-sitter (tree-sitter-kotlin).
  2. Build a symbol index: file → declared symbols, file → imported symbols, file → source set.
  3. Resolve the bumped Maven coordinate to a set of Kotlin package roots via the MAVEN_TO_KOTLIN mapping table (e.g. io.ktor:*io.ktor.*).
  4. Mark every file whose imports intersect those roots as impact_level = 2 (direct).
  5. BFS over the symbol graph from each direct file. Record the parent at every step in propagated_from. Mark each newly reached file as impact_level = 1 (transitive).
  6. Tag every impacted file with its source set based on its path under src/<sourceSet>Main/kotlin/.
  7. Scan the impacted files for expect / actual declarations. Pairs are surfaced as review targets — not compatibility proofs.
  8. Compute per-file metrics: rloc (real lines of code), mcc (a McCabe-like heuristic). These feed Phase 5.

Output sample

A single FileImpact entry inside phase2/impact_graph.json#impacted_files:

{
  "file_path": "shared/src/commonMain/kotlin/com/example/api/PokedexClient.kt",
  "relation": "direct",
  "distance": 0,
  "imports_from_dependency": ["io.ktor.client.HttpClient"],
  "propagated_from": [],
  "metrics": { "rloc": 84, "functions": 9, "mcc": 12 },
  "declarations": ["PokedexClient"],
  "source_set": "common"
}

Detected pairs travel separately under impact_graph.json#expect_actual_pairs:

{
  "expect_fqcn": "com.example.HttpEngineFactory",
  "expect_file": "shared/src/commonMain/kotlin/com/example/HttpEngineFactory.kt",
  "actual_files": [
    "shared/src/androidMain/kotlin/com/example/HttpEngineFactory.android.kt",
    "shared/src/iosMain/kotlin/com/example/HttpEngineFactory.ios.kt"
  ]
}

Per-source-set counts are not pre-computed in the model — the renderer groups impacted_files by source_set at report time. The PR-comment sunburst preview is built from the same grouping.

Edge cases

Contracts

Next phase

Phase 3 reads the same shadow copies and builds the APKs for the dynamic analysis. It does not read Phase 2 output — the two phases run in parallel in CI.

Phase 3 — Dynamic analysis