How it works
Empowering democracy from the citizens up.
Nanaimo City Council’s record is public, but it sits in more than 12,800 PDFs and 150 hours of video. CityCounts turns that archive into clear civic analytics—showing how each councillor voted and what they said, decision by decision. Every vote and quote links straight to the City’s source.
- 2,414 decisions
- 20,443 votes
- 996 quotes
- 539/540 blind audit
1Collect
Every morning, our system checks the City’s website for new agendas, minutes, vote records, and meeting videos. Each file is locked with a digital fingerprint so we know our copy matches the City’s file.
Daily automated watch · SHA-256 source pinning · 12,846 PDFs indexed
2Read & Reconcile
Cllr: In Favour
“Left room (conflict)”
We turn every PDF and video into searchable text, then cross-check the City’s voting dashboard against the certified legal minutes. When they disagree—like when a councillor leaves the room for a conflict of interest—the legal minutes win, and we show both records.
PDF text + OCR · Neural speech-to-text · Automated minutes reconciliation
3Identify
Voice match: 94%
“Chair: Go ahead, Cllr...”
Floor call ✓
The Chair usually calls on each speaker by name, but captions can be messy and debate often goes back and forth. To make sure we get the speaker right—even when someone speaks out of turn—we match each councillor’s voice on the audio and track who has the floor in the transcript.
Neural voiceprint matching + floor-handoff detection
4Sort & Link
A single meeting can have 20 different votes, so the system ties each speech to its decision using agenda timestamps, spoken vote calls, and motion wording. Then a small AI model answers simple yes-or-no questions (Is this about housing?) to sort decisions into 11 civic topics.
3-signal decision join · Constrained yes/no classification
5Quote
“We need to know what this housing plan will cost.”
Council meetings are full of routine procedure (“I’ll second that”). A small AI model scores each turn so we filter out procedural chatter and keep only clear arguments. When a councillor takes a firm stand, a separate blind AI check verifies the quote before adding a Strong Opinion badge.
4-level substance filter · Blind stance verification · Video deep-links
6Check
No AI model can publish directly to the site. Fixed code calculates every vote count, weight, and link the same way every time, and automated checks block any update if a link breaks or a past record goes missing.
Immutable SQLite fact store · Idempotent builds · Automated release gates
Accuracy
We test the live site by auditing random samples from scratch against the City’s official records.
99.9% vote coverage
The City’s voting dashboard lists 1,593 motions this term, and 1,592 are on the site (the minutes show the other one was withdrawn). Cross-checking the certified minutes also fixed 100 decisions where the dashboard missed an absence or conflict of interest, and added 74 votes found only in the minutes—for 1,626 decisions this term.
0 wrong in blind vote audit
We picked 60 decisions at random (540 individual votes). A large AI model read the City’s minutes blind to our site and wrote down each vote. 539 matched the site, 1 wasn’t stated in the minutes, and 0 were wrong.
98.8% speaker accuracy
We checked 80 random quotes against the meeting transcripts. 79 had the right speaker, and across all voice-checked quotes on the site, 0% matched a different councillor’s voice.
A note on captions: All 996 quotes come from the meeting transcripts (885 from the City’s captions and 111 from our own speech-to-text). Because raw captions can be messy around speaker handoffs, we are rolling out a small AI pass to trim extra words and fix typos—and every quote links to the exact second in the video so you can hear it yourself.
Weights
Most council votes are routine and unanimous. To surface the decisions that show a councillor’s priorities, each decision counts once per councillor at the single highest weight that applies. We set the same rules for everyone:
- Put forwardBrought the motion to Council8
- Lone voteThe only vote on one side4
- Minority voteOn the smaller side of a divided vote2
- Strong opinionA firm position in their own words2
- Split voteOn the larger side of a divided vote1
- Unanimous voteEveryone voted the same way¼
Relevance
Relevance combines a saved AI assessment of how contentious a motion is (60%) with its highest Stands weight for the selected councillors (40%). Topic fit also affects the card order, including in All topics. Saved debate labels can strengthen that fit and bring a motion into another category. They reflect subjects discussed, including claimed consequences, rather than proving those consequences. Newest and Oldest sort by meeting date.
The calculation
Stands is divided by 8 and contentiousness is scaled from 0 to 1. Their 60/40 blend is multiplied by 0.25 + 0.75 × topic relevance. A debate topic score of at least 2 out of 3 qualifies; we use the highest passage score once per motion and topic. If that score exceeds the motion’s topic fit, the fit moves halfway toward it. All topics uses the strongest fit across the categories; a selected topic uses its own fit. Existing categories remain. Missing or incomplete debate labels keep the motion-fit baseline; missing motion classifications fall back to Stands. With no known topic fits, All topics keeps multiplier 1.
Sources
- Votes come from the City voting record, the Earlier voting record, and certified minutes. Documents and video come from Agendas and minutes.
- Questions? Email [email protected].