About the project
This site compares how Russian, Ukrainian and independent media cover the same events of the war in Ukraine. All content — event cards, summaries, translations — is created and published automatically, with no human review before publication. The site does not establish the truth: it shows what each group of sources reports, how, and where the versions diverge.
Methodology
One automatic pipeline (the update.py script) runs the steps below. Wherever possible each step is backed by a check in code — the model does not “check itself”.
- Collection. The script reads public pages of the sources (RSS, sitemaps, daily archives, article pages) and stores title, link, time, group and text (up to 6,000 characters) in a local database. Collection is incremental: URLs already known are not downloaded again. Requests to each site are rate-limited and robots.txt is honoured; pages closed to automated reading are not used.
- Pre-selection. A broad keyword list selects war-related items; everything else never reaches the cards.
- Clustering into events. A language model (OpenAI, gpt-6-luna) receives batches of up to 100 items together with the titles of recently opened events, and attaches items to existing events, creates new ones, or leaves an item without an event. Code validates the answer: removes duplicate ids, re-asks for missing ids (a separate request) and discards unknown ones. A separate pass then looks for events that were split into parts and merges them.
- Relevance filter. For every item the question “does it actually describe this event?” is asked separately. Only items answered “yes” enter a summary, so an unrelated item never becomes a side’s “version”.
- Summaries. For each of the three groups (Russia, Ukraine, independent) the model writes a short summary with attribution (“the Russian Defense Ministry says…”), a “Where the versions diverge” block, and 1–2 quotes per group. Events with numeric discrepancies (casualty-type figures pre-checked in code) or with many articles go straight to the stronger model (gpt-6.1-sol); the rest are drafted by gpt-6-luna first and retried once on gpt-6.1-sol if a check fails.
- Quote check. Every quote must be a verbatim substring of the stored text of an article from the same group (only whitespace may be repaired). A quote that fails is not published. If a group that has a summary is left with no verified quote, the card is not published.
- Number check. Every number in a summary and in the divergence block must occur in the source texts. A mismatch triggers a retry on the stronger model; several mismatches mean the card is not published. A figure conflict between groups is determined in code from numbers that the model cited with an article id and that the code found in that article’s text.
- Translations. Title, place, summaries and the divergence block are written in Russian and then machine-translated into Ukrainian and English (gpt-6-luna). Code checks that numbers in the translation match and that script and length are plausible; quotes are not translated. A card that fails is not published.
- Publication. A card goes live automatically if it passes all quality gates (below). There is no manual review.
Quality gates: a card is withheld if (1) it has fewer than two relevant articles or fewer than two distinct sources; (2) the relevance filter confirmed fewer than half of the clustered articles; (3) a group with a summary has no verified quote; (4) several numbers in a summary are not found in the sources; (5) the model reported high uncertainty; (6) the translation check failed; (7) the model output is incomplete or invalid. If a previously published card stops passing these checks (for example after new articles arrive), it is withdrawn automatically and the withdrawal is written to the corrections log.
Confirmation scale
Each event gets a confirmation level, computed mostly in code from formal features: how many groups and distinct sources describe the event; whether international or exile independent outlets are among them (Kyiv Independent counts as a Ukrainian outlet and is not treated as international for this purpose); whether the numbers differ (a number difference alone does not produce the “contradict” label: “launched” and “shot down” are different quantities; the label is set only when the model, reading the texts, flags incompatible statements); whether the quote and number checks passed; how far the relevance filter confirmed the grouping; how uncertain the model itself considered the card. The level is shown as an icon plus text (never colour alone).
| Label | Meaning | When assigned |
|---|---|---|
| confirmed by independent sources | The event is reported by international or exile independent outlets and no contradictions in the facts between the groups were detected. This does not mean the independent outlets verified every detail. | No check warnings or contradictions; the event is described by ≥2 international/exile independent sources, or ≥1 such source plus another side (Russia or Ukraine). |
| the sides contradict each other | The groups of sources give incompatible information (the model, reading the texts, flagged incompatible statements of fact; differing figures are shown in the card). The site does not decide who is right. | The model, reading the texts, flagged incompatible statements, and at least two “sides” describe the event. A difference in figures alone does not set the label. |
| both sides report it, no independent sources | Both Russian and Ukrainian sources describe the event, but there are no international independent sources in the selection. | Both Russian and Ukrainian items exist, no international independent ones, no detected contradiction. |
| claimed by one side only | Only one side reports the event (no independent international source); its statements are presented as statements. | Items from one “side” only (Russian or Ukrainian), with no international independent source. |
| insufficient data | Few materials, or the automatic quality checks passed only partly (few sources, model uncertainty, some quotes or figures not confirmed). | Any of: fewer than two sources, the relevance filter confirmed under 60% of the articles, the model reported high uncertainty, some quotes failed the check, a number not found in the sources, or only short headlines available. Checked first. |
Important: the label describes coverage and consistency of the materials in the collected data, not truth. “Confirmed by independent sources” means independent outlets describe the event, not that they verified every detail; they may be relaying one party’s statement. The label is assigned automatically and can be wrong.
What to expect: error forecast
Below are the kinds of errors to expect and rough figures from a single test run on 2026-10-04 (report llm-test/REPORT.md). Samples are small (the clustering test used 100 articles and 9 reference cards; the summary test 8 cards), so the figures are indicative and do not transfer to the whole site.
- Split and merged events. In the clustering test (gpt-6-luna, default setting) on average 63% of a reference card’s key articles landed in one best cluster; for 3 of 9 cards at least 75%. The model is cautious: of 100 articles 55–69 stay without an event, and the same event is often split into two cards. Of 17 clusters, 2 were mixed (adjacent episodes), both arguable. The reference itself is loose, so the estimate is approximate.
- Wrong article attribution. Without a relevance filter, in one of 8 checked cards the draft presented an unrelated article (a different story) as the “Russian version” of the event. That is why the filter exists; its own accuracy was not measured separately.
- Shallow “Where the versions diverge” block. This is the most variable field: weaker model settings often produced generic wording instead of concrete figures and phrasings; the stronger model described divergences more precisely. The block only records differences; it does not verify facts.
- Quotes and numbers. In the test, all 35 of 35 quotes from gpt-6-luna (default setting) were verbatim; a weaker setting had 40 of 42 (it is not used in the pipeline). Of 25 numbers in summaries, one was not found in the source (a date). The sample is small, and about 15 claims checked by hand contained no invented facts. A verbatim quote does not guarantee that it is well chosen or representative.
- Translation errors. Summaries and the divergence block are translated into Ukrainian and English. The translation error rate was not measured in the test; in one sample from the stronger model an English word leaked into a Russian text. Code catches only gross failures (numbers, language, length), not subtle meaning errors.
- Omissions and selection bias. “No reports found” means absent from the collected data, not from media in general. The set of events is determined by automatic clustering and the availability of sources.
Corrections policy
- How to report an error: the “Report an error” link on every card and in the site footer (an e-mail; the page address is filled in). The address is currently a placeholder and not configured.
- What happens to a report: the card is re-checked (the checks are run again on the stored texts); if the error is confirmed the card is withdrawn and, if needed, rebuilt. The project does not promise response times.
- Corrections log: all withdrawals and corrections are recorded on the public “Corrections” page — date, card, what happened and why. Automatic withdrawals (a card stopped passing the checks) are recorded there too and marked as automatic.
- A correction does not erase history: the entry stays in the log after a card is withdrawn or replaced.
Neutrality
- Claims are attributed to whoever made them (“the Russian Defense Ministry says…”, “according to the regional administration…”, “BBC writes…”); contested claims are not presented as fact.
- The site does not decide which version is true and does not judge the parties’ actions. The “Where the versions diverge” block records differences in figures and wording.
- The groups label a source’s affiliation, not its reliability: “Russia” — Russian state and state-friendly outlets; “Ukraine” — Ukrainian outlets (the public broadcaster and private ones); “Independent” — international and exile outlets plus Kyiv Independent. Some independent outlets receive state or public funding (BBC, DW, Al Jazeera); editorial independence is their own claim, which we do not verify.
- The choice of sources itself introduces bias: the Russian group has no outlets that are critical of the authorities and open to automated reading, and Kyiv Independent may hold a pro-Ukrainian stance.
Anonymity of the project
The project is anonymous: there are no names or personal contacts of the authors on the site or in the code. The only contact is a feedback address (currently a placeholder). The site uses no analytics counters or cookies; the browser stores only your chosen language and colour theme locally.
Sources and their limitations
The list below contains every source the pipeline uses, with its affiliation and access method. The article count is the number of stored articles in the database (including those unrelated to any event).
| Group | Source | Affiliation and access | Status | Articles |
|---|---|---|---|---|
| Russia | Russian Defense Ministry (Telegram) | the ministry’s official channel; public web preview t.me/s/mod_russia (mil.ru sites unreachable from the server) | working | 574 |
| Russia | TASS (tass.com) | Russian state news agency; English version, sitemap + pages | working | 1896 |
| Russia | TASS (tass.ru, RSS) | title and lead from RSS only: article pages are behind an anti-bot check | partial | 453 |
| Russia | RIA Novosti | Russian state news agency; robots.txt disallows the /services/ loader, so RSS, the “Ukraine” tag and daily section archives are read — coverage is incomplete | partial | 1989 |
| Russia | Interfax | private Russian news agency operating legally in Russia; RSS (≈25 latest items) + pages | partial | 1175 |
| Ukraine | Suspilne | Ukraine’s public broadcaster; sitemap + RSS | working | 1748 |
| Ukraine | Ukrainska Pravda | private Ukrainian outlet; daily archives | working | 1331 |
| Ukraine | RBC-Ukraine | private Ukrainian outlet; RSS with full text (≈3 days) | working | 865 |
| Independent | BBC News | British public broadcaster (licence-fee funded); RSS (≈100 recent articles for all of BBC) | working | 173 |
| Independent | The Moscow Times | independent English-language exile outlet (Amsterdam); designated an “undesirable organisation” in Russia; RSS + sitemap | working | 43 |
| Independent | France 24 | French international broadcaster (France Médias Monde, state-funded); section RSS | working | 7 |
| Independent | The Guardian | British newspaper owned by the Scott Trust; “Ukraine” RSS + pages | working | 83 |
| Independent | DW (EN, RU) | German international broadcaster funded from the federal budget (editorial independence is set by law); RSS + pages | working | 427 |
| Independent | Al Jazeera | Qatari broadcaster funded by the state of Qatar; RSS + pages (few items on Ukraine) | working | 151 |
| Independent | Meduza (RU, EN) | independent exile outlet (Latvia); RSS with full text (≈30 latest items per language); designated an “undesirable organisation” in Russia | working | 91 |
| Independent | Kyiv Independent | Ukrainian private English-language outlet; stance may be pro-Ukrainian — “independent” only nominally | working | 525 |
Sources that were tested but are not used, or only partly usable:
- Reuters — HTTP 401: needs JS/cookies — not used
- Ukrinform — ukrinform.ua and .net answer 403 to any request — not used
- Kommersant — RSS is served but robots.txt disallows automated reading of article pages — not used
- Lenta.ru — robots.txt disallows automated reading of article pages — not used
- RBC (rbc.ru) — HTTP 401 — not used
- ISW — report pages are served but they are analytical digests rather than reports on single events — not used
- Mediazona, Euronews, UNIAN — RSS is served (robots.txt does not disallow) but these sources are not connected yet — may be added later
- Ukrainian General Staff (zsu.gov.ua) — the site returns 200 but content is rendered by JS; not collected directly (its briefings are quoted by the collected Ukrainian outlets)
Limitations:
- Collection depth is limited by what RSS feeds, sitemaps and archives return: for RIA, BBC, France 24, Meduza, Guardian, DW, Interfax and others part of past days’ material is unavailable.
- For TASS in Russian only titles and leads from RSS are collected; for the Russian Defense Ministry — texts of posts in its Telegram channel (public web preview).
- The Russian group consists of state and state-friendly sources; the Ukrainian group of the public broadcaster and private outlets, and Kyiv Independent is “independent” only nominally. “Independence” is an approximate notion.
- The project does no independent fact-checking.
Contact
The feedback address is not configured yet: an example address is currently used in the links. To report an error or suggest a source: write by e-mail ([email protected]). Corrections log.