Conversation
`addWriteInToElectionWriteInSummary` called `store.getCastVoteRecords({ cvrId })`
for every non-invalid write-in to learn one contest's vote count. Each call
rebuilt the filter SQL (re-reading and zod-parsing system settings),
re-prepared two statements, and parsed both JSON blobs.
`getWriteInsForTallies` now always selects `votes`/`adjudicated_votes` (the
combined-primary branch already did) and carries the CVR's effective votes
on `WriteInForTally`. The now-unused `cvrId` lookup on `getCastVoteRecords`
is removed.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
| }): Tabulation.ElectionWriteInSummary { | ||
| const { | ||
| contestId, | ||
| cvrId, |
There was a problem hiding this comment.
We avoid hitting the store here by having the votes already on the write-in object.
There was a problem hiding this comment.
It may seem like object sprawl to have the votes on the write-in objects, but I think we've learned through these various tabulation cases (overvotes for write-ins, crossover, combined ballot) that we need that votes context to make sense of the write-in. In the DB query we're already doing the join.
| electionId, | ||
| election, | ||
| filter, | ||
| cvrId, |
There was a problem hiding this comment.
Optional argument made unnecessary by removing only consumer.
| if (isCombinedBallotPrimary(election)) { | ||
| selectParts.push('cvrs.votes as votes'); | ||
| selectParts.push('cvrs.adjudicated_votes as adjudicatedVotes'); | ||
| } else { | ||
| selectParts.push('ballot_styles.party_id as partyId'); |
There was a problem hiding this comment.
Previously we'd only pull the votes here if it was a combined ballot primary, because we needed them to infer the party of the ballot (rather than, in the else branch, it just being evident from the ballot style). Since downstream we're fetching the votes anyway, it is cleaner to just always fetch the votes and always parse them here (see below).
Overview
Stacked on #9311.
addWriteInToElectionWriteInSummarycalledstore.getCastVoteRecords({ cvrId })for every valid write-in, just to learn one contest's vote count and
whether the ballot had a crossover vote. Each call rebuilt the filter SQL
(which re-read and zod-parsed system settings), re-prepared two statements,
and parsed both JSON blobs. Because the CVR tabulation pass is memoized but
the write-in pass is not, this N+1 was most of what a repeat tally-report
request actually paid for.
getWriteInsForTalliesnow always selectsvotes/adjudicated_votes(thecombined-primary branch already did) and carries the CVR's effective votes on
WriteInForTally, so the summary builder needs no store access. Thenow-unused
cvrIdpoint-lookup parameter ongetCastVoteRecordsis removed.Output is identical.
Related to the scale testing in #9063.
Benchmark
Same harness as #9311: real
Store(in-memory SQLite) +tabulateElectionResults, NH test-ballot fixture, 50k HMPB CVRs, 13.3kwrite-ins, grouped by precinct × voting method,
includeWriteInAdjudicationResults. Dev VM (arm64, 3 vCPU). "Before" is#9311's tip; results hash identical before/after.
tabulateWriteInTallies(grouped)tabulateElectionResults, cache misstabulateElectionResults, cache hitSo we're getting 1.5x speed improvement with no write-ins, >2x speed improvement with heavy write-ins.
Demo Video or Screenshot
N/A (no UI change).
Testing Plan
Checklist
🤖 Generated with Claude Code