# ADR 0001: PIT Integration - Status: accepted; the class lookup is refined by [ADR 0002](0002-method-inventory.md) - Date: 2026-10-01 - PR: #2 ## Context werkcrappit joins PIT's mutation results with the JaCoCo complexity of the same JVM method. The specification demands the results from PIT's listener interface, the complexity from the original class files, and no extra test or PIT run. Section 3.4 of the specification warns that `ListenerArguments.getLocator()` yields source readers, not bytecode. So the first step had to prove where a result listener gets the original class bytes from. ## Decision werkcrappit is a PIT result listener plugin: one JAR on PIT's tool classpath, loaded through the Gradle PIT plugin's `pitest` configuration. - **Registration:** `MutationCrapListenerFactory` is listed in `META-INF/services/org.pitest.mutationtest.MutationResultListenerFactory` and registers the output format `WERKCRAPPIT_MUTATION_CRAP`. The specification starts with `MUTATION_CRAP` (section 2.3). The name is changed so that an `outputFormats` line shows which plugin provides the format, and so that no other plugin on PIT's tool classpath can claim it by chance. The metric id `mutation-crap` and the report file `mutation-crap.json` stay as specified. - **Mutation results:** the listener collects every `ClassMutationResults` block and evaluates nothing before `runEnd()`, since a class may arrive in several blocks. - **Method identity:** `MutationDetails.getId().getLocation()` carries class, JVM method name and full descriptor. The class name is normalized to the dotted binary name in `MethodId`; JaCoCo's slashed name is converted in the JaCoCo adapter. - **Original bytecode:** `ListenerArguments.data()` returns PIT's `ReportOptions`, a public type. `getMutationClassPaths().code()` names the classes PIT selected for mutation; `getClassPathElements()` gives the classpath in PIT's order. werkcrappit reads each class file from the first element that holds it, records that element as origin, and hashes the bytes with SHA-256. This is option 2 of section 3.4: data PIT was started with, no private fields, no reflection, no class loading. A dedicated Gradle hand-over (option 3) is not needed. - **Why the bytes are original:** PIT mutates in memory inside its minion processes; the class files on disk stay as the build compiled them. - **Complexity:** JaCoCo Core's `Analyzer` with an empty `ExecutionDataStore` and a `CoverageBuilder`; per method the total of `getComplexityCounter()`. - **Report:** written through `ListenerArguments.getOutputStrategy()`, so it lands in PIT's report directory next to the HTML and XML reports. - **Dependencies:** `pitest-entry` is `compileOnly`, since PIT provides it at run time. `org.jacoco.core` is a regular dependency and reaches PIT's tool classpath through the published metadata. PIT 1.30.0 and JaCoCo 0.8.15 both use ASM 9.10.1, so no shading is needed. ## Verification `PitWalkingSkeletonTest` (source set `functionalTest`) publishes the JAR into a repository under `build/`, then runs `pitest` with Gradle TestKit on the fixture `fixtures/java-basic`. The fixture consumes the published artifact, not the classes of this build. The test proves the five points of section 3.3: 1. PIT finds the factory and the report exists. 2. The results arrive with class, method and descriptor and are joined with complexity 3 for `classify(I)Ljava/lang/String;`. 3. The analysed bytes have the SHA-256 of `build/classes/java/main/demo/Classifier.class`. 4. No result stays unmatched, no class is missing. 5. `mutations.xml` and `index.html` exist; the `test` task did not run; no `.exec` file exists. The tested versions are in [docs/compatibility.md](../compatibility.md). ## Risks - PIT does not promise its extension interfaces across versions; `ReportOptions` is public but not documented as plugin API. An upgrade of PIT needs the functional test to pass before it is pinned. - `getClassPathElements()` includes dependency JARs. A selected class that also exists in an earlier JAR would be read from that JAR; the recorded origin makes that visible. Step 3 decides whether to restrict the lookup to PIT's code paths. - Duplicate and contradicting results are not handled yet (step 4). - The report has `schemaVersion` 0 and no score; step 2 adds the metric, step 5 the versioned contract.