go-learn/docs/plans/plan-phase-4.md
sab.code.lab 1c85091186 chore: восстановление репозитория из снапшота v0.3.1
Прежняя git-история утрачена при переносе проекта на машину владельца
(снапшот без .git). Хэши коммитов в docs/reports/* относятся к утраченной
истории.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-07 09:34:02 +02:00

81 lines
6.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# План фазы 4: этап 4 — ИИ ур. 46, MCTS + Web Worker (packages/ai)
Обновлено: 2026-08-05 | Статус: реализовано (гейты зелёные, 118 тестов)
## Критические долги (реестр — в начале, III.5)
- Нет.
## Ключевые решения (не пере-решать)
- MCTS-движок — чистый модуль в packages/ai (без воркер-API); воркер — тонкая
обёртка worker.ts с абстракцией порта. Однопоточно (без SharedArrayBuffer —
COOP/COEP на шареде не гарантированы).
- Плейаут — «лёгкая» политика, НЕ chooseMove этапа 3: тот сканирует всю доску
через applyMove на каждый ход (~мс на ход) — в плейауте непозволительно.
Лёгкая: дешёвая реакция на атари у последнего хода + случайные точки с
фильтром своего глаза и лимитом попыток. Компромисс силы ради бюджета —
зафиксирован здесь.
- Бюджеты: {4: 300, 5: 800, 6: 1500} мс; ур.5 — дефолт между уровнями (спека
задаёт только крайние) — записано в контракте.
- Сериализация позиции в протоколе — списком ходов от пустой доски (воркер
пересобирает и валидирует через applyMove), не снапшотом grid.
- cancel → воркер отвечает result с лучшим найденным, не молчит и не error.
- maxSimulations — override для детерминированных тестов.
- Контракт — docs/INTERFACES.md (зафиксирован 2026-08-05 до кода).
## Объём этапа 4
1. packages/ai/src/mcts.ts — дерево UCT (c=1.4), ленивая экспансия, лёгкий
плейаут, оценка scorePosition с komi, бюджет clock/shouldStop/maxSimulations,
topMoves (до 3) для подсказки этапа 5.
2. packages/ai/src/worker-protocol.ts — типы WorkerRequest/WorkerResponse +
пересборка BoardState из списка ходов (валидация, error при нелегальном).
3. packages/ai/src/worker.ts — тонкая обёртка порта (onmessage → choose →
result/error; cancel → result с лучшим найденным).
4. index.ts — экспорты движка и протокола.
## Тесты (гейт приёмки этапа)
- Детерминизм: maxSimulations=50 + фиксированный seed → идентичный move и
topMoves в двух прогонах на одной позиции.
- Легальность: ход MCTS легален на случайных позициях (запиненные seed'ы,
9×9 и 13×13); pass возвращается, только если легальных постановок нет или
он лучший по визитам (в любом случае applyMove не падает).
- Бюджет: фейк-clock (счётчик now()) — остановка по deadline; shouldStop() —
остановка после N симуляций, ответ всегда с легальным ходом.
- Качество (мягкий): MCTS ур.4 с maxSimulations=200 забирает группу в атари
на сконструированной позиции (где эвристика ур.1 с rng 0.99 пропускает) —
не эталон силы, а smoke «дерево реально ищет».
- Протокол: фейк-порт — choose → result с тем же requestId; нелегальный список
ходов → error; cancel активного → result, не error; cancel чужого id →
без эффекта.
- Полная партия 9×9 бот(MCTS ур.4, maxSimulations=100) против бота ур.3 —
завершается до over; все ходы легальны (предпосылка критерия v1 №2).
- Perf-smoke: 1500 мс бюджета → ≤ ~2.2 с фактически (overhead кроме симуляций
мал); число симуляций за 300 мс на 9×9 — в отчёт.
- Wiring: orphan-check обновить под новые экспорты.
## Критерий выхода
Все тесты зелёные + `npm run gates` зелёный. Критерий v1 №3 («ур.6 < 2 с на
среднем ноутбуке») по бюджету 1500 мс + overhead; факт в отчёт сессии.
## Пометки по факту реализации (2026-08-05)
- Все пункты объёма и тестов выполнены; гейты зелёные (118 тестов, lint без
предупреждений). Perf-факты: ~147 симуляций за 300 мс на 9×9; ур.6 на
13×13 фактически ~1500 мс (бюджет 1500 мс + overhead < 5 мс).
- Экспансия untried-детей в детерминированном порядке legalMoves, первыми
идут ходы со снятием камней (захваты разворачиваются в дерево раньше).
Контракт порядок экспансии не оговаривает эвристика внутри рамок UCT;
без неё сигнал качество-smoke (захват группы за 200 симуляций) не
выделяется на фоне шума плейаутов.
- createWorkerHandler(port, deps?) необязательный второй параметр
WorkerDeps с инжектируемыми часами (в контракте «функция вида…»): нужен
для детерминированных тестов протокола (фейк-часы, реентерабельный cancel
из колбэка now()).
- Качество-smoke: позиция «кольцо в атари + сплошные стены» единственная
из проверенных конструкций, где захват даёт устойчивый перекос winRate в
случайных плейаутах (≈0.95 против 0.57). Seed запинен: при 200 симуляциях
захват выбирается в ~75% seed'ов (при 800 12/12).