# Протокол валидации и результаты

INF-15 «Полотно» (`grid`), пакет v1.0.0, 2026-07-26. Восемь проверок
раздела 7 ТЗ (`handoff/09_next_research/BY_Maps_INF-15_grid_research_spec.md`).
Каждая проверка ниже даёт **число**, а не слово «пройдено» — так, как того
требует пункт 2 чеклиста аудита (раздел 9 ТЗ). Источники чисел —
`sources/raw/metrics_observed.json`, `sources/raw/metrics_forecast.json`,
`sources/raw/g3_nightlights_crosscheck.json`, `sources/raw/network_metrics.json`,
`sources/raw/reconciliation.csv`. Полное расследование G-1 (calibровка) —
`docs/notes/grid_validation.md`; полный отчёт G-6/C-3 — `docs/notes/
grid_network_findings.md`. Пути — относительно корня пакета `artifacts/grid/`.

---

## G-1. Сходится ли карта клеток с официальными числами района/страны

**Порог.** По району — |отклонение| ≤ 3 % на каждую наблюдаемую эпоху; по
стране — ≤ 1 %; если за допуском по району больше 15 территорий — районные
абсолютные числа снимаются вовсе (раздел 13 ТЗ).

**Результат (сырой продукт, ДО калибровки).**

| | значение |
|---|---|
| Территорий проверено | 119 (118 районов + Минск) |
| Хоть раз вне допуска ±3 % за 10 эпох | **119 из 119** |
| Провал по эпохам (число районов вне допуска / всего) | 1975: 110/118 · 1980: 103/118 · 1985: 93/118 · 1990: 61/118 · 1995: 40/119 · 2000: 53/119 · 2005: 99/119 · 2010: 79/119 · 2015: 53/119 · 2020: 81/119 |
| Максимальное |отклонение| по одной строке (район×эпоха) | **+209,78 %** (r-brahinski, 2015: сумма клеток 38 505,3 против официальных 12 430,0) |
| Национальное отклонение по эпохам (допуск ±1 %) | 1975: +2,34 % · 1980: +2,32 % · 1985: +2,21 % · 1990: +2,25 % · 1995: +3,35 % · 2000: +2,81 % · 2005: +1,69 % · 2010: +2,84 % · 2015: +2,65 % · 2020: +3,02 % |

**Порог.** ±3 % по району, ±1 % по стране.
**Пройдена ли сырым продуктом?** **НЕТ.** 119 из 119 территорий (далеко за
порогом «более 15» раздела 13 ТЗ) и все 10 национальных точек вне допуска.

**Что сделано при провале.** Раздел 13 ТЗ на случай провала более чем 15
районов предписывает: районные абсолютные числа снимаются, публикуются
национальные/областные показатели, карта подаётся как иллюстрация рисунка
расселения. Найдено более сильное и более прозрачное решение того же
семейства (сама методика раздела 13 ТЗ называет «constrained»-подход
WorldPop запасным продуктом того же типа): **constrained dasymetric
redistribution** — клетки каждого района домножаются на коэффициент
`official(epoch)/raw_grid_sum(epoch)`, так что сумма клеток района/страны
становится ТОЧНО равна официальному ряду. После этого шага **G-1 выполняется
по построению** — это не эмпирический тест, а тождество, и `sources/raw/
metrics_observed.json → reconciliation_summary.calibration_applied` явно
помечает это текстом. Полное расследование (проверка геометрии маски,
проверка гипотезы «нужно прибавлять город отдельно» — отклонена, находка
про метаданные JRC о переписи 2009 года, голосование трёх ролей 3:0
«одобрить с условиями») — `docs/notes/grid_validation.md`.

**Список районов вне допуска.** Полный, неотредактированный результат
сырой сверки (1190 строк = 119 территорий × 10 эпох, включая проходные и
непроходные строки, поля `grid_sum`, `official`, `pct_diff`, `pass`) —
`sources/raw/reconciliation.csv`. Не копируется в этот документ построчно;
уникальный список территорий, хоть раз вышедших за допуск (все 119) —
`sources/raw/metrics_observed.json → reconciliation_summary.failed_raions_ever`.

---

## G-2. Сходится ли прогноз по клеткам с прогнозом по районам

**Порог.** Сумма клеток района на прогнозный год = прогноз района ±0,1 %,
проверяется для всех сценариев/вариантов.

**Результат.**

| | значение |
|---|---|
| Проверок (район × год × сценарий × вариант) | **4284** |
| Максимальное |отклонение| по факту | **0,0 %** |
| Допуск | 0,1 % |

