WikiWar

Live Wikipedia edits and source-backed dispute evidence

Connecting
@WikiWarLive
Connecting…
Live · past 2 hours
0 conflicts in atlas window 0updates in the past 2h 0 article subjects mapped 0 articles without map points
Article-subject locations for Wikipedia conflicts in the selected atlas window Every mapped atlas article has a persistent point. Badges count stored changes in the selected time window; animated pulses mark new or replayed changes. No point represents an editor.
Waiting for a conflict article with coordinates…
Article in atlas Changes in selected window Linked location fallback No map point
Live updates · replay available 0 stored
No map point 0

Conflict atlas

Case files include conflicts that qualified anywhere in the selected live window. “Seen in window” marks disputes that are no longer active now.

Developing Established Cooling Seen in window

Loading conflicts in the selected window…

Historical controls

Replay

Choose a stored window or local day. Playback opens on the Live map.

Hand-picked case files

Curated

A deliberate collection of exact wording swaps, the arguments around them, and how Wikipedia responded.

Selecting a dispute… The wording battle and its linked talk-page arguments will appear here.
01 · PICK A TARGET

Rank articles or battles?

Article summarizes edit wars with a strongest-bout baseline and capped recurrence. Battle compares each article’s single strongest bout.

Choose whether to rank articles or battles
02 · SET YOUR CALCULUS

Allocate 100 controversy points

Move either divider to rebalance the three score components.

70
Battle strengthText changes, reversals, mutual reverts
10
ParticipationDistinct editors in the fight
20
Wikipedia involvementProtection, RfCs, restrictions, arbitration
More filters
Loading the biggest fights…
  1. Loading leaderboard…

Building WikiWar

July 2026

Current State

WikiWar began as a way for me to try and detect edit wars live on English Wikipedia. In doing this, it accidentally became an evidence-backed system for classifying and cataloguing historical Wikipedia disputes.

The current product has four main evidence views:

  • Live — a global edit map of current developing disputes.
  • Curated — a hand-picked selection of complete edit-war case files.
  • Leaderboard — configurable rankings of eligible conflicts.
  • Review — blind, fingerprinted annotations for a supervised model.

Defining Controversy

At first, I wanted just to look at the current edit wars on Wikipedia (materials like this one were a fun read, but not quite live). This is actually harder than you might think, and the obvious approaches have obvious flaws:

Working Locally

The conclusion I came to is that “most controversial” is not one heuristic. It’s just not possible for one scalar to simultaneously represent mutual reverting, broad page activity, discussion volume, formal intervention, and a readable dispute story, all controlled and filtered to remove graffiti. This meant a lot more post-processing than I initially envisioned.

Building this at runtime was obviously impossible, and collecting a multi-year page history across thousands of pages from an API crawl would be slow, rate-limit-prone, incomplete, and difficult to reproduce (compared to prototyping these things, where I could work off of the MediaWiki Action API and EventStreams for a live source of truth).

Local mirroring was the only option, but this meant processing ~127 GiB of compressed Wikimedia dumps from the May 2026 English mediawiki_history snapshot. Naturally, processing this snapshot turns the data into monthly snapshots—additional work had to be done to make it continuous, just at minimum. Still, this was much better than GPT 5.5’s “solution” (xHigh btw) of hitting the API for this data in what would have been effectively the world’s least effective and wasteful DoS attack on MediaWiki, which it silently reverted to not once, but three times. Sol 5.6 was smarter, here.

13,989,608historical aggregate rows
6,264,773talk-active rows with exact editor sets
550,809exact protection-log events
490local evidence rows
932source-linked contested segments
1,343proven talk claims
135year and all-time ranking snapshots
46.5 GBpromoted viewer database

The project also built:

  • a historical_evidence_cache;
  • a wikiwar.evidence command-line pipeline;
  • local parsing of pages-meta-history revision-content dumps;
  • candidate-first article and talk-page targeting;
  • target-to-shard indexes, page-ID caches, checkpoints, early stopping, and stale-state recovery.

What’s Our Unit, Again?

As I was building this out conceptually, I realized I was caught between simultaneously trying to look at two types of units of analysis: articles and wars.

Articles are useful for answering “which pages keep attracting conflict?” but they are a terrible container for saying when one war starts or ends. The same page, especially frequently controversial ones, can have unrelated fights years apart. So the actual behavioral unit became the war: a bounded bout of source-linked, mutual reverting around a particular piece of text. Focusing on a distinct selection of text here helped for visual comprehension and the product perspective, as well.

