Files
werkator/docs/prs/2026-10-14-PR#162-history-nulls-without-loop.md
claude-code b470c1d080
werkator build succeeded after 02:18
werkator/deploy build succeeded after 00:10
werkator/mutation build succeeded after 23:06
The gap filler of the metrics history has no loop, so its mutants no longer run out of memory (v1.43.2) (#162)
Co-authored-by: claude-code <claude-code@javagil.de>
2026-10-14 16:23:44 +02:00

2.6 KiB

PR#162: The gap filler of the metrics history has no loop, so its mutants no longer run out of memory

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.

Problem

The nightly build mutation failed on main at 15b1251 after 32:45, in the gate mutationCrapCheck. The gate refused to judge HistoryTier.nulls(I): two of its four mutants ended with MEMORY_ERROR, which werkcrappit reports as INCONCLUSIVE. The method is List(size) { null }, unchanged since PR#29. Kotlin compiles it to a counting loop that fills an ArrayList. PIT mutates the counter, the loop never ends, and the list grows. Whether such a mutant first meets the PIT timeout (detected) or the heap limit (MEMORY_ERROR) depends on the load of the night. On 2026-10-10 all four were killed; on 2026-10-14 two ran out of memory.

Non-Goals

  • No change to werkcrappit: whether a MEMORY_ERROR counts as detected stays its own decision.
  • No change to the minions' heap or the PIT timeouts.
  • No other method: the last report names no other MEMORY_ERROR.

Specification

Feature: the history fills a new series with nulls

Scenario#162.01: A series that appears later starts with one null per earlier point!

So that every column of a tier has as many points as the tier has timestamps.

  • Given a sample tier with three points and no series disk.hdd.usedGib
  • When a fourth sample has a value for that series
  • Then the series is null, null, null and the new value
Verified by

Solution

  • HistoryTier.nulls builds its list as arrayOfNulls<Double>(size).asList(). The bytecode has no loop for PIT to mutate into an endless one; the behaviour is the same.
  • Measured locally with PIT on HistoryTier alone: nulls has one mutant instead of four, killed; complexity 1, Mutation-CRAP 1.00; no INCONCLUSIVE, the gate passes.
  • A KDoc on the method says why, so nobody turns it back into List(size) { null }.
  • Werkbaum: a node under #tests.
  • Version 1.43.2, with an entry in the release notes.

Open Questions

  • TODO.werkcrappit: PIT counts MEMORY_ERROR as detected, werkcrappit as inconclusive. Another mutant with an endless allocation would fail the gate the same way. Whether werkcrappit should count it as detected is a decision in werkcrappit, not here.