Chicago '27 Mayoral Housing Tracker

Methodology

This tracker records where 2027 Chicago mayoral candidates stand on housing, based on what they say in public media — podcasts, interviews, candidate forums, and news coverage. It is an accountability tool: every position links back to the source it came from.

How positions get here

  1. Discovery. On a schedule, the system scans local-outlet news feeds, video and podcast channels, and candidate social posts for new appearances.
  2. Ingestion. Articles are read as text; videos use their captions; audio is transcribed. We store only the extracted quotes and a link to the source — not full transcripts or media files.
  3. Extraction. An AI model reads the transcript and drafts each housing position with the exact supporting quote.
  4. Review. A second, independent AI model checks that each quote is real and correctly attributed. Then a human reviews and approves every position before it appears here.

What we do and don't claim

Summaries are our paraphrase; the linked quote and source are the record. A blank cell means a candidate has not addressed that issue on the record that we've found — not that they have no view. We track housing closely; other issues a candidate raises are noted internally but not published here.

Saying you support housing is not a position

Every candidate is for affordable housing. The question worth asking is how — so for each position we record the specific mechanism the candidate named: a program, a rule change, a funding source, a quantity, or a deadline. It has to be present in their own quoted words.

Where a candidate voiced support but named no mechanism, the cell is marked ● and the profile says "No specific mechanism stated." We show those rather than hiding them: a blank cell cannot tell you the difference between a candidate we have little coverage of and one who talks about housing constantly without ever committing to anything.

Borderline cases are recorded as no mechanism. "Streamline permitting" is a direction; "cut permit review to 30 days" is a mechanism. We would rather understate a candidate's specificity than credit them with a plan they did not describe — a second model checks every claimed mechanism against the transcript, and flags any it cannot find.

This makes some candidates look thin, and for a few that is because we have found little coverage of them rather than because they have said nothing. The remedy for that is more sourcing, not a lower bar. If we have missed a place where a candidate laid out specifics, tell us — see Corrections.

Under the hood

For the technically curious: this is a scheduled pipeline that runs on GitHub Actions and publishes a static site. Everything is open source, and every language-model step is dependency-injected so the whole flow is tested offline on fixtures before it ever touches the live models.

Sources it watches

X, Instagram, and TikTok are not auto-tracked (no open feed / terms of service), but a link to any of them can still be submitted manually.

The pipeline

discover → ingest → extract → propose → review → human approval → publish

  1. Discover polls each source daily, de-duplicates against a ledger, and a cheap AI triage call decides whether an item plausibly features a candidate discussing policy.
  2. Ingest turns the item into clean text — article readability, audio → transcript, or a social post's text directly. Transcripts are never stored; only the extracted quote and a source link are kept (copyright).
  3. Extract asks a model to pull each housing position with a verbatim quote. Any quote that doesn't literally appear in the transcript is dropped, as is any statement about a candidate or topic that isn't in our registry.
  4. Propose writes the evidence and a draft position and opens a pull request.
  5. Review — a second, different-family model re-fetches the source, re-verifies every quote, and labels the PR verified or flagged. For audio there is a wrinkle worth stating plainly: we don't store transcripts, so the reviewer re-transcribes the recording, and two transcriptions of the same audio are never quite identical — filler words, hyphens and trailing clauses move. When a quote isn't word-for-word in the new transcription, we show the reviewer the closest passage and ask whether it is the same statement: same numbers, same polarity, same promise-versus-possibility. That verdict is labelled reconciled rather than verified, and the PR shows the passage and a similarity score so the human deciding can see exactly what differed.
  6. Human approval — nothing publishes automatically; a person merges the PR, which rebuilds and redeploys the site.

The models

Language models are accessed through OpenRouter; the model choices live in a config file and can change. The extractor is trusted only to draft: a wrong or fabricated quote has to get past a verbatim-quote check, a different-family reviewer, and a human before it can reach this site — and the auto-publish switch ships off. The verbatim check is never relaxed at extraction: a quote that isn't literally in the transcript the model read is dropped, always. The reconciliation described above applies only to the reviewer's second, independent transcription of audio.

Candidates we don't track

We focus on candidates with a realistic path in the race. These declared candidates are not shown in the matrix; we'll add anyone here if that changes or they put a housing position on the record.

Corrections

Found a misquote, a wrong attribution, or a missed appearance? Corrections are welcome and taken seriously. Please open an issue — you can also use that form to submit a media link for us to process.