ReceiptBuilder.java

1
// SPDX-License-Identifier: Apache-2.0
2
// Copyright 2026 Egothor
3
// Copyright 2026 Accenture
4
package org.egothor.methodatlas.receipt;
5
6
import java.io.IOException;
7
import java.nio.charset.StandardCharsets;
8
import java.nio.file.Path;
9
import java.security.MessageDigest;
10
import java.security.NoSuchAlgorithmException;
11
import java.time.Instant;
12
import java.util.HexFormat;
13
import java.util.List;
14
import java.util.Map;
15
import java.util.TreeMap;
16
17
import org.egothor.methodatlas.CliConfig;
18
import org.egothor.methodatlas.ai.AiOptions;
19
import org.egothor.methodatlas.ai.PromptTemplateKind;
20
import org.egothor.methodatlas.ai.PromptTemplateSet;
21
import org.egothor.methodatlas.command.ContentHasher;
22
23
/**
24
 * Assembles a {@link ReproducibilityReceipt} from a parsed
25
 * {@link CliConfig} and the resolved tool version.
26
 *
27
 * <p>
28
 * Package-private because nothing outside the {@code receipt} package needs to
29
 * call this; {@code MethodAtlasApp} is the sole external caller, accessing it
30
 * through {@link #build(CliConfig, String, String)}.
31
 * </p>
32
 */
