Learn how Consensus calculates election results using different voting strategies and handles edge cases
Consensus uses a Strategy pattern to calculate election results, with each voting system implementing its own calculation algorithm. Results are only available for CLOSED elections.
Results can only be calculated for elections that have been closed:
// From src/services/VotingService.ts:157-166calculateResults(electionID: string): VoteResult[] { const election = this.electionRepository.findById(electionID); if (!election) { throw new Error("Election not found"); } // Election must be closed to view results if (election.status !== ElectionStatus.CLOSED) { throw new Error("Results only available for closed elections"); } // ...}
Attempting to view results for DRAFT or ACTIVE elections will fail. Close the election first to calculate results.
All voting systems return results in a standardized format:
// From src/services/strategies/IVotingStrategy.ts:4-11export interface VoteResult { candidateID: string; candidateName: string; votes: number; percentage: number; isWinner: boolean; isTied?: boolean; // True when multiple candidates have the same top votes}
Results calculation uses the Strategy pattern to apply different algorithms:
// From src/services/VotingService.ts:26-41private strategyMap: Map<ElectionType, IVotingStrategy>;constructor(...) { this.anonymousAdapter = new AnonymousBallotAdapter(); this.strategyMap = new Map(); this.strategyMap.set(ElectionType.FPTP, new FPTPStrategy()); this.strategyMap.set(ElectionType.STV, new STVStrategy()); this.strategyMap.set(ElectionType.AV, new AVStrategy()); this.strategyMap.set(ElectionType.PREFERENTIAL, new STVStrategy());}
The PREFERENTIAL election type is an alias for STV and uses the same calculation strategy.
After redistribution, the candidate with the most votes wins
Consensus implements a simplified single-round STV. Full STV implementations may perform multiple elimination rounds until a candidate reaches the quota.
All results are calculated from anonymous ballots with no link to voters:
// From src/services/VotingService.ts:169-177// Get ballots and candidatesconst ballots = this.ballotRepository.findByElectionId(electionID);const candidates = this.candidateRepository.findByElectionId(electionID);const strategy = this.strategyMap.get(election.electionType);if (!strategy) { throw new Error(`No voting strategy for election type: ${election.electionType}`);}return strategy.calculateResults(ballots, candidates);
Ballots retrieved from the repository contain no voter identification. The anonymization happens during vote casting through the AnonymousBallotAdapter.
All voting strategies return results sorted by vote count (descending):
// From FPTPStrategy.ts:32results.sort((a, b) => b.votes - a.votes);// From STVStrategy.ts:85results.sort((a, b) => b.votes - a.votes);// From AVStrategy.ts:90results.sort((a, b) => b.votes - a.votes);
The winner (or tied candidates) will always appear first in the results array.