In terms of classifying intensity and features of actual conflict episodes, we score each conflict independently. Defining the boundary was its own shitty problem, because this naturally raises the pair of hard questions of “how long is an edit war?” and “what level of intensity defines an edit war, especially a prolonged one?” The workable rule is a 30-day quiet gap: if the evidence goes silent for longer than that, the next flare-up is a new bout. Every phrase, revision, talk quote, editor count, score, and protection event shown for a battle is scoped to that same pile.

Cleaning Graffiti

Graffiti is not a corner case here; it is the adversarial baseline. On the byte level, a sincere disagreement over whether a territory was “occupied” or “annexed” can look functionally identical to someone adding a slur and another editor removing it. Raw revert counts cannot tell the difference, and neither can a semantic-distance trick without a lot of contextual help (recall the vector-map issues from before).

The filtering stack therefore combines behavior and text: bot filtering, cleanup and anti-vandal edit-summary markers, one-sided reverter concentration, generated undo boilerplate, repeated junk tokens, obvious graffiti, personal attacks, media-caption churn, and leaked wikitext or template fragments. It is deliberately contextual rather than title-based. If a case still cannot prove mutual conflict around source-linked article text after that cleaning, it does not get ranked.

The current deterministic-v2 logic:

  • requires at least three source-linked article revisions and one contested segment;
  • classifies cleanup when cleanup-marked evidence reaches 70%;
  • classifies one-sided activity when the top reverter reaches 75%;
  • requires at least one effective mutual-revert pair for a verified historical conflict;
  • treats live behavioral matches without complete phrase evidence as provisional;
  • calls narrow repeated wording changes localized;
  • calls large spans, many segments, or large total changes broad;
  • separates formal, discussed, and low escalation;
  • maps verified localized conflict to the petty lane and verified broad conflict to substantive, leaving cases that cannot be defended either way ambiguous.

The classifier explicitly excludes article title, topic keywords, language, editor identity, human labels, and trained-model output. Every result retains normalized facts, rule IDs, reasons, completeness, version, and sensitivity flags. This replaced earlier candidate boosts for known contentious titles and removed the risk that a handwritten topic list would quietly define “controversy.”

What Are “Substantive” and “Petty,” Really?

There’s a scene in Who Framed Roger Rabbit where Eddie Valiant is sawing the handcuffs off of himself and Roger Rabbit under considerable effort. Midway through, Roger Rabbit easily slides out as a bit, prompting Eddie to angrily ask, “Do you mean to tell me you could’ve taken your hand out of that cuff at any time?” Roger answers: “No, only when it was funny.”

One obvious problem with this project is that one man’s petty dispute is another man’s very substantive and consequential academic disagreement. But even if I did have a magical button to divine the difference objectively and toss the former, I wouldn’t really want to use it, because showing Wikipedia editor pettiness and pedanticness is exactly what I was trying to smuggle into the ranking. The Roger Rabbit rule basically applies: a dispute should be included when it is funny, especially when it is petty, even if the figures might suggest it isn’t that “controversial.” This is a good editorial instinct, but a dogshit production classifier.

So instead of pretending “petty” and “substantive” are objective truths, the system classifies observable geometry: how many words changed, how many segments moved, whether the same swap recurred, and whether Wikipedia formally intervened. This determines a sort of magnitude, and then a human layer determines the classification of “petty” versus “substantive.” The “human layer” in question is, of course, me, but this isn’t sustainable. The idea was to then translate my subjective judgment into a basic model that could automatically classify between Petty, Substantive, and hopefully even Graffiti at scale.

Data annotation platforms are notoriously really, definitely… pieces of software, but thankfully for something as simple as classification I could just rebuild a Tinder-style UI and swipe left, right, or down.

Human annotation lab See if we agree.

Classify ten of the clearest current results. The system’s answer stays hidden until your final scorecard.

0 / 10 classifications complete
Loading current classifications… Choosing the clearest five Petty and five Substantive cases.

A first candidate linear model trained on 48 usable labels produced 30% held-out accuracy and macro-F1 of 0.361. It performed worse than a trivial majority baseline on important classes and failed the promotion gates. This is terrible and will be improved; for now we are letting GPT 5.6 classify things.

The Tech Stack

WikiWar architecture flowchart. Live Wikimedia events and historical dumps pass through recoverable pipelines, converge in a shared evidence and scoring engine, enter purpose-specific stores, and reach the browser through FastAPI.
Live source Wikimedia EventStreams

Recent changes arrive continuously; the bounded MediaWiki API adds page identity, revision SHA-1, content metadata, catch-up, and spot checks.

Recoverable live pipeline Outbox → Redis Streams → Workers

PostgreSQL commits the event and outbox together. Dedicated ingest, enrichment, and scoring workers use idempotent keys, retries, stale reclaim, and a durable dead-letter stream.

Historical sources Local Wikimedia Dumps