**Пройдена: ДА.** Нормировка клеток к прогнозу района работает точно (это
и есть цель шага — прогноз по клеткам не подменяет уже опубликованный
прогноз проекта, а лишь распределяет его внутри района). Построчный отчёт
всех 4284 проверок — `sources/raw/g2_reconciliation.csv`.

---

## G-3. Согласны ли с независимым сенсором (ночная светимость)

**Порог.** Направление изменения численности (2012→2020) совпадает со
знаком изменения светимости минимум для 70 % районов.

**Результат.**

| | значение |
|---|---|
| Районов проверено | **119** |
| Согласие знака | **32,8 %** (39 из 119) |
| Порог | 70 % |
| «Население упало, свет вырос» (доминирующий паттерн) | 76 из 119 (**63,9 %**) |
| «Оба упали» | 30 из 119 (25,2 %) |
| «Оба выросли» | 9 из 119 (7,6 %) |
| «Население выросло, свет упал» | 4 из 119 (3,4 %) |
| Согласие у «районов-хозяев городов» | 36,4 % (4 из 11) |
| Согласие у остальных районов | 32,4 % (35 из 108) |

**Пройдена: НЕТ** (32,8 % < 70 %).

**Что сделано при провале.** Применён буквально предписанный разделом 7 ТЗ
(проверка 3) fallback: расхождение двух сенсоров стало главным
дополнительным сюжетом исследования (отдельная видная панель на странице),
а утверждения C-1 и C-2 переведены в статус **«открытый вопрос»**
(`claims.yaml`), а не «подтверждено». Расхождение не сосредоточено в
группе «районов-хозяев городов», вызывавшей опасения при ревью calibровки
(36,4 % там против 32,4 % у остальных — сопоставимо низко в обеих группах),
то есть это общестрановой эффект, не артефакт калибровки G-1. Вероятная
(не доказанная причинно) гипотеза — модернизация уличного освещения (LED),
отвязанная от численности населения. Полный отчёт находки —
`docs/decisions/INF-15.md` D-007; построчные данные —
`sources/raw/g3_nightlights_rows.csv`.

---

## G-4. Не объясняется ли всё Полесьем и Чернобылем

**Порог.** Рост `area_share_below(5)` (1975→2020) сохраняется после
исключения полесских (27) и чернобыльских (12) районов из числителя И
знаменателя.

**Результат.**

| | значение |
|---|---|
| Районов исключено (объединение списков, 3 в пересечении) | **36** |
| `area_share_below(5)`, 1975 (без Полесья/Чернобыля) | 0,6828 |
| `area_share_below(5)`, 2020 (без Полесья/Чернобыля) | 0,7120 |
| Рост 1975→2020 | **+0,0292** |
| Монотонность (нет падения между соседними эпохами свыше шума 0,5 п.п.) | да |
| Для сравнения: полный ряд (119 территорий), 1975→2020 | 0,7155 → 0,7422 |

**Порог.** Рост > 0 и монотонность сохраняются.
**Пройдена: ДА.**

---

## G-5. Устойчив ли центр масс населения

**Порог.** Трек центра масс сдвигается менее чем на 15 км при альтернативных
разумных допущениях (случайное дифференцированное по районам возмущение
веса ±10 % для дореволюционных/довоенных лет; порог заселённости ≥5 вместо
>0 при взвешивании клеток для лет, где есть сетка).

**Результат (сдвиг по годам, км).**

| Год | Сдвиг, км | | Год | Сдвиг, км |
|---|---:|---|---|---:|
| 1897 | 0,00 | | 1995 | 0,04 |
| 1959 | 0,00 | | 2000 | 0,04 |
| 1970 | **2,03** | | 2005 | 0,05 |
| 1975 | 0,08 | | 2010 | 0,06 |
| 1980 | 0,07 | | 2015 | 0,07 |
| 1985 | 0,07 | | 2020 | 0,07 |
| 1990 | 0,05 | | | |

**Максимальный сдвиг: 2,03 км** (год 1970), допуск 15 км.
**Пройдена: ДА** (с большим запасом).

---

## G-6. Полна ли карта дорог

**Порог.** Сумма длины сети OSM против официальной статистики протяжённости
дорог — расхождение ≤15 %.

**Результат.**

| | значение |
|---|---|
| OSM-сумма (снимок INF-04, только 5 классов + `_link`) | **76 958,8 км** |
| Официальная статистика (РУП «Белдорцентр», 01.01.2026) | **86 446,0 км** |
| Δ | **−10,97 %** |
| Допуск | ±15 % |
| Режим публикации `network_per_capita` | `absolute` (абсолютные км, не только индекс) |

