🗺️ Roadmap: value-модель и сильный алгоритм

Как читать

Это живой документ: статусы и даты правим по месту, историю решений держит журнал. Каждый шаг имеет гейт — проверяемое условие, без которого на следующий шаг не переходим. Обоснование всей архитектуры: win-probability-for-sparse-positions.

Статусы: ✅ готово · 🔄 в работе · ⏳ ждёт гейта · 📋 запланировано · 🧊 горизонт

Шаг 0 — чистые данные и Brier-бенчмарк ✅

Фундамент обеих веток (prior аналитики и eval бота): на каких метках учимся и как сравниваем оценщиков.

  • Решение по фильтру меток: только termination = king_captured — разом отсекает таймауты (проигрыш по часам ≠ качество позиции), отказы от удвоения (double_declined = поражение без доигрывания), ранние договорные ничьи турниров и частичные финальные ходы (они бывают только у timeout/draw/resign). Решено 2026-08-09.
  • Рейтинг на экспорте НЕ фильтруем: срезы и веса делаются в ev (train.py уже взвешивает: бот-партии 0.3, unrated 0.5, рейтинг-рампа 0.6–1.5).
  • Свежий экспорт training_data_kc_20260809.csv.gz — 1 330 746 партий / 19 992 727 строк за 12 мин (09.08).
  • Фильтрация kcp_full_20260803 до king_captured — 17,1 из 18,9 млн строк выжило (90,6%).
  • Переобучение на чистых метках (09.08): rich AUC 0.706 / rich+KCP AUC 0.728 (log-loss 0.602) / kcp-nodice 0.710 — KCP-фичи подтверждены, roll-aware сильнее dice-free; таблица в журнале.
  • Rich-обогащение свежего экспорта (20 млн строк за 8 мин) + переобучение rich на нём: AUC 0.7008 — стабильно с 02.08-снапшотом, дрейфа нет (09.08).
  • KCP-обогащение дельты — завершено chunk-раннером с автобисектом (09.08): 2 738 404 из 2 738 412 строк, 8 в карантине (4 партии с повёрнутой доской, движковый баг #549); beturanga-строки досчитаны отдельно — 125 764, карантин 0.
  • Слияние полного датасета: 19 991 736 строк, 0 дублей (training_data_kcp_full_20260809.csv.gz).
  • Флагман переобучен на полном корпусе — kcpdice_full_20260809: AUC 0.7260 / log-loss 0.6032 против 0.7280 / 0.6021 на снапшоте 02.08. Вывод: 🔑 объём данных исчерпан как рычаг, ограничивают фичи (тот же результат независимо показал rich); king_capture_attack — фича №2 по важности.
  • После мержа #593 и бампа движка — пересчитать 8 карантинных строк (косметика: 0,0004% корпуса).
  • Изотоническая пост-калибровка — померено, НЕ требуется (0.2132 против 0.2132 по Brier; модель уже откалибрована).
  • Brier-бенчмарк собран (холдаут 2 млн ходов, сегментация по частоте позиции): модель выигрывает у эмпирики во всех сегментах, включая n≥10; смесь (w+α·prior)/(n+α) проигрывает чистой модели (α упирается в максимум сетки); эмпирика по (позиция+бросок) хуже, чем по позиции. MC: MAE 4,5 пп, сохраняет 43% сигнала, 25 с/позицию.
  • rawboard_l000 в бенче не участвовал (требует своей фича-сборки) — добить при возврате к шагу 3(b).

Гейт взят 09.08. Решение по итогам: 🔑 вероятность считает модель — одна, без смеси и без пост-калибровки; эмпирика остаётся в explorer’е как описательные данные головы распределения, но в оценку не подмешивается; MC уходит из горячего пути. Подробности и таблицы — журнал; исходный план с пометками об опровержении — win-probability-for-sparse-positions.

Шаг 1 — измерительный стенд силы 📋

Прежде чем «улучшать алгоритм» — договориться, как меряем. Уроки: «плато K=24», которого не было (400 партий дают ±4–5 пп) и разворот эффекта K=all по контролю.

  • Целевые контроли: 3+2 — основной (все текущие дуэли уже на нём), 10+10 — вторичный (качество без цейтнота).
  • Зафиксировать протокол вердикта: парные партии с зеркальными костями, 1600 партий (разрешение ~2 пп) или SPRT; seeded-прогоны.
  • Референс-скрипт стенда (referee/timed-arena чанками, как на текущих дуэлях) — задокументировать как «стандартный замер».

Гейт: любой будущий «+X пп» принимается только со стенда.

Шаг 2 — учитель размечает ✅

Учитель = медленный сильный оценщик; его роль — не играть, а размечать позиции для дистилляции и prior-прекомпьюта.

  • Уже готово заранее: training_data_kcp_full_20260803.csv.gz — KCP-разметка всей базы (снапшот 02.08) сделана облачным CPU-прогоном ещё до этого плана.
  • Дельта дозаметена (09.08) — считал MacBook, а не Azure: временная ВМ дважды умерла на движковом баге и была снесена, счёт ~€2 (см. журнал).
  • Решить, нужен ли учитель сильнее статики (2-ply поверх лучшей модели) для следующего витка дистилляции.

Гейт взят: KCP-покрытие = весь актуальный корпус (19 991 736 строк), непокрыто 8 карантинных строк.

Шаг 3 — студент: быстрый наследник учителя ⏳

  • (a) LightGBM-дистиллят — проверено 09.08, НЕ работает больше: свип lambda даёт разброс 0.0003 AUC, лучшая точка — контроль (чистый rich). Июльские +2.2 пп были эффектом малых данных; на 20 млн строк rich-9 насыщен. Переобучение rich на свежем корпусе даёт Brier −0.0016 — арену на это не тратим (неизмеримо).
  • (b) Raw-board / MLP — ЗАКРЫТА как игрок, замерено 12.08. Timed-дуэль rawboard-1 vs oracle-3 (K=24, 3+2, зеркальные кости, 7 400 партий): 46.37%, ci95 ±0.99 пп → −25 elo. Условие «дешевизна разрыв не отыгрывает» подтвердилось, причём решает не win-rate, а 0/0 поражений по времени на всех промежуточных срезах: сеть проигрывает оценкой, а не тем, что не влезает в часы. Согласуется с поправкой, что rawboard оказался ~5× дороже rich за оценку, а не дешевле. Как кандидат prior’а остаётся в бенче шага 0. Сырые данные: dicechess-ev, logs/timed-duel-rawboard-2026-08-12/.
  • 🔑 (c) NNUE-прототип — теперь ЕДИНСТВЕННЫЙ оставшийся рычаг (PyTorch/MPS → офлайн-сравнение), см. what-is-nnue. Три замера 09.08 (данные, дистилляция, ретрейн) показали, что rich-9 упёрся в фичи, а KCP-фичи дают 5% по Brier, но не влезают в бюджет листа. Рукописный инференс в движке — только после доказанной силы офлайн.

Гейт: студент ≥ учитель − ε по log-loss на holdout при цене ≤ бюджета листа поиска.

Шаг 4 — студент в поиске → oracle-4 📋

  • 2-ply expectimax поверх студента; K подбирается под контроль (урок ev#14: потолок K растёт с бюджетом времени).
  • Wall-clock дисциплина: TimeManager/deadline на ход.
  • Парная дуэль против oracle-3 на стенде шага 1.

Гейт: статистически значимый плюс на 3+2 → деплой как oracle-4.

Продуктовый трек: анализ партий 📋

Применение готовых serving-моделей к просмотрщику партий — дизайн: game-analysis-design. Не зависит от шагов 3–5 (использует уже задеплоенные модели), поставляется фазами:

  • Фаза 1 — шкала оценки (только UI, бэкенд готов): точка на границе каждого хода от 13-входовой модели — analytics-ui#206.
  • Фаза 2 — удача против решения: roll-aware эндпоинт для kcpdice_serving (19 входов, EV_ROLL_MODEL_PATH) — analytics#276; полоски «что дали кости / что сделал игрок».
  • Фаза 3 — оценка ходов: грейдер TurnGenerator × модель — analytics#277; winrate-loss, зевки, accuracy. Порог зевка калибруется по mine_blunders.py (задача в ev).

Гейт фазы 3: цена типичного хода ≤ ~3 с на 4 ядрах (померено, не угадано) и корректная деградация на деплоях без моделей.

Шаг 5 — self-play / TD 🧊

Вторая половина замысла ev#16: TD self-play снимает зависимость от качества человеческих меток. Заводить только после полного оборота цикла «учитель → студент → поиск» и работающего стенда.


Ресурсы и дедлайны

  • MacBook — экспорт, rich-обогащение, LightGBM, калибровка, бенч, прототипы сетей (MPS).
  • Azure-кредит €150 — остаётся под арены и возможные GPU-свипы шага 3(c). При круглосуточных ВМ горит ~€9.4/день; четыре ВМ заняты дуэлями. 🔑 Квота кредитной подписки — 4 vCPU на регион, и поверх неё capacity-ограничения: из пяти проверенных регионов D4 нашёлся только в polandcentral.
  • Бюджетный алерт на кредитной подписке не предупреждает об истощении кредита — следить руками (Cost Management → Credits).