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

Mutations

141

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

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:configHash_changesWhenAiProviderChanges()]
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:configHash_changesWhenAiModelChanges()]
removed conditional - replaced equality check with false → KILLED

150

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

151

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

152

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

161

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

182

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

186

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

197

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

211

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

212

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

214

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

224

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

255

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

269

1.1
Location : orEmpty
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 true → KILLED

2.2
Location : orEmpty
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

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

273

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.30.1 support