33
final class ReceiptBuilder {
34
35
    /**
36
     * Schema version of the JSON payload; bumped on any breaking change.
37
     *
38
     * <p>
39
     * v2 (4.1.0) replaced the single {@code inputs.promptTemplateHash} of v1 with
40
     * three per-template hashes ({@code classificationPromptHash},
41
     * {@code triageAppendixPromptHash}, {@code dedicatedTriagePromptHash}) and folds
42
     * all three into {@code configHash}. See {@code docs/usage-modes/reproducibility-receipts.md}.
43
     * </p>
44
     */
45
    private static final String SCHEMA_VERSION = "2";
46
47
    /** Algorithm string passed to {@link MessageDigest#getInstance(String)}. */
48
    private static final String SHA256_ALGO = "SHA-256";
49
50
    /** Sentinel for "no value" in the canonical key=value serialisation. */
51
    @SuppressWarnings("InlineTrivialConstant")
52
    private static final String EMPTY = "";
53
54
    // Canonical key=value separator characters: kept as constants so the
55
    // algorithm is unambiguous to an auditor re-deriving the hash from
56
    // standard tooling (e.g. sha256sum + printf).
57
58
    /** Separator between key and value in the canonical serialisation. */
59
    private static final String CONFIG_HASH_KV_SEP = "=";
60
61
    /** Separator between key=value pairs in the canonical serialisation. */
62
    private static final String CONFIG_HASH_SEPARATOR = "\n";
63
64
    // TreeMap keys: alphabetical insertion is enforced by TreeMap, not by the
65
    // declaration order here.
66
67
    /** TreeMap key for the AI cache file fingerprint. */
68
    private static final String KEY_AI_CACHE_FILE_SHA = "aiCacheFileSha256";
69
    /** TreeMap key for the configured AI model name. */
70
    private static final String KEY_AI_MODEL = "aiModel";
71
    /** TreeMap key for the configured AI provider. */
72
    private static final String KEY_AI_PROVIDER = "aiProvider";
73
    /** TreeMap key for the built-in taxonomy mode name. */
74
    private static final String KEY_BUILT_IN_TAXONOMY = "builtInTaxonomy";
75
    /** TreeMap key for the MethodAtlas tool version. */
76
    private static final String KEY_METHOD_ATLAS_VERSION = "methodAtlasVersion";
77
    /** TreeMap key for the override file fingerprint. */
78
    private static final String KEY_OVERRIDE_FILE_SHA = "overrideFileSha256";
79
    /** TreeMap key for the effective method-classification prompt template hash. */
80
    private static final String KEY_CLASSIFICATION_PROMPT = "classificationPromptHash";
81
    /** TreeMap key for the effective folded credential-triage appendix template hash. */
82
    private static final String KEY_TRIAGE_APPENDIX_PROMPT = "triageAppendixPromptHash";
83
    /** TreeMap key for the effective standalone credential-triage template hash. */
84
    private static final String KEY_DEDICATED_TRIAGE_PROMPT = "dedicatedTriagePromptHash";
85
    /** TreeMap key for the taxonomy file fingerprint. */
86
    private static final String KEY_TAXONOMY_FILE_SHA = "taxonomyFileSha256";
87
88
    /**
89
     * Rough capacity estimate for the canonical key=value buffer: ten keys
90
     * with combined length ≈ 200 characters plus up to ten 64-char SHA-256
91
     * values plus separators leaves the StringBuilder near its final size
92
     * without reallocations.
93
     */
94
    private static final int CANONICAL_BUFFER_CAPACITY = 1024;
95
96
    private ReceiptBuilder() {
97
        // Utility class.
98
    }
99
100
    /**
101
     * Builds a reproducibility receipt for the supplied configuration.
102
     *
103
     * <p>
104
     * The {@code configHash} field is computed as follows:
105
     * </p>
106
     * <ol>
107
     *   <li>A {@link TreeMap} is populated with the ten canonical keys
108
     *       documented at class scope. Absent inputs map to the empty
109
     *       string.</li>
110
     *   <li>The map is serialised as {@code key1=value1\n…keyN=valueN\n}
111
     *       using {@link StandardCharsets#UTF_8}; {@link TreeMap} guarantees
112
     *       alphabetical key order.</li>
113
     *   <li>SHA-256 is applied to those bytes and the result is emitted as
114
     *       lowercase hex via {@link HexFormat#of()}.</li>
115
     * </ol>
116
     *
117
     * @param config         parsed CLI configuration; must not be {@code null}
118
     * @param toolVersion    resolved tool version string (use {@code "dev"} when
119
     *                       no implementation version is available)
120
     * @param outputModeName textual name of the chosen output mode (e.g.
121
     *                       {@code "SARIF"}); included in the receipt's
122
     *                       {@code outputMode} field
123
     * @return a populated receipt with a stable {@code configHash} that an
124
     *         auditor can recompute from the other fields
125
     * @throws IOException if any input file referenced by {@code config}
126
     *                     (override file, taxonomy file, AI cache) cannot be
127
     *                     read for hashing
128
     */
129
    /* default */ static ReproducibilityReceipt build(CliConfig config, String toolVersion,
130
            String outputModeName) throws IOException {
131
        AiOptions ai = config.aiOptions();
132
        FileArtifact overrideArtifact = hashIfPresent(config.overrideFile());
133
        FileArtifact aiCacheArtifact = hashIfPresent(config.aiCacheFile());
134
135
        FileArtifact taxonomyArtifact = null;
136
        String builtInTaxonomy = null;
137 2 1. build : removed conditional - replaced equality check with true → KILLED
2. build : removed conditional - replaced equality check with false → KILLED
        if (ai.taxonomyFile() != null) {
138
            taxonomyArtifact = hashIfPresent(ai.taxonomyFile());
139
        } else {
140
            builtInTaxonomy = ai.taxonomyMode().name();
141
        }
142
143 2 1. build : removed conditional - replaced equality check with false → SURVIVED
2. build : removed conditional - replaced equality check with true → KILLED
        String aiProvider = ai.enabled() ? ai.provider().name() : null;
144 2 1. build : removed conditional - replaced equality check with false → SURVIVED
2. build : removed conditional - replaced equality check with true → KILLED
        String aiModel = ai.enabled() ? ai.modelName() : null;
145
        PromptTemplateSet templates = ai.promptTemplates();
146 2 1. build : removed conditional - replaced equality check with true → KILLED
2. build : removed conditional - replaced equality check with false → KILLED
        String classificationPromptHash = ai.enabled() ? templates.hash(PromptTemplateKind.CLASSIFICATION) : null;
147 2 1. build : removed conditional - replaced equality check with true → KILLED
2. build : removed conditional - replaced equality check with false → KILLED
        String triageAppendixPromptHash = ai.enabled() ? templates.hash(PromptTemplateKind.TRIAGE_APPENDIX) : null;
148 2 1. build : removed conditional - replaced equality check with true → KILLED
2. build : removed conditional - replaced equality check with false → KILLED
        String dedicatedTriagePromptHash = ai.enabled() ? templates.hash(PromptTemplateKind.DEDICATED_TRIAGE) : null;
149
150
        ReceiptInputs inputs = new ReceiptInputs(taxonomyArtifact, builtInTaxonomy,
151
                overrideArtifact, aiCacheArtifact, aiProvider, aiModel,
152
                classificationPromptHash, triageAppendixPromptHash, dedicatedTriagePromptHash);
153
154
        String configHash = computeConfigHash(toolVersion, ai, overrideArtifact, aiCacheArtifact,
155
                taxonomyArtifact, builtInTaxonomy,
156
                classificationPromptHash, triageAppendixPromptHash, dedicatedTriagePromptHash);
157
158 1 1. build : replaced return value with null for org/egothor/methodatlas/receipt/ReceiptBuilder::build → KILLED
        return new ReproducibilityReceipt(
159
                SCHEMA_VERSION,
160
                Instant.now().toString(),
161
                toolVersion,
162
                javaVersion(),
163
                outputModeName,
164
                resolveScanRoots(config),
165
                computeDeterministicReplay(config),
166
                inputs,
167
                configHash);
168
    }
169
170
    /**
171
     * Returns a {@link FileArtifact} for {@code file} or {@code null} when
172
     * {@code file} is itself {@code null}.
173
     *
174
     * @param file path to fingerprint; may be {@code null}
175
     * @return populated artefact or {@code null}
176
     * @throws IOException if the file cannot be read
177
     */
178
    private static FileArtifact hashIfPresent(Path file) throws IOException {
179 2 1. hashIfPresent : removed conditional - replaced equality check with true → KILLED
2. hashIfPresent : removed conditional - replaced equality check with false → KILLED
        if (file == null) {
180
            return null;
181
        }
182
        String sha = ContentHasher.hashFile(file);
183 1 1. hashIfPresent : replaced return value with null for org/egothor/methodatlas/receipt/ReceiptBuilder::hashIfPresent → KILLED
        return new FileArtifact(file.toAbsolutePath().toString(), sha);
184
    }
185
186
    /**
187
     * Resolves the JVM's reported Java version to a non-null string.
188
     *
189
     * @return Java version, or the literal {@code "unknown"} when the
190
     *         {@code java.version} property is unset
191
     */
192
    private static String javaVersion() {
193
        String v = System.getProperty("java.version");
194 3 1. javaVersion : removed conditional - replaced equality check with true → SURVIVED
2. javaVersion : removed conditional - replaced equality check with false → SURVIVED
3. javaVersion : replaced return value with "" for org/egothor/methodatlas/receipt/ReceiptBuilder::javaVersion → SURVIVED
        return v == null ? "unknown" : v;
195
    }
196
197
    /**
198
     * Maps scan roots to absolute path strings. An empty input list means
199
     * "scan the current directory"; the absolute resolution captures the
200
     * actual directory that was scanned.
201
     *
202
     * @param config parsed CLI configuration
203
     * @return absolute path strings for every scan root, in the order
204
     *         supplied on the command line
205
     */
206
    private static List<String> resolveScanRoots(CliConfig config) {
207
        List<Path> roots = config.paths();
208 2 1. resolveScanRoots : removed conditional - replaced equality check with true → SURVIVED
2. resolveScanRoots : removed conditional - replaced equality check with false → SURVIVED
        if (roots.isEmpty()) {
209 1 1. resolveScanRoots : replaced return value with Collections.emptyList for org/egothor/methodatlas/receipt/ReceiptBuilder::resolveScanRoots → SURVIVED
            return List.of(Path.of("").toAbsolutePath().toString());
210
        }
211 2 1. resolveScanRoots : replaced return value with Collections.emptyList for org/egothor/methodatlas/receipt/ReceiptBuilder::resolveScanRoots → SURVIVED
2. lambda$resolveScanRoots$0 : replaced return value with "" for org/egothor/methodatlas/receipt/ReceiptBuilder::lambda$resolveScanRoots$0 → SURVIVED
        return roots.stream().map(p -> p.toAbsolutePath().toString()).toList();
212
    }
213
214
    /**
215
     * Computes the {@code deterministicReplay} flag.
216
     *
217
     * @param config parsed CLI configuration
218
     * @return {@code true} when AI is disabled or an AI cache is configured
219
     */
220
    private static boolean computeDeterministicReplay(CliConfig config) {
221 5 1. computeDeterministicReplay : removed conditional - replaced equality check with true → KILLED
2. computeDeterministicReplay : removed conditional - replaced equality check with false → KILLED
3. computeDeterministicReplay : removed conditional - replaced equality check with true → KILLED
4. computeDeterministicReplay : removed conditional - replaced equality check with false → KILLED
5. computeDeterministicReplay : replaced boolean return with true for org/egothor/methodatlas/receipt/ReceiptBuilder::computeDeterministicReplay → KILLED
        return !config.aiOptions().enabled() || config.aiCacheFile() != null;
222
    }
223
224
    /**
225
     * Produces the SHA-256 hex of the canonical {@code key=value} buffer.
226
     *
227
     * @param toolVersion        MethodAtlas tool version string
228
     * @param ai                 parsed AI options
229
     * @param overrideArtifact   override file artefact, or {@code null}
230
     * @param aiCacheArtifact    AI cache file artefact, or {@code null}
231
     * @param taxonomyArtifact   taxonomy file artefact, or {@code null}
232
     * @param builtInTaxonomy    built-in taxonomy mode name, or {@code null}
233
     * @param classificationPromptHash effective classification template hash, or {@code null}
234
     * @param triageAppendixPromptHash effective folded triage-appendix template hash, or {@code null}
235
     * @param dedicatedTriagePromptHash effective standalone triage template hash, or {@code null}
236
     * @return 64-character lowercase hex SHA-256
237
     */
238
    private static String computeConfigHash(String toolVersion, AiOptions ai,
239
            FileArtifact overrideArtifact, FileArtifact aiCacheArtifact,
240
            FileArtifact taxonomyArtifact, String builtInTaxonomy,
241
            String classificationPromptHash, String triageAppendixPromptHash,
242
            String dedicatedTriagePromptHash) {
243
        Map<String, String> keys = new TreeMap<>();
244
        keys.put(KEY_AI_CACHE_FILE_SHA, shaOrEmpty(aiCacheArtifact));
245 4 1. computeConfigHash : removed conditional - replaced equality check with true → SURVIVED
2. computeConfigHash : removed conditional - replaced equality check with false → KILLED
3. computeConfigHash : removed conditional - replaced equality check with true → KILLED
4. computeConfigHash : removed conditional - replaced equality check with false → KILLED
        keys.put(KEY_AI_MODEL, ai.enabled() && ai.modelName() != null ? ai.modelName() : EMPTY);
246 2 1. computeConfigHash : removed conditional - replaced equality check with true → KILLED
2. computeConfigHash : removed conditional - replaced equality check with false → KILLED
        keys.put(KEY_AI_PROVIDER, ai.enabled() ? ai.provider().name() : EMPTY);
247 2 1. computeConfigHash : removed conditional - replaced equality check with false → SURVIVED
2. computeConfigHash : removed conditional - replaced equality check with true → KILLED
        keys.put(KEY_BUILT_IN_TAXONOMY, builtInTaxonomy == null ? EMPTY : builtInTaxonomy);
248 2 1. computeConfigHash : removed conditional - replaced equality check with true → SURVIVED
2. computeConfigHash : removed conditional - replaced equality check with false → KILLED
        keys.put(KEY_CLASSIFICATION_PROMPT, classificationPromptHash == null ? EMPTY : classificationPromptHash);
249 2 1. computeConfigHash : removed conditional - replaced equality check with true → SURVIVED
2. computeConfigHash : removed conditional - replaced equality check with false → KILLED
        keys.put(KEY_DEDICATED_TRIAGE_PROMPT, dedicatedTriagePromptHash == null ? EMPTY : dedicatedTriagePromptHash);
250
        keys.put(KEY_METHOD_ATLAS_VERSION, toolVersion);
251
        keys.put(KEY_OVERRIDE_FILE_SHA, shaOrEmpty(overrideArtifact));
252
        keys.put(KEY_TAXONOMY_FILE_SHA, shaOrEmpty(taxonomyArtifact));
253 2 1. computeConfigHash : removed conditional - replaced equality check with true → SURVIVED
2. computeConfigHash : removed conditional - replaced equality check with false → KILLED
        keys.put(KEY_TRIAGE_APPENDIX_PROMPT, triageAppendixPromptHash == null ? EMPTY : triageAppendixPromptHash);
254
255
        StringBuilder canonical = new StringBuilder(CANONICAL_BUFFER_CAPACITY);
256 1 1. computeConfigHash : removed call to java/util/Map::forEach → KILLED
        keys.forEach((k, v) -> canonical.append(k).append(CONFIG_HASH_KV_SEP)
257
                .append(v).append(CONFIG_HASH_SEPARATOR));
258
259
        try {
260
            MessageDigest digest = MessageDigest.getInstance(SHA256_ALGO);
261
            byte[] bytes = digest.digest(canonical.toString().getBytes(StandardCharsets.UTF_8));
262 1 1. computeConfigHash : replaced return value with "" for org/egothor/methodatlas/receipt/ReceiptBuilder::computeConfigHash → KILLED
            return HexFormat.of().formatHex(bytes);
263
        } catch (NoSuchAlgorithmException e) {
264
            throw new IllegalStateException("SHA-256 not available", e);
265
        }
266
    }
267
268
    /**
269
     * Extracts the SHA-256 string from a {@link FileArtifact}, or returns the
270
     * empty-string sentinel when the artefact is absent.
271
     *
272
     * @param artifact artefact to inspect; may be {@code null}
273
     * @return SHA-256 hex or {@code ""}
274
     */
275
    private static String shaOrEmpty(FileArtifact artifact) {
276 3 1. shaOrEmpty : removed conditional - replaced equality check with false → KILLED
2. shaOrEmpty : replaced return value with "" for org/egothor/methodatlas/receipt/ReceiptBuilder::shaOrEmpty → KILLED
3. shaOrEmpty : removed conditional - replaced equality check with true → KILLED
        return artifact == null ? EMPTY : artifact.sha256();
277
    }
278
}

