feat(elections): STV tabulation engine with test fixtures
Open
Nobody has claimed this yet.
- Dominant language
- HTML
- Stars
- 33
- Forks
- 104
- Avg merge
- 12h 3m
- Merged PRs (30d)
- 10
Description
Summary
Implement a Single Transferable Vote tabulation engine that elects multiple winners using the Droop quota and surplus transfer.
Part of #1933.
Requirements
- Pure function: `tabulateSTV(ballots, candidates, seats) → { rounds[], winners[], exhaustedBallots }`
- Compute Droop quota: `floor(validBallots / (seats + 1)) + 1`
- Elect any candidate reaching quota; transfer surplus using a documented method (Meek, Gregory, or Weighted Inclusive Gregory — pick and document one)
- When no candidate reaches quota, eliminate lowest and redistribute
- Handle tie-breaks deterministically (same rule as IRV)
- Handle exhausted ballots explicitly
- Stop when all seats filled, or when remaining candidates ≤ remaining seats (auto-elect)
- Document the chosen surplus-transfer method in code comments AND in `docs/elections/tabulation.md`
- Golden fixture tests with hand-calculated multi-seat elections
- Tabulation runs server-side only
Context
- Epic: #1933
- Depends on schema issue
- STV handles multi-seat races (board elections)
- IRV issue: see sibling issue
Implementation notes
- Start with Weighted Inclusive Gregory (WIG) — simpler to explain publicly than Meek, widely used (e.g., Scottish local elections)
- Same `packages/tabulation/` package as IRV
- Compare against a reference (e.g., OpenSTV) for at least 3 test cases
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in the packages/tabulation/ package and read the IRV sibling issue and the schema issue first. Define the server-side STV API, then add hand-calculated golden fixtures and compare at least three cases with OpenSTV. Done means deterministic quota, transfers, eliminations, exhaustion, auto-election, and documented WIG behavior in code and docs/elections/tabulation.md.
Written by the indexing model from the issue text.
Assessment
- Domain
- backend, documentation, testing-qa
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100