Расследование ошибки в партии e7a94f8d-f7a6-11f0-bb4c-4725c2f0a926

Причина ошибки кроется в баге на стороне самого сервера dicechess.com, который пропустил запись одного из микро-ходов в историю, из-за чего наш движок валидации в аналитике посчитал ход нелегальным.

Ниже подробный разбор того, какой код за это отвечает и что произошло внутри данных.


1. Какой код отвечает за обработку и ошибку?

  1. Конвертация (Сборщик): В репозитории dicechess-sync файл normalize.ts разбирает сырой gameMoveHistoryStateMap от сайта. Он берет ходы из поля gameMoveHistoryMove каждого узла состояния:
    } else if (move) {
      let uci = `${move.from.toLowerCase()}${move.to.toLowerCase()}`;
      if (move.promotion && move.promotion !== "NONE") uci += PROMO_TO_CHAR[move.promotion] ?? "q";
      curMoves.push(uci);
    }
  2. Валидация (Аналитика): В репозитории dicechess-analytics файл GameReplay.scala воспроизводит ходы через Scala-движок и сверяет их с легальными путями из TurnGenerator.
    • Правило максимального потребления кубиков (Maximum Micro-moves Rule): Движок требует, чтобы ход использовал максимальное количество доступных кубиков (в данном случае все 3). Если ход использует меньше кубиков, чем возможно, он считается нелегальным (IllegalTurn).

2. Что произошло в данных (Ход 17)

Давайте посмотрим на состояния в присланном вами файле 2026-06-25T183822.200.json на 17-м ходу (состояния 75, 76 и 77 в истории):

Шаг 75 (Начало хода черных)

  • FEN: rnk1r3/pppb1Npp/3P1p2/3p4/6n1/2Q5/PPPBP1PP/1R2KB1R b - - 2 1 (Черные, на доске есть черный пешка на d5, белый ферзь на c3 и черная ладья на e8).
  • Кубики: [p, p, r] (Пешка, Пешка, Ладья).
  • Ход: null (просто бросок кубиков).

Шаг 76 (Первый микро-ход)

  • Ход: { "from": "D5", "to": "D4" } (черная пешка ходит d5 -> d4).
  • FEN: rnk1r3/pppb1Npp/3P1p2/8/3p2n1/2Q5/PPPBP1PP/1R2KB1R b - - 0 1 (пешка теперь на d4, ферзь на c3).
  • Использован кубик: 1-я пешка (p). Остались: пешка (p) и ладья (r).

Шаг 77 (Второй и третий микро-ходы — здесь баг сервера сайта)

  • Ход: { "from": "E8", "to": "F8" } (черная ладья ходит e8 -> f8).
  • FEN: rnk2r2/pppb1Npp/3P1p2/8/6n1/2p5/PPPBP1PP/1R2KB1R b - - 1 0
  • Проблема: Посмотрите на изменения в FEN между шагом 76 и 77:
    1. Ладья переместилась с e8 на f8 (согласно ходу).
    2. Пешка с d4 переместилась на c3 (взяв белого ферзя!).

Сервер сайта обработал взятие ферзя пешкой (d4c3), изменил FEN, но забыл записать этот ход в массив gameMoveHistoryMove! Он сразу перепрыгнул на шаг 77, где записал только последний ход ладьей (e8f8), сохранив при этом результирующий FEN, где выполнены оба хода.

Результат парсинга:

Наш краулер собрал список ходов для этого хода: ["d5d4", "e8f8"] (взятие d4c3 потерялось, так как его не было в истории).

Результат валидации движком:

Движок видит кубики [p, p, r]. С этими кубиками у черных была возможность сделать три хода (включая взятие d4c3). Попытка сыграть только два хода ["d5d4", "e8f8"] нарушает правило максимального количества микро-ходов и отклоняется движком как нелегальная.


Как это выглядит на сайте?

На сайте игра выглядит нормально, потому что фронтенд сайта (или его внутренний парсер) восстанавливает ход d4xc3 динамически, сравнивая разницу FEN-ов между шагами, либо используя список ходов из другого внутреннего поля, недоступного в стандартном API истории шагов.


Что делать с этой ошибкой?

Поскольку эта ошибка вызвана битыми данными на сервере сайта, а не багом в нашем коде, у нас есть несколько путей:

  1. Просто пропустить эту партию (Рекомендуется): В вашей базе данных из 63 985 партий только одна получила статус rejected (это как раз e7a94f8d...). Доля таких ошибок ничтожно мала (0.0015%). Проще всего оставить её в статусе rejected / skipped и не тратить ресурсы на усложнение парсера.
  2. Написать костыль-обходчик в normalize.ts: Мы можем добавить проверку конкретно для этого gameId, и если это он — принудительно вставлять ход d4c3 между d5d4 и e8f8.
  3. Написать полноценный FEN-дефайлер: Анализировать разницу FEN между шагами истории и автоматически генерировать пропущенные ходы (сложно в реализации и тестировании из-за правил рокировок/превращений).