**Пройдена: ДА.** Разбивка OSM-суммы по классам: motorway 1013,3 км
(+109,2 `_link`), trunk 4471,2 (+447,6), primary 13 257,8 (+154,7), secondary
7887,7 (+23,8), tertiary 49 559,2 (+34,3) — tertiary даёт **≈64 %** длины
снимка. Снимок содержит только 5 классов из 8 возможных (нет
residential/unclassified/track) — официальная статистика включает ВСЕ
дороги общего пользования, поэтому сравнение сделано только по общему
итогу против общего итога, без сопоставления классов 1:1 (административная
и функциональная классификации не совместимы напрямую). Риск односторонний:
доснятие недостающих классов могло бы только приблизить сумму к
официальной — пройденный результат «робастный», не «на грани». Полный
отчёт — `docs/notes/grid_network_findings.md`, разделы 1–2.

---

## G-7. Ни одного числа без подтверждения

**Порог.** Каждое число со страницы присутствует в контрольном списке
внутри архива (`checks/expected_results.json`).

**Результат.** **20** контрольных метрик, покрывающих: национальные ряды
(area_share_below, обе плотности), G-1 (число провалившихся районов,
максимальное расхождение), G-2 (максимальное отклонение), G-3 (процент
согласия, число районов), G-4 (рост без Полесья/Чернобыля), G-5
(максимальный сдвиг), settlement_components (число «островов», доля
крупнейшего), G-6 (сумма OSM, отклонение, факт прохождения), C-3
(коэффициент Спирмена, log10 p-value).

**Пройдена: ДА.** Список — `checks/expected_results.json`; сверка —
`code/verify.py` (запускается `bash code/run.sh`).

---

## G-8. Скорость и вес

**Порог.** Все кадры карты вместе ≤12 МБ; первая загрузка страницы ≤3,5 МБ;
один кадр ≤220 КБ.

**Результат (`params/assumptions.yaml → budgets`).**

| | значение | бюджет |
|---|---:|---:|
| `grid.json` (материализуется сборкой) | ≈202 КБ (206 694 байт на момент написания) | 1536 КБ |
| Все кадры вместе | **2,82 МБ** | 12,0 МБ |
| Максимальный размер одного кадра | **220 КБ** | 220 КБ |

**Пройдена: ДА**, но по размеру одного кадра — **впритык, без запаса**
(фактическое значение равно самому бюджету). Проверка веса первой загрузки
страницы (≤3,5 МБ) выполняется на опубликованном сайте разработчиком
страницы (этап 6 ТЗ) и не входит в данные этого архива — измерение веса
кадров и `grid.json` относится к данным, измерение первой загрузки страницы
целиком — к готовому сайту.

---

## Сводная таблица

| # | Проверка | Результат (число) | Порог | Статус |
|---|---|---|---|---|
| G-1 | Сходство с офиц. числами | 119/119 территорий вне допуска (сырой); после калибровки — тождество | ±3 %/район, ±1 %/страна | не пройдена сырым продуктом → исправлено calibровкой (по построению) |
| G-2 | Прогноз клеток = прогноз района | макс. откл. 0,0 % из 4284 проверок | ±0,1 % | пройдена |
| G-3 | Согласие с независимым сенсором | 32,8 % (39/119) | ≥70 % | **не пройдена** — fallback применён (C-1/C-2 = открытый вопрос) |
| G-4 | Устойчивость к Полесью/Чернобылю | рост +0,0292 (0,6828→0,7120), 36 районов исключено | рост > 0, монотонно | пройдена |
| G-5 | Устойчивость центра масс | макс. сдвиг 2,03 км | <15 км | пройдена |
| G-6 | Полнота карты дорог | Δ = −10,97 % (76 958,8 vs 86 446,0 км) | ±15 % | пройдена |
| G-7 | Покрытие контрольным списком | 20 метрик | 100 % чисел страницы | пройдена |
| G-8 | Вес и скорость | 2,82 МБ кадров, кадр 220 КБ, grid.json ≈202 КБ | 12 МБ / 220 КБ / 3,5 МБ | пройдена (кадр — впритык) |

Итог: **семь из восьми проверок пройдены** (одна из них, G-1, — по
построению после исправления методики, не как исходный эмпирический тест);
**одна не пройдена** (G-3) — с предписанным разделом 7 ТЗ честным
fallback'ом, применённым без исключений во всех текстах пакета.
