ModuleClassifier

Extension point for teaching Aalekh your conventions.

Aalekh infers a module's layer from path segments and its team from glob patterns, and both are guesses about a convention it was not told. A classifier replaces the guess with the rule the team actually uses - a naming scheme, a marker file, a registry, an annotation - and says whether the answer is observed or inferred.

class ServiceRegistryClassifier : ModuleClassifier {
override val id = "service-registry"

override fun classify(modulePath: String, graph: ModuleDependencyGraph) =
registry[modulePath]?.let {
ModuleClassification(
team = it.owningTeam,
purpose = it.description,
provenance = Provenance.OBSERVED, // read from the registry, not guessed
)
}
}

Register it with a META-INF/services/com.aalekh.aalekh.analysis.spi.ModuleClassifier file in a jar on the plugin's runtime classpath.

Precedence. A classifier sits between the two things it must not override: anything the user declared directly - layers { }, teams { }, .aalekh/modules.json - always wins, because an explicit declaration outranks any rule that infers one; and a classifier always beats Aalekh's own path-segment guesses, because a team's real convention beats a generic heuristic. A classifier that returns null for a module simply leaves it to the next source.

Like every Aalekh extension point this is a pure function: no filesystem, no network, no Gradle API, and deterministic. One that throws is skipped and reported; it never breaks the build.

Properties

Link copied to clipboard
abstract val id: String

Stable, kebab-case identifier. Used to attribute failures.

Functions

Link copied to clipboard
abstract fun classify(modulePath: String, graph: ModuleDependencyGraph): ModuleClassification?

Classifies one module, or returns null when this classifier has nothing to say about it - which is the normal case for a classifier that only knows about part of the project.