Files
werkcrappit/docs/adr/0003-result-aggregation.md
miandmhoennig 6453ecc24b
werkator build succeeded after 00:35
Step 4 of 8: complete aggregation of PIT results (#5)
Step 4 of 8 from section 8.3 of the specification.

- `MutantAggregator` (core): statuses per distinct mutant (MethodId + mutator + instruction indexes); duplicates count once, contradicting final results count under none and make the method INCONCLUSIVE (`contradicting-results:<n>`), preliminary NOT_STARTED/STARTED give way to the final status, block order no longer matters.
- Listener test with real PIT result objects and a real `ReportOptions`: merged blocks, byte-identical report for every order, duplicates, contradictions.
- Functional test: every mutant of PIT's `mutations.xml` is counted exactly once; PIT's analysis ran once.
- ADR 0003, feature 04, MC-014 to MC-018 mapped.

CI on werkator.javagil.de: green (33 s), 79 unit and 10 functional tests.

PR-doc: `docs/prs/2026-10-01-PR#5-result-aggregation.md`

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: mhoennig <michael@hoennig.de>
Reviewed-on: #5
2026-10-01 15:59:41 +02:00

30 lines
1.8 KiB
Markdown

# ADR 0003: Result Aggregation
- Status: accepted
- Date: 2026-10-01
- PR: #5
## Context
PIT delivers results in `ClassMutationResults` blocks; one class may arrive in several of them.
PIT holds some results back and delivers them later, for example to consolidate inlined code.
The specification (4.5) forbids double counting, "last write wins" and confusing preliminary states with extra mutants.
## Decision
- **Threading.** PIT 1.30.0 calls every listener from one thread, in `MutationAnalysisExecutor.processResult`, then `runEnd()`.
The listener's methods stay synchronized anyway; its state lives in the listener instance, one per run, with no static caches.
- **Identity.** A mutant is identified by its `MethodId` plus PIT's mutator id and instruction indexes from `MutationIdentifier`.
The listener keeps only identities and status names, never PIT's result objects.
- **Aggregation.** `MutantAggregator` collects the set of statuses per mutant and decides at `runEnd()`:
- one final status, however often delivered → counted once under it;
- several different final statuses → counted under none and reported as contradicted; the method becomes `INCONCLUSIVE` with `contradicting-results:<n>`;
- `NOT_STARTED` or `STARTED` beside a final status → preliminary, gives way to the final one;
- only preliminary statuses → counted under the latest of them, which makes the method `INCONCLUSIVE` under `strict-v1`.
- **Order.** Statuses are kept as sets and results sorted by identity, so the report depends only on what arrived.
## Consequences
- The sum of all status counts in the report equals the number of mutants in PIT's `mutations.xml`, minus contradicted mutants; the functional test checks it.
- Which statuses count as preliminary is the policy's knowledge (`StatusTreatment.INCOMPLETE`), not the aggregator's.