Observation
Your AGENTS.md <rules> block lists a bunch of strict invariants — no java.*/android.*/platform APIs in commonMain, an explicit ~13-type allowlist for public declarations (MqttClient, MqttConfig, MqttMessage, PublishProperties, MqttEndpoint, QoS, ConnectionState, ReasonCode, WillConfig, MqttLogger, MqttLogLevel, RetainHandling, AuthChallenge + the named convenience extensions), MqttTransport/MqttProperties internal, zero deps beyond Ktor + coroutines + kotlinx-io, etc.
You already have a great foundation: library/src/jvmTest/kotlin/org/meshtastic/mqtt/architecture/ArchitectureTest.kt covers 5 of these via Konsist (no java./javax./android./platform. imports in commonMain, MqttTransport internal, MqttProperties internal). Nice — that already catches the most common drift class that apiCheck can't see.
This issue is just to suggest closing the remaining gap between the prose rules and the mechanical ones, and a couple of small structural tweaks.
Proposal
1. Move (or duplicate) the suite into commonTest
Konsist's Konsist.scopeFromProduction() reads source files, not compiled classes, so it works fine from commonTest on a KMP project. Putting the suite in commonTest means it runs as part of allTests on every CI matrix entry, not only jvmTest. That's mostly belt-and-braces — the rules are source-level — but it makes the architectural contract a property of the library rather than of the JVM target.
(If there's a reason it's intentionally jvmTest-only — e.g. CI cost — totally fair, ignore this part.)
2. Additional rules from AGENTS.md that translate cleanly
Each of these maps to a Konsist one-liner against scopeFromProduction() — see the Konsist snippet inspiration page for close analogues:
- Public-API allowlist. Every top-level
public declaration in commonMain must be in the named set above (plus the messagesForTopic / messagesMatching / use extensions and the MqttClient(clientId) {} factory). Today this is enforced by apiCheck at the symbol level — but apiCheck only fires once a leak ships in the dump. A Konsist test can fail on the introducing PR with a clearer error message ("FooHelper was made public; either add it to the allowlist in ArchitectureTest or mark it internal").
MqttPacket and all its subtypes are internal. The sealed interface plus all 15 packet implementations.
- All packet classes are
data class (or data object). Catches accidental class / object declarations under the packet sealed hierarchy.
- All
data class packet fields are val. Konsist's properties().assertTrue { it.hasValModifier } filtered to the packet hierarchy.
- (Optional) No
println / System.err.println in commonMain or nonWebMain production sources — the repo already calls this out implicitly via the MqttLogger abstraction.
3. Implementation notes
- Konsist (
com.lemonappdev:konsist:0.17.3) is already in your version catalog and on the jvmTest classpath, so the only build change to move to commonTest is shifting the testImplementation(libs.konsist) dependency from the jvm test source set to commonTest.
- Single suite typically runs in 1–3s; not a CI cost concern.
- For the public-API allowlist test, keeping the allowlist as a private
val ALLOWED = setOf("MqttClient", …) inside the test file means contributors get a one-line diff to review when surface intentionally grows.
- Konsist works on KMP projects today and operates on the entire source tree from
commonTest. Their docs cover the KMP setup directly: https://docs.konsist.lemonappdev.com.
4. Offer
Happy to send a starter PR with the four highest-value rules (public-API allowlist, MqttPacket internal, packet data class-ness, packet-field immutability) if it'd help. Just say the word and I'll target a fork of main.
Observation
Your
AGENTS.md<rules>block lists a bunch of strict invariants — nojava.*/android.*/platform APIs incommonMain, an explicit ~13-type allowlist forpublicdeclarations (MqttClient,MqttConfig,MqttMessage,PublishProperties,MqttEndpoint,QoS,ConnectionState,ReasonCode,WillConfig,MqttLogger,MqttLogLevel,RetainHandling,AuthChallenge+ the named convenience extensions),MqttTransport/MqttPropertiesinternal, zero deps beyond Ktor + coroutines + kotlinx-io, etc.You already have a great foundation:
library/src/jvmTest/kotlin/org/meshtastic/mqtt/architecture/ArchitectureTest.ktcovers 5 of these via Konsist (nojava./javax./android./platform.imports in commonMain,MqttTransportinternal,MqttPropertiesinternal). Nice — that already catches the most common drift class thatapiCheckcan't see.This issue is just to suggest closing the remaining gap between the prose rules and the mechanical ones, and a couple of small structural tweaks.
Proposal
1. Move (or duplicate) the suite into
commonTestKonsist's
Konsist.scopeFromProduction()reads source files, not compiled classes, so it works fine fromcommonTeston a KMP project. Putting the suite incommonTestmeans it runs as part ofallTestson every CI matrix entry, not onlyjvmTest. That's mostly belt-and-braces — the rules are source-level — but it makes the architectural contract a property of the library rather than of the JVM target.(If there's a reason it's intentionally
jvmTest-only — e.g. CI cost — totally fair, ignore this part.)2. Additional rules from
AGENTS.mdthat translate cleanlyEach of these maps to a Konsist one-liner against
scopeFromProduction()— see the Konsist snippet inspiration page for close analogues:publicdeclaration incommonMainmust be in the named set above (plus themessagesForTopic/messagesMatching/useextensions and theMqttClient(clientId) {}factory). Today this is enforced byapiCheckat the symbol level — butapiCheckonly fires once a leak ships in the dump. A Konsist test can fail on the introducing PR with a clearer error message ("FooHelperwas madepublic; either add it to the allowlist inArchitectureTestor mark itinternal").MqttPacketand all its subtypes areinternal. The sealed interface plus all 15 packet implementations.data class(ordata object). Catches accidentalclass/objectdeclarations under the packet sealed hierarchy.data classpacket fields areval. Konsist'sproperties().assertTrue { it.hasValModifier }filtered to the packet hierarchy.println/System.err.printlnincommonMainornonWebMainproduction sources — the repo already calls this out implicitly via theMqttLoggerabstraction.3. Implementation notes
com.lemonappdev:konsist:0.17.3) is already in your version catalog and on thejvmTestclasspath, so the only build change to move tocommonTestis shifting thetestImplementation(libs.konsist)dependency from the jvm test source set to commonTest.val ALLOWED = setOf("MqttClient", …)inside the test file means contributors get a one-line diff to review when surface intentionally grows.commonTest. Their docs cover the KMP setup directly: https://docs.konsist.lemonappdev.com.4. Offer
Happy to send a starter PR with the four highest-value rules (public-API allowlist,
MqttPacketinternal, packetdata class-ness, packet-field immutability) if it'd help. Just say the word and I'll target a fork ofmain.