This document records how each architectural invariant in the SDK is
mechanically checked. Per ADR-008,
we deliberately keep the toolset small: every invariant is enforced by a tool
that already runs as part of ./gradlew check.
If you add a new invariant, add a row here and pick exactly one enforcement home — do not duplicate the same rule across tools.
| Invariant | Source of truth | Enforced by | Where to look |
|---|---|---|---|
:core depends only on :proto |
ADR-002, module-graph.md |
Gradle task: :core:verifyModuleBoundary (wired into check) |
core/build.gradle.kts |
No transport / storage code in :core |
ADR-002 | Same :core:verifyModuleBoundary task — any non-:proto project dep fails the build |
core/build.gradle.kts |
Engine paths use no shared-state primitives (Mutex, Semaphore, ReentrantLock) |
ADR-002 — single-writer actor | detekt ForbiddenImport rule (style.ForbiddenImport) |
config/detekt/detekt.yml |
kotlin.Result is never used (public or internal) |
ADR-005 | detekt ForbiddenImport rule + Binary Compatibility Validator catches public-API leaks |
config/detekt/detekt.yml, api/*.api |
| Public API surface is reviewed and stable | ADR-005, docs/versioning.md |
Kotlinx Binary Compatibility Validator (./gradlew checkKotlinAbi) |
api/jvm/*.api, api/android/*.api per module |
| Static analysis (complexity, naming, exceptions) | detekt defaults + project overrides | detekt (./gradlew detekt) |
config/detekt/detekt.yml, per-module detekt-baseline.xml |
| Agent / tooling guardrails (CODEOWNERS, AGENTS.md sync, hook policy) | Repo convention | bash .github/tooling/check.sh (run by pre-commit hook and CI) |
.github/tooling/ |
- Gradle — module dependency graph and lifecycle. Best place to enforce structural invariants (who can depend on whom).
- detekt — file-level static analysis. Best place to enforce idiom invariants (forbidden imports, complexity, exception handling).
- Binary Compatibility Validator (BCV) — golden snapshots of every public
type and member. Best place to enforce surface invariants. Generated
baselines live under
<module>/api/. - Spotless + ktlint — formatting only. Never used for semantic rules.
Konsist was previously listed in the version catalog and referenced from
AGENTS.md and CONTRIBUTING.md, but no Konsist test was ever written. The
invariants we actually need are already covered by tools that we already run
(detekt, Gradle, BCV). ADR-008
records the decision to remove the dangling Konsist references rather than
introduce a third enforcement engine for the same rules.
- Decide which tool category fits (structural → Gradle; idiom → detekt; surface → BCV; format → Spotless).
- Implement the rule in the corresponding config file.
- Add a row to the matrix above with a link to the source of truth and a link to the rule.
- If the rule is non-obvious, write or extend an ADR explaining the why
and reference it from the rule's
reasonfield (detekt) or task description (Gradle). - Run
./gradlew checkto confirm the rule passes on the current tree, and ideally write a negative test demonstrating that it fails when violated.