Mutations

137

1.1
Location : build
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:inputs_omitsTaxonomyFileWhenUsingBuiltIn()]
removed conditional - replaced equality check with true → KILLED

2.2
Location : build
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:configHash_changesWhenTaxonomyFileContentChanges(java.nio.file.Path)]
removed conditional - replaced equality check with false → KILLED

143

1.1
Location : build
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:inputs_omitsAiFieldsWhenAiDisabled()]
removed conditional - replaced equality check with true → KILLED

2.2
Location : build
Killed by : none
removed conditional - replaced equality check with false → SURVIVED
Covering tests

144

1.1
Location : build
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:inputs_omitsAiFieldsWhenAiDisabled()]
removed conditional - replaced equality check with true → KILLED

2.2
Location : build
Killed by : none
removed conditional - replaced equality check with false → SURVIVED
Covering tests

146

1.1
Location : build
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:inputs_omitsAiFieldsWhenAiDisabled()]
removed conditional - replaced equality check with true → KILLED

2.2
Location : build
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:inputs_recordPromptHashesWhenAiEnabled()]
removed conditional - replaced equality check with false → KILLED

147

1.1
Location : build
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:inputs_omitsAiFieldsWhenAiDisabled()]
removed conditional - replaced equality check with true → KILLED

2.2
Location : build
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:inputs_recordPromptHashesWhenAiEnabled()]
removed conditional - replaced equality check with false → KILLED

