chore: восстановление репозитория из снапшота v0.3.1
Прежняя git-история утрачена при переносе проекта на машину владельца (снапшот без .git). Хэши коммитов в docs/reports/* относятся к утраченной истории. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
commit
1c85091186
184 changed files with 33303 additions and 0 deletions
40
docs/plans/plan-phase-1.md
Normal file
40
docs/plans/plan-phase-1.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# План фазы 1: этап 1 — движок правил (packages/core)
|
||||
|
||||
Обновлено: 2026-08-05 | Статус: завершена (этап 1 принят, гейты зелёные)
|
||||
|
||||
## Критические долги (реестр — в начале, III.5)
|
||||
|
||||
- Нет.
|
||||
|
||||
## Ключевые решения (не пере-решать)
|
||||
|
||||
- Профиль проекта M, триаж литании — ADR-0001.
|
||||
- Подсчёт — китайские правила (Tromp-Taylor), не японские: однозначно алгоритмизируется.
|
||||
- Группы/дамэ: flood fill или union-find — выбрать по бенчмарку в этапе 1, выбор — в ADR.
|
||||
- Ко: простое ко + позиционное суперко (оба, суперко нужен для китайских правил).
|
||||
- Определение мёртвых групп — отдельная функция + ручная корректировка игроком,
|
||||
не авто-анализ.
|
||||
|
||||
## Объём этапа 1
|
||||
|
||||
1. Доски 9×9, 13×13, 19×19; позиция — типизированный массив.
|
||||
2. Группы и дамэ, снятие камней, запрет самоубийства (кроме самоубийства с захватом),
|
||||
простое ко и суперко.
|
||||
3. Подсчёт Tromp-Taylor; коми 6.5 (19×19) / 5.5 (9×9); сэки обрабатывается корректно.
|
||||
4. SGF FF[4]: парсер и генератор (ходы, вариации, комментарии, разметка LB/TR/SQ/CR).
|
||||
5. История с откатом и ветвлением.
|
||||
6. Контракты — сначала в docs/INTERFACES.md, потом код.
|
||||
7. Бенчмарк flood fill vs union-find → ADR-0002.
|
||||
|
||||
## Тесты (гейт приёмки этапа)
|
||||
|
||||
- Захват камня и группы; запрет самоубийства; самоубийство с захватом (легально);
|
||||
простое ко; суперко; сэки при подсчёте; ничья.
|
||||
- Wiring: orphan-check «кто вызывает» по каждой публичной функции ядра
|
||||
(`gotcha-green-modules-dead-system`).
|
||||
- Интеграционный тест полной партии (по заранее записанной SGF).
|
||||
- Property-based тесты инвариантов (fast-check): инварианты — в docstring функций.
|
||||
|
||||
## Критерий выхода
|
||||
|
||||
Все тесты зелёные + `npm run gates` зелёный. К этапу 2 не переходим без этого.
|
||||
59
docs/plans/plan-phase-10.md
Normal file
59
docs/plans/plan-phase-10.md
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# План этапа 10 — дизайн-перенос (Kimi WebSites → каркас Astro)
|
||||
|
||||
Дата: 2026-08-06. Ветка интеграции: main.
|
||||
|
||||
## Контекст
|
||||
|
||||
Пользователь получил от Kimi WebSites переносной пакет дизайна
|
||||
(«васи + гобан», светлая тема, индиго + терракота). Эталон распакован и
|
||||
сохранён в `docs/design/kimi-export/`. Задача — натянуть дизайн на
|
||||
существующий каркас, не трогая логику, контент, API и тесты.
|
||||
|
||||
Контракт: `docs/INTERFACES.md`, раздел «Дизайн-перенос (этап 10)» —
|
||||
токены (с 3 правками контраста), каркас Layout, тема доски, изображения,
|
||||
паттерны страниц, критерии приёмки.
|
||||
|
||||
## Стадии
|
||||
|
||||
### Стадия 0 (оркестратор, сделано)
|
||||
|
||||
- Распаковка пакета, сжатие изображений в `apps/web/public/assets/`
|
||||
(hero 53КБ / ink 118КБ / stones 24КБ).
|
||||
- Эталон в `docs/design/kimi-export/`, контракт в INTERFACES.md.
|
||||
|
||||
### Стадия 1 — параллельные кодеры (3 ветки)
|
||||
|
||||
- **design-a (фундамент)**: Layout.astro (глобальные стили = адаптация
|
||||
kimi-export/style.css + правила [hidden]/go-task, шапка/подвал/проп
|
||||
section/мобильное меню/шрифты), packages/board render.ts DEFAULT_THEME →
|
||||
светлая, index.astro (hero+features+ink-band+home-strip). Файлы:
|
||||
`apps/web/src/layouts/Layout.astro`, `packages/board/src/render.ts`,
|
||||
`apps/web/src/pages/index.astro`, при необходимости
|
||||
`apps/web/src/ui/strings.ts` (только новые строки главной).
|
||||
- **design-b (контентные страницы)**: learn.astro, learn/[id].astro,
|
||||
tsumego.astro, progress.astro — разметка по паттернам контракта,
|
||||
логика/id/data-атрибуты не меняются.
|
||||
- **design-c (страницы приложения)**: play.astro, account.astro,
|
||||
register.astro, password-reset.astro — то же правило.
|
||||
|
||||
Пересечений по файлам нет (Layout только у A). Общий API — проп
|
||||
`section` Layout, описан в контракте.
|
||||
|
||||
### Стадия 2 — интеграция (оркестратор)
|
||||
|
||||
- Слияние веток в main, разрешение конфликтов.
|
||||
- Гейты, точечные правки (wiring/тема-тесты).
|
||||
- Проверка веса страниц dist и контраста.
|
||||
- Сборка dist → `/mnt/agents/output/app`, НОВАЯ версия превью
|
||||
(website_version_manager) — старая рабочая версия остаётся для сравнения.
|
||||
|
||||
### Стадия 3 — ритуал закрытия
|
||||
|
||||
- PROJECT_STATE.md (0.3.0), отчёт session-10, docs(sync) коммит, zip.
|
||||
|
||||
## Риски
|
||||
|
||||
- Слияние: Layout меняет только A — конфликтов не ожидается; strings.ts
|
||||
могут трогать A и B — B не трогает strings (правило в брифе).
|
||||
- Контраст исправлен на уровне токенов — регрессий быть не должно.
|
||||
- Вес главной: hero 53КБ + CSS/JS — в бюджете.
|
||||
60
docs/plans/plan-phase-11.md
Normal file
60
docs/plans/plan-phase-11.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# План этапа 11 — аудит контента, страница «Источники», дисклеймер
|
||||
|
||||
Дата: 2026-08-07. Инициатор: владелец. Ветка интеграции: main.
|
||||
|
||||
## Вводные
|
||||
|
||||
Владелец спросил, насколько можно доверять обучающему контенту. Ответ:
|
||||
движок и проверка задач — машинно проверены; проза уроков и база цумэ-го
|
||||
написаны ИИ без рецензии сильного игрока. Решение владельца:
|
||||
|
||||
1. Провести аудит контента по авторитетным источникам (обязательно).
|
||||
2. Сделать на сайте отдельную страницу «Источники» — только голые
|
||||
проверяемые факты. Чего не нашли — пишем «не найдено». Выдумывать
|
||||
источники и факты КАТЕГОРИЧЕСКИ ЗАПРЕЩЕНО (требование владельца).
|
||||
3. Добавить дисклеймер об открытом редактировании курса.
|
||||
|
||||
## Стадии
|
||||
|
||||
### Стадия 0 (оркестратор)
|
||||
|
||||
- Контракт в INTERFACES.md (этап 11): правила аудита, формат страницы
|
||||
источников, текст и размещение дисклеймера.
|
||||
|
||||
### Стадия 1 — аудит (3 параллельных research-агента)
|
||||
|
||||
- audit-1: уроки 01–03 (дамэ/захват, атари/лестница/сеть, самоубийство/ко).
|
||||
- audit-2: уроки 04–07 (глаза, подсчёт/коми, связь/разрезание, фусэки).
|
||||
- audit-3: уроки 08–10 (дзёсэки — конкретные последовательности!, форма,
|
||||
ёсэ) + специфические числовые утверждения всего курса.
|
||||
|
||||
Каждый агент: читает markdown уроков из репо, извлекает проверяемые
|
||||
утверждения, ищет подтверждения в авторитетных источниках (Sensei's
|
||||
Library, Wikipedia, BGA/AGA, gobase и т.п.), КАЖДЫЙ источник обязан
|
||||
реально открыть инструментом и процитировать подтверждающую строку.
|
||||
Вердикты: ПОДТВЕРЖДЕНО (URL + цитата) | НЕ НАЙДЕНО | РАСХОЖДЕНИЕ (что
|
||||
именно расходится). Отчёт — markdown-файл docs/audit/NN.md, коммит в
|
||||
ветку audit/rN.
|
||||
|
||||
### Стадия 2 — интеграция (оркестратор + coder)
|
||||
|
||||
- Сверка отчётов, выборка подтверждённых источников (только реально
|
||||
открытые URL — оркестратор перепроверяет выборочно сам).
|
||||
- Страница /istochniki.html: по темам — факт + ссылка; раздел «что не
|
||||
удалось подтвердить» честно перечислен.
|
||||
- Дисклеймер: на странице курса и в футере (ссылка на «Источники»).
|
||||
- Если аудит нашёл РЕАЛЬНЫЕ ошибки контента — отдельный список владельцу;
|
||||
правки контента только с подтверждающим источником.
|
||||
|
||||
### Стадия 3 — приёмка и ритуал
|
||||
|
||||
- Гейты, вес, контраст; скриншот страницы источников; новая версия
|
||||
превью; PROJECT_STATE, отчёт, zip.
|
||||
|
||||
## Риски
|
||||
|
||||
- Главный риск — галлюцинация источников агентами. Митигация: правило
|
||||
«URL только из реально открытых страниц, с цитатой» + выборочная
|
||||
перепроверка оркестратором через web_open_url.
|
||||
- Sensei's Library и gobase могут быть медленными/недоступными — тогда
|
||||
честный «не найдено» по части утверждений.
|
||||
70
docs/plans/plan-phase-2.md
Normal file
70
docs/plans/plan-phase-2.md
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# План фазы 2: этап 2 — доска Canvas (packages/board)
|
||||
|
||||
Обновлено: 2026-08-05 | Статус: код и тесты готовы, gates зелёный (74 теста:
|
||||
43 core + 31 board). Осталось: визуальная проверка — на этапе 5.
|
||||
|
||||
## Пометки о ходе (2026-08-05)
|
||||
|
||||
- Объём выполнен целиком: geometry.ts, render.ts (тёмная тема по умолчанию),
|
||||
input.ts, dom.ts, index.ts; корневой tsconfig.json — reference на
|
||||
packages/board; зависимость @go-learn/core 0.1.0 в package.json пакета.
|
||||
- Все тесты из раздела «Тесты» ниже написаны и зелёные (31 тест board).
|
||||
- Отклонение: в packages/board/tsconfig.json нет references на ../core —
|
||||
`tsc -b --noEmit` (гейт typecheck) с project references падает с чистого
|
||||
состояния (TS6310, CLI --noEmit распространяется на referenced-проект,
|
||||
TS 5.9.3). Импорт резолвится через workspace-симлинк; подробности —
|
||||
комментарий в packages/board/tsconfig.json.
|
||||
- Уточнение семантики territory (в первой редакции контракта стороны не
|
||||
различались): структура TerritoryMap { black, white } с множествами ключей
|
||||
"x,y" по цветам — зафиксировано в контракте (правка main loop при приёмке).
|
||||
|
||||
## Критические долги (реестр — в начале, III.5)
|
||||
|
||||
- Нет.
|
||||
|
||||
## Ключевые решения (не пере-решать)
|
||||
|
||||
- Доска — Canvas 2D, не DOM/SVG (плавность на 361 пересечении) — мастер-промпт.
|
||||
- render(ctx, position, options) — чистая функция состояния, весь кадр из аргументов.
|
||||
- Геометрия, редьюсер ввода и рендер — headless-тестируемые; DOM — тонкий адаптер
|
||||
(setupCanvas, attachPointerInput), юнит-тестами не покрывается — см. матрицу
|
||||
«чего НЕ покрывает ни один тест» ниже.
|
||||
- Координаты — буквы без «I» (стандарт Го), числа снизу вверх.
|
||||
- Дефолтная тема — тёмная (мастер-промпт: минималистичный дизайн, тёмная тема).
|
||||
- Контракт — docs/INTERFACES.md, раздел «Контракт отрисовки доски» (зафиксирован
|
||||
2026-08-05 до кода).
|
||||
|
||||
## Объём этапа 2
|
||||
|
||||
1. packages/board: geometry.ts (computeGeometry, pointToPixel, pixelToPoint,
|
||||
hoshiPoints), render.ts (render + BoardTheme + дефолтная тёмная тема),
|
||||
input.ts (reduceInput), dom.ts (setupCanvas, attachPointerInput), index.ts.
|
||||
2. Отзывчивый размер и devicePixelRatio (setupCanvas).
|
||||
3. Хоси, координаты и номера ходов (переключаемые), фантомный камень,
|
||||
подсветка последнего хода, тач-ввод с подтверждением (первый тап — позиция,
|
||||
второй тап или confirm — ход), слои разметки (LB/TR/SQ/CR, заливка
|
||||
территории, приглушение мёртвых).
|
||||
4. Корневой tsconfig: references += packages/board; packages/board зависит от
|
||||
@go-learn/core (project reference).
|
||||
|
||||
## Тесты (гейт приёмки этапа)
|
||||
|
||||
- Геометрия: хоси для 9/13/19; roundtrip pixelToPoint∘pointToPixel; отклонение
|
||||
точки дальше половины клетки; padding при showCoordinates on/off.
|
||||
- Редьюсер ввода: тап → pending; второй тап по той же точке → commit; тап по
|
||||
другой точке → перенос; confirm без pending → commit null; cancel → сброс;
|
||||
тап мимо доски → без изменений.
|
||||
- Рендер: мок-ctx с записью вызовов — число камней = числу занятых клеток
|
||||
BoardState; фантом рисуется с phantomOpacity; метка последнего хода только
|
||||
при lastMove; LB/TR/SQ/CR из markup; заливка только для territory-ключей;
|
||||
мёртвые приглушены. Не проверяем каждый вызов — только инварианты.
|
||||
- Wiring: orphan-check по публичным функциям packages/board (вызывающие —
|
||||
тесты допустимы, дом-адаптер помечен как входная точка).
|
||||
- Матрица «чего НЕ покрывает ни один тест»: реальный вид кадра, pointer-события
|
||||
браузера, поведение на мобильном Safari — ручная проверка в этапе 5/7
|
||||
(смоук-сценарий, слой GUI — litany II.8).
|
||||
|
||||
## Критерий выхода
|
||||
|
||||
Все тесты зелёные + `npm run gates` зелёный. Визуальная проверка — на этапе 5
|
||||
(когда появится страница); до неё — demo-страница не нужна.
|
||||
53
docs/plans/plan-phase-3.md
Normal file
53
docs/plans/plan-phase-3.md
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# План фазы 3: этап 3 — ИИ ур. 1–3, эвристика (packages/ai)
|
||||
|
||||
Обновлено: 2026-08-05 | Статус: выполнен (gates зелёные; perf chooseMove 19×19 ≈ 8 мс)
|
||||
|
||||
## Критические долги (реестр — в начале, III.5)
|
||||
|
||||
- Нет.
|
||||
|
||||
## Ключевые решения (не пере-решать)
|
||||
|
||||
- Отдельный пакет packages/ai — core остаётся чистыми правилами (рекомендация
|
||||
отчёта сессии 2, принято).
|
||||
- ИИ — синхронный чистый вычислитель; воркер появится в этапе 4 (MCTS),
|
||||
протокол postMessage фиксируется там же.
|
||||
- Случайность — только seeded Rng из core, передаётся параметром (детерминизм
|
||||
= воспроизводимые партии и тесты).
|
||||
- Легальность — только через applyMove из core; дублирование правил запрещено.
|
||||
- Приоритеты и вероятности уровней — по контракту в docs/INTERFACES.md
|
||||
(зафиксирован 2026-08-05 до кода).
|
||||
- Простая эвристика глаза: все ортогональные соседи — свои камни, без анализа
|
||||
диагоналей; осознанно грубо, ручной игры «подложить себе» бот не имитирует.
|
||||
|
||||
## Объём этапа 3
|
||||
|
||||
1. packages/ai (@go-learn/ai 0.1.0, зависимость @go-learn/core):
|
||||
chooseMove + LEVEL_ATARI_PROBABILITY + типы по контракту.
|
||||
2. Внутренние эвристики: поиск групп в атари (groupAt/liberties из core),
|
||||
ходы-спасения (>1 дамэ после хода или контрзахват), ходы-захвата,
|
||||
фильтр своего глаза, кандидаты nearby (Chebyshev ≤ 2), взвешенный выбор.
|
||||
3. Корневой tsconfig: references += packages/ai (без project reference на core —
|
||||
TS6310, см. PROJECT_STATE; резолв через workspace-симлинк).
|
||||
|
||||
## Тесты (гейт приёмки этапа)
|
||||
|
||||
- Детерминизм: одинаковый seed → идентичная последовательность ходов в полной
|
||||
партии бот-бот (два прогона, сравнение SGF или списка ходов).
|
||||
- Приоритеты: сконструированные позиции — при rng «всегда 0» (ролл < p)
|
||||
бот спасает своё атари / забирает чужое; при rng «всегда 0.99» (ролл ≥ p)
|
||||
приоритет пропускается.
|
||||
- Фильтр глаза: бот не заполняет свой глаз при наличии других ходов.
|
||||
- Легальность: все ходы бота в длинных партиях легальны (property: случайные
|
||||
партии бот-бот до двух пасов, seed запинен; ни одного ok:false).
|
||||
- Завершение: партия бот-бот 9×9 завершается (over) за разумное число ходов;
|
||||
после over вызов chooseMove кидает Error.
|
||||
- Perf-smoke: chooseMove на позиции 19×19 средней игры < 200 мс в CI-среде
|
||||
(критерий приёмки «ур.3 < 50 мс на среднем ноутбуке» — замер фактический,
|
||||
число в отчёте сессии; порог в тесте с запасом, машинно-зависимый).
|
||||
- Wiring: orphan-check по экспортам packages/ai.
|
||||
|
||||
## Критерий выхода
|
||||
|
||||
Все тесты зелёные + `npm run gates` зелёный. Полная партия 9×9 бот-бот
|
||||
завершается корректно (предпосылка критерия приёмки v1 №2 для ур. 5 в этапе 4).
|
||||
81
docs/plans/plan-phase-4.md
Normal file
81
docs/plans/plan-phase-4.md
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# План фазы 4: этап 4 — ИИ ур. 4–6, 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).
|
||||
82
docs/plans/plan-phase-5.md
Normal file
82
docs/plans/plan-phase-5.md
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
# План фазы 5: этап 5 — игровой интерфейс (apps/web, Astro)
|
||||
|
||||
Обновлено: 2026-08-05 | Статус: завершён (гейты зелёные, astro build собирает dist)
|
||||
|
||||
## Итоговые пометки (факт против плана)
|
||||
|
||||
- Astro запинен **5.18.2**, а не 7.1.6: astro 6/7 жёстко требуют Node
|
||||
> =22.12.0 (bin/astro.mjs, проверено по tarball), в окружении Node 20.
|
||||
> 5.18.2 — последняя линия с engines `^20.3.0`. Конфиг и объём — по плану
|
||||
> (output: 'static', без интеграций).
|
||||
- Зона расширена на 3 корневых конфига игноров: eslint.config.js,
|
||||
.prettierignore, .gitignore — по одной записи `**/.astro/` (генерируемый
|
||||
astro каталог ломал lint/format).
|
||||
- AiClient дополнен `readonly fallback` (предусмотрено текстом контракта);
|
||||
loadSettings/saveSettings — необязательным параметром StorageLike.
|
||||
- Воркер собран Vite (chunk ai-worker-*.js в dist). Смоук dist в браузере:
|
||||
доска рендерится, ход игрока + ответ бота работают.
|
||||
|
||||
## Критические долги (реестр — в начале, III.5)
|
||||
|
||||
- Нет.
|
||||
|
||||
## Ключевые решения (не пере-решать)
|
||||
|
||||
- Astro 7.1.6 (версия сверена npm view 2026-08-05), output: 'static', без
|
||||
UI-фреймворков — vanilla TS + DOM (спека: «без тяжёлых UI-фреймворков»).
|
||||
- Строки UI — один ресурсный файл src/ui/strings.ts с первого дня (спека).
|
||||
- Отмена хода бота — terminate + пересоздание воркера (решение по известной
|
||||
проблеме cancel в реальном Worker, отчёт сессии 4).
|
||||
- Режим подсказки: topMoves последнего MCTS-ответа как разметка + оценка;
|
||||
дельта = изменение winRate лучшего хода между запросами (упрощение —
|
||||
оценка с точки зрения стороны, чей ход анализировался; зафиксировано).
|
||||
- Схема localStorage и AiClient — контракты в docs/INTERFACES.md
|
||||
(зафиксированы 2026-08-05 до кода).
|
||||
- Страницы: / — заглушка-визитка со ссылкой на партию; /play — игра.
|
||||
Курс — этап 6, полировка (a11y, .htaccess) — этап 7.
|
||||
|
||||
## Объём этапа 5
|
||||
|
||||
1. apps/web (Astro): package.json @go-learn/web 0.1.0, astro.config.mjs
|
||||
(static), tsconfig (extends базового, lib DOM), workspaces += "apps/*".
|
||||
2. Страница /play: доска (packages/board render + reduceInput + setupCanvas +
|
||||
attachPointerInput), панель: выбор доски 9/13/19, уровня 1–6, цвета
|
||||
(чёрные/белые/случайно), коми (auto/число), кнопки «Пас», «Сдаться»,
|
||||
«Отменить ход», «Новая партия»; счётчики пленников; статус-строка
|
||||
(чей ход, причина отказа из MoveError, итог партии).
|
||||
3. Подсчёт по окончании (два паса): scorePosition + отметка мёртвых
|
||||
(suggestDeadGroups + ручной toggle по клику) → итог.
|
||||
4. SGF: «Скачать SGF» (serializeSgf, blob-скачивание), «Загрузка SGF» —
|
||||
режим просмотра (parseSgf, навигация назад/вперёд без игры).
|
||||
5. Подсказки ур. 4+ (переключатель, hintsEnabled): топ-3 хода маркерами с
|
||||
оценкой; дельта winRate.
|
||||
6. 19×19 при ур. 4–6 — честное предупреждение (спека этапа 4).
|
||||
7. Тёмная минималистичная тема (согласована с палитрой packages/board),
|
||||
адаптивность desktop+мобильные.
|
||||
8. lib/storage.ts (по контракту), lib/ai-client.ts (по контракту),
|
||||
lib/game-store.ts (чистый, без DOM: GameTree + действия), ui/strings.ts.
|
||||
9. Воркер: entry ai-worker.ts (строка подключения — комментарий в
|
||||
packages/ai/src/worker.ts), сборка воркера средствами Astro/Vite.
|
||||
|
||||
## Тесты (гейт приёмки этапа)
|
||||
|
||||
- storage: roundtrip save→load; битый JSON/checksum/неизвестная version →
|
||||
дефолты + recovered; миграция-путь задокументирован.
|
||||
- game-store (чистый): новая партия, ход игрока через pending→confirm,
|
||||
отказ с reason при нелегальном, пас×2 → фаза подсчёта, toggle мёртвой
|
||||
группы, итог, resign → result, отмена хода, viewer: загрузка SGF,
|
||||
навигация prev/next.
|
||||
- ai-client: фейк-worker (инжекция) — маршрутизация ур. 1–3 в синхронный
|
||||
движок, ур. 4–6 в воркер; cancel → AiCancelledError; фолбэк при отказе
|
||||
воркера.
|
||||
- Матрица «чего НЕ покрывает ни один тест»: реальный кадр канвы в браузере,
|
||||
pointer на тачах, реальный Worker, astro build — смоук этапа 7 +
|
||||
ручная проверка владельцем.
|
||||
- vitest.config: include += apps/*/src.
|
||||
|
||||
## Критерий выхода
|
||||
|
||||
Все тесты зелёные + `npm run gates` зелёный + `astro build` собирает dist.
|
||||
Критерий v1 №4 («чистый клон собирается») проверяется сборкой в этой фазе;
|
||||
№2 (партия против ур.5) и №5 (мобильный Safari) — ручная приёмка владельцем
|
||||
после фазы 5–7.
|
||||
62
docs/plans/plan-phase-6.md
Normal file
62
docs/plans/plan-phase-6.md
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# План этапа 6 — курс и цумэ-го
|
||||
|
||||
Дата: 2026-08-06. Статус: завершён (413/413, dist 280 КБ). Предшественник: этап 5 (игровой UI)
|
||||
завершён, main = 4aee5b7 + hotfix play.html.
|
||||
|
||||
## Ключевые решения (не пере-решать)
|
||||
|
||||
1. Контент — оригинальный, авторский (не скачиваем чужие сборники цумэ-го):
|
||||
это снимает лицензионный вопрос; атрибуция — CREDITS.md. Спека допускает
|
||||
«свободная лицензия с атрибуцией ЛИБО формат импорта»; собственный
|
||||
контент строго безопаснее (ADR-0001, I.16).
|
||||
2. Интерактив в Markdown — raw HTML-элемент `<go-task data-task-id="…">`,
|
||||
гидратация клиентским скриптом страницы. Никаких remark/rehype-плагинов
|
||||
и новых зависимостей. Теория читаема без JS (запасной текст внутри
|
||||
элемента).
|
||||
3. Критерий успеха задачи — goal-предикат, вычисляемый движком
|
||||
(apps/web/src/lib/goals.ts поверх @go-learn/core), НЕ сравнение с
|
||||
координатами решения. Дерево вариантов в SGF — только автоответы
|
||||
соперника и подсказки.
|
||||
4. Формальный глаз — упрощение v1 (пустая область 1–3 пункта, окружённая
|
||||
одним цветом); ложный глаз не отличаем, уроки про ложный глаз строятся
|
||||
на capture-target. Уточнение — через ADR, не в этой фазе.
|
||||
5. Прогресс — ключ `go-learn:progress` (ProgressV1) в том же конверте
|
||||
version+checksum, API — расширение существующего storage.ts. Серия дней —
|
||||
чистая функция touchStreak.
|
||||
6. Зона работы — apps/web + CREDITS.md + docs; packages/board и
|
||||
packages/ai не трогаем (goal-предикаты живут в apps/web). Исключение по
|
||||
ADR-0003: в core добавлена одна аддитивная функция buildPosition
|
||||
(parseSgf не умеет AB/AW), разметка connect — CR вместо MA.
|
||||
7. Параллельные ветки: stage-6-core (механика: goals, storage, виджет,
|
||||
страницы, строки) и stage-6-content (уроки, цумэ-го, CREDITS,
|
||||
контентные тесты). Мерж: core → content.
|
||||
|
||||
## Объём
|
||||
|
||||
- Механика: goals.ts (4 предиката + формальные глаза), прогресс в storage.ts,
|
||||
виджет задачи (канва board, автоответы по дереву, сброс/подсказка),
|
||||
страницы /learn, /learn/[id], /tsumego, /progress, навигация, strings.ts.
|
||||
- Контент: 10 уроков (по разделу каждый, программа из мастер-промпта),
|
||||
≥30 цумэ-го (difficulty 1–5, ≥3 на градацию), задачи для уроков
|
||||
(≥1 интерактив там, где уместно), CREDITS.md.
|
||||
- Тесты: goals (все предикаты + ложный/формальный глаз), storage roundtrip
|
||||
прогресса, touchStreak (вчера/сегодня/разрыв), валидация контента (все
|
||||
TaskV1 парсятся, SGF легальны движком, goal-разметка присутствует, id
|
||||
уникальны, у уроков валидный frontmatter и существующие task-id),
|
||||
wiring-страниц.
|
||||
|
||||
## Приёмка этапа
|
||||
|
||||
- npm run gates зелёные (0 warnings), astro build PASS.
|
||||
- ≥10 уроков, ≥30 цумэ-го, фильтры работают, прогресс и серия дней
|
||||
сохраняются в localStorage (roundtrip).
|
||||
- Страница урока читаема без JS (проверка отключением гидратации).
|
||||
- Вес страниц остаётся скромным (жёсткий бюджет ≤300 КБ — гейт этапа 7, но
|
||||
не раздуваем заранее).
|
||||
|
||||
## Риски
|
||||
|
||||
- suggestDeadGroups грубовата (PROJECT_STATE) — two-eyes предикат пишем
|
||||
собственный, на неё не опираемся.
|
||||
- Контент-объём большой: качество SGF важнее количества сверх минимума;
|
||||
валидационный тест — обязательный страховочный гейт.
|
||||
50
docs/plans/plan-phase-7.md
Normal file
50
docs/plans/plan-phase-7.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# План этапа 7 — полировка
|
||||
|
||||
Дата: 2026-08-06. Статус: завершён (431/431, dist 296 КБ). Предшественник: этап 6 завершён,
|
||||
main = 2b249a5 (413/413, dist 280 КБ).
|
||||
|
||||
## Ключевые решения (не пере-решать)
|
||||
|
||||
1. .htaccess — apps/web/public/.htaccess (Astro копирует public/ в dist
|
||||
как есть); содержимое зафиксировано в INTERFACES.md; HTTPS-редирект
|
||||
сознательно ОТСУТСТВУЕТ (только панель хостинга,
|
||||
gotcha-https-redirect-proxy).
|
||||
2. Клавиатурный ввод — НЕ новый код в packages/board: чистый редьюсер
|
||||
курсора в apps/web/src/lib/keyboard.ts, подтверждение хода идёт через
|
||||
существующий reduceInput (tap по курсору → фантом → повтор → commit).
|
||||
Семантика подтверждения едина с тач-вводом (I.6, одна механика).
|
||||
3. ARIA-live — role="status" polite на существующих статусных строках,
|
||||
без live-region-спама: меняется только текстовое содержимое.
|
||||
4. Бюджет 300 КБ — по сырым байтам dist (с запасом к gzip); тест считает
|
||||
html + локальные ассеты, на которые страница ссылается.
|
||||
5. Отметка «урок пройден» — ручная кнопка + markLessonDone в storage.ts;
|
||||
авто- done для уроков с задачами (этап 6) сохраняется, кнопка —
|
||||
дополнение, не замена.
|
||||
6. Зона — только apps/web; packages и корневые конфиги не трогаем.
|
||||
|
||||
## Объём
|
||||
|
||||
- public/.htaccess + wiring-проверка директив в dist.
|
||||
- keyboard.ts (reduceCursor, кламп, тесты) + подписки в play-page.ts и
|
||||
task-widget.ts (курсор, стрелки/Enter/Space/Escape, aria-labels).
|
||||
- prefers-reduced-motion блок, :focus-visible, контроль контраста
|
||||
(--muted при недоборе), role="status" на статусах.
|
||||
- Кнопка «Отметить пройденным» на странице урока + markLessonDone + тест.
|
||||
- Wiring-тест бюджета веса уроков ≤300 КБ.
|
||||
- Строки — strings.ts.
|
||||
|
||||
## Приёмка этапа (и критерии v1, что можно проверить автоматически)
|
||||
|
||||
- npm run gates зелёные, 0 warnings; astro build PASS.
|
||||
- dist/.htaccess с требуемыми директивами; без RewriteCond %{HTTPS}.
|
||||
- Каждая страница урока ≤ 300 КБ по тесту.
|
||||
- Критерии v1: №1 (тесты) и №4 (чистый клон собирается) — автоматически;
|
||||
№2 (партия vs ур.5), №3 (тайминги бота), №5 (мобильный Safari) —
|
||||
ручные, владельцу.
|
||||
|
||||
## Риски
|
||||
|
||||
- Клавиатурный курсор не должен ломать pointer-ввод: общий InputState,
|
||||
подписки независимы.
|
||||
- suggestDeadGroups грубовата (PROJECT_STATE) — в этап 7 НЕ входит
|
||||
(отдельная задача через ADR при жалобах на подсчёт).
|
||||
47
docs/plans/plan-phase-8-1.md
Normal file
47
docs/plans/plan-phase-8-1.md
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
# План этапа 8.1 — регистрация отдельной страницей, восстановление пароля, капча
|
||||
|
||||
Дата: 2026-08-06. Статус: завершён (467/467 + smoke 58 OK). Предшественник: этап 8 завершён,
|
||||
main = 7da814c (461/461 + smoke OK). Решения владельца: своя автономная
|
||||
капча; OAuth — позже (дизайн docs/design/oauth-vk-yandex.md).
|
||||
|
||||
## Ключевые решения (не пере-решать)
|
||||
|
||||
1. Регистрация — ОТДЕЛЬНАЯ страница /register.html (не модалка): проще,
|
||||
доступнее (a11y), диплинкабельна. /account.html становится страницей
|
||||
входа со ссылками «Нет аккаунта? Зарегистрируйтесь» и «Забыли
|
||||
пароль?».
|
||||
2. Капча — автономная SVG (БЕЗ GD): glyph-повроты + шумовые кривые;
|
||||
код в сессии (sha256, 10 мин), одноразовая; только на регистрации
|
||||
(login прикрыт rate limit). SVG выбран вместо GD: GD не везде есть
|
||||
на хостингах, а локальный рантайм из deb — тем более.
|
||||
3. Восстановление — токен 1 час, sha256 в БД, request всегда 200 (нет
|
||||
enumeration), сбой mail() → 503; тестовый режим GOLEARN_TEST=1:
|
||||
письмо в файл, капча-код в заголовке X-Captcha-Debug.
|
||||
4. Параллельные ветки: stage-8-1-server (эндпоинты + миграция
|
||||
password_resets + smoke) и stage-8-1-web (страницы + строки);
|
||||
зоны не пересекаются. Мерж: server → web.
|
||||
|
||||
## Объём
|
||||
|
||||
- server/: api/captcha.php, api/password-reset/request.php,
|
||||
api/password-reset/confirm.php; register.php += captcha; миграция
|
||||
password_resets; config.example.php += base_url, mail_from;
|
||||
smoke.sh += сценарии капчи и восстановления.
|
||||
- apps/web: pages/register.html, pages/password-reset.html (два
|
||||
режима по query), правки account.astro (ссылки), sync-client.ts
|
||||
+= requestPasswordReset/confirmPasswordReset + captcha в register,
|
||||
strings.ts.
|
||||
- docs/deploy.md += шаги: проверка mail() (тестовое письмо), base_url
|
||||
в config.php.
|
||||
|
||||
## Приёмка
|
||||
|
||||
- npm run gates зелёные; smoke.sh (с новыми сценариями) зелёный
|
||||
локально; astro build PASS (18 страниц).
|
||||
|
||||
## Риски
|
||||
|
||||
- Доставляемость mail() с shared-хостинга (SPF/DKIM) — ручная проверка
|
||||
владельцем на деплое; риск в PROJECT_STATE.
|
||||
- SVG-капча слабее GD/сервисной к OCR-ботам — для учебного сайта
|
||||
приемлемо; при злоупотреблениях — Yandex SmartCaptcha через ADR.
|
||||
50
docs/plans/plan-phase-8.md
Normal file
50
docs/plans/plan-phase-8.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# План этапа 8 — личный кабинет и синхронизация прогресса
|
||||
|
||||
Дата: 2026-08-06. Статус: завершён (461/461 + smoke.sh OK). Предшественник: этапы 1–7 завершены,
|
||||
main = a99aeb9 (431/431). Активация — команда владельца; модель учётки и
|
||||
до-триаж раздела V — ADR-0004.
|
||||
|
||||
## Ключевые решения (не пере-решать)
|
||||
|
||||
1. Модель — email+пароль (ADR-0004); БЕЗ верификации почты и
|
||||
восстановления пароля (нет SMTP на shared-хостинге; предупреждение в
|
||||
UI при регистрации).
|
||||
2. PHP 8 без фреймворка, PDO SQLite (WAL, busy_timeout, БД вне web root),
|
||||
prepared statements везде, лимит тела 256 КБ, rate limit по IP,
|
||||
SameSite=Lax + заголовок X-GoLearn-Client как CSRF-мера. Синтаксис
|
||||
PHP ≥ 8.0 — совместимость с хостингами.
|
||||
3. Прогресс на сервере — opaque ProgressV2 (ProgressV1 + updatedAt),
|
||||
last-write-wins по updatedAt; localStorage — SoT для гостей;
|
||||
миграция V1→V2 в storage.ts по контракту конверта.
|
||||
4. Превью статическое: кабинет деградирует тихо при недоступном API
|
||||
(status 'unavailable', пометка в UI, без алертов).
|
||||
5. Локальная проверка бэкенда: PHP 8.2 CLI (распакованные deb-пакеты в
|
||||
/tmp/debs, обёртка /tmp/php-run) + php -S + curl smoke.sh. В среде
|
||||
нет системного PHP — гейты npm PHP не запускают.
|
||||
6. Параллельные ветки: stage-8-server (server/) и stage-8-web (apps/web);
|
||||
общих файлов нет. Мерж: server → web.
|
||||
|
||||
## Объём
|
||||
|
||||
- server/: api/{register,login,logout,me,progress,health}.php,
|
||||
lib/{db,http,auth,ratelimit}.php, config.example.php, .htaccess
|
||||
(заголовки, запрет листинга), tests/smoke.sh.
|
||||
- apps/web: storage.ts (ProgressV2 + миграция), sync-client.ts
|
||||
(mergeDecision чистая + fetch), pages/account.astro, nav + strings.
|
||||
- docs/deploy.md — деплой-чеклист V.2 (артефакты, порядок, smoke,
|
||||
откат, пути на хостинге, бэкап/restore SQLite).
|
||||
- PROJECT_STATE: этап 8 разморожен → в работе → завершён.
|
||||
|
||||
## Приёмка этапа
|
||||
|
||||
- npm run gates зелёные (0 warnings), astro build PASS.
|
||||
- server/tests/smoke.sh зелёный локально (PHP 8.2): полный прогон
|
||||
register/login/put/get/401/403/429/health.
|
||||
- Ручная приёмка владельцем на хостинге — по docs/deploy.md.
|
||||
|
||||
## Риски
|
||||
|
||||
- PHP на хостинге владельца может отличаться (версия, pdo_sqlite) —
|
||||
чек-лист deploy.md начинается с проверки `php -v` и модулей.
|
||||
- Сессии PHP на shared-хостинге: gc и путь сессий — зафиксировать
|
||||
session_save_path в config при проблемах (заметка в deploy.md).
|
||||
Loading…
Add table
Add a link
Reference in a new issue