Skip to content

Kotlin Standards Plugin

Extraction of the Kotlin Coding Standards enforcement machinery out of the operations repository into a shared, published Gradle plugin with its own repository, consumable by any Arda Kotlin repository.

The machinery existed and worked. It was built inside operations and is thoroughly measured; what it did not have was a second consumer, an extension surface, or any way to reach a repository that is not operations. This project gives it all three.

AspectValue
StatusIn progress — published as 2.0.0, consumed by print-module and operations
TicketPDEV-1790
Repositorykotlin-standards-gradle-plugin
Plugin idcards.arda.standards.kotlin
First consumerprint-module
Seam validatoroperations

Where to read next. Automated Checks is the page for someone adopting or using the gate. Kotlin Standards Plugin describes the apparatus as it stands. Design records how it was arrived at, and the decision log holds the reasoning behind each choice.

The keystone ruling, MP, 2026-08-27:

print-module is acting as a guinea pig for how to build modules and components in the future, so we should not drop rules or other mechanisms if there is no current use case in the repository, as it is likely that this repository, or a sibling one will have that use case.

This reverses the obvious reading of a port. The naive move is to carry across only the rules that have something to judge in the destination — print-module has no persistence at all, so three rules would have no subject there. Under this framing that is precisely backwards: a rule a future Module repository will need is exactly what the exemplar should carry, and carrying it before the subject exists is how the mechanism gets proven while the stakes are low.

It has a sharp consequence, recorded as DT-007. A rule with no subject reports zero forever — and zero is also what a rule reports when it has silently stopped running. For a rule with a subject, going dark is at least visible as a count dropping from N to 0. For a subjectless rule, dead and clean are the same number, permanently. The liveness fixture stops being good practice and becomes the only thing holding those rules up.

That asymmetry is the reason the apparatus insists on three report states everywhere, and it is the single idea most of the design decisions descend from.

PDEV-1304 — “Extract the Gradle build conventions into a shared, published plugin” — already covers Helm packaging, image conventions, manifest generation and OpenAPI jar packaging. MP ruled that standards enforcement is a sibling to it rather than part of it: the two are separately adoptable, and sharing a version train would force every consumer to take both. PDEV-1304’s acceptance criteria already require the extension pattern this project also needs, which is the shape to imitate rather than the repository to move into. → DT-003.

The one boundary that moved: the Spotless/ktlint formatting gate comes here rather than staying a PDEV-1304 candidate, because two owners for one gate is worse than either owner alone. Kover thresholds and the JUnit platform pin stay with PDEV-1304. The line that results states itself — PDEV-1790 owns what enforces the Kotlin Coding Standards; PDEV-1304 owns build configuration — which is worth more than a boundary drawn item by item. → DT-012.

Three words carry a fixed meaning across this project’s documents.

Facet — what a repository is made of: its layers, technologies and patterns. Distinct from capability, which MP reserved for what a Module offers — its features, use cases, scenarios and APIs. The word follows IntelliJ’s project-configuration vocabulary, where a facet is a characteristic of a module that brings its own tooling with it; declaring a facet is what brings that facet’s rules into scope. → DT-004.

Tier A / Tier B — Tier A rules are file-local: their verdict depends on one file, and detekt runs them. Tier B rules are structural: their verdict is a property of the whole program, and a runner over imports and bytecode evaluates them.

Scope — how hard a rule is held in a given repository: tree blocks anywhere, ratchet blocks only in files the branch changed, advisory never blocks, and none does not run the rule at all. It is a property of the repository, not of the rule. → DT-005.


Copyright: (c) Arda Systems 2025-2026, All rights reserved