Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standardize CVR identification across audit logs and RCTab output #913

Draft
wants to merge 13 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main/java/network/brightspots/rcv/BaseCvrReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public void runAdditionalValidations(List<CastVoteRecord> castVoteRecords)
if (!isRankingAllowed(maxRanking, cvr.getContestId())) {
Logger.severe(
"CVR \"%s\" has a ranking %d, but contest \"%s\" has max ranking %s!",
// TODO: Do we want this to use the getSuppliedId or the getId method?
cvr.getId(), maxRanking, cvr.getContestId(), config.getMaxRankingsAllowedAsString());
throw new CastVoteRecord.CvrParseException();
}
Expand Down
13 changes: 7 additions & 6 deletions src/main/java/network/brightspots/rcv/CastVoteRecord.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,13 @@ boolean doesUseLastAllowedRanking() {
return usesLastAllowedRanking;
}

// This represents the canonical ID used for audit logs and RCTab CVR
String getId() {
return suppliedId != null ? suppliedId : computedId;
return !isNullOrBlank(computedId) ? computedId : suppliedId;
}

String getSuppliedId() {
return suppliedId != null ? suppliedId : "";
}

// logs the outcome for this CVR for this round for auditing purposes
Expand All @@ -138,11 +143,7 @@ void logRoundOutcome(

StringBuilder logStringBuilder = new StringBuilder();
logStringBuilder.append("[Round] ").append(round).append(" [CVR] ");
if (!isNullOrBlank(computedId)) {
logStringBuilder.append(computedId);
} else {
logStringBuilder.append(suppliedId);
}
logStringBuilder.append(getId());
if (outcomeType == VoteOutcomeType.IGNORED) {
logStringBuilder.append(" [was ignored] ");
} else if (outcomeType == VoteOutcomeType.EXHAUSTED) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ private int parseCvrFile(
String computedId =
Stream.of(tabulatorId, batchId, Integer.toString(recordId))
.filter(s -> s != null && !s.isBlank())
.collect(Collectors.joining("|"));
.collect(Collectors.joining("-")); // using a dash since this is an Id

// filter out records which are not current and replace them with adjudicated ones
HashMap adjudicatedData = (HashMap) session.get("Original");
Expand Down
12 changes: 8 additions & 4 deletions src/main/java/network/brightspots/rcv/OutputWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -696,14 +696,15 @@ String writeRcTabCvrCsv(
CSVFormat format = CSVFormat.DEFAULT.builder().setNullString("").build();
csvPrinter = new CSVPrinter(writer, format);
// print header:
// ContestId, TabulatorId, BatchId, RecordId, Precinct, Precinct Portion, rank 1 selection,
// rank 2 selection, ... rank maxRanks selection
// RCTab CVR Id, ContestId, TabulatorId, BatchId, RecordId, Precinct, Precinct Portion,
yezr marked this conversation as resolved.
Show resolved Hide resolved
// rank 1 selection, rank 2 selection, ... rank maxRanks selection
csvPrinter.print("Source Filepath");
csvPrinter.print("CVR Provider");
csvPrinter.print("Contest Id");
csvPrinter.print("RCTab CVR Id");
csvPrinter.print("Tabulator Id");
csvPrinter.print("Batch Id");
csvPrinter.print("Record Id");
csvPrinter.print("Vendor Id");
csvPrinter.print("Precinct");
csvPrinter.print("Precinct Portion");

Expand Down Expand Up @@ -740,9 +741,10 @@ String writeRcTabCvrCsv(
csvPrinter.print(currentSourceData.source.getFilePath());
csvPrinter.print(currentSourceData.source.getProvider());
csvPrinter.print(castVoteRecord.getContestId());
csvPrinter.print(castVoteRecord.getId());
csvPrinter.print(castVoteRecord.getTabulatorId());
csvPrinter.print(castVoteRecord.getSlice(TabulateBySlice.BATCH));
csvPrinter.print(castVoteRecord.getId());
csvPrinter.print(castVoteRecord.getSuppliedId());
csvPrinter.print(castVoteRecord.getSlice(ContestConfig.TabulateBySlice.PRECINCT));
csvPrinter.print(castVoteRecord.getPrecinctPortion());
printRankings(currentSourceData.source.getUndeclaredWriteInLabel(), maxRank,
Expand Down Expand Up @@ -875,6 +877,7 @@ private List<Map<String, Object>> generateCdfMapForCvrs(List<CastVoteRecord> cas
for (CastVoteRecord cvr : castVoteRecords) {
List<Map<String, Object>> cvrSnapshots = new LinkedList<>();
cvrSnapshots.add(generateCvrSnapshotMap(cvr, null, null));
// TODO: Do we want this to use the getSuppliedId or the getId method?
yezr marked this conversation as resolved.
Show resolved Hide resolved
String sanitizedId = sanitizeStringForOutput(cvr.getId());
// copy most recent round snapshot data to subsequent rounds
// until more snapshot data is available
Expand Down Expand Up @@ -981,6 +984,7 @@ private Map<String, Object> generateCvrSnapshotMap(
entry("@type", "CVR.CVRContest"));

return Map.ofEntries(
// TODO: Do we want this to use the getSuppliedId or the getId method?
entry("@id", generateCvrSnapshotId(sanitizeStringForOutput(cvr.getId()), round)),
yezr marked this conversation as resolved.
Show resolved Hide resolved
entry("CVRContest", new Map[] {contestMap}),
entry("Type", round != null ? "interpreted" : "original"),
Expand Down
Loading
Loading