148

1.1
Location : build
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:inputs_omitsAiFieldsWhenAiDisabled()]
removed conditional - replaced equality check with true → KILLED

2.2
Location : build
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:inputs_recordPromptHashesWhenAiEnabled()]
removed conditional - replaced equality check with false → KILLED

158

1.1
Location : build
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:inputs_omitsTaxonomyFileWhenUsingBuiltIn()]
replaced return value with null for org/egothor/methodatlas/receipt/ReceiptBuilder::build → KILLED

179

1.1
Location : hashIfPresent
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:inputs_overrideFile_pathIsAbsolute(java.nio.file.Path)]
removed conditional - replaced equality check with true → KILLED

2.2
Location : hashIfPresent
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:inputs_omitsTaxonomyFileWhenUsingBuiltIn()]
removed conditional - replaced equality check with false → KILLED

183

1.1
Location : hashIfPresent
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:inputs_overrideFile_pathIsAbsolute(java.nio.file.Path)]
replaced return value with null for org/egothor/methodatlas/receipt/ReceiptBuilder::hashIfPresent → KILLED

194

1.1
Location : javaVersion
Killed by : none
removed conditional - replaced equality check with true → SURVIVED
Covering tests

2.2
Location : javaVersion
Killed by : none
removed conditional - replaced equality check with false → SURVIVED Covering tests

