# 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:`; - `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.