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.
phase1/before/, phase1/after/ — the shadow copies from Phase 1.phase1/manifest.json — the resolved coordinates and bump category.phase2/
├── impact_graph.json
└── symbol_index.json
.kt under src/ with Tree-sitter (tree-sitter-kotlin).MAVEN_TO_KOTLIN mapping table (e.g. io.ktor:* → io.ktor.*).impact_level = 2 (direct).propagated_from. Mark each newly reached file as impact_level = 1 (transitive).src/<sourceSet>Main/kotlin/.expect / actual declarations. Pairs are surfaced as review targets — not compatibility proofs.rloc (real lines of code), mcc (a McCabe-like heuristic). These feed Phase 5.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.
plugin_or_toolchain bumps — AGP, KSP, the Gradle wrapper. Zero static impact by design (no Kotlin imports). See L2.org.jetbrains.compose.* coordinates are not yet mapped to androidx.compose.* package roots. See L7.src/<sourceSet>Main/kotlin/ are tagged unknown. See L3.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.