3.3
Location : javaVersion
Killed by : none
replaced return value with "" for org/egothor/methodatlas/receipt/ReceiptBuilder::javaVersion → SURVIVED Covering tests

208

1.1
Location : resolveScanRoots
Killed by : none
removed conditional - replaced equality check with true → SURVIVED
Covering tests

2.2
Location : resolveScanRoots
Killed by : none
removed conditional - replaced equality check with false → SURVIVED Covering tests

209

1.1
Location : resolveScanRoots
Killed by : none
replaced return value with Collections.emptyList for org/egothor/methodatlas/receipt/ReceiptBuilder::resolveScanRoots → SURVIVED
Covering tests

211

1.1
Location : resolveScanRoots
Killed by : none
replaced return value with Collections.emptyList for org/egothor/methodatlas/receipt/ReceiptBuilder::resolveScanRoots → SURVIVED
Covering tests

2.2
Location : lambda$resolveScanRoots$0
Killed by : none
replaced return value with "" for org/egothor/methodatlas/receipt/ReceiptBuilder::lambda$resolveScanRoots$0 → SURVIVED Covering tests

221

1.1
Location : computeDeterministicReplay
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:deterministicReplay_trueWhenAiDisabled()]
removed conditional - replaced equality check with true → KILLED

2.2
Location : computeDeterministicReplay
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:deterministicReplay_falseWhenAiEnabledWithoutCache()]
removed conditional - replaced equality check with false → KILLED

