DeltaEntry.java
package org.egothor.methodatlas;
import java.util.Set;
import org.egothor.methodatlas.api.ScanRecord;
/**
* A single change entry in a MethodAtlas delta report.
*
* <p>
* Each entry describes one test method that was added, removed, or modified
* between two scan outputs. Entries are produced by {@link DeltaReport#compute}
* and consumed by {@link org.egothor.methodatlas.emit.DeltaEmitter} to produce human-readable output.
* </p>
*
* <h2>Change types</h2>
*
* <ul>
* <li>{@link ChangeType#ADDED} — method is present in the <em>after</em> scan
* but absent from the <em>before</em> scan. {@link #before()} is
* {@code null}.</li>
* <li>{@link ChangeType#REMOVED} — method is present in the <em>before</em>
* scan but absent from the <em>after</em> scan. {@link #after()} is
* {@code null}.</li>
* <li>{@link ChangeType#MODIFIED} — method is present in both scans but one
* or more comparable fields differ. Both {@link #before()} and
* {@link #after()} are non-{@code null}. The {@link #changedFields()} set
* names each field that differs.</li>
* </ul>
*
* <h2>Changed field names</h2>
*
* <p>
* The {@link #changedFields()} set uses the following identifiers, which
* correspond to CSV column names or human-readable labels:
* </p>
*
* <ul>
* <li>{@code "loc"} — lines of code changed</li>
* <li>{@code "tags"} — JUnit {@code @Tag} set changed</li>
* <li>{@code "source"} — {@code content_hash} differs (class source was
* edited); only present when both records have a non-{@code null}
* {@code contentHash}</li>
* <li>{@code "ai_security_relevant"} — security-relevance classification
* flipped; only present when both records have a non-{@code null}
* {@code aiSecurityRelevant}</li>
* <li>{@code "ai_tags"} — AI taxonomy tag set changed; only present when
* both records have non-{@code null} {@code aiTags}</li>
* </ul>
*
* @param changeType the type of change
* @param before the record from the <em>before</em> scan; {@code null}
* for {@link ChangeType#ADDED} entries
* @param after the record from the <em>after</em> scan; {@code null}
* for {@link ChangeType#REMOVED} entries
* @param changedFields names of fields that differ between {@code before} and
* {@code after}; empty for {@link ChangeType#ADDED} and
* {@link ChangeType#REMOVED} entries
*
* @see DeltaReport
* @see org.egothor.methodatlas.emit.DeltaEmitter
*/
public record DeltaEntry(ChangeType changeType, ScanRecord before, ScanRecord after, Set<String> changedFields) {
/**
* The type of change represented by a {@link DeltaEntry}.
*/
public enum ChangeType {
/** Method is present in the <em>after</em> scan but not the <em>before</em> scan. */
ADDED,
/** Method is present in the <em>before</em> scan but not the <em>after</em> scan. */
REMOVED,
/** Method is present in both scans but at least one comparable field differs. */
MODIFIED
}
/**
* Creates an {@code ADDED} entry for a method discovered in the <em>after</em> scan.
*
* @param after the record from the <em>after</em> scan
* @return new ADDED entry
*/
/* default */ static DeltaEntry added(ScanRecord after) {
return new DeltaEntry(ChangeType.ADDED, null, after, Set.of());
}
/**
* Creates a {@code REMOVED} entry for a method absent from the <em>after</em> scan.
*
* @param before the record from the <em>before</em> scan
* @return new REMOVED entry
*/
/* default */ static DeltaEntry removed(ScanRecord before) {
return new DeltaEntry(ChangeType.REMOVED, before, null, Set.of());
}
/**
* Creates a {@code MODIFIED} entry for a method present in both scans but with
* differing field values.
*
* @param before the record from the <em>before</em> scan
* @param after the record from the <em>after</em> scan
* @param changedFields names of the fields that differ
* @return new MODIFIED entry
*/
/* default */ static DeltaEntry modified(ScanRecord before, ScanRecord after, Set<String> changedFields) {
return new DeltaEntry(ChangeType.MODIFIED, before, after, Set.copyOf(changedFields));
}
/**
* Returns the primary record for this entry.
*
* <p>
* For {@link ChangeType#ADDED} and {@link ChangeType#MODIFIED} entries this is
* the {@link #after()} record. For {@link ChangeType#REMOVED} entries this is
* the {@link #before()} record. Never returns {@code null}.
* </p>
*
* @return the representative record for this entry
*/
public ScanRecord record() {
return after != null ? after : before;
}
}