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
Agendas & PDFsVote TableMeeting Video

1Collect

Agenda
Minutes.pdf
Votes
Video.mp4
✓ Locked with digital fingerprint (SHA-256)
↓ PDFs & Votes↓ Audio & Captions

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

City Dashboard

Cllr: In Favour

Certified Minutes

“Left room (conflict)”

Carried 5–4Minutes verified (1,207 match · 100 fixed · 74 added)

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 ✓

SAArmstrong

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

Carried 5–4SAArmstrong
✓ Agenda time✓ Vote call✓ Wording
Housing?Yes
Parks & rec?No
Procedural only?No
Housing

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

“Thank you, Your Worship, I’ll second that.”Procedural
SAArmstrong“We need to know what this housing plan will cost.”
Strong opinionVideo 1:14:22 ↗
“All those in favour? Carried.”Procedural

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

Speaker matchExact wordsVote mathSource link
Housing · Verified against minutesCarried 5–4
The voteThe words, with videoThe minutes

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.

1,592 of 1,593

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.

539 of 540

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.

79 of 80

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 Council
    8
  • Lone voteThe only vote on one side
    4
  • Minority voteOn the smaller side of a divided vote
    2
  • Strong opinionA firm position in their own words
    2
  • Split voteOn the larger side of a divided vote
    1
  • 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.

See the councillors

Sources