3.3
Location : computeDeterministicReplay
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:deterministicReplay_falseWhenAiEnabledWithoutCache()]
removed conditional - replaced equality check with true → KILLED

4.4
Location : computeDeterministicReplay
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:deterministicReplay_trueWhenAiCachePresent(java.nio.file.Path)]
removed conditional - replaced equality check with false → KILLED

5.5
Location : computeDeterministicReplay
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:deterministicReplay_falseWhenAiEnabledWithoutCache()]
replaced boolean return with true for org/egothor/methodatlas/receipt/ReceiptBuilder::computeDeterministicReplay → KILLED

245

1.1
Location : computeConfigHash
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:configHash_changesWhenAiModelChanges()]
removed conditional - replaced equality check with false → KILLED

2.2
Location : computeConfigHash
Killed by : org.egothor.methodatlas.MethodAtlasAppReceiptTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppReceiptTest]/[method:configHash_matchesCanonicalReDerivation(java.nio.file.Path)]
removed conditional - replaced equality check with true → KILLED

3.3
Location : computeConfigHash
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:configHash_changesWhenAiModelChanges()]
removed conditional - replaced equality check with false → KILLED

4.4
Location : computeConfigHash
Killed by : none
removed conditional - replaced equality check with true → SURVIVED
Covering tests

