From fbefe33b1f874e7f7d34430ff56012dcccf8ce91 Mon Sep 17 00:00:00 2001 From: "Claude (backend session)" Date: Sun, 2 Aug 2026 03:04:23 +0300 Subject: [PATCH] Ratify D39.84: frontend and platform stacks pinned, eight owner decisions recorded, zone backlogs split out, four engine work rows opened, translation never indexable --- .gitignore | 2 + docs/ORCHESTRATOR_SESSION_PROMPT.md | 2 +- docs/PROGRESS.md | 24 +- docs/README.md | 1 + docs/architecture/05-decisions-log.md | 6 +- docs/glossary.md | 4 +- docs/product-requirements.md | 7 +- frontend/README.md | 29 ++ frontend/docs/BACKLOG.md | 12 + frontend/docs/FRONTEND_SESSION_PROMPT.md | 425 +++++++++++++++++++++++ frontend/docs/STACK_DECISIONS.md | 225 ++++++++++++ platform/BACKLOG.md | 10 + platform/README.md | 45 +++ platform/go.mod | 3 + 14 files changed, 781 insertions(+), 14 deletions(-) create mode 100644 frontend/README.md create mode 100644 frontend/docs/BACKLOG.md create mode 100644 frontend/docs/FRONTEND_SESSION_PROMPT.md create mode 100644 frontend/docs/STACK_DECISIONS.md create mode 100644 platform/BACKLOG.md create mode 100644 platform/README.md create mode 100644 platform/go.mod diff --git a/.gitignore b/.gitignore index 5df23d8a..03d337db 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,5 @@ backend/dist/ # exp16 versioned contrast corpus (jieba 0.42.1 dict.txt, 5MB) — SHA pinned in the report, reproducible eval/exp16/data/ + +frontend/references/ \ No newline at end of file diff --git a/docs/ORCHESTRATOR_SESSION_PROMPT.md b/docs/ORCHESTRATOR_SESSION_PROMPT.md index f2361abf..5e9c59f8 100644 --- a/docs/ORCHESTRATOR_SESSION_PROMPT.md +++ b/docs/ORCHESTRATOR_SESSION_PROMPT.md @@ -42,7 +42,7 @@ - **Двухступенчатая верификация:** промты сессий несут мандат самопроверки ИСПОЛНЕНИЕМ (код+запросы+результаты); твоя пост-хок адверсариальная верификация при лендинге — второй рубеж, author≠reviewer, воркфлоу-инструментом, по СЫРЬЮ с пере-выводом чисел. Эра №6: рубеж-2 поймал CRITICAL-артефакт (окно судьи HEAD_CHARS) и спас контракт от трёх ложных заголовков — не ослабляй. - **Пре-рег дисциплина полигона:** фриз коммитом ДО платных вызовов (единственный коммит сессии); изменения после = новый experiment-ID; девиации — явно в отчёте; стоп-гейты по бюджету легитимны; «если не влезает — стоп и пинг, не резать молча». -- **Лендинг:** микро-дефекты доков чинишь сам с пометкой «испр. оркестратором»; отчёты получают ревью-шапку; код не правишь — находки в фикс-лист; коммиты скоуп-раздельные, стейджинг пофайловый; `git status` перед каждым коммитом (в дереве бывают ≥2 живые сессии) + **`git diff --cached` перед `commit`** — коммит уносит ВЕСЬ индекс: чужой staged `git mv` уедет в твой коммит (инцидент 77dd9b8); `add` общего файла сметает чужую секцию — diff-контент/`add -p`. **Лендинг, двигающий файлы или состав активных промтов, обновляет `docs/README.md` тем же коммитом** (норма D39.80; урок 02.08: README объявлял заленденный пак «можно запускать» с мёртвой ссылкой — поймал не процесс, а новая сессия). Статус/голову README не несёт вовсе — единственный носитель состояния = PROGRESS CURRENT-STATE. +- **Лендинг:** микро-дефекты доков чинишь сам с пометкой «испр. оркестратором»; отчёты получают ревью-шапку; код не правишь — находки в фикс-лист; коммиты скоуп-раздельные, стейджинг пофайловый; `git status` перед каждым коммитом (в дереве бывают ≥2 живые сессии) + **`git diff --cached` перед `commit`** — коммит уносит ВЕСЬ индекс: чужой staged `git mv` уедет в твой коммит (инцидент 77dd9b8); `add` общего файла сметает чужую секцию — diff-контент/`add -p`. **Лендинг, двигающий файлы или состав активных промтов, обновляет `docs/README.md` тем же коммитом** (норма D39.80; урок 02.08: README объявлял заленденный пак «можно запускать» с мёртвой ссылкой — поймал не процесс, а новая сессия). Статус/голову README не несёт вовсе — единственный носитель состояния = PROGRESS CURRENT-STATE. **Перед коммитом ратификации — механический чек головы:** `grep "голова D" docs/PROGRESS.md` обязан показать номер ТОЛЬКО ЧТО ратифицированной ноты (голова отставала дважды: D39.81 и D39.83 — оба раза «Текущее» обновлено, число головы забыто). - **Findings-ledger процесс (концерн 5):** каждая находка — явная диспозиция до закрытия; вопросы «к бэкенду» из ресёрчей маршрутизируются обратно; completeness-critic на границах фаз. - **Ратификация:** D-блоки (образцы D39.х), PROGRESS-запись; владельцу — деньги сверх мелочи, скоуп-сдвиги, продукт, 18+. - **Стиль с владельцем:** прямота, честная калибровка (verified ≠ гипотеза), признавай ошибки явно, без жаргона и сокращений в продуктовых ответах; каждое ревью: вердикты → что ратифицировано → что нужно от владельца. diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 08a87db4..decb582a 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -1,8 +1,8 @@ # Журнал прогресса -> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-08-02, голова D39.82). **Источник истины по РЕШЕНИЯМ — `architecture/05-decisions-log.md`; этот файл — ЖУРНАЛ.** +> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-08-02, голова D39.84). **Источник истины по РЕШЕНИЯМ — `architecture/05-decisions-log.md`; этот файл — ЖУРНАЛ.** > - **Сделано (сводно; детали — D-лог и архив-слайсы):** Ф0 ✅ · Ф1-инфра ✅ · арх-ресет D39 (7 слоёв, паки 11–16) ✅ · паки 17 «канал B» · 18 «долги» · 19 «голос/состояние» · 20 «банк+терминолог» ✅ (D39.26–28/31/41–56) · мини-прогон (D39.37) и ХОЛОДНЫЙ прогон (D39.58: recall банка 0.918/0.980, банк приходит переведённым) приняты · полигон-пакеты 5–8, ToS-речек (D39.57), Р6+P4 (D39.61) закрыты · **карта языковой привязки движка (D39.60): 149 сайтов/45 файлов, книго-ось чиста (4), ja→ru безопасно без правки Go, en→ru — нет** · Р1–Р4 закрыты целиком (D39.63: Р2 = ЗНАЧЕНИЕ, Р4 = норма потолка recall) · **ФАЗА 2 ОБЩНОСТИ ✅ (D39.64: П0 эмбед-хеш · П1 цель-шов · П2 скрипт-шов, ko-баг закрыт · П3 нарезка · П4 манифест-по-каналам; голден вердикт-нейтрален 0/172, майнер-парити EXACT)** · жанровый словарь отменён как класс (D39.47) · петля ремонта построена и НЕ включена (D39.38). -> - **Курс (D39.59–78): ОБЩНОСТЬ ✅ → КАЧЕСТВО БАНКА ✅ (D39.69/75/77) → ПАКЕТ-ЧЕКЕРОВ ✅ (D39.78: строка 25 целиком; харнесс labels В GIT 12/12; K2 r0.85 · K4b r0.22 · K6 fp 14→6; Р2 hard/soft + Р4-потолки в контрактах).** **Текущее: МЕЛКАЯ ПАЧКА ✅ ПРИНЯТА И ЗАЛЕНДЕНА (D39.82: строки 89/53/83 закрыты · 93 сужена до остатков · F4-бэкап+pre-flight построен · register/жанр → книжный слой · DC7 пере-гейчен сид-покрытием → строка 98); решения §6 исполнены (D39.79/82); **РЕ-ПРОБА + ОТЛАДОЧНЫЙ ХОЛОДНЫЙ ПРОГОН coldrun-b САНКЦИОНИРОВАНЫ (D39.83: промт выдан и холодно аудирован — 3 major вправлены; потолки $0.15 ре-проба / $5 прогон; ступени 2+8 глав, автобанк по D39.77)**; ре-проба flash (строка 74) — по слову владельца; finding-1 ЗАКРЫТ (D39.77); онбординг-оверхол доков исполнен (D39.80); **ФРОНТ ОТКРЫТ владельцем (D39.81: продукт = SaaS; зоны `frontend/` + `platform/` живые, фронт работает на моках; движковая очередь НЕ пере-упорядочена — ранняя вставка одна: строка 95 «контракт API» $0; строки 96/97 и перевесы 49/94 заведены)**.** ⚠ **DeepSeek-V4-Flash-0731: платные прогоны СТОП до ре-пробы (строка 74; там же 6/6-порог классификатора и слоты Q2/Q7). Перекупок нет (D39.63).** +> - **Курс (D39.59–78): ОБЩНОСТЬ ✅ → КАЧЕСТВО БАНКА ✅ (D39.69/75/77) → ПАКЕТ-ЧЕКЕРОВ ✅ (D39.78: строка 25 целиком; харнесс labels В GIT 12/12; K2 r0.85 · K4b r0.22 · K6 fp 14→6; Р2 hard/soft + Р4-потолки в контрактах).** **Текущее: МЕЛКАЯ ПАЧКА ✅ ПРИНЯТА И ЗАЛЕНДЕНА (D39.82: строки 89/53/83 закрыты · 93 сужена до остатков · F4-бэкап+pre-flight построен · register/жанр → книжный слой · DC7 пере-гейчен сид-покрытием → строка 98); решения §6 исполнены (D39.79/82); **РЕ-ПРОБА + ОТЛАДОЧНЫЙ ХОЛОДНЫЙ ПРОГОН coldrun-b САНКЦИОНИРОВАНЫ (D39.83: промт выдан и холодно аудирован — 3 major вправлены; потолки $0.15 ре-проба / $5 прогон; ступени 2+8 глав, автобанк по D39.77)**; ре-проба flash (строка 74) — по слову владельца; finding-1 ЗАКРЫТ (D39.77); онбординг-оверхол доков исполнен (D39.80); **ФРОНТ ОТКРЫТ владельцем (D39.81: продукт = SaaS; зоны `frontend/` + `platform/` живые, фронт работает на моках; движковая очередь НЕ пере-упорядочена — ранняя вставка одна: строка 95 «контракт API» $0; строки 96/97 и перевесы 49/94 заведены)**; **СТЕК ФРОНТА/ПЛАТФОРМЫ ЗАПИНЕН, 8 решений владельца ратифицированы (D39.84: SEO Google-only · PWA-первый · денег в MVP-UI нет · стоп-на-банке = параметр запуска, `--verify-bank` готов · перевод НИКОГДА на индексируемый URL = ПТ-34 · якорь чтения = edit-unit, ПТ-21; работы движка под фронт = строки 99–102; фронт/платформа ведут ЗОННЫЕ бэклоги — `frontend/docs/BACKLOG.md` · `platform/BACKLOG.md`, строки 96/97 → П-1/П-2; зоны залендены, фронт-промт S0–S7 в `frontend/docs/`)**.** ⚠ **DeepSeek-V4-Flash-0731: платные прогоны СТОП до ре-пробы (строка 74; там же 6/6-порог классификатора и слоты Q2/Q7). Перекупок нет (D39.63).** > - **Горизонт (D39.62/67):** ре-проба flash (74; + платный порог 6/6 классификатора + пробы 36б-замера Q2/эмиссии Q7 по слову) → **ДОБОР ИДЕАЛА** (первым прогоном: оси голоса 24 · авто-режим · итерация №2 редакторов 65 · цена 16 · веса K1–K12 13а · вне-претрейн чекпоинт 55) → ВТОРАЯ ПАРА живьём (ja→ru; преп 81) → МАСШТАБ → пилот Ф2.5 (гейт резюме-строки 80; строки 62–68, 85) → Ф3 ридер-IDE (69–71). **Стоячие:** ToS-триггер 25.10 · Ш-2 до go1.27 · строка 74 перед любым платным прогоном. > - **Стек:** draft deepseek-v4-flash thinking-ON (+банкнота) **⚠0731** → терминолог (та же модель, батчи, экран `target_script`) → editor deepseek-v4-pro БИЛИНГВ ИНТЕРИМ (вендором НЕ тронут; glm-5 резерв) → судья gemini (Ф2, полигон); канал B Mistral+grok; ~$0.85/ранобэ (D30.4) — пере-калибровка после развилки 74. > - **ЕДИНЫЙ БЭКЛОГ — секция «Бэклог» ниже** (одна таблица, единственный трекер; каждая петля обязана иметь диспозицию: решено / отложено-с-записью / отклонено; ведёт оркестратор). @@ -10,7 +10,7 @@ ## Бэклог (ЕДИНЫЙ, собран 26.07, актуализация 02.08 D39.80; правки — только через оркестратора) -Закрытые строки здесь НЕ хранятся — они уходят в D-лог с номером решения. **ID строки стабилен навсегда** (не перенумеровывается и не переиспользуется — на «строку N» ссылаются доки и промты, D39.80). Вес: «блокер-очереди» = мешает текущему шагу · «скоро» = ближайшие 1–2 касания · «когда-нибудь» = записано, не потеряно. Длинная строка начинается жирным лидом — таблица сканируется по лидам. +Закрытые строки здесь НЕ хранятся — они уходят в D-лог с номером решения. **ID строки стабилен навсегда** (не перенумеровывается и не переиспользуется — на «строку N» ссылаются доки и промты, D39.80). Вес: «блокер-очереди» = мешает текущему шагу · «скоро» = ближайшие 1–2 касания · «когда-нибудь» = записано, не потеряно. Длинная строка начинается жирным лидом — таблица сканируется по лидам. **Зонные бэклоги (решение владельца 02.08, D39.84):** фронт и платформа ведут СВОИ бэклоги (`frontend/docs/BACKLOG.md` · `platform/BACKLOG.md`) — их строки сюда НЕ заходят; здесь движок/полигон/доки, включая движковые стыки фронта (зона «бэкенд», как 99–102); строки 96/97 переехали в платформенный (П-1/П-2), надгробия-указатели сохранены. | ID | Хвост (одной фразой) | Зона | Вес | Чем закрывается | Источник | |---|---|---|---|---|---| @@ -101,9 +101,17 @@ | 70 | Action-security gate перед выдачей tools/webfetch (D25 п.5) | бэкенд | когда-нибудь | Ф3 | D39.34(7) | | 71 | **Планы research/22**: epub-tag-rewrite · Q7-леджер ; + F3-brief из D29 п.3 (chat-edit · Not-useful-петля · cost-of-fix) + Ф3-скоуп 02-mvp-plan (TMX/TBX · Bertalign · дистилляция 7–14B); + V5: фронт ВЕБ-ПЕРВЫЙ, SEO/ранжирование (куки · страницы-сироты · актуальные алгоритмы Google) — определяет выбор фреймворка (SSR vs SPA), в Ф3-дизайн ДО выбора стека (ПТ-23) | бэкенд | когда-нибудь | Ф3 | D39.34(7), START_PROMT V5, D39.80 | | 94 | **Продукт-механика входа и прогона** (V2, ПТ-16..18): абьюз/misuse-прескрин дёшево и точно ДО трат токенов (H8) + UI-контракт отказа (проект-решение D39.80) · лимит размера входа настройкой (H7) · продукт-кнопки «стоп/продолжить» поверх построенных graceful stop и redrive, абьюзивный прогон НЕ продолжать (H10); API-форма — через контракт 95 | бэкенд | к подключению фронта (ПОДТЯНУТА D39.81; лимит можно раньше, к пилоту) | отдельный пак при Ф3-препе (после 95) | START_PROMT V2, H7/H8/H10, D39.80, D39.81 | -| 95 | **Контракт API v0 + продуктовый словарь статусов ($0, ранняя вставка):** зафиксировать артефактом ДО большого кода обеих сторон — фронт пишется на моках, без пришпиленного контракта моки и API разойдутся (класс «док↔код», 26/180 переписи); дом — `docs/architecture/14-api-contract.md`; продуктовые статусы «загрузка → разбор → перевод → подпись банка → финал → готово», слой перевода внутренних вердиктов в продуктовые (flag_reason/стадии/модели НЕ протекают — инвариант D39.81); двухфазный поток уже в движке (`--verify-bank`, банк-пауза) — ВЫВЕСТИ, не проектировать; резерв полей прогресс/ETA (54) и стоп/продолжить (94); ревью-вопрос контракта: «сменится стадия конвейера — придётся ли править фронт?» | оркестратор/бэкенд/фронт | скоро (единственная ранняя вставка Ф3) | дизайн-промт по слову владельца | релей фронта 02.08, D39.81, research/16 | -| 96 | **HTTP/SSE-слой и сервисная обвязка — в `platform/`, НЕ в backend:** движок = процесс-на-прогон (EXCLUSIVE flock `store.go:43` — ратифицированный инвариант D39.81, сервер в backend НЕ пишется); read-API поверх готовых `OpenReadOnly`-путей; пользователи/квоты/очередь = platform (SaaS — решение владельца 02.08) | платформа/бэкенд | когда-нибудь (Ф3, после 95) | Ф3-пак платформы | релей фронта 02.08, D39.81 | -| 97 | **Глобальный брокер рейт-лимитов провайдеров:** гарды сейчас per-процесс (`pipeline/ratelimit.go`; mistral ~48% отказов под параллелизмом — :11), лимит провайдера — на ВЕСЬ аккаунт: N параллельных прогонов = N независимых гардов против общего лимита, ломается на втором пользователе | платформа/бэкенд | когда-нибудь (ДО второго параллельного пользователя SaaS) | Ф3-пак платформы (дизайн вместе с 96) | релей фронта 02.08, D39.81 | +| 95 | **Контракт API v0 + продуктовый словарь статусов ($0, ранняя вставка):** зафиксировать артефактом ДО большого кода обеих сторон — фронт пишется на моках, без пришпиленного контракта моки и API разойдутся (класс «док↔код», 26/180 переписи); дом — `docs/architecture/14-api-contract.md`; продуктовые статусы «загрузка → разбор → перевод → подпись банка → финал → готово», слой перевода внутренних вердиктов в продуктовые (flag_reason/стадии/модели НЕ протекают — инвариант D39.81); двухфазный поток уже в движке (`--verify-bank`, банк-пауза) — ВЫВЕСТИ, не проектировать; резерв полей прогресс/ETA (54) и стоп/продолжить (94); ревью-вопрос контракта: «сменится стадия конвейера — придётся ли править фронт?»; входы D39.84: контракт подписи учитывает пересборку банка (подпись ≠ UPDATE — пишем в файлы-источники) · формы пофазного прогресса/манифеста/таблицы подписи = строки 99–101 | оркестратор/бэкенд/фронт | скоро (единственная ранняя вставка Ф3) | дизайн-промт по слову владельца | релей фронта 02.08, D39.81, research/16 | +| 96 | **→ переехала в `platform/BACKLOG.md` П-1** (зонные бэклоги, D39.84: HTTP/SSE-слой, обвязка, аутентификация, порядок деплоя); здесь остаётся ратифицированным сам ИНВАРИАНТ D39.81 — движок = процесс-на-прогон (EXCLUSIVE flock `store.go:43`), сервер в backend НЕ пишется | платформа | — | зонный бэклог | D39.81, D39.84 | +| 97 | **→ переехала в `platform/BACKLOG.md` П-2** (глобальный брокер рейт-лимитов; гейт «до второго параллельного пользователя» зафиксирован там же) | платформа | — | зонный бэклог | D39.81, D39.84 | +| 99 | **Пофазный прогресс `draft N/M ∥ edit N/M`**: unit = done только при всех draft-строках членов + edit-строке (`status.go:328-331/365`) — индикатор «готово N/M» стоит 0% ВСЮ черновую волну; данные уже есть (`chunk_status` — строка-на-стадию, `migrate.go:111-126`; status уже делит стадии по волнам `status.go:332-334`) — вывод пофазных счётчиков в StatusReport/JSON без миграции схемы | бэкенд | к подключению фронта (первая по критичности из четырёх D39.84) | малое касание read-model | релей фронта 02.08, D39.84 | +| 100 | **Персист манифеста глав/чанков** (+ `chunker_version` из снапшота + хеш источника): каждый read-вызов заново ингестит и режет исходник (`status.go:177-195` bookChunks; redrive — дважды за вызов; замер фронта 1.42–1.51 с CPU на книге 23 МБ, умножается на число книг) — нужен под экран разбора и дерево глав; дизайн обязан пережить смену чанкера (`--resnapshot`) | бэкенд | к подключению фронта | отдельное решение (дизайн с 95) | релей фронта 02.08, D39.84 | +| 101 | **Машиночитаемая таблица подписи банка**: кап 20 — только stdout (`render.go:98`), полная таблица — текстовый сайдкар `.bank-stop.txt`, JSON/структурного выхода нет (mined-signature.yaml — сид-дельта без freq/spread/evidence); нужна фронту S5; помнить ловушку «подпись ≠ UPDATE» (банк пересобирается: `seeding.go:18/110`, `glossary.go:158-162` — контракт подписи пишет в файлы-источники) | бэкенд | к подключению фронта | малое касание (форма — с контрактом 95) | релей фронта 02.08, D39.84 | +| 102 | **Приём внешнего trace-контекста в tmctl**: TraceID минтится заново каждым вызовом (`main.go:67-70`; внутри вызова трасса цельная, `request_log.trace_id` есть) — прогон, запущенный платформой, должен быть одной трассой | бэкенд | когда-нибудь (Ф3, с 96) | малое касание | релей фронта 02.08, D39.84 | +## Оркестратор №9 — СТЕК ФРОНТА/ПЛАТФОРМЫ ПРИНЯТ И ЗАЛЕНДЕН, ВОСЕМЬ РЕШЕНИЙ ВЛАДЕЛЬЦА РАТИФИЦИРОВАНЫ (D39.84), 02.08 + +По релею отчёта фронт-сессии (стек-исследование закрыто: 15 агентов, артефакты `frontend/docs/STACK_DECISIONS.md` + `FRONTEND_SESSION_PROMPT.md` S0–S7). Приёмка: 10-агентный refute-воркфлоу — все несущие бэкенд-утверждения записки CONFIRMED по коду, 8/8 веб-пинов подтверждены первоисточниками; 4 уточнения точности (гранулярность draft-only · кап 20 = stdout-only · «4276» не выводится из артефактов — принято как замер · якорь export.go = internal/pipeline). Ратифицированы 8 решений владельца (SEO Google-only · выравнивание по единицам экспорта, `--pairs` готов · подсветка блок/глава без спанов · стоп-на-банке = параметр запуска, `--verify-bank` готов · денег в MVP-UI нет · PWA-первый · вид = замеры референса · одна сессия кука/Bearer) + ПТ-34 (перевод НИКОГДА на индексируемом URL) + переформулировка ПТ-21 (якорь = edit-unit, не чанк). Работы движка = НОВЫЕ строки 99–102 (пофазный прогресс · манифест глав/чанков · машиночитаемая таблица подписи · внешний trace-контекст), все проверены кодом. Противоречие «демон в backend» разрешено сессией верно — D39.81 удержан. Две ловушки подтверждены и заведены входами дизайна (строка 95 и П-1: подпись ≠ UPDATE; read-путь не мигрирует схему). Зоны `frontend/`+`platform/` залендены. **Зонные бэклоги (решение владельца при лендинге):** фронт и платформа ведут свои — `frontend/docs/BACKLOG.md` (Ф-1..Ф-6) · `platform/BACKLOG.md` (П-1..П-4, туда переехали строки 96/97); единый бэклог фронт/платформа-строк больше не принимает. ⚠ Норма-вопрос владельцу: промт S0 велит фронт-сессии коммитить самой — против «сессии не коммитят»; рекомендация — право коммита фронту В СВОЕЙ зоне, пост-хок ревью; до слова владельца действует старая норма. + ## Оркестратор №9 — РЕ-ПРОБА И ОТЛАДОЧНЫЙ ХОЛОДНЫЙ ПРОГОН САНКЦИОНИРОВАНЫ, ПРОМТ ВЫДАН (D39.83), 02.08 По слову владельца («надо идти и делать холодный прогон с контролем бэкенда; цель — отладка»). Промт `BACKEND_COLDRUN_DEBUG_SESSION_PROMPT.md`: фаза A — верификация готовности сессией ($0: батарея · сквозной fake-путь · чек-лист наблюдаемости с правом чинить дыры) → фаза B — ре-проба flash по строке 74 (≤$0.15, боевая форма через live-риг; пограничные числа = НЕ здоров → развилка владельцу; ручка #77 сама не включается) → фаза C — холодный прогон coldrun-b с автобанком (≤$5, ступени 2+8 глав в ОДНОЙ БД, банк-пауза как инспекция сессии по D39.77, намеренный стоп+резюм, наблюдения per-узел вкл. цену строки 16 и голос-оси для 13б). Дебаг-дисциплина: фикс только мультиязычный с батареей, архитектурная дыра = СТОП+пинг. Холодный аудит промта агентом: 3 major вправлены ДО выдачи (`budget_usd` не существует → `ceilings.book_usd/day_usd` с миной day_usd 0.25 эталона · у ре-пробы не было носителя боевой формы → live-риг + кандидаты терминолога из coldrun-a · механика смока/добора и легитимный re-pin/подпороговая перекупка — против ложного СТОПа) + 4 minor. Вне скоупа: Q2/Q7-полигон-слоты, судья Ф2, DC7-остаток (требует сидового прогона). Строка 74 → в работе. @@ -241,6 +249,8 @@ Q1 = П1 цель-шов санкционирован («главное бэке *(Хроника сессии «Голос и состояние» (09.07 → research/15, D21) — в [archive/PROGRESS-2026-07-04-10.md](archive/PROGRESS-2026-07-04-10.md), D31.)* ## Ридер-IDE -(секция ресёрч-сессии — записи добавлять сюда) +(секция ресёрч-сессии и фронт-сессий — записи добавлять сюда) + +**Фронт-сессия — исследование стека закрыто (02.08).** 15 агентов (7 направлений × независимый скептик-опровергатель + синтез), версии сверены с вебом 02.08; скептики дали 5 blocker/45 major — записаны исправленные варианты. Артефакты: `frontend/docs/STACK_DECISIONS.md` (пины точными версиями · ловушки «вся документация в сети описывает прошлые версии» · работы движка §8) + переписанный `frontend/docs/FRONTEND_SESSION_PROMPT.md` (фронт режется на этапы S0–S7; первая кодовая сессия кончается витриной токенов). — **ЛЕНД D39.84** (10-агентный refute-воркфлоу оркестратора: все несущие бэкенд-утверждения CONFIRMED, 8/8 веб-пинов подтверждены первоисточниками; работы движка = строки 99–102; ПТ-34/ПТ-21/ПТ-23 в реестре; вопрос коммит-прав фронт-сессий — у владельца). *(Хроника сессии «Ридер-IDE» (11.07 → research/16, D29) — в [archive/PROGRESS-2026-07-04-10.md](archive/PROGRESS-2026-07-04-10.md), D31.)* diff --git a/docs/README.md b/docs/README.md index 26a5d8fb..c5f5ccc5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,6 +16,7 @@ - `research/` — фактура ресёрчей 01–22; у принятых — ревью-шапки, часть тел под ⚠ superseded: **читай баннер прежде содержимого**. Ключевые для навигации: 15 голос · 16 ридер-IDE · 17 внешняя критика · 18 рычаги качества · 19 нарезка · 20 банк-майнинг · 21 обзор транспорта · 22 доменные харнессы. - [PROGRESS.md](PROGRESS.md) — журнал: CURRENT-STATE + **ЕДИНЫЙ БЭКЛОГ** (единственный трекер) + живой хвост хроники. НЕ источник решений. - Активные хендофф-промты сессий (состав обновляется при каждом лендинге — норма D39.80): [ORCHESTRATOR_SESSION_PROMPT.md](ORCHESTRATOR_SESSION_PROMPT.md) (роль/нормы; состояния не дублирует) · [POLYGON_PACKAGE4_SESSION_PROMPT.md](POLYGON_PACKAGE4_SESSION_PROMPT.md) (полигон, отложен). · [BACKEND_COLDRUN_DEBUG_SESSION_PROMPT.md](BACKEND_COLDRUN_DEBUG_SESSION_PROMPT.md) (**текущий бэкендный**: ре-проба flash + отладочный холодный прогон coldrun-b). Фронт-промт — в чужой зоне `frontend/docs/`. +- Зоны фронта (чужие, читать при касании стыка; каждая ведёт СВОЙ зонный бэклог — единый бэклог их строк не принимает, D39.84): [../frontend/](../frontend/) — веб-интерфейс: промт фронт-сессий S0–S7 + [STACK_DECISIONS.md](../frontend/docs/STACK_DECISIONS.md) (пины версий точными числами и ловушки, сверены с вебом 02.08) + [BACKLOG.md](../frontend/docs/BACKLOG.md) · [../platform/](../platform/) — SaaS control plane: README-заглушка + [BACKLOG.md](../platform/BACKLOG.md). - `archive/` — история ([правила архива](archive/README.md)): закрытые промты (`prompts/`) · отчёты с ревью-шапками (`reports/` — на них ссылаются приёмки) · исполненные арх-доки (`architecture/`) · слайсы хроники `PROGRESS-*.md`. Инструкции оттуда не исполнять. - Диаграммы: [../backend/docs/components.puml](../backend/docs/components.puml) · [../backend/docs/pipeline.puml](../backend/docs/pipeline.puml) — дом рядом с кодом (D39.80), правятся бэкендом одним коммитом с кодом; вручную НЕ рендерить (владелец смотрит PlantUML-расширением VS Code). diff --git a/docs/architecture/05-decisions-log.md b/docs/architecture/05-decisions-log.md index 0b6d0923..413a2164 100644 --- a/docs/architecture/05-decisions-log.md +++ b/docs/architecture/05-decisions-log.md @@ -1,4 +1,4 @@ -# Журнал решений оркестратора — контракт D1–D39.83 (развязки 04.07 · пакеты 09–10.07 · приёмка/качество-первым/пивот/эмпирика 11–12.07 · арх-ресет+стройка пере-прогонного стека 13–19.07) +# Журнал решений оркестратора — контракт D1–D39.84 (развязки 04.07 · пакеты 09–10.07 · приёмка/качество-первым/пивот/эмпирика 11–12.07 · арх-ресет+стройка пере-прогонного стека 13–19.07) > **⟶ КАРТА АКТУАЛЬНОСТИ (ревизия D31, продлена до D38.2 [12.07]; исторические записи ниже НЕ переписываются — дисциплина D23.3).** Читая контракт целиком, держи под рукой, что чем перекрыто: > ⚠ **Навигация (актуализация 01.08):** карта ниже детально покрывает D1–D39.28; решения D39.29+ живут хронологически в теле файла, **свежая голова — С ХВОСТА** (новые ноты аппендятся вниз). Сводка текущей головы и очередь — CURRENT-STATE в `../PROGRESS.md`. @@ -1251,3 +1251,7 @@ API-529-долг закрыт: 8-осевой refute-by-default воркфлоу ## D39.83 — Ре-проба flash и отладочный холодный прогон с автобанком санкционированы; промт выдан с потолками и двухфазным контролем (02.08) По слову владельца («бэкенд готов? надо идти и делать холодный прогон с контролем бэкенда; цель — отладка; никаких хаков и ворэраундов — только поддерживаемые мультиязычные решения»). Выдан `docs/BACKEND_COLDRUN_DEBUG_SESSION_PROMPT.md`, три фазы со СТОП-точками: **A** — верификация готовности САМОЙ сессией ($0; батарея с фрозен-числами · сквозной fake-путь · чек-лист наблюдаемости как приоры с правом чинить дыры — вердикт готовности за сессией, по предпочтению владельца); **B** — ре-проба DeepSeek-V4-Flash-0731 (строка 74; ≤$0.15; боевая форма через расширение live-рига, N≈8–12 + терминолог-батчи на cap 8000 + классификатор 6/6; критерии бинарны, пограничное = НЕ здоров → развилка (а) флор 16000 / (б) reasoning_effort / (в) ждать — РЕШЕНИЕ ВЛАДЕЛЬЦА; ручка #77 сессией не включается); **C** — холодный прогон coldrun-b с автобанком (≤$5 через `ceilings.book_usd/day_usd`; ступени 2+8 глав в ОДНОЙ БД; банк-пауза `--verify-bank` = инспекционная точка сессии, продолжение неподписанным банком по D39.77; намеренный стоп+резюм посреди волны; наблюдения per-узел: эхо · упоры · банкнота→банк · инъекция байт-диффом (не injected_ids) · flag_reason · голос-оси (для 13б) · wall-clock (первые данные ПТ-19) · деньги двумя путями · F4-бэкапы). Дебаг-дисциплина: фикс = мультиязычный + тест + батарея до resume; архитектурная дыра = СТОП+пинг с вариантами, заморозка чекпойнтом — легитимный исход. Прогон закроет замер цены холодного старта ЦЕЛИКОМ (строка 16). Вне скоупа: Q2/Q7 (полигон), судья Ф2, DC7-остаток (строка 98 — нужен СИДОВЫЙ прогон). Промт холодно аудирован агентом ДО выдачи: 3 major вправлены (`budget_usd` не существует — реальные потолки `ceilings.book_usd`/`day_usd`, мина day_usd 0.25 эталона · носитель боевой формы ре-пробы назван · механика смока/добора одной БД + легитимный re-pin/подпороговая перекупка против ложного СТОПа) + 4 minor; факты аудита вложены в промт приорами (голос-счётчики есть в read-model, но не печатаются; риг 6/6 исполним из бэкенда). Строка 74 → «в работе». Владельцу при запуске: стартовать в долину DeepSeek (02.08.2026, оркестратор №9). ✅ + +## D39.84 — Стек фронта/платформы запинен, восемь решений владельца ратифицированы, работы движка под фронт получили строки, перевод не индексируется (02.08) + +По релею отчёта фронт-сессии (исследование стека закрыто: 15 агентов — 7 направлений × независимые скептики-опровергатели + синтез, версии сверены с вебом 02.08, blocker/major-поправки скептиков записаны исправленными вариантами; артефакты `frontend/docs/STACK_DECISIONS.md` и переписанный `frontend/docs/FRONTEND_SESSION_PROMPT.md` — фронт режется на этапы S0–S7, первая кодовая сессия кончается витриной токенов). Приёмка оркестратора: 10-агентный refute-воркфлоу — ВСЕ несущие бэкенд-утверждения записки CONFIRMED по коду, 8/8 веб-пинов подтверждены первоисточниками (TS7 GA 08.07.2026 БЕЗ программного API до 7.1 → TS 6.0.3 · Vite 8 = Rolldown · Fleet закрыт 22.12.2025 · react-resizable-panels v4 Group/Separator · react-router 8.3 Node≥22.22 — стенд 22.22.3 проходит). **(1) Восемь решений владельца:** рынок глобальный, SEO только Google (Яндекс снят) · выравнивание колонок грубое по единицам экспорта — механизм ГОТОВ (`tmctl export --pairs`, побайтное выравнивание по edit-unit, `internal/pipeline/export.go:89-93`; уточнение приёмки: draft-only-пайплайн шипит по чанкам, для штатного edit-пайплайна утверждение точно) · подсветка сомнительных мест только блок/глава, внутритекстовые спаны НЕ строятся (у $0-гейтов нет байтовых смещений) · остановка на подписи банка = параметр запуска per-run — ГОТОВО (`--verify-bank`, exit 3, `invocation.go:108`/`main.go:39-46`; галочка формы = передача флага, движок не трогается; в draft-only не останавливает — `mining.go:193-197`) · оплат в MVP нет, денежных полей в UI нет вовсе (расход остаётся телеметрией владельца; потолки/rebill-согласие движка канон §5 не трогает) · десктоп = устанавливаемое PWA первым шагом, Tauri по явным триггерам · макет-инструменты не используются, источник вида = пиксель-замеры референса (Fleet невоспроизводим — растровое совпадение не критерий готовности) · аутентификация: ОДНА серверная сессия, предъявление кукой (браузер) или Bearer (десктоп/CLI), principal только в middleware — вход дизайна П-1 платформенного бэклога. **(2) ПТ-34, продуктовый запрет:** ни один символ пользовательского перевода никогда не попадает на публично индексируемый URL — ни витрин, ни «поделиться», ни публичных ссылок чтения (авторское право + политика Google по масштабируемому машин-контенту бьют по всему домену); носитель — двухконтурный деплой (SPA `app.<домен>` целиком под noindex + статический публичный контур, STACK_DECISIONS §4). **(3) ПТ-21 переформулировано:** якорь чтения = edit-unit экспорта, НЕ «чанк пайплайна» — финальный текст существует только на уровне юнита (~1.9 юнита/главу по замеру фронта; «4276 юнитов» из артефактов репо не выводится — полнокнижной БД не существует, что само подтверждает тезис о ре-ингесте; принято как замер сессии, порядок величин сходится с coldrun-a); читалка обязана жить с «глава = один блок». **(4) Работы движка → строки 99–102** (каждая проверена кодом): 99 пофазный прогресс draft N/M ∥ edit N/M (done = все draft-строки членов + edit-строка, `status.go:328-331/365` — индикатор 0% ВСЮ черновую волну; `chunk_status` уже несёт гранулярность — выводимо без миграции схемы) · 100 персист манифеста глав/чанков + хеш источника (каждый read-вызов заново ингестит и режет исходник — `status.go:177-195`, redrive дважды за вызов; замер фронта 1.42–1.51 с CPU/23 МБ; `chunker_version` уже в снапшоте — `pipeline/render.go:53`) · 101 машиночитаемая таблица подписи банка (кап 20 = только stdout `render.go:98`; полная таблица — текстовый сайдкар `.bank-stop.txt`; JSON нет нигде) · 102 внешний trace-контекст в tmctl (TraceID минтится заново каждым вызовом — `main.go:67-70`; внутри вызова трасса цельная, `request_log.trace_id` персистится). **(5) Противоречие разрешено ВЕРНО:** рекомендация интеграционного агента «долгоживущий демон в backend» отвергнута самой сессией по D39.81 — ратификация удержана, HTTP/SSE/очередь в `platform/`. **(6) Две ловушки эксплуатации подтверждены и заведены входами дизайна (строка 95 · П-1):** подпись термина ≠ UPDATE строки — банк пересобирается каждым прогоном (seedGlossary REPLACES + ReplaceBank DELETE/re-INSERT, `seeding.go:18/110`, `glossary.go:158-162`; контракт подписи пишет в файлы-источники: mined-delta/сид; след затирания — только журнальная строка glossary_revisions, без предупреждения) · порядок деплоя платформы: read-путь схему НЕ мигрирует никогда (`store.go:135-143`, «schema vN … expects vM» в обе стороны; чинит write-команда, годится и `redrive --dry-run`; `tmctl backup` НЕ мигрирует). **(7) Норма зонных бэклогов (решение владельца при лендинге):** фронт и платформа держат СВОИ бэклоги в своих зонах — `frontend/docs/BACKLOG.md` (Ф-1..Ф-6) · `platform/BACKLOG.md` (П-1..П-4); засеяны оркестратором при лендинге переносом уже записанных отложенных решений, дальше ведут зоны; ЕДИНЫЙ бэклог PROGRESS фронт/платформа-строк НЕ принимает — остаётся трекером движка/полигона/доков; движковые стыки фронта (зона «бэкенд») живут в едином (строки 99–102); строки 96/97 переехали в платформенный (П-1/П-2) с ID-надгробиями-указателями (ID стабильны навсегда — внешние ссылки не рвутся). **(8) Лендинг зон** `frontend/` + `platform/` + `.gitignore` (`frontend/references/` — скриншоты вне git, пины замеров сохранены в доках). ⚠ Норма-вопрос ВЛАДЕЛЬЦУ: промт S0 велит фронт-сессии «заленди отдельным коммитом» — против нормы «сессии не коммитят» (ORCHESTRATOR_SESSION_PROMPT §роль; прецедент исключения есть — пре-рег фризы полигона); рекомендация оркестратора: дать фронт-сессиям право коммита В СВОЕЙ зоне (изолирована от движка/голдена; шесть сессий визуальных итераций через релей-приёмку каждой = трение без выигрыша), пост-хок ревью оркестратора; до слова владельца действует старая норма, промт фронта не правился (чужая зона) (02.08.2026, оркестратор №9). ✅ diff --git a/docs/glossary.md b/docs/glossary.md index 865cfa65..bf4c9c8c 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -27,7 +27,7 @@ ## Пайплайн и код - **Волны** — waveDraft (черновик) → терминолог → waveEdit (редактура); имена только полные, аббревиатуры W0/W1 запрещены (решение владельца 19.07). -- **Чанк** — единица нарезки книги; будущий якорь синхронизации фронта. +- **Чанк** — единица нарезки книги; **edit-unit (юнит редактуры)** — member-чанки, схлопнутые редактором в один финальный текст: гранулярность финала и экспорта пар (~1.9 юнита/главу; якорь синхронизации фронта — D39.84; draft-only-пайплайн шипит по чанкам). - **Банк (памяти)** — термины/имена/голоса книги на весь прогон; **сид** — стартовый банк книги (YAML; подпись владельца — только вкусовые поля, D39.77); **бриф** — книжные вводные; **банкнота** — канал выноса кандидатов из ответа переводчика; **майнер** — $0-извлечение кандидатов из исходника; **KWIC** — конкорданс-контекст кандидата; **терминолог** — роль перевода/подписи терминов батчами. - **Гейты** — детерминированные $0-проверки перевода; **чекеры K1–K12** — классы дефектов рубрики; **DC1–DC7** — data-driven чекеры на данных пары; **репэйр** — платная петля ремонта (построена, выключена — строка 13). - **Судья** — Ф2-оценка качества (gemini); **канал B** — путь чувствительного контента (Mistral+grok); **лейблы (labels)** — размеченный корпус для precision/recall чекеров, метрики заморожены числами в приёмках. @@ -35,5 +35,5 @@ - **Эхо-мина** — DeepSeek без thinking эхоит вход вместо перевода; гейт `echoMineViolation` принуждает thinking-ON. - **Langpack / пар-файл** — данные языковой пары (`backend/configs/langpacks/`); книжное в пар-слое = утечка; **общность** — ревью-вопрос «заработает ли пара/вторая книга без правки Go». - **Ведро B/D** — корзины триажа карты общности D39.60 (B «пар-модуль без гейта» · D «удалить»). -- **tmctl** — CLI бэкенда (translate / report / status / export / redrive / seed-lint). +- **tmctl** — CLI бэкенда (translate / report / status / export / redrive / seed-lint / backup). - **COGS** — себестоимость перевода; **ре-проба** — дешёвый повторный замер провайдера после аномалии (строка 74). diff --git a/docs/product-requirements.md b/docs/product-requirements.md index 791be7d5..1ce971d4 100644 --- a/docs/product-requirements.md +++ b/docs/product-requirements.md @@ -46,18 +46,19 @@ | ПТ-16 | Абьюз/misuse-прескрин: дёшево, точно, до трат токенов, минимум false positive (V2-п.1, H8) | ⭕ | строка 94; UI-контракт отказа — проект-решение D39.80 к Ф3-брифу (вывод оркестратора, не цитата брифа) | | ПТ-17 | Лимит размера входа настройкой (V2-п.3, H7) | ⭕ | строка 94 | | ПТ-18 | Стоп и продолжение пайплайна; абьюзивный прогон НЕ продолжать (V2-п.2, H10) | 🔶 | graceful stop по сигналу (`cmd/tmctl/main.go` NotifyContext) + чекпойнты/redrive; продукт-кнопки и связка с прескрином = строка 94; API-форма — контракт 95 | -| ПТ-19 | Скорость: «очень быстрый перевод книги — киллерфича» (V4-п.1, H9); видимый прогресс/ETA — из Ф3-видения ридер-IDE (цветная полоса статуса), не из V4 | 🔶 | волны параллельны по чанкам; замер скорости и ETA на целой книге = строка 54 (МАСШТАБ) | +| ПТ-19 | Скорость: «очень быстрый перевод книги — киллерфича» (V4-п.1, H9); видимый прогресс/ETA — из Ф3-видения ридер-IDE (цветная полоса статуса), не из V4 | 🔶 | волны параллельны по чанкам; замер скорости и ETA на целой книге = строка 54 (МАСШТАБ); пофазный индикатор draft/edit = строка 99 (D39.84 — текущий done-счётчик стоит 0% всю черновую волну) | ## Фронт (Ф3) | ID | Требование (источник) | Статус | Носитель / доказательство | |---|---|---|---| | ПТ-20 | Ридер-IDE: VS Code-подобный фронт агентного перевода (V0-п.20/23) | ⭕ | research/16 принят (D29); строки 69–71; F3-brief — D29 п.3. Ф3 ОТКРЫТА 02.08 (D39.81): фронт-сессия живёт на моках (`frontend/`), бэкенд-сторона = строки 95/96 | -| ПТ-21 | Параллельное чтение двух текстов с выравниванием по смыслам (V0-п.21) | ⭕ | якорь = чанк пайплайна (решено); реализация Ф3 | +| ПТ-21 | Параллельное чтение двух текстов с выравниванием по смыслам (V0-п.21); выравнивание грубое, по единицам экспорта — принято владельцем 02.08, спаны внутри текста не строятся | 🔶 | механизм готов: `tmctl export --pairs` выравнивает пары побайтно по единицам редактуры (`internal/pipeline/export.go:89-93`); якорь = **edit-unit**, НЕ чанк (переформулировано D39.84 — финальный текст существует только на уровне юнита, ~1.9 юнита/главу, местами глава = один блок; читалка обязана это выдерживать); UI-читалка = Ф3 (этап S6) | | ПТ-22 | Настройки от человека: 18+, жанр и т.п. (V0-п.22) | 🔶 | `book.yaml` (labels/жанр) данными; UI = Ф3 | -| ПТ-23 | Веб-ПЕРВЫЙ фронт; SEO/ранжирование Google — куки, страницы-сироты, актуальные алгоритмы (V5-п.2); продукт = **SaaS**, не локальное приложение (решение владельца 02.08, D39.81 — натив-прицел V0-п.26 СНЯТ этим решением, вернуть только новым словом владельца) | ⭕ | строка 71 (Ф3-бриф); ⚠ SEO определяет выбор фреймворка (SSR vs SPA) — обязан войти в Ф3-дизайн ДО выбора стека | +| ПТ-23 | Веб-ПЕРВЫЙ фронт; SEO/ранжирование Google — куки, страницы-сироты, актуальные алгоритмы (V5-п.2); продукт = **SaaS**, не локальное приложение (решение владельца 02.08, D39.81 — натив-прицел V0-п.26 СНЯТ этим решением, вернуть только новым словом владельца); SEO только под Google, Яндекс снят; рынок глобальный; десктоп = PWA первым шагом, Tauri по явным триггерам (решения владельца 02.08, D39.84) | ⭕ | строка 71 (Ф3-бриф); SEO вошёл в стек-дизайн ДО выбора (D39.84, требование исполнено): двухконтурный деплой — SPA `app.<домен>` целиком под noindex + статический публичный контур ≤3 кликов от главной (лечение страниц-сирот), `STACK_DECISIONS.md` §4; SSR-вопрос закрыт этим решением | | ПТ-24 | Цикл согласования глоссария с профпереводчиком/редактором (V0-п.23) | 🔶 | подписной цикл терминолога в бэкенде есть; UI = Ф3 | | ПТ-33 | Интерфейс НЕ раскрывает конвейер: ни моделей, ни стадий, ни внутренней терминологии — пользователь видит «загрузка → разбор → перевод → подпись банка → финал → готово» (решение владельца 02.08) | ⭕ | инвариант D39.81; носитель — строка 95 (контракт API: слой перевода внутренних вердиктов в продуктовые понятия); ревью-вопрос «сменится стадия конвейера — придётся ли править фронт?» | +| ПТ-34 | Пользовательский перевод НИКОГДА не попадает на публично индексируемый URL — ни витрин примеров, ни «поделиться главой», ни публичных ссылок чтения (жёсткий продуктовый запрет, решение владельца 02.08; авторское право на исходники + политика Google по масштабируемому машин-контенту действуют на весь домен) | ⭕ | инвариант D39.84; носители: двухконтурный деплой `STACK_DECISIONS.md` §4 (SPA под `X-Robots-Tag: noindex` на каждом HTML-ответе; публичный контур без контента переводов) + контракт 95 + платформенный бэклог П-1 | ## Качество процесса и самоулучшение diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 00000000..f7f989f4 --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,29 @@ +# frontend — веб-интерфейс + +Зона записи новой сессии «Фронт». Пусто: заведено под будущий интерфейс, кода ещё нет. + +## Что здесь будет + +Веб-приложение поверх `../platform/`. MVP — не IDE, а **дашборд + читалка**: библиотека книг, +наблюдение за прогоном, подпись банка памяти, сравнение оригинала с переводом, добавление главы. +Редактирование перевода прямо в интерфейсе — ПОЗЖЕ (тогда появится редактор текста; в MVP не нужен). + +Десктоп — то же самое приложение в окне (Tauri), отдельной логики не имеет. В MVP не делается. + +## Документы + +- [`docs/FRONTEND_SESSION_PROMPT.md`](docs/FRONTEND_SESSION_PROMPT.md) — промт фронт-сессий: + область этапов, референсы с измеренными значениями, экраны, ограничения, порядок работы. +- [`docs/STACK_DECISIONS.md`](docs/STACK_DECISIONS.md) — пины версий, ловушки и список того, + что достраивается в движке. Источник: многоагентное исследование 02.08.2026. +- `references/` — три скриншота-референса (Fleet, Antigravity). + +## Источник внешнего вида — один + +**Замеры с `references/fleet.png`, зафиксированные в `tokens.css`.** Промежуточных дизайн-макетов +нет: инструменты проектирования макетов не используются (решение владельца 02.08). Палитра и +геометрия сняты с референса пипеткой и лежат в `STACK_DECISIONS.md` и §1.1 промта — их берут +как данность, а не выводят заново. + +⚠ JetBrains Fleet закрыт (скачивание прекращено 22.12.2025) — добрать новые измерения неоткуда. +Всё, что не замерено (кегли, интерлиньяж, внутренние отступы), подбирается на глаз по скриншоту. diff --git a/frontend/docs/BACKLOG.md b/frontend/docs/BACKLOG.md new file mode 100644 index 00000000..69ac2c7a --- /dev/null +++ b/frontend/docs/BACKLOG.md @@ -0,0 +1,12 @@ +# Бэклог фронта (зонный) + +> Ведёт зона `frontend/` (решение владельца 02.08, D39.84: фронт и платформа держат СВОИ бэклоги; единый бэклог `docs/PROGRESS.md` — трекер движка/полигона/доков, фронт-строк не принимает). Нормы те же: ID стабилен навсегда, каждая петля получает диспозицию. Запросы к ДВИЖКУ сюда не пишутся — они заходят строками единого бэклога через оркестратора (пример: строки 99–102 — пофазный прогресс · манифест глав · машиночитаемая таблица подписи · трасса). Засеян оркестратором при лендинге D39.84 — дальше правят фронт-сессии. + +| ID | Хвост | Вес | Источник | +|---|---|---|---| +| Ф-1 | **Этапы S2–S7** (`FRONTEND_SESSION_PROMPT.md`): S2 оболочка + слой `src/ui/` · S3 слой данных/MSW/фикстуры всех состояний · S4 библиотека/загрузка/разбор/прогресс · S5 банк памяти и подпись (самый тяжёлый) · S6 читалка двух колонок и замечания · S7 метаданные/экспорт/настройки/сквозной прогон | по очереди сессий (S0/S1 — текущая) | FRONTEND_SESSION_PROMPT | +| Ф-2 | **React Compiler** — включить ОТДЕЛЬНЫМ шагом после заморозки интерфейса, с CI-проверкой, что вставки реально попали в бандл (в MVP выключен; совместимость держит линт eslint-plugin-react-hooks) | после заморозки UI | STACK_DECISIONS §1 | +| Ф-3 | **Пересмотр TS 6 → TS 7** после выхода TS 7.1 с программным API (~октябрь 2026); решение обратимо — тайпчек не участвует в сборке | триггер: релиз TS 7.1 | STACK_DECISIONS §1 | +| Ф-4 | **Токен-гейт на отступы** (`padding`/`margin`/`gap`/`border-radius`) — вторым шагом, когда шкала токенов зафиксирована (иначе гейт мешает подбору) | после S1-витрины | STACK_DECISIONS §3 | +| Ф-5 | **Tauri 2.x вторым шагом** — по явным триггерам (трей · глобальные горячие клавиши · распространяемый .exe · офлайн · хранилище учёток ОС); до того — установимое PWA, только браузерные API | триггеры названы | STACK_DECISIONS §6, D39.84 | +| Ф-6 | **`@tanstack/react-virtual`** — в резерве, подключать только по замеру (дефолт виртуализации — RAC Virtualizer) | по замеру | STACK_DECISIONS §2 | diff --git a/frontend/docs/FRONTEND_SESSION_PROMPT.md b/frontend/docs/FRONTEND_SESSION_PROMPT.md new file mode 100644 index 00000000..42d9c00e --- /dev/null +++ b/frontend/docs/FRONTEND_SESSION_PROMPT.md @@ -0,0 +1,425 @@ +# Промт: сессия ФРОНТ TextMachine — MVP веб-интерфейса + +## Область ЭТОЙ сессии — этапы S0 и S1, дальше не идти + +Фронт режется на шесть сессий. Ты — первая. **Твоя работа кончается на витрине токенов, до единого +экрана приложения.** Это не осторожность: без проверяемой петли обратной связи и сошедшихся токенов +все следующие этапы слепы, а смешивание инструментальной работы с интерфейсной сжигает контекст. + +| Этап | Что | Сессия | +|---|---|---| +| **S0** | Планирование: как писать фронт. Пины версий, карта файлов, правила, протокол проверки | **твоя** | +| **S1** | Инструменты, скриншот-цикл, `tokens.css`, витрина | **твоя** | +| S2 | Оболочка (три панели, вкладки, статус-полоса) + слой `src/ui/` | отдельная | +| S3 | Слой данных, MSW, фикстуры всех состояний | хвост S2 или отдельная | +| S4 | Библиотека, загрузка, разбор, прогресс перевода | отдельная | +| S5 | Банк памяти и подпись (самый тяжёлый) | отдельная | +| S6 | Читалка двух колонок и замечания | отдельная | +| S7 | Метаданные, экспорт, настройки, сквозной прогон | отдельная | + +**S0 лендится отдельным коммитом до первой строки кода** — иначе план останется словами. + +## Обязательное чтение перед работой + +1. `frontend/docs/STACK_DECISIONS.md` — **пины версий и ловушки**. Все версии сверены 02.08.2026 + многоагентным исследованием с адверсариальной проверкой. Не выбирай библиотеки сам, + не «обновляй» пины по памяти: твои знания об экосистеме устарели, а вся документация + в сети описывает ПРОШЛЫЕ версии этих инструментов. +2. `docs/product-requirements.md` — реестр продуктовых требований владельца. +3. `docs/glossary.md` — расшифровка проектных сокращений. +4. `frontend/references/*.png` — три скриншота, **открой и посмотри** (ты умеешь читать изображения). + +## Кто ты и твоя зона + +Ты фронтенд-сессия. **Зона записи — только `frontend/`.** `backend/`, `platform/`, `docs/`, `eval/` — read-only; расхождения и вопросы — пингом владельцу, не правкой чужой зоны. Параллельные сессии в проекте — норма: перед любой git-операцией `git status`, чужие незакоммиченные файлы не трогать, никаких `reset --hard` и перезаписи истории. + +Общие правила проекта — в `CLAUDE.md` в корне. Коммиты: английский, одно предложение ≤30 слов, без Co-Authored-By. + +## Что за продукт + +Веб-сервис перевода книг (веб-новеллы, ранобэ) с одного языка на другой через ИИ. Пользователь загружает книгу, запускает перевод, подписывает словарь терминов, читает результат, выгружает готовое. + +**Бэкенда пока нет** — точнее, движок перевода есть, но HTTP-API к нему ещё не построено. Ты работаешь на моках (см. §6). Это не помеха: контракт данных зафиксирован ниже, замена моков на реальные запросы будет точечной. + +--- + +## 1. Референсы — копировать, а не вдохновляться + +В `frontend/references/` лежат три скриншота. **Открой их своим инструментом чтения файлов — ты умеешь смотреть изображения.** Это обязательный первый шаг, до единой строки кода. + +- `fleet.png` — **главная основа макета**. Копируем оболочку целиком: как устроены панели, отступы, скругления, плотность, палитра. +- `antigravity_main.png` — пустое состояние (ничего не выбрано). +- `antigravity_chat.png` — рабочее состояние с тремя колонками и правой панелью-документом. + +Владелец сформулировал прямо: **«взять макет Fleet как он есть по блокам и стилю и полностью скопировать, переделав под наши нужды»**. Это не тот случай, где нужна своя эстетика. Нужна чужая, воспроизведённая точно. + +### 1.1. Измеренные значения — брать эти, не выводить свои + +Ниже — не оценка на глаз, а **замер пикселей** `fleet.png` (Python/PIL: гистограмма поверхностей, поиск насыщенных пикселей, срез по горизонтали, детект края скругления). Скриншот снят при масштабе **2x** — установлено по кнопкам окна macOS: шаг 40 физических пикселей против штатных 20 CSS. Все размеры ниже уже переведены в CSS-пиксели. + +**Поверхности Fleet:** + +| Роль | Значение | Где замерено | +|---|---|---| +| Фон оболочки: промежутки, верхняя полоса, статус-полоса | `#090909` | 10.5% площади | +| Заливка панели (все три панели одинаковы) | `#17191a` | 80.5% площади | +| Приподнятая поверхность / наведение | `#27292b` | | +| Выбранная строка, активная вкладка | `#353739` | | +| Подсветка текущей строки (синеватая) | `#152945` | | +| Выделение | `#164e8d` | | +| Основной текст | `#dfe1e3` | | +| **Акцент (фокус ввода)** | **`#746deb`** | тон 243°, насыщенность 0.76 | +| Красный индикатора | `#b82e45` | тон 350° | + +**Геометрия Fleet:** + +- **Промежуток между панелями — ровно 8px**, одинаковый везде: слева, между всеми панелями, справа (замер среза: четыре промежутка по 16 физических пикселей, без единого исключения). +- **Радиус скругления панели — 6px** (край выходит на прямую за ~11 физических пикселей). +- Панели не имеют ни рамок, ни теней: отделение только промежутком и разницей заливки `#090909` → `#17191a`. + +**Antigravity — для пустого состояния и настроек** (чистый нейтральный серый, без холодного оттенка, в отличие от Fleet): + +| Роль | Значение | +|---|---| +| Фон | `#101010` | +| Боковая панель | `#161616` | +| Приподнятая карточка (поле ввода) | `#1c1c1c` | +| Заливка кнопки основного действия | `#252525` | +| Разделитель / граница | `#323232` | +| Текст | `#cecece` | + +**Что НЕ замерено и требует проверки скриншот-циклом:** размеры шрифтов, высота строк, внутренние отступы панелей. Их снимай сам сравнением своей витрины с `fleet.png`. + +### Что именно снято с `fleet.png` (следуй этому буквально) + +**Оболочка.** Очень тёмный, почти чёрный фон окна. Панели лежат на нём **отдельными скруглёнными «карточками»** (радиус ~8–10px) с чуть более светлой заливкой, разделённые узкими промежутками фона ~6–8px. Теней нет вообще — разделение только промежутком и разницей заливки. Это главная визуальная подпись Fleet, и владельцу нравится именно она. + +**Верхняя полоса.** Слева кнопки сворачивания панелей (левая / нижняя / правая), по центру — название текущего контекста, справа — ряд иконок-действий. Тонкие линейные монохромные иконки. + +**Левая панель.** Сверху **ряд вкладок внутри самой панели** (`Files · Search · Git · History · +`) — не отдельный сайдбар с иконками, а вкладки в шапке панели. Ниже дерево: корень, узлы с шевронами, иконки типов, у выбранной строки — светлая скруглённая подложка (~6px), а не рамка. + +**Центр.** Полоса вкладок: иконка + имя + крестик; активная вкладка светлее и скруглена. Ниже содержимое с колонкой номеров строк приглушённого цвета, у текущей строки — едва заметная подсветка всей полосы. Мелкие подписи-подсказки над блоками очень тусклым серым. В правом верхнем углу — компактный индикатор проблем. + +**Нижняя панель центра** — отдельная скруглённая карточка со своей вкладкой. + +**Правая панель.** Вкладка с заголовком и `+`. В пустом состоянии — центрированный блок: иконка, заголовок, описание, ряды «клавиша + подпись». Внизу поле ввода с **акцентной рамкой** — единственное цветное пятно в панели. + +**Нижняя статус-полоса** лежит на фоне оболочки, вне карточек: слева хлебные крошки, справа компактные метаданные состояния. + +**Цвет.** Практически монохром: серый текст на тёмном. Цвет встречается редко и всегда что-то означает. Акцент — один, холодный. + +**Типографика.** Компактный чистый гротеск ~13px в интерфейсе, моноширинный в содержимом. Плотные строки. + +### Что снято с `antigravity_main.png` — пустое состояние + +Главная область почти пустая, и по её **центру стоит один составной блок** — скруглённая карточка ввода с подсказкой внутри и рядом мелких управляющих элементов по нижнему краю. Никаких иллюстраций, никаких «начните работу» с картинками. Просто действие по центру пустоты. + +В левой панели: **выделенная кнопка основного действия во всю ширину сверху**, ниже пункты навигации с иконками, ниже секция-заголовок мелким приглушённым шрифтом с иконками действий справа, ниже дерево. **`Настройки` прибиты к самому низу панели.** + +### Что снято с `antigravity_chat.png` — рабочее состояние + +Три колонки. В правой панели — **ряд вкладок сверху** (несколько именованных разделов) и содержимое как форматированный документ: заголовки, абзацы, **блоки-выноски с цветной левой границей** (синяя — заметка, зелёная — подсказка) и мелкие «чипы» с моноширинным текстом внутри абзацев. + +**Эти выноски — наша модель для подсветки неточностей перевода** (см. §4, пункт про ненавязчивость). Цветная полоска слева и тусклая подпись — вместо заливки текста. + +--- + +## 2. Раскладка нашего приложения + +Оболочка Fleet, наполнение наше. + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ верхняя полоса: сворачивание панелей · название книги · действия │ +├──────────────┬────────────────────────────────┬─────────────────┤ +│ ЛЕВАЯ │ ЦЕНТР │ ПРАВАЯ │ +│ │ │ │ +│ вкладки: │ вкладки открытых глав │ вкладки: │ +│ Книги · │ │ О книге · │ +│ Банк · │ содержимое: │ Замечания │ +│ Поиск │ — две колонки оригинал/перевод │ │ +│ │ — или таблица банка памяти │ метаданные, │ +│ дерево: │ — или пустое состояние │ выноски с │ +│ книга │ │ неточностями │ +│ ├ глава 1 │ │ │ +│ ├ глава 2 │ │ │ +│ └ + глава │ │ │ +│ │ │ │ +│ ⚙ Настройки │ │ │ +├──────────────┴────────────────────────────────┴─────────────────┤ +│ статус-полоса: путь · состояние · прогресс │ +└─────────────────────────────────────────────────────────────────┘ +``` + +- **Левая панель** — вкладки в шапке (`Книги` / `Банк памяти` / `Поиск`), дерево книг и глав, `Настройки` внизу. Клик по книге открывает её состояние, клик по главе открывает главу в центре. +- **Центр** — вкладки открытых глав, как файлы в Fleet. +- **Правая панель** — вкладки `О книге` (метаданные) и `Замечания` (места, требующие внимания). +- Все три панели сворачиваются кнопками в верхней полосе. + +--- + +## 3. Сценарий и экраны + +### 3.1. Пусто — ни одной книги + +Центр пустой, по центру — блок добавления книги в духе `antigravity_main.png`: скруглённая карточка, зона переноса файла с подсказкой, под ней компактный ряд полей (язык оригинала, язык перевода, жанр) и кнопка. Без иллюстраций. + +### 3.2. Загрузка книги + +После выбора файла: **видимое подтверждение, что файл загружен целиком и успешно** — размер, объём, определённый язык. Не молчаливый переход. + +### 3.3. Разбор на главы + +Дальше книга разбирается на главы. Показать прогресс разбора; по завершении главы появляются деревом в левой панели. Это отдельный видимый шаг, а не часть перевода. + +### 3.4. Перевод — первый проход + +Кнопка запуска перевода. Пока идёт: + +- **у каждой главы в дереве — свой индикатор выполнения** (крутящийся/прогресс), главы обрабатываются не по порядку и это нормально; +- общий прогресс по книге в статус-полосе; +- ⚠ **не рассказывать, что происходит внутри.** Никаких «сейчас работает редактор», «идёт добыча глоссария», никаких названий моделей. Пользователь видит «идёт перевод» и прогресс. Всё. + +### 3.5. Банк памяти — подпись + +По завершении первого прохода становится доступен **банк памяти**: таблица терминов книги (имена персонажей, места, термины) с предложенным переводом. Пользователь правит и подписывает. + +Таблица должна быть быстрой в работе: терминов бывают сотни, идут подряд, **клавиатура важнее мыши** (перемещение по строкам, утверждение, правка без мыши). Массовые действия. Отдельная кнопка завершения подписи. + +### 3.6. Перевод — финальный проход + +После подписи — кнопка запуска финального перевода. Те же индикаторы, что и в 3.4. + +### 3.7. Чтение и сравнение + +Открытая глава в центре: **две колонки — оригинал и перевод**, пролистываются вместе. Абзацы слева и справа по количеству часто НЕ совпадают — это нормально для художественного перевода, выравнивание идёт по крупным блокам, не построчно. Возможность листать главы вперёд-назад. + +### 3.8. Замечания + +Места, где перевод может быть неточен, помечаются **ненавязчиво**: тонкая цветная полоска у левого края блока и тусклая подпись — по образцу выносок из `antigravity_chat.png`. Никакой заливки текста, никаких ярких маркеров, никаких иконок-восклицаний. Список всех замечаний главы — в правой панели, вкладка `Замечания`. + +Правило: **если экран выглядит тревожным — он неправильный.** Замечание — это приглашение посмотреть, а не сигнал аварии. + +### 3.9. Метаданные книги + +Правая панель, вкладка `О книге`: название, языки, жанр, число глав, объём, даты, состояние перевода. Спокойный список пар «поле — значение», не карточки со статистикой. + +⚠ Денежных полей здесь нет — см. §4.8. + +### 3.10. Добавление главы + +В дереве, под главами книги — действие добавления новой главы. Загруженная глава встаёт в дерево и может быть переведена отдельно. + +### 3.11. Экспорт + +Кнопка выгрузки текущей книги. Выбор формата, подтверждение готовности. + +### 3.12. Настройки + +Отдельный раздел (открывается из низа левой панели). Внутри: профиль и доступ, конфигурация моделей, параметры перевода по умолчанию. **Всё техническое живёт здесь и только здесь** — в рабочем потоке его нет. + +⚠ Подписки, тарифов, остатка и счетов в MVP НЕТ — см. §4.8. + +--- + +## 4. Жёсткие ограничения + +1. **Не раскрывать устройство бэкенда.** Ни названий моделей, ни стадий конвейера, ни внутренней терминологии в рабочих экранах. Пользователю видны: загрузка, разбор, перевод, банк, готово. Всё техническое — в настройках. +2. **Цвет означает состояние и больше ничего.** Интерфейс монохромный. Цветными бывают: полоска замечания, индикатор состояния главы, акцент фокуса. Никаких зелёных кнопок «сохранить» и красных «удалить». +3. **Ненавязчивость замечаний** — §3.8. Это отдельное требование владельца, не деталь. +4. **Плотность.** Работают подолгу; лучше видеть много, чем красиво и мало. Компактные строки, небольшие отступы, маленькие скругления — как во Fleet. +5. **Только десктоп**, тёмная тема, базовая ширина 1440, работать должно и на 1920. Мобильной версии нет. +6. **Русский интерфейс**, кириллица в реальных пропорциях. +7. **Никаких готовых UI-китов** (MUI, Ant, Chakra) — они не дадут воспроизвести Fleet. Только собственные компоненты на токенах; для поведения выпадающих меню, диалогов и подсказок — headless-примитивы без своих стилей. + +### Решения владельца от 02.08 — приняты, не переоткрывать + +8. **Денег в интерфейсе MVP нет вообще.** Ни сумм, ни потолков, ни оценки стоимости до запуска, ни + счётчика во время прогона, ни подписки, ни остатка. Оплаты в MVP не будет, показывать нечего. + Учёт расхода остаётся внутри движка как телеметрия владельца. Если видишь денежное поле в + каком-либо разделе этого промта — это остаток прошлой редакции, его быть не должно. +9. **Подсветка сомнительных мест — только на уровне блока и главы.** Подчёркивания внутри текста + не делаем: у проверок движка нет байтовых смещений, только счётчики. Вопрос закрыт, к нему не + возвращаться. +10. **Выравнивание колонок — грубое, по единицам экспорта**, ориентир «глава целиком». Механизм в + движке уже есть (`tmctl export --pairs`), достраивать ничего не надо. Читалка обязана нормально + выглядеть и когда вся глава оказалась одним блоком. +11. **Остановка на подписи банка — параметр запуска**, задаётся галочкой в форме перед каждым + прогоном, а не глобальной настройкой. + +--- + +## 5. Технический стек + +**Стек зафиксирован в `frontend/docs/STACK_DECISIONS.md` — бери пины оттуда, не выбирай сам.** +Коротко: React 19.2.8 · TypeScript 6.0.3 (не 7 — там нет программного API) · Vite 8.2.0 (внутри +Rolldown, не Rollup) · react-router 8.3.0 в библиотечном режиме · TanStack Query 5 + Zustand 5 · +CSS Modules + `tokens.css` · **react-aria-components 1.20.0 как ЕДИНСТВЕННАЯ библиотека +примитивов** · react-resizable-panels 4.12.2 (API v4: `Group`/`Panel`/`Separator`). + +Три вещи, которые чаще всего делают неправильно, — прочитай про них в STACK_DECISIONS: +раздел про гейт «одно место для цвета», раздел про читалку без синхронизации прокруток, +и §7 «Ловушки». + +**Никакого редактора текста** в этом MVP: тексты только читают и сравнивают. + +Структура: + +``` +frontend/ + references/ скриншоты (уже лежат) + docs/ этот промт и последующие заметки + src/ + tokens/ tokens.css — ЕДИНСТВЕННЫЙ источник цвета и размера + api/ слой данных: сейчас моки, потом HTTP. Один вход. + mock/ фикстуры + shell/ оболочка: панели, вкладки, статус-полоса + features/ books, chapters, bank, reader, settings + ui/ кнопки, поля, таблица, дерево, выноска +``` + +--- + +## 5.1. Поддерживаемость — требование владельца, не пожелание + +Владелец сформулировал прямо: **«главное, чтоб это было очень легко поддерживаемо»**. Этот код будут править другие сессии, не ты. Правила ниже — проверяемые, не лозунги. + +1. **У каждой вещи одно место.** Цвет и размер — только `tokens.css`. Данные — только `src/api/`. Если значение появилось во втором месте, это ошибка, а не удобство. +2. **Плоско и скучно.** Никаких абстракций «на будущее», фабрик, слоёв ради слоёв. Проектный норматив: механизм строится там, где несёт ценность, а не ради архитектурной красоты. Дублирование двух строк лучше преждевременного обобщения. +3. **Файл = один компонент** плюс его `.module.css` рядом. Больше ~150 строк — делить. +4. **Компоненты глупые.** Данные приходят пропсами. Запросы живут на уровне экрана, не в листьях дерева. +5. **Состояние ровно в двух местах:** TanStack Query — всё серверное, Zustand — состояние интерфейса. Копий серверных данных в локальном состоянии нет. Контекстов «на всякий случай» нет. +6. **Глобальных стилей два файла:** сброс и `tokens.css`. Всё остальное — CSS Modules, они скоупятся сами. +7. **Никаких обёрток над обёртками** и никаких UI-китов. +8. **Имена человеческие, без аббревиатур** — проектная норма. +9. **Комментарии короткие:** одна-две строки «почему», не «что». Простыни не нужны. +10. **Каждый экран открывается в изоляции** — свой маршрут и своя фикстура, чтобы его можно было снять скриншотом и проверить отдельно от остальных. + +**Проверка на поддерживаемость, которую применяй к своему коду:** добавление нового состояния главы или нового вида замечания должно требовать правки **одного** файла. Если требует трёх — структура неверная, переделай до того, как двинешься дальше. + +## 6. Данные: моков придерживаться, API не выдумывать + +HTTP-слоя ещё нет. **Весь доступ к данным — через `src/api/`, внутри которого сейчас моки.** Компоненты не знают, что данные поддельные. Когда появится сервер, меняется один модуль. + +Заведи фикстуры на одну книгу целиком: метаданные, 5–8 глав, у каждой главы оригинал и перевод по несколько абзацев, несколько помеченных мест, таблица банка на 20–30 терминов в разных состояниях, состояние прогона. + +**Материал для фикстур бери реальный** — китайский текст с русским переводом, имена и термины. Выдуманный «Lorem ipsum» даст неверную плотность: кириллица длиннее латиницы, иероглифы короче всего, и колонки поедут. Пример реального фрагмента лежит в `backend/example/chapter1-zh.txt` (читать можно, править нельзя). + +Состояния, которые обязаны быть в фикстурах и нарисованы: книга не начата · разбирается · переводится (первый проход) · ждёт подписи банка · переводится (финал) · готова · остановлена пользователем · отклонена (не удалось разобрать файл) · прервана ошибкой. + +--- + +## 7. Как работать — это важнее, чем что писать + +### 7.1. Смотри на то, что построил + +**Заведи цикл со скриншотами первым делом, до экранов.** Скрипт `npm run shot` поднимает приложение, снимает PNG в `frontend/.shots/`, ты **открываешь этот PNG и смотришь на него** (ты умеешь читать изображения), сравниваешь с `references/fleet.png`, правишь. + +Без этого цикла ты пишешь вслепую: код валиден, вид случаен. Это единственный способ выполнить требование «скопировать Fleet». + +**Установка проверена на этой машине — делай ровно так, sudo не нужен ни на одном шаге.** Среда: WSL2, Ubuntu 24.04, Node 22, пароль root недоступен. + +```bash +npm i -D playwright +npx playwright install chromium # БЕЗ --with-deps: он требует sudo и ставит лишнее +``` + +Chromium запустится не сразу: не хватает четырёх системных библиотек (`libnss3.so`, `libnssutil3.so`, `libnspr4.so`, `libasound.so.2`). Ставятся локально, без root: + +```bash +mkdir -p .tooling && cd .tooling +apt-get download libnss3 libnspr4 libasound2t64 +for d in *.deb; do dpkg -x "$d" root; done +rm -f *.deb && cd .. +``` + +Путь к ним — `.tooling/root/usr/lib/x86_64-linux-gnu`. Пропиши его прямо в команду, чтобы никто о нём больше не думал: + +```json +"scripts": { + "shot": "LD_LIBRARY_PATH=$PWD/.tooling/root/usr/lib/x86_64-linux-gnu node scripts/shot.mjs" +} +``` + +В `.gitignore`: `.tooling/` и `.shots/` — бинарники и снимки в репозиторий не едут. + +Проверка, что цикл живой (сделай её до всякого интерфейса): отрисуй страницу с панелью `#17191a` на фоне `#090909`, радиус 6, отступ 8 — сними, открой, убедись, что видишь именно это. Работает браузер headless, окна нет, графический сервер не нужен. + +### 7.2. Порядок твоей сессии + +**S0 — план (кода нет).** Прочитай всё из блока обязательного чтения. Напиши +`frontend/docs/FRONTEND_PLAN.md`: таблица пинов (пакет · версия · дата релиза · зачем именно нам, +сверенная по npm), карта `src/` с назначением каждой папки, правила поддерживаемости в проверяемой +форме, протокол скриншот-цикла и критерий сравнения с референсом. **Заленди отдельным коммитом.** + +**S1 — инструменты и токены.** + +1. Проверь `node -v` — нужно **≥ 22.22**. Установи Playwright по процедуре из §7.1 (без sudo). +2. Каркас: Vite + React + TS, ESLint + stylelint + prettier, единая команда `npm run check`. +3. Скриншот-цикл и проверка, что он живой (страница с панелью на фоне, снять, посмотреть). +4. `tokens.css` — значения из `STACK_DECISIONS`/§1.1 этого промта, с комментарием об источнике. + Задай `@layer` явно: порядок каскада между стилями React Aria, токенами и модулями — источник + тихих расхождений. Сразу стилизуй скроллбары: дефолтные на Windows толстые и светлые, они + ломают вид на трёх панелях. +5. **Витрина**: страница из панелей, вкладок, строки дерева и строки таблицы. Сними, положи рядом + с `fleet.png`, **посмотри обе**, сведи. +6. Контракт-тест токенов: рендерим корень, сверяем вычисленные значения CSS-переменных с + замеренными числами. Это заменяет визуальный гейт с эталонами. + +**На витрине остановись.** Если токены не сошлись — это и есть результат сессии, честно описанный; +дальше не иди. Экраны пишут следующие сессии. + +### 7.3. Ревью исполнением — обязательно + +Проектная норма: любая сессия, пишущая код, обязана **проверять себя исполнением**, а не заявлением. Для тебя это значит: + +- приложение реально запускается, экран реально открывается — проверено запуском, не предположением; +- скриншот снят и просмотрен, а не «должно выглядеть так»; +- расхождения с референсом названы вслух, даже если исправить не успел; +- если чего-то не сделал — сказано прямо, без «в основном готово». + +Отчёт в конце: что построено, что видно на скриншотах, где отошёл от референса и почему, что осталось. + +### 7.4. Чего не делать + +- Не изобретать API и не ходить в `backend/` за данными — только моки. +- Не тащить UI-киты и не «улучшать» референс своим вкусом. +- Не рисовать мобильную версию, светлую тему, иллюстрации пустых состояний. +- Не раскрывать конвейер (§4.1) — это самое лёгкое требование забыть. +- Не хардкодить цвета и размеры мимо `tokens.css`. + +--- + +## 8. Готово — это когда (для ТВОЕЙ сессии, S0+S1) + +- `FRONTEND_PLAN.md` заленден отдельным коммитом до кода. +- `npm run check` зелёный и делает все четыре шага. +- `npm run shot` снимает PNG, ты его открывал и смотрел. +- `tokens.css` — единственный источник цвета и размера; гейт против хардкода включён и **проверен + на живом нарушении** (вставь `#fff` в компонент, убедись, что проверка падает, убери). +- Витрина снята и сведена с `fleet.png`; расхождения названы вслух. +- Контракт-тест токенов проходит. + +⚠ **Критерий сравнения — не растровое совпадение.** JetBrains Fleet закрыт (скачивание прекращено +22.12.2025), референс снят на macOS при 2x, наша цель — Windows-Chromium с другим хинтингом +шрифтов. Пиксель-в-пиксель недостижим и не является целью. Сходиться обязаны: **замеренные цвета, +промежутки 8px, радиусы 6px, плотность строк и общее впечатление**. Кегли и интерлиньяж — подбором +на глаз до похожести, потому что померить их больше негде. + +## 9. Что уже известно про движок — учесть в плане, не открывать заново + +Разобрано по коду 02.08. Влияет на форму данных, поэтому знать надо уже на S0. + +- **Индикатор прогресса нельзя строить на «готово N из M»**: unit становится `done` только когда + есть и черновые строки всех его членов, и строка редактуры. Во время черновой волны это ноль + почти всё время. Правильно — **пофазно**: `черновик N/M` ∥ `редактура N/M`. +- **Подпись термина — не UPDATE строки.** Банк пересобирается из файлов на каждом прогоне, прямая + запись в таблицу молча стирается следующим прогоном. Форма контракта подписи это учитывает. +- **Байтовых смещений у замечаний нет** — только счётчики. Поэтому подсветка сомнительных мест + идёт **на уровне блока и главы**, а не внутри текста. Владелец это принял 02.08 (§4.9), + вопрос закрыт. +- **Гранулярность пар грубее ожидаемой**: финальный текст существует на уровне edit-unit, замерено + ~1.9 блока на главу — местами вся глава окажется одним блоком. Читалка обязана нормально + выглядеть и в этом случае. + +Полный список того, что достраивается в движке — `STACK_DECISIONS.md` §8. diff --git a/frontend/docs/STACK_DECISIONS.md b/frontend/docs/STACK_DECISIONS.md new file mode 100644 index 00000000..962915ba --- /dev/null +++ b/frontend/docs/STACK_DECISIONS.md @@ -0,0 +1,225 @@ +# Решения по стеку — фронт и платформа + +> Источник: многоагентное исследование 02.08.2026 (15 агентов: 7 направлений, у каждого независимый +> скептик-опровергатель, затем синтез). Все версии сверены с вебом на 2026-08-02. Где скептик дал +> поправку уровня blocker/major — записан ИСПРАВЛЕННЫЙ вариант, не исходный. +> +> **Правило пользования:** пины ниже — не пожелания. Ставить точными версиями, без `^`. +> Экосистема сдвинулась за последний год сильно, и **весь корпус документации в сети описывает +> прошлые версии** — это главная ловушка (см. §7). + +--- + +## 1. Фронт — ядро + +| Что | Пин | Заметка | +|---|---|---| +| React | `19.2.8` | React 20 не существует. Ветка 19.2 живая | +| TypeScript | `6.0.3` | **НЕ 7.x** — см. ниже | +| Сборщик | `vite 8.2.0` + `@vitejs/plugin-react 6.0.5` | Vite 8 (12.03.2026) заменил Rollup+esbuild на Rolldown | +| Маршрутизация | `react-router 8.3.0` | библиотечный (data) режим, без framework mode и SSR | +| Серверное состояние | `@tanstack/react-query 5.101.4` | мажор 5 актуален; «v6» — это svelte-адаптер | +| Состояние интерфейса | `zustand 5.0.14` | никакого `useStore()` без селектора или `useShallow` | +| Пакетный менеджер | npm из поставки Node | один `package.json` в `frontend/`, воркспейсы не нужны | +| Node | **≥ 22.22** | нижняя граница react-router 8; проверить ПЕРВЫМ делом | + +**Почему TypeScript 6, а не 7.** TS 7 (нативный компилятор на Go, GA 08.07.2026) даёт 8–12× скорости, +но **не поставляет программный API** — он обещан в 7.1. Следствие: не работают `typescript-eslint`, +плагины языкового сервера, `typescript-plugin-css-modules`. Официальный обход — держать обе версии +через npm-алиасы, то есть ровно та связность, которую владелец запретил. Выигрыш в скорости +измерялся на миллионных кодовых базах; у нас один пакет, где `tsc` и на TS 6 занимает секунды. +**Пересмотреть после выхода TS 7.1 (~октябрь 2026)** — решение обратимо, тайпчек не участвует +в сборке. + +**React Compiler — НЕ включать в MVP.** Совместимость держим линтом +(`eslint-plugin-react-hooks 7.1.1` с compiler-powered правилами), сам компилятор — отдельным шагом +после заморозки интерфейса и только с проверкой в CI, что вставки реально попали в бандл. +Причина: в Vite 8 плагин React выбросил Babel, старый рецепт подключения удалён, а весь интернет +показывает именно его; при неверном порядке плагинов компилятор молча не запускается. + +**Почему React Router, а не TanStack Router.** Оба выбора обоснованы: TanStack даёт типобезопасность +маршрутов, React Router — то, что AI-сессии знают его кратно лучше и генерируют по его образцам +корректный код. При требовании «поддерживаемость важнее» выигрывает узнаваемость. +Типизация параметров запроса — тонкий хелпер на zod вокруг `useSearchParams`, а не типобезопасный +роутер целиком. + +## 2. Фронт — внешний вид и компоненты + +| Что | Пин | Заметка | +|---|---|---| +| Стилизация | CSS Modules (нативно в Vite) | Tailwind не берём | +| Токены | единственный `src/tokens/tokens.css` | CSS-переменные; минификация — Lightning CSS 1.33.0 | +| Примитивы | `react-aria-components 1.20.0` | **ОДНА библиотека на всё**, Apache-2.0 | +| Панели | `react-resizable-panels 4.12.2` | API v4: `{ Group, Panel, Separator }` | +| Виртуализация | RAC `Virtualizer` | `@tanstack/react-virtual 3.14.9` — в резерве, по замеру | +| Иконки | `lucide-react 1.28.0` | `size 16`, `strokeWidth 1.5`, БЕЗ `absoluteStrokeWidth` | +| Шрифты | `@fontsource-variable/inter 5.3.0` + `jetbrains-mono 5.3.0` | CJK — системный стек + обязательный `lang` из данных пары | + +**Одна библиотека примитивов, не две.** React Aria Components закрывает всё сразу: `Table` + +`Virtualizer` под банк памяти, `Tree` под дерево глав, `Tabs/Menu/Dialog/Popover/Tooltip` под +оболочку, `I18nProvider` под русские служебные строки. Две библиотеки означали бы два focus-scope +и два портальных менеджера в одном приложении — это ломает поддерживаемость. +Импортируется **только внутри `src/ui/`**; экраны ходят в наши обёртки. + +**⚠ Читалка двух колонок — синхронизации прокруток НЕТ.** Это исправление моей прежней рекомендации. +Правильно: **один скролл-контейнер**, список строк-пар, у каждой строки внутри +`display:grid; grid-template-columns:1fr 1fr`. Тогда колонки физически не могут разъехаться. +Единица пары — edit-unit из экспорта движка (`--pairs`). Копирование текста ограничить колонкой. + +**Панели: персист раскладки** — через хук `useDefaultLayout({panelIds, storage})` плюс +`Group defaultLayout` и `onLayoutChanged`, а **не** через проп `storage`. Докинг (dockview) в MVP нет. + +## 3. Фронт — контроль качества + +| Что | Пин | +|---|---| +| Линтер | `eslint 10.8.0` + `typescript-eslint 8.65.0` + `eslint-plugin-react-hooks 7.1.1` | +| CSS-линтер | `stylelint 17.14.1` + `stylelint-config-standard 40.0.0` | +| Формат | `prettier 3.9.6` (точный пин) | +| Тесты | `vitest 4.1.10` | +| Моки | `msw 2.15.0` | +| Браузер | `@playwright/test 1.62.1` (точный пин) | + +**Почему ESLint, а не oxlint.** oxlint быстрее и связнее, но его type-aware режим требует TS 7, +а мы на TS 6. Плюс конкретно для нас у ESLint есть `no-restricted-syntax` — правила, которого +в oxlint нет вовсе, и на котором строится главный гейт (ниже). + +### Машинный гейт «одно место для цвета и размера» + +Прямой ответ на требование владельца о поддерживаемости. Двухсторонний, в одной команде: + +- **в CSS** — stylelint `declaration-property-value-allowed-list` со значением `/^var\(--/` на + `color`, `background-color`, `border-color`, `fill`, `stroke`, `z-index`, `font-size`; + исключение по пути только для `tokens.css` и сброса; +- **в TSX** — ESLint `no-restricted-syntax` на литералы `#hex` / `rgb(` / `hsl(` / `oklch(` + плюс запрет атрибута `style` (уровень warn); +- **в CI** — stylelint с `reportDisables: true`, чтобы отключение правила комментарием тоже падало. + +Отступы (`padding`/`margin`/`gap`/`border-radius`) подключить **вторым шагом**, когда шкала +токенов зафиксирована — иначе гейт будет мешать на этапе подбора. + +### Одна команда проверки + +``` +npm run check # prettier --check → eslint → tsc --noEmit → vitest run +npm run check:full # + vite build + e2e +``` + +CI вызывает **именно их**, а не дублирует список инструментов. Path-фильтры на уровне job'ов +(правка CSS не должна гонять тесты Go) плюс агрегирующий job с явной проверкой +`contains(needs.*.result,'failure')||contains(needs.*.result,'cancelled')`. Git-хуков в MVP нет. + +**Визуальный гейт с эталонными скриншотами — ОТЛОЖЕН.** Он флейкует между платформами, а наш +референс снят на macOS при 2x, целевая платформа — Windows. Вместо него **контракт-тест токенов**: +рендерим корень, сверяем вычисленные значения CSS-переменных с замеренными числами. + +## 4. Форма продукта и SEO + +**Два независимых деплоя.** + +- **Приложение** — чистая SPA на `app.<домен>`, `X-Robots-Tag: noindex` на КАЖДОМ HTML-ответе. + `robots.txt` обход HTML **не** запрещает (иначе Google не увидит noindex), `Disallow` только для `/api/*`. +- **Публичный контур** — лендинг, цены, справка, политика куков, страницы входа и регистрации — + статический HTML на апексе, отдаётся CDN или существующим Go-сервисом. **Astro в MVP не берём.** + Каждая публичная страница достижима обычным `` не дальше трёх кликов от главной + (это и есть лечение «страниц-сирот», о которых писал владелец). `sitemap.xml` — дубль, не основной канал. + +**Продуктовый запрет (жёсткий):** ни один символ пользовательского перевода никогда не попадает на +публично индексируемый URL. В MVP нет ни витрины примеров, ни «поделиться главой», ни публичных +ссылок на прочтение. Причины две: авторские права на исходники и политика поисковиков в отношении +машинно-сгенерированного контента. + +## 5. Платформа + +| Что | Пин | Заметка | +|---|---|---| +| Go | `1.26.4` | | +| HTTP | стандартный `net/http` + `ServeMux` | роутер-библиотеку не тянуть | +| Postgres | `pgx v5.10.0` | нижняя допустимая граница 5.9.2, **не** 5.9.0 | +| Миграции | `goose v3.27.3` | как библиотека, `embed.FS`, `WithLocker` | +| Очередь | `river v0.42.0` | на том же Postgres | +| Безопасность | `govulncheck` | обязательный гейт CI | + +**Redis не заводим нигде** — зафиксировано как архитектурное «нет», иначе он приползёт по частям. + +**Конкурентность по книге.** Одна книга = один процесс-воркер; сериализация в очереди по `book_id` +плюс пиннинг книги к одному хосту на MVP. Лизы `book_leases` с heartbeat — поверх, ради вежливого +ожидания вместо аварии. Глобальный брокер исходящих LLM-вызовов — отдельный компонент, включаемый +по гейту «до второго параллельного пользователя». + +**Прогресс — SSE, и события ПУШИТ воркер**, а не фронт опрашивает read-model (см. §7, риск про +ре-ингест). Браузер — нативный `EventSource` на cookie; десктоп и CLI — обычный GET с +`Authorization: Bearer` и построчным парсером. WebSocket не нужен. Обязательно: HTTP/2 на границе, +`Cache-Control: no-store`, `X-Accel-Buffering: no`, heartbeat ~20 с, монотонный `id` + +`Last-Event-ID` для докачки. + +**Аутентификация — одна серверная сессия, два способа предъявления.** Запись сессии в Postgres, +непрозрачный токен 256 бит (в БД только SHA-256), и предъявляется он либо `__Host`-cookie +(HttpOnly, Secure, SameSite=Lax) для браузера, либо `Authorization: Bearer` для десктопа и CLI. +Principal создаётся **только** в middleware; ни один эндпоинт не имеет права предполагать cookie — +именно это сохраняет портируемость на десктоп, ради которой владелец и требовал Bearer. +CSRF только на cookie-пути: `Sec-Fetch-Site` → фолбэк на `Origin` по allowlist → обязательный +кастомный заголовок; та же проверка `Origin` на любом стрим-handshake. JWT отвергнут. + +## 6. Десктоп + +**Первый шаг — устанавливаемое PWA** на том же origin, что API: ноль второго режима +аутентификации, ноль подписи кода, ноль сборочного конвейера. + +**Tauri 2.11.5 — вторым шагом**, по явным триггерам: нужен трей или глобальные горячие клавиши, +нужен распространяемый `.exe`, появился офлайн-режим, нужен доступ к папке без диалога выбора, +нужно хранилище учётных данных ОС. Electron 43.2.0 и Wails v3 (всё ещё alpha) отвергнуты. + +До этого решения в приложении — только браузерные API, вся связь с движком через HTTP-контракт +платформы. + +## 7. Ловушки, на которые мы наступим + +Отсортировано по вероятности укусить. + +1. **Вся документация в сети описывает прошлые версии.** Vite 8 сделал `build.commonjsOptions` + молчаливым no-op; `react-resizable-panels` v4 сменил экспорты (`PanelGroup`/`PanelResizeHandle` + → `Group`/`Separator`); рецепт React Compiler для Vite удалён. AI-сессия скопирует конфиг из + статьи 2025 года и получит тихо неработающую опцию. **Лечение:** конфиги минимальные, каждая + нестандартная опция с комментарием «зачем», версии проверять по npm перед использованием. +2. **`types` в tsconfig теперь по умолчанию `[]`**, а не `["*"]` — забыть прописать + `"types": ["node", "vite/client"]` значит внезапно потерять глобальные типы. +3. **Дефолтные скроллбары Chromium на Windows** толстые и светлые — ломают Fleet-вид сразу на трёх + панелях и в читалке. Стилизовать с первого дня. +4. **Порядок каскада** между стилями React Aria, `tokens.css` и CSS Modules — источник тихих + расхождений. Задать `@layer` явно на этапе токенов. +5. **Fleet закрыт** (объявлено 08.12.2025, скачивание прекращено 22.12.2025). Референс + невоспроизводим: всё, что не замерено (кегли, интерлиньяж, внутренние отступы), больше + посмотреть негде. Скриншот снят на macOS при 2x, цель — Windows-Chromium с другим хинтингом. + **Растровое совпадение недостижимо и не должно быть критерием готовности.** +6. **Node на стенде** объявлен как 22, но react-router 8 требует ≥22.22, Vite 8 — ≥22.12. + Проверить первым действием. + +## 8. Что придётся достроить в движке + +Через оркестратора, в зону `backend/`, в порядке критичности. Обосновано разбором кода. + +1. **Пофазный прогресс** `draft N/M` ∥ `edit N/M` поверх `chunk_status`. Сейчас unit объявляется + `done` только когда есть и все draft-строки его членов, и edit-строка — то есть во время черновой + волны индикатор показывал бы 0% почти всё время. +2. **Персист манифеста глав и чанков** (+ `chunker_version` и хеш источника). Нужен под экран + разбора и дерево глав, и снимает ре-ингест: сейчас каждый read-вызов заново читает и режет + исходник — замерено 1.42–1.51 с процессорного времени на книге 23 МБ, и это умножается на число + книг в библиотеке. +3. **JSON-выход таблицы подписи банка** — сейчас только человеческий текст с ограничением 20 строк. +4. **Приём внешнего `TRACEPARENT`** в `cmd/tmctl`, чтобы прогон был одной трассой. + +Спаны для подсветки **внутри** текста — **не делаем** (владелец решил 02.08): у дешёвых гейтов +нет ни одного байтового смещения, только счётчики, а подсветка на уровне блока признана достаточной. + +**Выравнивание колонок достраивать не нужно** — `tmctl export --pairs` уже отдаёт колонку +исходника, выровненную по единицам редактора (`export.go:189`). Гранулярность грубая и владельцем +принята. + +⚠ **Подпись термина — это НЕ UPDATE строки.** Банк пересобирается из файлов на каждом прогоне +(`seedGlossary` + `ReplaceBank`), поэтому прямая запись в таблицу `glossary` молча стирается +следующим прогоном. Контракт подписи обязан это учитывать. + +⚠ **После апгрейда бинарника движка** все read-запросы по старым книгам падают +(«schema vN, expects vM»), пока по книге не пройдёт write-команда: `OpenReadOnly` требует точного +совпадения версии схемы. Это влияет на порядок деплоя платформы. diff --git a/platform/BACKLOG.md b/platform/BACKLOG.md new file mode 100644 index 00000000..638573a6 --- /dev/null +++ b/platform/BACKLOG.md @@ -0,0 +1,10 @@ +# Бэклог платформы (зонный) + +> Ведёт зона `platform/` (решение владельца 02.08, D39.84: фронт и платформа держат СВОИ бэклоги; единый бэклог `docs/PROGRESS.md` остаётся трекером движка/полигона/доков и фронт/платформа-строк не принимает). Нормы те же: ID стабилен навсегда, каждая петля получает диспозицию. Запросы к ДВИЖКУ сюда не пишутся — они заходят строками единого бэклога через оркестратора (пример: строки 99–102). Засеян оркестратором при лендинге D39.84 — дальше правит платформа-сессия. + +| ID | Хвост | Вес | Источник | +|---|---|---|---| +| П-1 | **HTTP/SSE-слой и сервисная обвязка** (экс-строка 96 единого бэклога): read-API поверх готовых `OpenReadOnly`-путей движка; SSE-события ПУШИТ воркер, фронт read-model не опрашивает (каждый read-вызов движка — дорогой ре-ингест, до строки 100 единого); аутентификация ратифицирована D39.84: одна серверная сессия в Postgres — `__Host`-кука браузеру · `Authorization: Bearer` десктопу/CLI · principal создаётся ТОЛЬКО в middleware, CSRF только на cookie-пути; ⚠ порядок деплоя: read-путь движка схему НЕ мигрирует (`store.go:135-143`, «schema vN … expects vM») — после апгрейда бинарника по каждой книге первой идёт write-команда | Ф3, после контракта API (строка 95 единого) | D39.81, D39.84, STACK_DECISIONS §5 | +| П-2 | **Глобальный брокер рейт-лимитов провайдеров** (экс-строка 97): гарды движка per-процесс (`pipeline/ratelimit.go:11`, mistral ~48% отказов под параллелизмом), а лимит провайдера — на ВЕСЬ аккаунт: N прогонов = N независимых гардов против общего лимита; воркер отпрашивается у платформы перед вызовом | ДО второго параллельного пользователя | D39.81, D39.84 | +| П-3 | **Очередь и конкурентность по книге**: River на том же Postgres, сериализация по `book_id` + пиннинг книги к одному хосту на MVP, лизы `book_leases` с heartbeat — вежливое ожидание вместо аварии | Ф3-пак платформы | STACK_DECISIONS §5, D39.84 | +| П-4 | **Учёт токенов/денег per-user + бюджет-гейт ДО старта задачи** (сырьё уже считает движок: `request_log` + `internal/ledger`; помнить: леджер = нижняя граница — строка 78 единого) | Ф3-пак платформы | platform/README, D39.84 | diff --git a/platform/README.md b/platform/README.md new file mode 100644 index 00000000..2f6a52bf --- /dev/null +++ b/platform/README.md @@ -0,0 +1,45 @@ +# platform — control plane (SaaS-слой) + +Зона записи новой сессии «Платформа». Пусто: заведено под будущий сервис, кода ещё нет. + +## Что здесь будет + +Сервис между фронтом и движком перевода. Всё, что относится к ПОЛЬЗОВАТЕЛЯМ и не относится +к переводу: + +- аутентификация и аккаунты (подписки и оплата — ПОСЛЕ MVP, решение владельца 02.08: в MVP + оплаты нет и денежных полей в интерфейсе нет); +- библиотека книг: чья книга, права доступа, хранение исходников и экспортов; +- учёт токенов и денег **на пользователя** (сырьё уже считает движок: `request_log` + + `internal/ledger`), потолки и гейт бюджета ДО старта задачи; +- очередь задач и запуск воркеров, статусы прогонов, ретраи; +- SSE-поток прогресса и живой стоимости во фронт. + +## Чего здесь НЕ будет + +Перевода. Движок (`../backend/`) остаётся как есть: один процесс на книгу, свой SQLite под +эксклюзивным flock (`store.Open` — «один процесс владеет файлом проекта»). Платформа его +ЗАПУСКАЕТ как воркер, а не поглощает. Причина та же, по которой движок не ветвится по паре +языков: пользователи и квоты ничего не меняют в проводе запроса, значит им нечего делать в +кодовой базе, где каждый байт свёрнут в снапшот-хеш. + +## Известное требование к движку (не забыть) + +⚠ **Глобальный брокер конкурентности.** `pipeline/ratelimit.go` строит рейт-гарды НА ПРОГОН, +а лимит провайдера — на весь аккаунт. N параллельных пользователей = N независимых гардов +против общего лимита (в комментарии там зафиксировано: mistral валит ~48% вызовов под +параллелизмом). Воркер должен отпрашиваться у платформы перед вызовом. Это единственная +по-настоящему новая механика на стыке. + +## Стек + +Пины и обоснования — [`../frontend/docs/STACK_DECISIONS.md`](../frontend/docs/STACK_DECISIONS.md) §5 +(общий документ решений по обоим новым сервисам; исследование 02.08). + +Коротко: Go 1.26.4 · стандартный `net/http` + `ServeMux` без роутер-библиотеки · pgx v5.10.0 · +goose v3.27.3 · очередь River v0.42.0 на том же Postgres · `govulncheck` гейтом CI. +**Redis не заводим нигде** — зафиксировано как архитектурное «нет». + +Прогресс наружу — SSE, события **пушит воркер**, а не фронт опрашивает read-model. +Аутентификация — одна серверная сессия в Postgres, два способа предъявления: `__Host`-кука для +браузера и `Authorization: Bearer` для десктопа и CLI; эндпоинты про куки не знают ничего. diff --git a/platform/go.mod b/platform/go.mod new file mode 100644 index 00000000..d5b23fea --- /dev/null +++ b/platform/go.mod @@ -0,0 +1,3 @@ +module textmachine/platform + +go 1.26.4