Files
werkator/docs/prs/2026-10-04-PR104-mutation-crap-limits.md
miandmhoennig 7d445dc673
werkator build succeeded after 01:46
werkator/deploy build succeeded after 00:08
Mutation-CRAP target 15 for Kotlin, red from 12, gate as ratchet (v1.34.1) (#104)
- Target: Mutation-CRAP at most 15 for Kotlin, code city red from 12 (score never below complexity; JaCoCo counts compiler-generated Kotlin branches).
- Gate `maxMutationCrap = 650` as a ratchet (today max 647.55), lowered with every refactoring PR down to 15.
- werkcrappit 0.15.0 -> 0.16.4 for `codeCharta.colorRedFrom`.
- AGENTS.md: rule, ratchet, split along domain steps.

PR-doc: `docs/prs/2026-10-04-PR#104-mutation-crap-limits.md`

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: mhoennig <michael@hoennig.de>
Reviewed-on: #104
2026-10-04 10:14:06 +02:00

3.7 KiB
Raw Permalink Blame History

WARNING: This document describes only the change applied in this PR. It may already be outdated once the next PR is merged. Historic PR-documentation is not maintained along with new PRs — treat it as a snapshot, not as current documentation.

The Problem

The nightly build mutation reports every method's Mutation-CRAP, but it judged nothing: no limit, and the code city coloured by werkcrappit's defaults. The first full report has 108 methods at 10 or above, the limit used for Java projects. The score is C² × (1 − MS)³ + C, so it never falls below the method's complexity: a limit of 10 is also a complexity limit of 9, however well a method is tested. JaCoCo counts the branches of the bytecode, and the Kotlin compiler adds branches nobody wrote: the implicit else of an exhaustive when, the branches of inlined let and takeIf. Java's 10 would therefore ask for smaller methods than the same code needs in Java.

CodeCharta Mutation CRAP Metric before

Non-Goals

  • No method is changed here; the refactorings follow, one PR per domain area.
  • No limit for Java projects: they keep 10.
  • ?. and ?: stay real branches: a surviving mutant there is a missing test, and the mutation part of the score still says so.

The Scenarios

Feature: Werkator's methods aim at a Mutation-CRAP of at most 15

Scenario#104.01: The code city shows red from 12

So that the methods to look at next stand out before they reach the limit.

  • Given the nightly build mutation
  • When werkcrappit writes the code city and its viewer link
  • Then a method from 12 on is red, from 6 on yellow
Verified by
  • The build definition mutation on werkator.javagil.de, whose code city link carries the colour range.

Scenario#104.02: The gate is a ratchet towards 15

So that nothing gets worse while the 45 methods above 15 are refactored, and the nightly build keeps its meaning.

  • Given today's highest score of 647.55
  • When the nightly build runs with maxMutationCrap = 650
  • Then it passes today and fails as soon as a method scores above 650
  • And every refactoring PR lowers the limit to just above the new highest score, until it reaches 15
Verified by
  • The build definition mutation on werkator.javagil.de (mutationCrapCheck).

The Solution

  • werkcrappit 0.15.0 → 0.16.4, for codeCharta.colorRedFrom.
  • maxMutationCrap = 650 and colorRedFrom = 12 in build.gradle.kts, with the reasoning as a comment.
  • AGENTS.md states the target, the ratchet, and that a method above 15 is split along its domain steps.

Why 15 and 12:

Score Methods at or above of which by complexity alone of which by weak tests
10 108 58 50
12 84 34 50
15 45 15 30

At 15 the complexity cases left are the genuine ones (BuildExecutor.execute 40, SystemMetricsCollector.sample 35, BuildDefinition.applyTo 34); the test gaps stay almost all visible. NIST SP 500-235 names 10 as the complexity limit and up to 15 as acceptable for experienced teams with well-tested code.

Additional Changes

  • Version 1.34.1 with its release note.

Follow-up PRs

  • The home page's repository card (HomeCardView.from, HomeTexts.meta), then BuildExecutor.execute, ConfigLoader, metrics and sizing, the Forgejo export, and the environment probes; each lowers the ratchet.