chore: восстановление репозитория из снапшота v0.3.1

Прежняя git-история утрачена при переносе проекта на машину владельца
(снапшот без .git). Хэши коммитов в docs/reports/* относятся к утраченной
истории.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
sab.code.lab 2026-08-07 09:34:02 +02:00
commit 1c85091186
184 changed files with 33303 additions and 0 deletions

51
docs/reports/session-1.md Normal file
View file

@ -0,0 +1,51 @@
# Отчёт сессии 1 (для следующей сессии)
Дата: 2026-08-05 | Ветка: main | Последний коммит: см. git log
## Что сделано
1. **Шаг 0 — каркас.** Триаж литании (ADR-0001, профиль M), git + .gitattributes
(`* text=auto eol=lf`) с первого коммита, docs-каркас, AGENTS.md (точка входа),
гейты `npm run gates` (prettier + eslint + tsc -b --noEmit + vitest).
Запинены: typescript 5.9.3, vitest 4.1.10, eslint 10.8.0, prettier 3.9.6,
fast-check 4.9.0. CI — GitHub Actions (ubuntu+windows), написан, не запускался.
2. **Этап 1 — packages/core.** Движок правил полностью по контракту
docs/INTERFACES.md: доски 9/13/19, группы/дамэ (flood fill — ADR-0002,
бенчмарк: union-find медленнее в 1.74×), захваты, запрет самоубийства
(самоубийство с захватом легально), простое ко + позиционное суперко,
подсчёт Tromp-Taylor со снятием dead-камней и ничьей, история-дерево с
ветвлением, SGF FF[4] (парсер+генератор, roundtrip), seeded RNG (mulberry32).
Тесты: 43/43 (юнит, wiring orphan-check, интеграция полной партии 9×9,
property-based fast-check).
3. **Решения владельца (молчание = дефолт):** каркас подтверждён, коми 13×13 = 5.5,
LICENSE = MIT (файл добавлен), CI на GitHub Actions.
## Что НЕ сделано
- Этапы 29 не начаты.
- CI не проверен на GitHub (репо локальный).
- Настоящая позиция двойного ко для юнит-теста суперко (см. PROJECT_STATE).
## Подводные камни для следующей сессии
- **Среда выполнения:** `/mnt/agents/output` НЕ поддерживает симлинки →
`npm install` невозможен там. Работать только через git worktree в `$HOME`
(`git worktree add $HOME/work-<name> <branch>` из /mnt/agents/output/go-learn).
Каталог `$HOME` может сбрасываться между сессиями — worktree пересоздавать,
коммиты в общем .git не теряются. `git worktree prune` не запускать, пока
живы субагенты; мёртвые записи удалять `git worktree remove --force <path>`.
- **У субагентов своя файловая система** (или $HOME сбрасывается): НЕЗАКОММИЧЕННЫЕ
правки в worktree теряются. Правило: перед передачей работы субагенту всё
коммитить; контракты передавать и в тексте задания, не только файлами.
- Контракт core уже зафиксирован — изменения только через обновление
INTERFACES.md ПЕРЕД кодом. UI этапа 5 ветвится по полю `reason` (MoveError),
не по тексту error.
- В /mnt-репозитории были мусорные пустые каталоги от ошибочной команды с
brace-expansion (шелл без bash) — вычищены в сессии 1; mkdir писать без `{}`.
## С чего начать продолжение
Этап 2 (доска Canvas): сначала дописать контракт рендера в docs/INTERFACES.md
(render(ctx, position, options) — чистая функция, devicePixelRatio, хоси,
тач-ввод), затем код. План — docs/plans/plan-phase-1.md обновить или создать
plan-phase-2.md.

View file

@ -0,0 +1,75 @@
# Отчёт сессии 10 — этап 10: дизайн-перенос «васи»
Дата: 2026-08-06. Ветка main: 0a5e2bd → 3f8fc5b (+docs(sync)). Версия 0.3.0.
## Вводные
Пользователь получил от Kimi WebSites переносной пакет дизайна
(`/mnt/agents/upload/Иго-сайт-перенос.md`: 8 HTML-страниц, style.css ~23 КБ,
2 JS, 3 JPG в base64) и попросил натянуть его на наш каркас. Эталон
распакован и сохранён в `docs/design/kimi-export/` (только как референс, в
сборку не входит).
## Что сделано
1. **Контракт** (INTERFACES.md, «Дизайн-перенос (этап 10)»): токены,
каркас Layout, тема доски, паттерны страниц, приёмка. Три сознательных
отклонения от палитры эталона ради WCAG AA ≥ 4.5:1 (замерено расчётом):
`--ink-faint` #a29885#6e675c, `--terra` #c25a33#a84e2c,
`--ok` #4a7a4e#46734a.
2. **Изображения**: hero/ink/stones сжаты (276→53 КБ, 215→118 КБ,
96→24 КБ) в `apps/web/public/assets/`.
3. **Три параллельных кодера** (ветки design/a,b,c, слиты --no-ff):
- A: Layout.astro — глобальные стили = адаптация style.css целиком +
`[hidden]` + go-task на светлых токенах; шапка-стекло с канji 碁,
проп `section` → aria-current, мобильное меню, подвал, Google Fonts
(PT Sans/Serif/Mono); DEFAULT_THEME доски → светлая; главная по
эталону (hero-meta с честными числами: 10/33/6).
- B: learn, урок, tsumego, progress — разметка по паттернам.
- C: play, account, register, password-reset — разметка по паттернам.
4. **Интеграционные правки оркестратора** (найдены скриншот-проверкой):
- страницы потока B без `.container` — контент уезжал в полную ширину;
- сортировка уроков по `data.order` не работала (во frontmatter у всех
уроков `order: 1` — исторически) → сортировка по id файла;
- shiki рендерил ASCII-диаграммы тёмной темой поверх светлого pre →
`markdown.shikiConfig.theme: 'github-light'` в astro.config;
- дублирующий H1 из тела markdown → скрыт через
`.lesson-body > :global(h1:first-child)` (scoped-стили Astro не
достают до разметки `<Content/>` — важный нюанс, записать в опыт).
## Проверки
- gates: 467/467 (28 файлов), format+lint+typecheck зелёные — после
каждого слияния и финально.
- Вес страниц (HTML+CSS+JS+img eager): максимум ~157 КБ (index с hero);
ink/stones — loading="lazy". Бюджет ≤300 КБ выполнен.
- Контраст ключевых пар ≥ 4.5:1 (расчёт по токенам + отчёт кодера A).
- Скриншот-проверка в браузере: index, learn, урок, tsumego, play,
account, register — соответствуют эталону; логика (id, data-атрибуты,
островки) на месте.
## Доставка
- dist → /mnt/agents/output/app, сохранена **новая версия превью**
(website_version_manager, id b0b2da7). Прежняя рабочая версия не
тронута — можно сравнить.
## Опыт сессии
- Scoped-стили .astro не действуют на разметку из `<Content/>` и
`set:html` — использовать `:global(...)` с узким селектором.
- Shiki в Astro по умолчанию тёмный: при смене темы сайта не забыть
`shikiConfig.theme`.
- /mnt FS: повторяющиеся сбои `index.lock`/`HEAD.lock` при git-операциях —
лечатся повтором; stale HEAD.lock удалять вручную после проверки, что
git-процессов нет. merge лучше делать маленькими порциями.
## Открыто
- Тексты кикеров/абзацев этапа 10 живут прямо в разметке страниц
(помечены комментариями «до переноса в strings.ts») — кандидат на
чистку при следующем касании.
- Поле `order` во frontmatter уроков у всех = 1 (не используется;
порядок — по id). Либо проставить 1..10, либо убрать из схемы.
- Восстановление пароля/капча в статическом превью не работают (API на
хостинге) — by design, картинка капчи в превью битая.

View file

@ -0,0 +1,96 @@
# Отчёт сессии 11 — этап 11: аудит контента, страница «Источники», дисклеймер
Дата: 2026-08-07. Ветка main: 32199a6 → 66dc7a5 (+docs(sync)). Версия 0.3.1.
## Вводные
Владелец спросил, насколько можно доверять обучающему контенту, и принял
решение: (1) обязательный аудит курса по авторитетным источникам; (2) отдельная
страница «Источники» — только голые проверяемые факты, что не нашли — честно
«не найдено», выдумывать КАТЕГОРИЧЕСКИ ЗАПРЕЩЕНО; (3) дисклеймер об открытом
редактировании. Железное правило зафиксировано в INTERFACES.md (этап 11).
## Что сделано
1. **Контракт** (INTERFACES.md, «Аудит контента, страница „Источники“,
дисклеймер (этап 11)», 4b6bf80): правило реально открытых URL с цитатой,
формат отчётов и страницы, приёмка с выборочной перепроверкой оркестратором.
2. **Аудит — 3 параллельных research-агента** (ветки audit/r1..r3, слиты
--no-ff; отчёты `docs/audit/01-03.md`, `04-07.md`, `08-10.md`):
- 85 проверяемых утверждений: **70 подтверждено, 10 расхождений,
5 не найдено**. Источники: правила AGA (зеркала BGA и cs.cmu.edu),
Sensei's Library, rusgolib.gofederation.ru.
- Каждое подтверждение — URL + дословная цитата из реально открытой
страницы.
3. **Перепроверка оркестратором** (приёмка контракта): открыто и сверено
с цитатами 5 URL из отчётов (Atari, Calling Out Atari, Ladder,
Bamboo Joint, Dango — все Sensei's Library); дополнительно curl'ом
подтверждены ключевые для правок страницы ChineseRules (коми 7.5, cost 0),
Komi и 34PointHighApproachAttachDrawbackJoseki (цукэ-хики). Часть страниц
SL/BGA в момент проверки отвечала таймаутами — то же наблюдали аудиторы.
4. **Дисклеймер** (32199a6): примечание на /learn.html («курс создан с
помощью ИИ и находится в открытом редактировании…») со ссылкой на
«Источники»; пункт «Источники» в футере.
5. **Страница /istochniki.html** (218c292): 8 тематических разделов,
формат «факт одной строкой — ссылка на первоисточник», 50 ссылок
(все — только из аудит-отчётов, `target="_blank" rel="noopener"`),
обязательный честный раздел «Что пока не удалось подтвердить» (5 пунктов).
Строки вынесены в `strings.ts` (раздел `sources`).
6. **Правки уроков по подтверждённым расхождениям** (218c292, 9 файлов):
- урок 01: «атари» вслух — практика обучающих партий, опытные не объявляют;
- урок 02: атари вынуждает, но не обязывает отвечать; «сирэ» →
«ситё-прерыватель» (ladder breaker);
- урок 03: нелегальный ход по AGA отменяется и засчитывается как пас;
- урок 05: ход в свою территорию — 1 очко только по японским правилам,
по китайским (нашим) счёт тот же; про коми добавлено: наши 6,5/5,5,
стандарт китайских — 7,5;
- урок 06: изолированное косуми локально неразрезаемо (миаи);
- урок 07: неподтверждённые числа камней → канонические «стены 2/3/4»;
убран термин «линия смерти»;
- урок 08: «ханэ у подошвы 3-4» → цукэ-хики с верными ролями цветов
(цукэ/хики — чёрные, ханэ — белые);
- урок 09: «танэки» → «такэфу»; «столб» → «данго» (пельменная форма);
диаграммы тигровой пасти и бамбука приведены к собственному тексту;
- урок 10: убран неподтверждённый диапазон «13 очка» и суперлатив
«самый частый приём».
## Проверки
- gates: **467/467** (28 файлов), format+lint+typecheck зелёные — прогон
оркестратором в чистом worktree на merge-коммите 66dc7a5.
- Сборка: 19 страниц, `dist/istochniki.html` на месте; eager-вес страницы
источников ~38 КБ (HTML 20 КБ + общий CSS 18 КБ) — бюджет ≤300 КБ с
большим запасом.
- Скриншот-проверка /istochniki.html в браузере: шапка, разделы, ссылки —
в порядке.
- Контрактная перепроверка ≥5 URL — выполнена (см. выше).
## Доставка
- dist → /mnt/agents/output/app (rsync с `--exclude=.git`), сохранена
**новая версия превью** (website_version_manager, id 70226a8).
## Опыт сессии
- Sensei's Library периодически отвечает таймаутами на web_open_url —
аудиторам и оркестратору стоит делать повторы и дублировать проверку
curl'ом; недоступность источника фиксировать честно («не найдено»).
- Аудит-отчёты от субагентов пришли неформатированными — prettier --check
падал; механическая нормализация docs/audit/*.md (только формат, без
изменения текста) включена в коммит 218c292.
## Открыто
- **Расхождение коми**: движок и INTERFACES.md держат 6,5 (19×19) по решению
владельца от 2026-08-05, а стандарт китайских правил — 7,5. Урок теперь
честно разводит «наши партии» и «стандарт». Сменить ли дефолт движка на
7,5 — отдельное решение владельца (затронет контракт, тесты подсчёта,
сохранённые партии).
- Поле `order` во frontmatter уроков у всех = 1 (не используется; порядок —
по id). Либо проставить 1..10, либо убрать из схемы.
- Тексты кикеров этапа 10 частично живут в разметке (помечены «до переноса
в strings.ts»).
- Этап 8.2 (OAuth VK ID / Yandex ID) ждёт ключи приложений от владельца;
дизайн — docs/design/oauth-vk-yandex.md. Иностранные провайдеры запрещены.
- Этап 9 (KataGo ONNX) заморожен; деплой на хостинг и ручная приёмка —
«немного попозже» (владелец).

54
docs/reports/session-2.md Normal file
View file

@ -0,0 +1,54 @@
# Отчёт сессии 2 (для следующей сессии)
Дата: 2026-08-05 | Ветка: main | Этап 2 (доска Canvas) — завершён
## Что сделано
1. **Контракт packages/board** зафиксирован в docs/INTERFACES.md до кода
(геометрия, рендер, редьюсер ввода, DOM-адаптер).
2. **packages/board реализован:** geometry.ts (computeGeometry, pointToPixel,
pixelToPoint, hoshiPoints 19→9/13→5/9→5), render.ts (render — чистая функция,
11 слоёв в контрактном порядке, дефолтная тёмная тема, координаты без «I»,
хоси, фантом, метка последнего хода, номера ходов, разметка LB/TR/SQ/CR,
заливка территории TerritoryMap, приглушение мёртвых), input.ts (reduceInput:
тап → фантом, повторный тап или confirm → ход), dom.ts (setupCanvas с DPR,
attachPointerInput с отпиской).
3. **Тесты: 74/74** (43 core + 31 board): геометрия, таблица переходов редьюсера,
инварианты рендера через мок-рекордер ctx, orphan-check.
4. **Интеграционные правки main loop при приёмке:**
- TerritoryMap { black, white } вместо префиксной кодировки "w:x,y" —
контракт синхронизирован;
- eslint: `no-undef: off` для TS-файлов (typescript-eslint рекомендация,
DOM-глобалы видит только tsc) — костыльные eslint-disable убраны;
- в контракте board типы ключей приведены к string (типа PointKey в core нет);
- вычищены пустые мусорные каталоги `{docs…` от команды с brace-expansion.
## Что НЕ сделано
- Этапы 39 не начаты.
- Визуальная проверка кадра, pointer-события, мобильный Safari — смоук этапа 5/7
(записано в матрице «чего НЕ покрывает ни один тест», plan-phase-2).
- CI на GitHub не запускался (репо локальный).
## Подводные камни для следующей сессии
- Среда: работать только через `git worktree add $HOME/work-<name> <branch>` из
/mnt/agents/output/go-learn; $HOME субагента/сессии может быть чистым —
worktree пересоздавать (`git worktree remove --force <старый путь>` если
«already checked out»), коммиты в общем .git не теряются. Незакоммиченное
теряется — коммитить перед концом работы. Контракты дублировать в тексте
задания субагенту, не только файлами.
- `tsc -b --noEmit` несовместим с project references (TS6310, TS 5.9.3) —
packages/board без reference на core, резолв через workspace-симлинк.
Не «чинить» добавлением reference — сломает гейт с чистого состояния.
- docs/*.md коммитить только после prettier --write (format-гейт ловит и md).
- mkdir без фигурных скобок — шелл без brace-expansion плодит мусорные каталоги.
## С чего начать продолжение
Этап 3 (ИИ ур. 13, эвристика): сначала контракт модуля ИИ в docs/INTERFACES.md
(выбор хода по эвристикам: спасти своё атари → забрать чужое → взвешенный
случайный ход вблизи хода противника → не заполнять свой глаз → пас; уровни
0.3/0.6/0.9; RNG — createSeededRng из core), затем код. Решить и записать:
packages/ai отдельным пакетом или модулем в core — рекомендация: отдельный
packages/ai (core остаётся чистыми правилами). Создать docs/plans/plan-phase-3.md.

53
docs/reports/session-3.md Normal file
View file

@ -0,0 +1,53 @@
# Отчёт сессии 3 (для следующей сессии)
Дата: 2026-08-05 | Ветка: main | Этап 3 (ИИ ур. 13, эвристика) — завершён
## Что сделано
1. **Контракт packages/ai** зафиксирован в docs/INTERFACES.md до кода:
chooseMove, AiLevel 13, LEVEL_ATARI_PROBABILITY {1:0.3, 2:0.6, 3:0.9},
приоритеты save-atari → capture-atari → nearby (Chebyshev ≤ 2) → random →
pass, фильтр своего глаза, легальность только через applyMove из core.
2. **packages/ai реализован** (@go-learn/ai 0.1.0): ai.ts (chooseMove, роллы
rng в фиксированном порядке — позиция в потоке не зависит от доски),
candidates.ts (легальные + фильтр глаза), tactics.ts (атари, спасение
по факту «>1 дамэ после хода» — контрзахват покрыт без частных случаев),
pick.ts (равномерный/взвешенный выбор, nearby с весами 2/1).
3. **Тесты: 99/99** (74 + 25 новых): приоритеты на сконструированных позициях
с rng-заглушками (0 / 0.99), фильтр глаза, Error при over, детерминизм
(3 seed × 2 прогона полных партий), 12 партий бот-бот 9×9 до over ≤ 200
ходов с проверкой легальности каждого хода, perf-smoke, orphan-check.
4. **Perf: chooseMove 19×19 ≈ 7.7 мс** (критерий «ур.3 < 50 мс» с запасом).
5. Интеграционная правка main loop: return type в хелперах теста — lint
0 warnings (цель литании для нового кода).
## Что НЕ сделано
- Этапы 49 не начаты. Воркер и протокол postMessage — этап 4 (по контракту).
## Подводные камни для следующей сессии
- Среда: git worktree в $HOME, пересоздание (`git worktree remove --force` при
«already checked out»), коммитить всё перед концом — незакоммиченное теряется;
контракты дублировать в тексте задания субагенту.
- packages без project references на core (TS6310 при `tsc -b --noEmit`) —
резолв через workspace-симлинк; не «чинить».
- docs/*.md — через prettier --write перед коммитом (format-гейт).
- Ролл-семантика chooseMove задокументирована в шапке ai.ts: два ролла на ход
всегда — менять порядок/число роллов = менять воспроизводимость партий,
только через ADR.
- Порог perf-теста 200 мс — машинно-зависимый; не ужесточать в CI.
## С чего начать продолжение
Этап 4 (ИИ ур. 46, MCTS в Web Worker):
1. Сначала в docs/INTERFACES.md: протокол postMessage (запрос/ответ/отмена,
сериализация позиции, бюджет времени, уровень) И контракт движка MCTS
(UCT, плейауты по эвристикам этапа 3 — переиспользовать packages/ai).
2. Бюджеты: ур.4 — 300 мс, ур.6 — 1500 мс; таргет 9×9 и 13×13, на 19×19 —
честное предупреждение в UI (этап 5).
3. Только однопоточный код — SharedArrayBuffer требует COOP/COEP, которых
может не быть на шаред-хостинге.
4. Плейауты тоже через seeded Rng — реплеи MCTS воспроизводимы.
5. Создать docs/plans/plan-phase-4.md.

63
docs/reports/session-4.md Normal file
View file

@ -0,0 +1,63 @@
# Отчёт сессии 4 (для следующей сессии)
Дата: 2026-08-05 | Ветка: main | Этап 4 (MCTS ИИ ур. 46 + воркер) — завершён
## Что сделано
1. **Контракт MCTS + протокол postMessage** зафиксирован в docs/INTERFACES.md
до кода: chooseMoveMcts (UCT c=1.4, ленивая экспансия, лёгкий плейаут,
бюджеты {4:300, 5:800, 6:1500} мс, maxSimulations для тестов, topMoves до 3),
WorkerRequest/WorkerResponse (позиция — списком ходов, cancel → result).
2. **packages/ai/src/mcts.ts** — движок: лёгкая плейаут-политика (атари-реакция
вокруг последнего хода + случайные точки с фильтром глаза), оценка
scorePosition с komi, стоп по deadline/shouldStop/maxSimulations.
Детерминированная экспансия (захваты первыми) — задокументирована.
3. **worker-protocol.ts + worker.ts** — пересборка позиции из списка ходов с
валидацией, createWorkerHandler(port, deps?) с инжектируемыми часами;
браузерный self.onmessage опущен — подключает этап 5 (строка в комментарии).
4. **Тесты: 118/118** (+19): детерминизм, легальность 9×9/13×13, бюджет по
фейк-часам, shouldStop, захват в атари за 200 симуляций (smoke качества),
партия MCTS vs ур.3, протокол через фейк-порт, perf-smoke.
5. **Perf: ~147 симуляций за 300 мс на 9×9**; ур.6 на 13×13 ≈ 1500 мс wall —
критерий v1 №3 «<2 с» выполнен.
## Что НЕ сделано
- Этапы 59 не начаты. UI и реальное подключение воркера — этап 5.
## Подводные камни для следующей сессии (этап 5)
- **Cancel в реальном Worker**: синхронный handler не примет сообщение во время
счёта (event loop). Варианты: чанкование chooseMoveMcts через setTimeout в
воркере (меняет код движка/обёртки — через контракт!) или terminate воркера
- пересоздание (протокол stateless — позиция передаётся списком ходов,
поэтому пересоздание дёшево). Рекомендация: terminate+recreate, код не трогать.
- **Сила MCTS ограничена** ~147 сим/300 мс на 9×9 (applyMove копирует
positionHashes — O(n²) в плейаутах). Если на приёмке ур. 46 слабоваты —
отдельная задача оптимизации core (хэш инкрементальный), через ADR.
- **19×19 для MCTS**: UI обязан показать честное предупреждение (спека этапа 4);
рекомендуемые таргеты — 9×9 и 13×13.
- Среда: worktree в $HOME, пересоздание, коммитить всё; контракты дублировать
в задании; docs через prettier перед коммитом; project references не добавлять.
- Seed воркера: протокол передаёт seed в каждом choose — UI формирует
(например, seed партии + requestId); это часть воспроизводимости реплеев.
## С чего начать продолжение
Этап 5 (игровой интерфейс) — первый этап с реальным сайтом:
1. Astro в apps/web (проверить актуальную версию astro через npm view ДО
конфигов — gotcha-llm-stale-configs; статический выход, без SSR).
2. Страница партии: packages/board render + input-редьюсер, выбор
доски/уровня/цвета, коми (defaultKomi + ручное), пас/сдаться/отмена/новая,
счётчики пленников, скачивание SGF (serializeSgf) и загрузка для просмотра
(parseSgf), режим подсказки на ур. 4+ (topMoves из MctsResult, дельта
после хода игрока).
3. Подключение worker.ts: строка подключения — комментарий в worker.ts;
fallback: если Worker недоступен — синхронный вызов в основном потоке
(fail-safe, с пометкой в UI).
4. Строки UI — в один ресурсный файл с первого дня (спека).
5. Смоук вручную: визуальная проверка кадра из матрицы plan-phase-2.
6. Контракт: схема localStorage для настроек/прогресса партии — в INTERFACES.md
ДО кода (version + checksum + миграция + roundtrip-тест).
7. Создать docs/plans/plan-phase-5.md.

68
docs/reports/session-5.md Normal file
View file

@ -0,0 +1,68 @@
# Отчёт сессии 5 (для следующей сессии)
Дата: 2026-08-05 | Ветка: main | Этап 5 (игровой интерфейс) — завершён
## Что сделано
1. **Контракты этапа 5** в docs/INTERFACES.md до кода: схема localStorage
(конверт version+checksum FNV-1a, SettingsV1, recovered при битом состоянии)
и AiClient (ур. 13 синхронно, ур. 46 воркер, cancel=terminate+recreate,
fail-safe синхронный фолбэк с пометкой).
2. **apps/web (Astro 5.18.2, static, vanilla TS + DOM):**
- lib: storage.ts, ai-client.ts, game-store.ts (чистый: фазы
playing/scoring/viewer, гонка requestId, undo пары ходов, подсчёт с
toggle мёртвых, SGF-просмотр), territory.ts (карта территории для заливки);
- страницы: / (визитка) и /play (канва + полная панель: размер/уровень/
цвет/коми, чекбоксы, Пас/Сдаться/Отменить/Новая, счётчики пленников,
статус-строка с причинами MoveError, предупреждение 19×19 при ур. 46,
подсказки топ-3 с winRate и дельтой, скачивание/загрузка SGF);
- ui/strings.ts — все строки UI одним файлом; тёмная тёплая тема,
адаптивность.
3. **Тесты: 147/147** (+29: storage 7, ai-client 5, game-store 12, territory 3,
wiring 2), lint 0 warnings. **astro build PASS, dist 80K**, worker-chunk
9.75 kB. Браузерный смоук исполнителем: рендер доски, пас + ответ бота,
hidden-состояния.
4. Интеграционная правка main loop: astro 5.18.2 (MIT) добавлен в
THIRD_PARTY_LICENSES.md — лицензионный гейт.
## Принятые отклонения (задокументированы исполнителем)
- Astro 5.18.2 вместо 7.1.6: astro 6/7 требуют Node ≥22.12 (hardcoded в bin),
окружение Node 20.20.2. Записано в PROJECT_STATE.
- AiClient.fallback: boolean и StorageLike-инжекция в storage — дополнения
контрактов, поведение не меняют.
- eslint.config.js/.prettierignore/.gitignore += `**/.astro/`.
## Что НЕ сделано
- Этапы 69 не начаты.
- Ручная приёмка: критерии v1 №2 (партия vs ур.5 до подсчёта) и №5 (мобильный
Safari) — владельцем; визуальный смоук кадра — по матрице plan-phase-2.
## Подводные камни для следующей сессии (этап 6)
- Среда: worktree в $HOME, пересоздание, коммитить всё; контракты дублировать
в задании; docs через prettier; project references не добавлять; `.astro/`
в игноре — не пугаться генерируемого каталога.
- suggestDeadGroups грубовата (предлагает живые группы на разрежённых
позициях) — при работе с уроками «жизнь и смерть» это станет заметно;
кандидат на уточнение (через ADR, зона core).
- Строки UI — только через ui/strings.ts, новые строки туда же.
- Worker-chunk собирается Vite; при изменении packages/ai/src/worker.ts
пересобирать apps/web.
## С чего начать продолжение
Этап 6 (курс + цумэ-го):
1. Контракт форматов в docs/INTERFACES.md ДО кода: схема Markdown-урока
(разделы → уроки → шаги), формат интерактивной задачи (SGF-позиция +
условие успеха, проверяемое движком — не хардкод координат), схема
localStorage прогресса курса (version + checksum, ключ go-learn:progress).
2. Программа по спеке: дамэ/захват → атари/лестница/сеть → самоубийство и ко →
глаза, жизнь и смерть, ложный глаз → подсчёт/пас/конец → связь/разрезание →
углы-стороны-центр → 34 базовых дзёсэки → форма → простое ёсэ.
3. Цумэ-го ≥30 задач, фильтры, свободная лицензия с атрибуцией (CREDITS.md)
либо формат импорта.
4. «Мой прогресс»: уроки, задачи, серия дней.
5. Создать docs/plans/plan-phase-6.md.

76
docs/reports/session-6.md Normal file
View file

@ -0,0 +1,76 @@
# Отчёт сессии 6 (для следующей сессии)
Дата: 2026-08-06 | Ветка: main | Этап 6 (курс + цумэ-го) — завершён
## Что сделано
1. **Контракты этапа 6 в INTERFACES.md до кода** (раздел «Форматы данных
уроков и задач»): схема Markdown-урока (10 фиксированных разделов,
`<go-task data-task-id>` raw-HTML в теле), TaskV1 (goal-предикаты вместо
хардкода координат), ProgressV1 + touchStreak, страницы
/learn, /learn/[id], /tsumego, /progress. План — docs/plans/plan-phase-6.md.
2. **ADR-0003**: аудит контракта выявил, что parseSgf не умеет AB/AW и MA.
В core добавлена ОДНА аддитивная функция `buildPosition` (валидация:
вне доски/дубли/группа без дамэ → Error; корректный positionHashes);
разметка connect — CR вместо MA. +6 тестов core.
3. **Механика (подагент, ветка stage-6-core)**: goals.ts (4 предиката +
формальный глаз v1: пустая область 13 пункта, окружённая одним цветом),
storage.ts += ProgressV1 (тот же конверт), task-session.ts (чистая
машина: illegal/wrong с откатом/playing/solved, авто-ответ по дереву,
reset, hint), task-widget.ts (гидратация go-task, JSON-островок
#go-task-data), 4 страницы, content.config.ts (zod из astro:schema),
nav + строки в strings.ts.
4. **Контент (подагент, ветка stage-6-content)**: 10 уроков (300700 слов,
разделы 16 и 10 с интерактивом), 33 цумэ-го + 7 задач уроков
(capture 20 / connect 5 / two-eyes 5 / liberties 3; difficulty 15,
≥3 на градацию), валидационный content.test.ts (217 проверок: позиции
легальны buildPosition, вариации легальны applyMove, разметка цели),
CREDITS.md (контент оригинальный, CC BY 4.0).
5. **Интеграция (main loop)**: wiring-тесты переведены с placeholder на
реальный контент; добавлен тест «главная линия каждой задачи достигает
goal». Он поймал реальный дефект: goal проверялся только ПОСЛЕ
авто-ответа соперника → транзиентные цели (liberties) недостижимы.
Фикс task-session по контракту: проверка после КАЖДОГО хода игрока,
до авто-ответа. Placeholder-контент удалён.
6. **Гейты main: 413/413** (включая astro build в wiring-тесте),
0 lint warnings. dist = 15 страниц, 280 КБ. Превью обновлено
(version 89825fe).
## Принятые отклонения (подагенты задокументировали)
- env.d.ts в apps/web/src: tsc -b не видит сгенерированные типы astro:content
(каталог .astro/ в .gitignore) — модуль объявлен через entry astro.
- Для toPlay:'white' task-session инвертирует B/W в SGF перед parseSgf
(парсер моделирует от пустой доски с чёрных). Контент v1 весь
toPlay:'black' — инверсия не задействована.
- lessons.done = решены все lsn-задачи урока; чисто теоретические уроки
(79) пометки «пройден» не получают (в контракте нет UI для ручной
отметки) — кандидат на этап 7.
- Wiring-тест запускает реальный `npm run build` внутри vitest (timeout
240 с) — гейты включают сборку.
## Известные ограничения контента v1 (в PROJECT_STATE)
- Мотив снэпбэк невыразим (parseSgf падает на occupied при повторной игре
точки); тема «сеть» в цумэ-го отсутствует (есть в тексте урока 2);
у two-eyes задач авто-ответ иногда тэнуки.
## Подводные камни для следующей сессии (этап 7)
- Среда прежняя: worktree в $HOME, коммитить всё, контракты inline в
задании, prettier на docs, sh без brace expansion, no `worktree prune`.
- Удаление чужих worktree после мержа: `git worktree remove --force` +
при необходимости `rm -rf .git/worktrees/<name>`, затем `git branch -d`.
- Этап 7 по спеке: .htaccess (gzip, кэш, MIME application/wasm),
prefers-reduced-motion, клавиатурное управление доской, ARIA-live,
страница урока ≤ 300 КБ по сети, теория без JS (уже держим), HTTPS
ТОЛЬКО панелью хостинга (НЕ RewriteCond %{HTTPS} — вечный редирект за
SSL-прокси). Плюс кандидаты: ручная отметка «урок пройден», suggestDeadGroups
грубовата для уроков жизни и смерти (через ADR, зона core).
- Ручная приёмка владельцем: критерии v1 №2 (партия vs ур.5) и №5
(мобильный Safari) всё ещё открыты.
## С чего начать продолжение
Этап 7 (полировка) по мастер-промпту; docs/plans/plan-phase-7.md создать,
контракты .htaccess/a11y — в INTERFACES.md до кода.

62
docs/reports/session-7.md Normal file
View file

@ -0,0 +1,62 @@
# Отчёт сессии 7 (для следующей сессии)
Дата: 2026-08-06 | Ветка: main | Этап 7 (полировка) — завершён
## Что сделано
1. **Контракты этапа 7 в INTERFACES.md до кода** (раздел «Полировка:
.htaccess, a11y, бюджет веса») + docs/plans/plan-phase-7.md.
2. **.htaccess** (apps/web/public/.htaccess → dist): AddType
application/wasm, mod_deflate (html/css/js/json/svg), mod_expires
(_astro 1 год immutable, html no-cache, прочее 1 час), Options
-Indexes, DirectoryIndex index.html. HTTPS-редиректа НЕТ (комментарий
с gotcha-https-redirect-proxy). Wiring-тест проверяет директивы в dist.
3. **Клавиатура** (/play и go-task): чистый reduceCursor в
lib/keyboard.ts (кламп по краям, старт — центр), стрелки/Enter/Space/
Escape через существующий reduceInput (фантом → commit, единая
семантика с тачем); курсор — квадратный маркер accent через render.
4. **A11y**: role="status" aria-live="polite" на статусах партии/задачи/
отметки урока; prefers-reduced-motion глушит анимации; :focus-visible
outline; контраст посчитан: --text 13.2/11.6, --muted 5.64/4.97 —
≥4.5:1, осветление не потребовалось.
5. **Отметка «урок пройден»**: markLessonDone в storage.ts (чистая,
сохраняет tasksSolved авто-done этапа 6, streak через touchStreak) +
кнопка на странице урока.
6. **Бюджет веса**: wiring-тест — каждая страница урока ≤300 КБ (самая
тяжёлая ~10.3 КБ по формуле контракта, ~42 КБ с транзитивными чанками).
7. **Гейты main: 431/431** (+12 keyboard, +4 markLessonDone, +2 wiring),
0 lint warnings, astro build PASS, dist 296 КБ. Превью обновлено
(version 7f93e64).
## Инцидент среды
Финальное сообщение подагента stage-7 не доставлено (alive=0 при
посылке), но работа была полностью закоммичена в ветку stage-7 —
потерь нет. Правило «коммить всё» сработало как страховка. Независимая
проверка гейтов main loop выполнена после мержа.
## Состояние критериев приёмки v1
- №1 (тесты движка, суперко, сэки, wiring) — зелёные.
- №3 (тайминги) — частично: perf-smoke в packages/ai (ур.13 < 200 мс
среднее по 20 вызовам 19×19); полная проверка на ноутбуке владельца.
- №4 (чистый клон собирается) — проверяется каждым воркрием с нуля.
- №2 (партия vs ур.5 до подсчёта) и №5 (мобильный Safari) — ручные,
владельцу.
## Что осталось (этапы 17 завершены)
- Ручная приёмка владельцем (критерии №2, №3, №5).
- По желанию владельца: этап 8 (PHP+SQLite синхронизация прогресса,
ОПЦИОНАЛЬНО, требует до-триажа раздела V литании) и этап 9 (KataGo
ONNX, «этап мечты», не начинать до приёмки 17).
- Кандидаты на уточнение (через ADR, по жалобам): suggestDeadGroups
грубовата; контент v1 (снэпбэк невыразим, тема «сеть» только в тексте,
двухглазые авто-ответы иногда тэнуки); метрика веса — только прямые
ассеты (уточнить при росте).
## Подводные камни среды (без изменений)
Worktree в $HOME; коммитить всё перед делегированием и завершением;
контракты inline в задании; prettier на docs; sh без brace expansion;
не `git worktree prune`; чистка: remove --force + rm .git/worktrees/<n>.

View file

@ -0,0 +1,56 @@
# Отчёт сессии 9, этап 8.1 (для следующей сессии)
Дата: 2026-08-06 | Ветка: main | Этап 8.1 (кабинет 2.0) — завершён
## Что сделано
1. **Контракты 8.1** в INTERFACES.md + plan-phase-8-1.md; дизайн OAuth
VK ID / Яндекс ID — docs/design/oauth-vk-yandex.md (что нужно от
владельца: приложения в консолях id.vk.com/business/go и
oauth.yandex.ru, ключи в config.php, HTTPS redirect URI; реализация —
этап 8.2, ~1 сессия, когда будут ключи).
2. **server (подагент)**: api/captcha.php (SVG-капча БЕЗ GD: 5 символов,
повороты/шумовые кривые, sha256+expires 10 мин в сессии, одноразовая);
register += captcha (порядок: 429→403→422 captcha→422→409→201);
api/password-reset/request.php (всегда 200, anti-enumeration; токен
bin2hex(32), sha256 в БД, 1 час; mail() со ссылкой; сбой → 503;
5/10мин) и confirm.php (200/400/422; 10/10мин); миграция
password_resets; config.example.php += base_url/mail_from; тестовый
режим GOLEARN_TEST=1 (X-Captcha-Debug, письмо в GOLEARN_TEST_MAIL).
3. **web (подагент)**: /account.html — только вход + ссылки «Нет
аккаунта? Зарегистрируйтесь» и «Забыли пароль?»; новые страницы
/register.html (email, пароль ×2, капча с кнопкой обновления,
авто-login → /account) и /password-reset.html (два режима по
?token=); sync-client += requestPasswordReset/confirmPasswordReset,
register(email, password, captcha); все статусы role=status.
4. **Гейты main: 467/467** (+6), 0 warnings, astro build PASS
(18 страниц). **smoke.sh: 58 проверок**, прогнан main loop
независимо — SMOKE OK (капча, полный цикл reset: письмо→токен→новый
пароль→login старым 401/новым 200, 429-е).
5. docs/deploy.md += base_url/mail_from и шаг проверки почты (4.1).
## Отклонения исполнителей (приняты)
- confirm.php: 422 (пароль <8) проверяется до 400 token_invalid
контракт порядок не фиксировал, оба кода по контракту.
- rate_check в register — до проверки заголовка (403-пробы не тратят
лимит); запись попытки после заголовка.
- Тема письма — сырой UTF-8 без RFC 2047 (риск отображения темы на
части MTA; ссылка не страдает) — в PROJECT_STATE.
## Среда
- /tmp обнуляется между сессиями: PHP-рантайм (debs в /tmp/debs +
/tmp/php-run) пересоздавать; рецепт — в session-8.md. Статический
бинарь с dl.static-php.dev не докачивается (обрывы); deb-способ рабочий.
- Финальные сообщения подагентов второй раз приходят пустыми/теряются,
но «коммить всё» спасает: проверять ветки гитом перед повторной
делегацией.
## Что осталось
- Этап 8.2 (VK ID / Яндекс ID) — когда владелец получит ключи;
дизайн готов.
- Ручная приёмка: деплой по docs/deploy.md (включая проверку почты),
критерии v1 №2/№3/№5.
- Этап 9 (KataGo ONNX) — после приёмки 17.

57
docs/reports/session-8.md Normal file
View file

@ -0,0 +1,57 @@
# Отчёт сессии 8 (для следующей сессии)
Дата: 2026-08-06 | Ветка: main | Этап 8 (личный кабинет, синхронизация) — завершён
## Что сделано
1. **ADR-0004**: владелец выбрал email+пароль (отступление от «анонимного
токена» спеки); до-триаж раздела V литании выполнен и задокументирован
(IN: V.1, V.2, V.4, V.5, V.6-минимум, V.7-минимум, V.8; OUT: V.3,
внешняя наблюдаемость). Без верификации почты/восстановления пароля
(нет SMTP) — предупреждение в UI.
2. **Контракты этапа 8** в INTERFACES.md до кода: схема SQLite, 7
эндпоинтов, ProgressV2 (+updatedAt) с миграцией V1→V2, mergeDecision
(pull/push/noop/unauthorized/unavailable), тихая деградация.
3. **server/ (подагент stage-8-server)**: PHP 8 без фреймворка, PDO
SQLite (WAL, busy_timeout, foreign_keys, идемпотентная init-миграция),
prepared statements везде, 256 КБ лимит тела (413), rate limit 10/10мин
по IP (429), X-GoLearn-Client как CSRF-мера (403), security-заголовки,
config.example.php ([SECRET], config.php в .gitignore), health.php
(200 {"status":"ok"}; 503 при сбое БД без текста исключений).
smoke.sh: 30+ проверок — зелёный.
4. **apps/web (подагент stage-8-web)**: ProgressV2 + миграция + Clock-
инжекция, sync-client.ts (mergeDecision + fetch-обёртки + метка
серверного времени после push → следующая сверка noop), страница
/account (вход/регистрация/выход/ручной sync, role=status), навигация
«Кабинет». Интеграционная доработка main loop: тихий авто-sync на
/progress при активной сессии (до отрисовки цифр).
5. **docs/deploy.md** (V.2): 3 артефакта (dist → web root, server/ →
/api, config.php + БД вне web root), порядок, smoke, откат, бэкап/
restore SQLite, канонические пути — заполнить при первом деплое.
6. **Гейты main: 461/461**, 0 warnings, astro build PASS (16 страниц).
Smoke PHP прогнан main loop независимо — SMOKE OK.
## Среда: локальный PHP-рантайм
Системного PHP нет и apt недоступен. Решение: deb-пакеты Debian bookworm
(php8.2-cli/common/sqlite3) распаковываются dpkg-deb -x в /tmp/debs,
обёртка /tmp/php-run (pdo → pdo_sqlite → sqlite3, порядок важен).
ВНИМАНИЕ: /tmp между сессиями обнуляется — рантайм пересоздавать
(команды в отчёте кодера stage-8-server и в этом абзаце).
Статический бинарь с dl.static-php.dev не скачался (обрывы ~14 МБ).
## Известные ограничения (в PROJECT_STATE)
- Кабинет в статическом превью = «сервер синхронизации недоступен»
(by design; API оживает на хостинге).
- Риски хостинга: Secure-cookie за TLS-прокси без HTTPS=on; rate limit
общий за NAT; WAL на NFS медленный; Apache 2.2 игнорирует Require
(защита config.php — тогда БД строго вне web root).
## Что осталось
- Ручная приёмка владельцем: деплой на хостинг по docs/deploy.md +
критерии v1 №2/№3/№5.
- Этап 9 (KataGo ONNX) — «этап мечты», только после приёмки 17.
- Кандидаты через ADR: suggestDeadGroups грубовата; контент v1 (снэпбэк,
«сеть», тэнуки-ответы); метрика веса — только прямые ассеты.