Teaches AI agents to write idiomatic Kotlin instead of Java-in-a-.kt-file.
98
98%
Does it follow best practices?
Impact
99%
1.20xAverage score across 8 eval scenarios
Passed
No known issues
Process steps in order. Do not skip ahead.
Before (Java-style POJO):
class Customer {
var customerId: String? = null
var email: String? = null
fun getCustomerId(): String? = customerId
fun setCustomerId(value: String?) { customerId = value }
fun getEmail(): String? = email
fun setEmail(value: String?) { email = value }
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Customer) return false
return customerId == other.customerId && email == other.email
}
override fun hashCode(): Int = 31 * (customerId?.hashCode() ?: 0) + (email?.hashCode() ?: 0)
override fun toString(): String = "Customer(customerId=$customerId, email=$email)"
}After (idiomatic Kotlin):
data class Customer(
val customerId: String? = null,
val email: String? = null
)A class is a candidate when it has all of:
equals, hashCode, AND toString — all threeIf any of these are missing, stop and report what you found. Not every class with equals/hashCode is a data class candidate — some have legitimate inheritance or behaviour.
data class primary constructor parameters MUST appear in the same order — otherwise existing componentN() destructuring breaks for callersgetCustomerId → customerId)class Foo { val a: String; val b: Int; … } to data class Foo(val a: String, val b: Int)var to val UNLESS the field has a documented reason to mutate (flag any retained var in the conversion summary)val derived: T get() = …) into the class body, after the primary constructorequals, hashCode, and toString — the compiler generates them nowtoString was overridden to MASK a sensitive field (passwords, tokens), keep ONLY toString as a manual override and delete equals and hashCodeinit blocks that only validated equality contract assumptionsfoo.setX(value) with foo.copy(x = value) — the idiomatic mutation pattern from rule use-data-classFoo(a, b)) keeps working if Step 2 preserved field orderFinish here. Do not commit — that's the operator's call.