246

1.1
Location : computeConfigHash
Killed by : org.egothor.methodatlas.MethodAtlasAppReceiptTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppReceiptTest]/[method:configHash_matchesCanonicalReDerivation(java.nio.file.Path)]
removed conditional - replaced equality check with true → KILLED

2.2
Location : computeConfigHash
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:configHash_changesWhenAiProviderChanges()]
removed conditional - replaced equality check with false → KILLED

247

1.1
Location : computeConfigHash
Killed by : none
removed conditional - replaced equality check with false → SURVIVED
Covering tests

2.2
Location : computeConfigHash
Killed by : org.egothor.methodatlas.MethodAtlasAppReceiptTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppReceiptTest]/[method:configHash_matchesCanonicalReDerivation(java.nio.file.Path)]
removed conditional - replaced equality check with true → KILLED

248

1.1
Location : computeConfigHash
Killed by : org.egothor.methodatlas.MethodAtlasAppReceiptTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppReceiptTest]/[method:configHash_matchesCanonicalReDerivation(java.nio.file.Path)]
removed conditional - replaced equality check with false → KILLED

2.2
Location : computeConfigHash
Killed by : none
removed conditional - replaced equality check with true → SURVIVED
Covering tests

249

1.1
Location : computeConfigHash
Killed by : org.egothor.methodatlas.MethodAtlasAppReceiptTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppReceiptTest]/[method:configHash_matchesCanonicalReDerivation(java.nio.file.Path)]
removed conditional - replaced equality check with false → KILLED

2.2
Location : computeConfigHash
Killed by : none
removed conditional - replaced equality check with true → SURVIVED
Covering tests

253

1.1
Location : computeConfigHash
Killed by : none
removed conditional - replaced equality check with true → SURVIVED
Covering tests

2.2
Location : computeConfigHash
Killed by : org.egothor.methodatlas.MethodAtlasAppReceiptTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.MethodAtlasAppReceiptTest]/[method:configHash_matchesCanonicalReDerivation(java.nio.file.Path)]
removed conditional - replaced equality check with false → KILLED

256

1.1
Location : computeConfigHash
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:configHash_changesWhenToolVersionChanges()]
removed call to java/util/Map::forEach → KILLED

262

1.1
Location : computeConfigHash
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:configHash_changesWhenToolVersionChanges()]
replaced return value with "" for org/egothor/methodatlas/receipt/ReceiptBuilder::computeConfigHash → KILLED

276

1.1
Location : shaOrEmpty
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:inputs_omitsTaxonomyFileWhenUsingBuiltIn()]
removed conditional - replaced equality check with false → KILLED

2.2
Location : shaOrEmpty
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:configHash_changesWhenOverrideFileContentChanges(java.nio.file.Path)]
replaced return value with "" for org/egothor/methodatlas/receipt/ReceiptBuilder::shaOrEmpty → KILLED

3.3
Location : shaOrEmpty
Killed by : org.egothor.methodatlas.receipt.ReceiptBuilderTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.receipt.ReceiptBuilderTest]/[method:configHash_changesWhenOverrideFileContentChanges(java.nio.file.Path)]
removed conditional - replaced equality check with true → KILLED

Active mutators

Tests examined


Report generated by PIT 1.22.1