Architecture Baselines
When integrating architecture tests into large, established codebases, you will often encounter thousands of pre-existing violations. Forcing developers to fix all historical violations immediately is a massive blocker.
Konture solves this with Architecture Baselines, allowing you to record all existing violations to a baseline file, ignore them in subsequent runs, and focus entirely on preventing new architectural erosion!
π¦ Distributed Baselines
Unlike traditional architecture test frameworks that record violations into a single, massive monolithic baseline file at the project root (creating merge conflicts on every pull request), Konture features Distributed Baselines.
If your project is a multi-module workspace and you specify a relative baseline file name, Kontureβs baseline engine (BaselineManager) automatically correlates recorded violations back to the submodules they originated from. It writes localized baseline files directly inside each submodule directory!
my-project/
βββ core/
β βββ database/
β βββ src/
β βββ konture-baseline.json <-- Violations local to database module
βββ feature/
β βββ payment/
β βββ src/
β βββ konture-baseline.json <-- Violations local to payment module
βββ konture-test/
This isolates changes, completely prevents git merge conflicts on PRs, and makes ownership of technical debt crystal clear!
π Generating & Committing Baselines
To establish your baseline and freeze existing technical debt:
Step 1: Run your tests in Generate Mode
You can run the built-in Gradle task registered by the Konture plugin, which automatically sets konture.baseline.generate=true and runs all test tasks:
π Gradle (Recommended)
./gradlew generateKontureBaseline
Or target a specific submodule to generate or update its baseline in isolation:
./gradlew :feature:payment:generateKontureBaseline
π Gradle (Alternative Manual CLI Override)
You can also manually execute your test task while passing the generate flag as a JVM system property:
./gradlew :konture-test:test -Dkonture.baseline.generate=true
π¦ Maven
For Maven projects, pass the system property directly:
mvn test -pl konture-test -Dkonture.baseline.generate=true
Upon completion, Konture will succeed and automatically generate a localized konture-baseline.json file in each module containing structural violations.
Step 2: Commit baselines to Git
Commit the generated konture-baseline.json files to your version control repository alongside your tests:
git add **/konture-baseline.json
git commit -m "chore: freeze architecture violations baseline"
In subsequent standard test executions (without the generate flag), Konture will load these files, filter out the pre-existing violations, and pass. Any new violation introduced by developers will fail the build immediately!
βοΈ Baseline Configuration Reference
You can customize baseline behavior either programmatically on the Konture runtime or via JVM system properties.
Precedence Rules: JVM system properties always take precedence over programmatic properties configured via the
Konturesingleton runtime or Gradle DSL extension.
| Programmatic Property | System Property | Default Value | Description |
|---|---|---|---|
Konture.baselinePath | konture.baseline.path | "konture-baseline.json" | Path of the baseline files. Can also be set in Gradle via the konture { baselinePath("custom.json") } block. If relative, and a Gradle/Maven graph is present, it writes distributed baseline files in submodules. |
Konture.generateBaseline | konture.baseline.generate | false | When true, enables generate mode to write or update baseline files, pruning resolved violations and deleting empty baseline files. |
Konture.reportResolvedViolations | konture.reportResolvedViolations | true | When true, logs an informational message during test execution if baseline violations have been resolved. |
Konture.failOnResolvedViolations | konture.failOnResolvedViolations | false | Ratchet Mode. When true, fails test execution if any previously baselined violation is resolved, prompting developers to regenerate the baseline. |
| N/A | konture.baseline.dir | System property | Overrides the target output directory for baseline files (see below for absolute-path check behavior). |
π Technical Debt Tracking & Delta Baselines
Konture computes violation deltas during test execution:
- Active Baseline Violations: Violations present in both the baseline and current codebase ($V_{\text{evaluated}} \cap V_{\text{baseline}}$).
- New Violations: Newly introduced violations that are not in the baseline ($V_{\text{evaluated}} \setminus V_{\text{baseline}}$). These fail your build.
- Resolved Violations: Violations that were in the baseline but are now fixed in the codebase ($V_{\text{baseline}} \setminus V_{\text{evaluated}}$).
Technical debt metrics are automatically included in test summary logs and JSON/HTML/SARIF reports under reportSummary:
{
"summary": {
"totalViolations": 1,
"activeBaselineCount": 1,
"resolvedCount": 2,
"newViolationsCount": 0
}
}
π Ratchet Mode (Prevent Regression of Fixed Debt)
When a developer refactors code and resolves existing architectural debt, you want to make sure new violations can never re-introduce that debt.
Enable Ratchet Mode to ensure baselines only shrink:
Gradle Configuration
konture {
failOnResolvedViolations = true
}
CLI / CI Flag
./gradlew test -Dkonture.failOnResolvedViolations=true
When Ratchet Mode is enabled and resolved violations are detected, Konture fails the build with an actionable error:
Baseline contains 3 resolved violation(s) but failOnResolvedViolations is enabled. Please update baseline using ./gradlew generateKontureBaseline.
Programmatic Ratchet Verification in Tests
You can also invoke Konture.checkRatchet() directly within test suites (such as in a @AfterAll or test lifecycle listener) to fail the test suite immediately if resolved technical debt is detected:
@AfterAll
fun verifyRatchet() {
Konture.checkRatchet()
}
Baseline Regeneration & Test Filtering: When regenerating baselines (
-Dkonture.baseline.generate=trueor./gradlew generateKontureBaseline), ensure the full test suite runs without--testsfiltering so all architecture rules across the project are evaluated before resolved violations are pruned.
π JSON Baseline Schema
Baselines are serialized using kotlinx-serialization for speed and consistency. The schema maps violations down to specific test classes and methods, preventing a violation under one test from accidentally ignoring a different rule.
Schema Format
Konture supports a multi-class baseline schema, grouping all recorded violations under the testClasses block by their respective class and test/method:
{
"version": 1,
"testClasses": [
{
"name": "com.acme.konture.MyArchitectureTest",
"tests": [
{
"name": "repositories should be interfaces",
"violations": [
{
"location": ":database, main source set, com/acme/database/SomeRepository.kt:12",
"message": "Class com.acme.database.SomeRepository must be declared as interface"
}
]
}
]
},
{
"name": "com.acme.konture.OtherArchitectureTest",
"tests": [
{
"name": "controllers should only depend on services",
"violations": [
{
"location": ":web, main source set, com/acme/web/SomeController.kt:34",
"message": "Class com.acme.web.SomeController depends on repository directly"
}
]
}
]
}
]
}
π Regenerating Baselines After an Upgrade
Baseline entries are matched against the exact violation text a rule produces. When an upgrade improves the wording or location of violation messages, previously recorded entries no longer match and their violations resurface as if new.
After upgrading Konture, regenerate your baselines once and commit the result:
./gradlew generateKontureBaseline
This is a one-time step per upgrade that changes message formatting; it does not weaken any rule, it only refreshes the stored text.