Files
werkator/docs/prs/2026-10-09-PR#129-build-rows-and-repo-summary-split.md
miandclaude-code 01b55120d4
werkator build succeeded after 02:40
werkator/deploy build succeeded after 00:07
Build rows, repository summary and page model split into steps (v1.37.10) (#129)
> Historic PR-documentation is not maintained along with new PRs — treat it as a snapshot, not as current documentation.

## The Problem

The nightly mutation build has been red since the gate reached the target of 15 (PR#126).
Five methods are above 15; three of them belong to the build lists and are above 15 in every run:

| Method                   | Mutation-CRAP | Complexity | Killed / eligible |
|--------------------------|--------------:|-----------:|------------------:|
| `RepoSummaryView.from`   |         17.44 |         13 |           26 / 37 |
| `BuildRowView.from`      |         16.40 |         10 |            6 / 10 |
| `UiController.baseModel` |         15.69 |         10 |            8 / 13 |

PR#126 missed them: the method list came from the build log, which shows only the five highest scores.

- `RepoSummaryView.from` counted with the inline `count` three times, so three loops and their overflow checks were compiled into one method.
- `BuildRowView.from(BuildResult, …)` was a second copy of the row mapping, used by the artifact page only.
  Every other page builds its row from the API's `BuildResultDto` since PR#43, and only those were tested well.
- `UiController.baseModel` also assembled the forge name and the footer.

## Non-Goals

- The other two methods above 15, `RepositoryPrivacy.isPrivate` and `ConfigLoader.renameLegacySandbox`, follow in their own pull requests.
- No change of what any page shows.

## The Solution

- `RepoSummaryView.from` names each part through one `phrase` step: the count of matching repositories, or null when none matches.
- The artifact page builds its row like every other page, through `BuildResultDto.from` and `BuildRowView.from(BuildResultDto, …)`.
  The copy `BuildRowView.from(BuildResult, …)` is gone, so a field can no longer be mapped one way on the artifact page and another way in the lists.
- `UiController.baseModel` takes the forge name from `forgeName` and fills the footer with `addFooter`.
- The test of the summary line also checks that every part is left out when no repository matches.

Measured locally with PIT on the changed classes:

| Method                                 | Mutation-CRAP before |      after |
|----------------------------------------|---------------------:|-----------:|
| `RepoSummaryView.from`                 |                17.44 | no mutants |
| `RepoSummaryView.phrase`               |                  new |       2.00 |
| `BuildRowView.from(BuildResult, …)`    |                16.40 |       gone |
| `UiController.baseModel`               |                15.69 |       8.81 |
| `BuildRowView.from(BuildResultDto, …)` |               < 13.7 |      11.19 |
| highest of the three classes           |                17.44 |      13.08 |

The gate stays at 15.

## Follow-up PRs

- `RepositoryPrivacy.isPrivate` (16.40) gets tests for its surviving mutants.
- `ConfigLoader.renameLegacySandbox` (15.93) is split, and `ConfigLoader.checkRestartsInstance` (exactly 15.00) gets room below the target.
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: claude-code <claude-code@javagil.de>
Reviewed-on: #129
2026-10-09 12:49:44 +02:00

3.2 KiB

PR#129: Build Rows, Repository Summary and Page Model Split into Steps

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 mutation build has been red since the gate reached the target of 15 (PR#126). Five methods are above 15; three of them belong to the build lists and are above 15 in every run:

Method Mutation-CRAP Complexity Killed / eligible
RepoSummaryView.from 17.44 13 26 / 37
BuildRowView.from 16.40 10 6 / 10
UiController.baseModel 15.69 10 8 / 13

PR#126 missed them: the method list came from the build log, which shows only the five highest scores.

  • RepoSummaryView.from counted with the inline count three times, so three loops and their overflow checks were compiled into one method.
  • BuildRowView.from(BuildResult, …) was a second copy of the row mapping, used by the artifact page only. Every other page builds its row from the API's BuildResultDto since PR#43, and only those were tested well.
  • UiController.baseModel also assembled the forge name and the footer.

Non-Goals

  • The other two methods above 15, RepositoryPrivacy.isPrivate and ConfigLoader.renameLegacySandbox, follow in their own pull requests.
  • No change of what any page shows.

The Solution

  • RepoSummaryView.from names each part through one phrase step: the count of matching repositories, or null when none matches.
  • The artifact page builds its row like every other page, through BuildResultDto.from and BuildRowView.from(BuildResultDto, …). The copy BuildRowView.from(BuildResult, …) is gone, so a field can no longer be mapped one way on the artifact page and another way in the lists.
  • UiController.baseModel takes the forge name from forgeName and fills the footer with addFooter.
  • The test of the summary line also checks that every part is left out when no repository matches.

Measured locally with PIT on the changed classes:

Method Mutation-CRAP before after
RepoSummaryView.from 17.44 no mutants
RepoSummaryView.phrase new 2.00
BuildRowView.from(BuildResult, …) 16.40 gone
UiController.baseModel 15.69 8.81
BuildRowView.from(BuildResultDto, …) < 13.7 11.19
highest of the three classes 17.44 13.08

The gate stays at 15.

Follow-up PRs

  • RepositoryPrivacy.isPrivate (16.40) gets tests for its surviving mutants.
  • ConfigLoader.renameLegacySandbox (15.93) is split, and ConfigLoader.checkRestartsInstance (exactly 15.00) gets room below the target.