306 mediawiki_history partitions join revision-content XML/7z and exact pages-logging protection actions.

Reproducible corpus pipeline Index → Checkpoint → Audit → Promote

Candidate-first targeting, shard indexes, page-ID caches, early stopping, fingerprints, fail-closed audits, and atomic promotion make rebuilds resumable and reproducible.

Shared conflict engine Reverts → Evidence → Episodes → Scores

Undo and rollback markers, content-identity restores, mutual-revert graphs, revision diffs, A ↔ B wording swaps, talk evidence, and protection sources become source-linked conflict packages.

Contested segments 5m / 1h / 24h windows 30-day bout boundaries Deterministic classifications
Concurrent live store PostgreSQL

Live events, enrichment, scores, episodes, and the transactional outbox.

Historical viewer SQLite · 46.5 GB

An atomically promoted, read-optimized corpus for evidence and rankings.

Durable feedback Separate SQLite

Annotations and product interactions survive every corpus replacement.

Application and API layer Python + FastAPI

One service exposes the dashboard, JSON APIs, health and corpus status, and server-sent events. It runs against local SQLite or as the read/API tier of the full container stack.

Browser layer Vanilla HTML + CSS + JavaScript
Live Curated Leaderboard Review
System-wide foundations
Across every store SQLAlchemy + Alembic

One data model, bounded repository queries, transactional writes, and 15 forward migrations across SQLite and PostgreSQL.

Across every stage Tests + Operations

Pytest, Ruff, mypy, JavaScript checks, Docker/Compose integration, and a three-hour forced-worker-restart soak ask whether it survives reality.

The Final Scoring System

Pre-scoring evidence gate (pass/fail). The score only runs after the evidence-gate and graffiti-removal layer. An edit war first has to prove at least three source-linked article revisions, a documented contested passage, and effective mutual reverting, while staying below the 70% cleanup-dominated and 75% top-reverter cutoffs. Base evidence is not a bonus; it is the price of admission, which avoids giving a well-documented fight extra points for being well documented.

Once admitted, the bout gets a bounded 0–100 score. Multiple times I tried an unbounded conflict index, as it felt more mathematically honest. I valued this for about ten minutes, until “2003 in music” became the most controversial article on Wikipedia. Removing the ceilings let routine volume sneak back in. The bounded score is built from three positive factors—battle strength, participation, and Wikipedia involvement—with a separate cleanup deduction. The default split is 70/10/20, with presets that lean toward pure battle strength, mass participation, or governance.

Main Scoring Parameters

Default allocation One score · 100 total points
Click a segment to inspect it

Select Battle Strength, Participation, or Wikipedia Involvement to reveal how that share of the score is calculated.

Additional Scoring Parameters

  • Cleanup Penalty 0 to −12 points

    If enabled, the first 10% of cleanup-like evidence is tolerated, then the penalty grows until the case reaches the hard 70% cleanup exclusion. Switching the penalty off changes the ranking among otherwise eligible wars; it cannot make a cleanup-dominated or one-sided case eligible.

    Deduction = min(12, 20 × max(0, cleanup share − 0.10))
  • Talk-Page Size 0 points

    Talk-edit counts and stored talk-text bytes remain available as evidence and for the separate “most discussed” historical snapshot, but they never add points to the configurable controversy score. Discussion volume is too easy to inflate with archiving, boilerplate, and trolling; a talk-page argument is valuable here because it explains a source-linked wording fight, not because it is large.

  • Battle vs. Article Ranking up to 15 recurrence points

    The component score above belongs to one bout. “Battle” ranks the strongest qualifying bout on each page. “Article” starts with that peak and adds 5% of each of the next four qualifying bout scores, capped at 15 recurrence points and 100 overall. Bouts are split after a 30-day quiet gap, and raw elapsed time, routine edit volume, and unverified flare-ups contribute nothing.

Yes, this is less emotionally satisfying than one magic controversy number, but it is vastly harder for a list page or vandalism cleanup to make its way up to number one.

Storytelling

Once the scoring system mostly worked, I realized the score was still the least interesting part. “Armenia: some number” is trivial, and “Israel: Rank 1” is not novel.

But watching editors repeatedly switch “Russia” and “Europe” in Armenia’s page of allies, and then reading the talk-page argument about whether Armenia belongs inside Europe’s borders, is a story. Seeing “occupation” go to “annexation”; that is a real controversy!

That changed the product architecture. Now, we prioritize this sort of word or phrase swapping and aim to produce narratives of controversies as opposed to nebulous numbers. This is the Curated tab, where we only admit complete packages: a verified conflict, an exact wording swap, and a readable talk-page argument tied to that same phrase. The Leaderboard answers the separate question of comparative controversy.

Historical corpus Checking promotion and ranking provenance…