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

53 lines
2.6 KiB
Markdown

# 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
- [MetricsHistoryUnitTest: every sample becomes one point of the sample tier, column-wise for all keys](../../src/test/kotlin/de/hoennig/werkator/metrics/MetricsHistoryUnitTest.kt)
## 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.