apolinario/urnas-tardias

Data

A one-off script that parses Brazilian election machine logs to count how many votes were cast after 5pm.

137
20
Python
new today

This is a small, single-question analysis rather than a reusable election-data toolkit: it exists to quantify late votes in the 25 October 2026 runoff after the STF extended voting to 19h. Read the published result first; the code matters only if you want to check the method or re-run it for other cutoffs.

The problem

After a contested runoff, a claim circulates that votes entered after 17h could have changed the outcome. Checking it means going beyond aggregate tallies into per-machine logs: one file per voting section, each inside a hashed folder whose path must be discovered from the TSE's configuration and auxiliary files. Doing that by hand for roughly half a million sections is not realistic, so the practical question is how to join opening, closing and vote-computed timestamps at scale and get a defensible number.

The project turns that into two CSV files: one row per machine with timezone, opening, closing, last vote and counts after 17h and 17h20, plus a municipal summary of extended machines.

What's different

Instead of counting reported totals, it reads the raw logd.dat inside each .jez archive and anchors on three event strings: machine ready, vote computed, and closing confirmed. That gives an independently checkable definition of a "late" vote rather than a derived statistic. Time zones are handled by inferring each municipality's zone from its most common opening hour, assuming 8am local, then converting to Brasília time. That inference is the central methodological trade-off: it is a reasonable heuristic for a country with several zones, but it is an assumption, and anyone auditing the number should inspect the zones assigned to municipalities that straddle a boundary.

The headline result is deliberately unexciting: with the default 17h45 cutoff, 7,352 machines closed late and the 5,052 votes after 17h in them amount to 0.004% of the 127.7 million recorded, or 0.11% of Lula's 4.4 million margin. The README also shows alternative cutoffs, including counting every vote after 17h, which still reaches only 0.77% of the margin. Foreign sections are excluded because voting follows local time abroad, and 72 sections lacked logs.

Who should try it

Good fit: a journalist, researcher or citizen who wants to reproduce or challenge the published figures, or adapt the crawl to another election or a different closing cutoff. The code is short enough to read in one sitting and the CSV outputs support follow-up analysis in a spreadsheet or pandas.

Poor fit: anyone wanting a general TSE data client. This is a targeted, single-election script, not a maintained scraping library, and it carries no declared license, so reuse terms are unclear. If you only want the answer, the README tables already provide it.

Requirements and limitations

Running the full crawl means about one million requests, rate-limited to 10 per second by default, and on a home connection that takes hours. The crawler resumes where it stopped, which matters for an interrupted multi-hour job. Setup is just Python with uv, but the ongoing cost is bandwidth and time, not configuration. The data source is dated and election-specific: URLs reference the 2026 runoff, and the log format assumptions apply to that publication. A single election's logs also cannot tell you why a machine ran late or whether a late vote was cast by someone already in line, which the README notes is allowed in any election.

HotRepo's take

HotRepo's only recorded observation is a NEW-REPOSITORY board (新项目榜, not the overall Trending board) position of #25 for python on 2026-10-27, with 137 total stars. That is a single dated snapshot, not a growth series, so persistence of interest cannot be judged. Before relying on it, check the timezone inference and cutoff definition in the project instructions against the raw TSE configuration and log archive yourself.

Written by AI from the project's README, updated October 27, 2026. The project's own docs are the source of truth.