Skip to content

v0.3.1 — Kotlin dependency edges, and cycles that only count where they bite

Choose a tag to compare

@Codewithaiyan Codewithaiyan released this 30 Oct 15:28
· 17 commits to master since this release

The two gaps the 0.3.0 sweep found and left open.

Fixed - a Kotlin dependency graph was empty and claimed to be fine

okhttp reported 0 edges, 6,869 external imports and 0 unresolved relative imports. By the diagnostic added in 0.2.5, that reads as "this code has no internal imports" - about a library that imports its own packages on nearly every file.

That made it the worst remaining honesty hole in the tool: the mechanism built specifically to stop an empty graph being misread was itself handing out a clean bill of health.

Imports were resolved by treating them as paths, relative or dotted, against the set of parsed files. A Kotlin import is not a path. import okhttp3.internal.platform.Platform names a declaration in a package, and the file holding it can be anywhere in the tree. Nothing mapped a package to a file, so every Kotlin import fell through to "external".

Each file's declared package is now read from its package header and indexed, together with the fully-qualified name of every declaration inside it. Three forms resolve:

  • app.platform.Platform - a declaration, by fully-qualified name
  • app.util.* - the whole package, so an edge to every file in it
  • app.config.Config.DEFAULT - a member, resolved to the declaration above it

okhttp: 0 edges to 1,632, external imports down from 6,869 to 4,768, and 64 dependency cycles that had been invisible. A mixed Kotlin/JavaScript/Python repository went from 2 edges to 89, its Android code finally connected to its own UI and test files.

android.os.Bundle and kotlin.math.roundToInt stay external, which is correct - they are outside the repository.

The index is consulted only for files that declare a package themselves, so a Python dotted import can never collide with a Kotlin fully-qualified name. There is a test for exactly that.

Go is not covered. A Go import is a module path such as github.com/spf13/cobra/..., which needs the module name from go.mod plus a directory mapping. cobra is a single package and genuinely has no internal imports, so the 190 external imports it reports are honest.

Fixed - a Kotlin cycle cost health points for being idiomatic

Resolving Kotlin edges immediately exposed a second defect. okhttp's 64 newly visible cycles cost it the full 20-point cycle penalty, dropping its health from 66.0 to 46.0 - for writing ordinary Kotlin.

That penalty was written for Python and JavaScript, where an import executes at module load and a cycle can raise at runtime. Kotlin, Java and Go compile a module as a whole, and circular references between files are normal; within a package Kotlin needs no import at all.

Every cycle is still reported by scan_repo, because the information is useful. Only a cycle touching a .py, .js, .jsx, .mjs, .cjs, .ts or .tsx file costs points, so a cycle spanning languages still counts.

okhttp is back to 66.0 with its 64 cycles reported. Flask keeps its 37 Python cycles and its 39.1, which is the right answer for a language where they bite.

Upgrading

uv tool upgrade reforge-mcp --refresh     # or: pip install -U reforge-mcp

Full detail in CHANGELOG.md.

🤖 Generated with Claude Code