diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 2e6945a4..16c6138f 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -1,9 +1,9 @@ # Журнал прогресса -> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-08-15, голова D39.134 — приёмка бэкенд-migrate; передача №16→№17 — D39.133; приёмки S3.6/S3.7 — D39.127/129, приёмка P5 — D39.130, приёмка эмиттера — D39.131, приёмка P6+дофикс — D39.132). Оркестраторов ДВА (решение владельца 07.08): этот — движок/платформа/фронт/доки; параллельный (РОЛЬЮ, без номера — счётчик один, D39.112 п.6) — приёмка полигона. Одновременно не запускаются; CURRENT-STATE ведут оба, чужие строки не трогают. Норма изоляции панелей после инцидента отката чужих файлов — D39.113, гардрейлы в CLAUDE.md. +> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-08-15, голова D39.135 — приёмка S4, контракт 0.2.3 в каноне; приёмка бэкенд-migrate — D39.134; передача №16→№17 — D39.133; приёмки S3.6/S3.7 — D39.127/129, приёмка P5 — D39.130, приёмка эмиттера — D39.131, приёмка P6+дофикс — D39.132). Оркестраторов ДВА (решение владельца 07.08): этот — движок/платформа/фронт/доки; параллельный (РОЛЬЮ, без номера — счётчик один, D39.112 п.6) — приёмка полигона. Одновременно не запускаются; CURRENT-STATE ведут оба, чужие строки не трогают. Норма изоляции панелей после инцидента отката чужих файлов — D39.113, гардрейлы в CLAUDE.md. > - **Эра №15 закрыта — семь приёмок, все ПРИНЯТЫ и залендены**; лента, коммиты и разборы — D39.109–123 (D-лог) и реестр нот `architecture/05-decisions-index.md`; снимок прежних бюллетеней этой шапки — архив-слайс `-08-02-04`. -> - **ЖИВОЕ:** полигон эксп-22/23 — дерево ЗАЛЕНДЕНО 10.08 с ревью-шапками приёмки №16 (числа подтверждены независимым пересчётом; **выводы НЕ ратифицированы** — владелец 10.08 признал постановку неполной), **фаза Д ИДЁТ (заказ 10.08)**: промт `docs/POLYGON_EXP2223_REDO_SESSION_PROMPT.md` (staged полигоном), потолок фазы $4.50 словом владельца (ход — секция «Полигон» ниже); при ратификации фазы Д в D-ноту: декой-правило + обязательный кросс-семейный опровергатель приёмки (одобрены владельцем 10.08) · фронт: S3.5–S3.7 ИСПОЛНЕНЫ и ПРИНЯТЫ (D39.127/D39.129, лендинги `57e6bd1`/`3e465bd`), контракт **0.2.2** в каноне, i18n-механизм построен (ПТ-36 🔶) — **гейт S4 ПАЛ (P5 принят D39.130): S4-промт по слову владельца** (вход: экраны библиотеки/загрузки на живом `POST /books` · находки приёмки S3.7 · спек-правка 0.2.3) · **платформа P5 ИСПОЛНЕНА и ПРИНЯТА в три раунда (D39.130, `69d485a`)**: интейк книг `POST /books` с сентинелом хранилища · стоп/резюм с намерением в Postgres · Prometheus · Go-floor 1.26.6; развилка `book.yaml`: бета = форма Б (стройка следующим касанием зоны), движковая форма = строка 170 · **эмиттер ИСПОЛНЕН и ПРИНЯТ (D39.131, `9cfe080`, дофикс до лендинга)**: `events.jsonl` (StreamVersion 1.1) + exit 4 потолок / 5 graceful / полоса отказов 10–19 + пер-вызовный репэйр-гейт; строки 103/135/165/102 закрыты; движковая половина PD-113/PD-196 построена D39.131 · **платформа P6 + дофикс ИСПОЛНЕНЫ и ПРИНЯТЫ (D39.132)**: потребительская половина шва (exit-коды одним словарём, `unit_done` присваиванием, scope потолка, TM_TRACE_ID против усыновления) + интейк формы Б + дев-стенд с сидом — **PD-113/PD-196 ЗАКРЫТЫ, шов закрыт с обеих сторон, major в регистре платформы 0**; деплой-порядок против деадлока v15 записан и исполним (`tmplatformctl books --migratable`) · **`tmctl migrate` ИСПОЛНЕН и ПРИНЯТ (D39.134, `d55edd4`; панель 6 линз, 6/6 мутаций приёмки пойманы)**: exit 13 ФИНАЛИЗИРОВАН, строка 174 закрыта, 175 пере-скоуплена на дальний остаток, новая 177 — гигиена restore point; деплой эмиттер-бинаря РАЗБЛОКИРОВАН · эскроу (136) — следующим денежным промтом (П-18). -> - **Открыто на владельце:** Приложение А контракта (148: реконструкция с баннером или заново) · продуктовое слово «остановлена: лимиты» (В-3) · К-13/Ф-31 (paused_reason один — «свой потолок» и «нет кредита» неразличимы) · В-4/Ф-30 (глава без заголовка) · фри-тир PD-104 (ноль на бете против автогранта $5 с суточным потолком) · порог 116 · мини-проба флора 44 (одобрена, промт не выдан) · подпись денежного шага 46 · лист В-3+К-6 · авто-резюм paused (вопрос платформы) · приёмка S4 фронта (следующая в очереди №17; migrate принят D39.134) · **строка 172: цены DeepSeek ×2.3–4.7 с 16.08 — СТОП-решение и пере-пин, носителя-промта нет** · **СТОП ja-оси фазы Д** (гардрейл 18+ на `isekai_majutsushi_jp`, 3 чанка из 184: выбросить помеченное или сменить книгу) · **возражение Sol по проходу `tier` эксп-23** (пере-судить починенным ригом или оставить с записанным возражением — PROGRESS «Полигон») · ~~поле `title` в `BookIntake`~~ РЕШЕНО 14.08: ратифицировано в 0.2.3 (замечание 12 S3.5, владелец подтвердил; исполняет S4) · фронт-вопросы зонного журнала: В-7 (плотность интерфейса; держит и Ф-54 — обрезку центра на зуме) · В-8 (слово состояния в дереве) · **В-9 (какие языки интерфейса обещает продукт — механизм готов, ПТ-36)** · Ф-38 (вкладка «Замечания») · граница ПТ-33 для добавочных полей `BankTerm` (черновик S3.5/S3.6, D39.127 п.2б). +> - **ЖИВОЕ:** полигон эксп-22/23 — дерево ЗАЛЕНДЕНО 10.08 с ревью-шапками приёмки №16 (числа подтверждены независимым пересчётом; **выводы НЕ ратифицированы** — владелец 10.08 признал постановку неполной), **фаза Д ИДЁТ (заказ 10.08)**: промт `docs/POLYGON_EXP2223_REDO_SESSION_PROMPT.md` (staged полигоном), потолок фазы $4.50 словом владельца (ход — секция «Полигон» ниже); при ратификации фазы Д в D-ноту: декой-правило + обязательный кросс-семейный опровергатель приёмки (одобрены владельцем 10.08) · фронт: **S4 ИСПОЛНЕН и ПРИНЯТ (D39.135, `267aa35`; панель 5 линз)** — путь «файл → загрузка → разбор → запуск с потолком → прогресс» построен в мире моков, контракт **0.2.3 В КАНОНЕ** (PD-172 уточнён по коду платформы; title/reject_reason — форвард с носителем в P7), фикс-лист ФС-1..12 → вход S5 (major: интейк-мир стартует прогон с total=0); S3.5–S3.7 — D39.127/D39.129; i18n-механизм построен (ПТ-36 🔶); **гейт S5 — живой канал банка (строка 169)** · **платформа P5 ИСПОЛНЕНА и ПРИНЯТА в три раунда (D39.130, `69d485a`)**: интейк книг `POST /books` с сентинелом хранилища · стоп/резюм с намерением в Postgres · Prometheus · Go-floor 1.26.6; развилка `book.yaml`: бета = форма Б (стройка следующим касанием зоны), движковая форма = строка 170 · **эмиттер ИСПОЛНЕН и ПРИНЯТ (D39.131, `9cfe080`, дофикс до лендинга)**: `events.jsonl` (StreamVersion 1.1) + exit 4 потолок / 5 graceful / полоса отказов 10–19 + пер-вызовный репэйр-гейт; строки 103/135/165/102 закрыты; движковая половина PD-113/PD-196 построена D39.131 · **платформа P6 + дофикс ИСПОЛНЕНЫ и ПРИНЯТЫ (D39.132)**: потребительская половина шва (exit-коды одним словарём, `unit_done` присваиванием, scope потолка, TM_TRACE_ID против усыновления) + интейк формы Б + дев-стенд с сидом — **PD-113/PD-196 ЗАКРЫТЫ, шов закрыт с обеих сторон, major в регистре платформы 0**; деплой-порядок против деадлока v15 записан и исполним (`tmplatformctl books --migratable`) · **`tmctl migrate` ИСПОЛНЕН и ПРИНЯТ (D39.134, `d55edd4`; панель 6 линз, 6/6 мутаций приёмки пойманы)**: exit 13 ФИНАЛИЗИРОВАН, строка 174 закрыта, 175 пере-скоуплена на дальний остаток, новая 177 — гигиена restore point; деплой эмиттер-бинаря РАЗБЛОКИРОВАН · эскроу (136) — следующим денежным промтом (П-18). +> - **Открыто на владельце:** Приложение А контракта (148: реконструкция с баннером или заново) · продуктовое слово «остановлена: лимиты» (В-3) · К-13/Ф-31 (paused_reason один — «свой потолок» и «нет кредита» неразличимы) · В-4/Ф-30 (глава без заголовка) · фри-тир PD-104 (ноль на бете против автогранта $5 с суточным потолком) · порог 116 · мини-проба флора 44 (одобрена, промт не выдан) · подпись денежного шага 46 · лист В-3+К-6 · авто-резюм paused (вопрос платформы) · **В-11: фразы PD-173 на утверждение** (таблица — §8а записи S4; кавеат приёмки: фраза not_configured говорит о «приёме» уже принятой книги) · **В-10: спойлер — защита или вежливость** (поиск/печать обходят размытие) · Ф-62 (переименовать книгу нечем — в контракте нет записи книги) · Ф-63 (рамка поля 1.20:1 — вид) · **строка 172: цены DeepSeek ×2.3–4.7 с 16.08 — СТОП-решение и пере-пин, носителя-промта нет** · **СТОП ja-оси фазы Д** (гардрейл 18+ на `isekai_majutsushi_jp`, 3 чанка из 184: выбросить помеченное или сменить книгу) · **возражение Sol по проходу `tier` эксп-23** (пере-судить починенным ригом или оставить с записанным возражением — PROGRESS «Полигон») · ~~поле `title` в `BookIntake`~~ РЕШЕНО 14.08: ратифицировано в 0.2.3 (замечание 12 S3.5, владелец подтвердил; исполняет S4) · фронт-вопросы зонного журнала: В-7 (плотность интерфейса; держит и Ф-54 — обрезку центра на зуме) · В-8 (слово состояния в дереве) · **В-9 (какие языки интерфейса обещает продукт — механизм готов, ПТ-36)** · Ф-38 (вкладка «Замечания») · граница ПТ-33 для добавочных полей `BankTerm` (черновик S3.5/S3.6, D39.127 п.2б). > - **Сделано (сводно)** — снимок ленты закрытых эр в [archive/PROGRESS-2026-08-04-09.md](archive/PROGRESS-2026-08-04-09.md); детали — D-лог и слайсы. > - **Курс:** ОБЩНОСТЬ ✅ → КАЧЕСТВО БАНКА ✅ → ПАКЕТ-ЧЕКЕРОВ ✅ (D39.59–78) → **ФРОНТ-ЭРА** (D39.81–100: зоны живые, контракт API ратифицирован) → **шов/платформа/движковые блокеры построены** (D39.106–123). Хвосты курса живут строками: 16 (edit-волна не гонялась НИ РАЗУ — держит и оси голоса 13б/24) · 46 (дизайн заморожен D39.92/93, промт ждёт выдачи) · coldrun-b фаза C заморожена чекпойнтом легитимно (D39.86; эталон денег/поведения — coldrun-a, read-only); развилка 0731 решена и исполнена (D39.87/91, код `553f1a3`). > - **Горизонт (D39.62/67, освежён D39.95):** **ДОБОР ИДЕАЛА** (первым прогоном: оси голоса 24 · авто-режим · цена 16; жильцы ролей решаются ДО прогона эксп-22 — строка 149 · веса K1–K12 13а · вне-претрейн чекпоинт 55; остаток арбитража банка = рецензент спорных кластеров при ре-пробе 74 — D39.102) → ВТОРАЯ ПАРА живьём (ja→ru; преп 81) → МАСШТАБ → пилот Ф2.5 (гейт резюме-строки 80; строки 62–68, 85) → Ф3 ридер-IDE (69–71). **Стоячие:** ToS-триггер 25.10 · Ш-2 до go1.27 (⚠ + x/text Unicode 17 тем же тулчейном — строка 119, реестр §Б-108 справочника якорей) · платные прогоны разблокированы (проба провода — D39.97, конфиги 112 залендены). diff --git a/docs/README.md b/docs/README.md index 561fe041..aeeddd2a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -17,7 +17,7 @@ - `research/` — фактура ресёрчей 01–27; у принятых — ревью-шапки, часть тел под ⚠ superseded: **читай баннер прежде содержимого**. Ключевые для навигации: 15 голос · 16 ридер-IDE · 17 внешняя критика · 18 рычаги качества · 19 нарезка · 20 банк-майнинг · 21 обзор транспорта · 22 доменные харнессы · 23 шов движок↔платформа (транспорт superseded D39.106) · 25 холодное ревью шва — форма D39.106, отвергнутые альтернативы, требования к эмиттеру (читать перед любым кодом стыка) · 24 арбитраж банка (ПРИНЯТ D39.102: консилиум закрыт классом, вход фикс-пака банка — §G) · 26 официальные практики Anthropic (D39.121: записка-план, сниппеты хендоффов, карта «уже делаем/перенять»). - [PROGRESS.md](PROGRESS.md) — журнал: CURRENT-STATE + **ЕДИНЫЙ БЭКЛОГ** (единственный трекер) + живой хвост хроники. НЕ источник решений. - `scripts/counts.py` — **производные числа доков считаются им, а не руками** (голова по трём носителям · счёт очереди и зон · вес открытых строк регистра платформы · полнота реестра нот); `--check` даёт ненулевой код на расхождении; `--lint` — линтер file:line-якорей живых доков (D39.126). Его же зовёт зонный хук `scripts/githooks/pre-commit` при коммите, задевающем D-лог или PROGRESS — предупреждает, не блокирует. Заведено по D39.112 п.5б: голова отставала трижды у трёх разных оркестраторов. -- Активные хендофф-промты сессий (состав обновляется при каждом лендинге — норма D39.80): [ORCHESTRATOR_SESSION_PROMPT.md](ORCHESTRATOR_SESSION_PROMPT.md) (роль/нормы; состояния не дублирует) · **Полигон: [POLYGON_EXP2223_REDO_SESSION_PROMPT.md](POLYGON_EXP2223_REDO_SESSION_PROMPT.md)** — фаза Д доводки эксп-22/23 ИДЁТ (заказ владельца 10.08, потолок фазы $4.50; выводы 22/23 заморожены до неё) · [POLYGON_PACKAGE4_SESSION_PROMPT.md](POLYGON_PACKAGE4_SESSION_PROMPT.md) (отложен) . **Фронт: [../frontend/docs/S4_SESSION_PROMPT.md](../frontend/docs/S4_SESSION_PROMPT.md)** — S4 выдан 14.08 (гейт пал D39.130, запуск одобрен владельцем: библиотека/загрузка/прогресс + спек-правка 0.2.3) · **Платформа: активного промта НЕТ** — P6 + дофикс ИСПОЛНЕНЫ и ПРИНЯТЫ (D39.132, промты в `platform/docs/archive/`); следующий пак — P7 (читающая поверхность), промт после приёмки бэкенд-migrate · **Бэкенд: активного промта НЕТ** — `tmctl migrate` ИСПОЛНЕН и ПРИНЯТ (D39.134, лендинг `d55edd4`; промт в `archive/prompts/`), деплой эмиттер-бинаря разблокирован. Эмиттер шва ИСПОЛНЕН и ПРИНЯТ (D39.131, промт в архиве). Все ОТРАБОТАННЫЕ промты — в `archive/prompts/`, отчёты с ревью-шапками — в `archive/reports/`; статусы паков — CURRENT-STATE и D-лог, здесь не дублируются. Зонные журналы фронта/платформы — `frontend-PROGRESS.md` / `platform-PROGRESS.md` в их зонах (прогресс зон только там, D39.100). +- Активные хендофф-промты сессий (состав обновляется при каждом лендинге — норма D39.80): [ORCHESTRATOR_SESSION_PROMPT.md](ORCHESTRATOR_SESSION_PROMPT.md) (роль/нормы; состояния не дублирует) · **Полигон: [POLYGON_EXP2223_REDO_SESSION_PROMPT.md](POLYGON_EXP2223_REDO_SESSION_PROMPT.md)** — фаза Д доводки эксп-22/23 ИДЁТ (заказ владельца 10.08, потолок фазы $4.50; выводы 22/23 заморожены до неё) · [POLYGON_PACKAGE4_SESSION_PROMPT.md](POLYGON_PACKAGE4_SESSION_PROMPT.md) (отложен) . **Фронт: активного промта НЕТ** — S4 ИСПОЛНЕН и ПРИНЯТ (D39.135, лендинг `267aa35`; контракт 0.2.3 в каноне; промт в `frontend/docs/archive/`); следующий — S5 (подпись банка), гейт — живой канал банка (строка 169), фикс-лист ФС — запись приёмки 15.08 в зонном журнале · **Платформа: активного промта НЕТ** — P6 + дофикс ИСПОЛНЕНЫ и ПРИНЯТЫ (D39.132, промты в `platform/docs/archive/`); следующий пак — P7 (читающая поверхность + форвард-половина 0.2.3: чтение `title` и проекция `reject_reason`, D39.135 п.2в + хвосты D39.134 п.4), промт — очередь №17 · **Бэкенд: активного промта НЕТ** — `tmctl migrate` ИСПОЛНЕН и ПРИНЯТ (D39.134, лендинг `d55edd4`; промт в `archive/prompts/`), деплой эмиттер-бинаря разблокирован. Эмиттер шва ИСПОЛНЕН и ПРИНЯТ (D39.131, промт в архиве). Все ОТРАБОТАННЫЕ промты — в `archive/prompts/`, отчёты с ревью-шапками — в `archive/reports/`; статусы паков — CURRENT-STATE и D-лог, здесь не дублируются. Зонные журналы фронта/платформы — `frontend-PROGRESS.md` / `platform-PROGRESS.md` в их зонах (прогресс зон только там, D39.100). - Зоны фронта (чужие, читать при касании стыка; каждая ведёт СВОЙ зонный бэклог — единый бэклог их строк не принимает, 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) (П-1..П-14) + `docs/` (зонный журнал `platform-PROGRESS.md` · регистр дефектов · архив промтов P0–P5). - `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-index.md b/docs/architecture/05-decisions-index.md index e1600fee..67f07b46 100644 --- a/docs/architecture/05-decisions-index.md +++ b/docs/architecture/05-decisions-index.md @@ -187,3 +187,4 @@ | D39.132 | 15.08 | Приёмка платформы P6 + дофикс: потребительская половина шва (exit-словарь, unit_done присваиванием, scope, TM_TRACE_ID) + интейк формы Б + дев-стенд; PD-113/PD-196 закрыты, 0 major; ратификации: day_usd вне шаблона (владелец), пере-подпись PLATFORM_DIRECTION §3, второй гейт батареи, exit 13 направлением, PD-241-направление; фикс-лист ФП-1..8 закрыт дофиксом (exit 2 status-канала) | ЖИВОЕ: шов закрыт с обеих сторон; строки 174/175 + финал exit 13 — приёмкой бэкенд-migrate; строка 176 движку (паника = exit 2, PD-212) | жив | шов деньги платформа приёмка | | D39.133 | 15.08 | Закрытие сессии оркестратора №16, передача №17; первые задачи: приёмка migrate пост-фактум (код в main без приёмки, до деплоя) → строка 172 → приёмка S4 → промт P7 | ЖИВОЕ: очередь — CURRENT-STATE | жив | хендофф оркестратор | | D39.134 | 15.08 | Приёмка бэкенд-пака tmctl migrate (d55edd4, панель 6 линз, 6/6 мутаций пойманы): строка 174 закрыта, 175 пере-скоуплена, exit 13 финализирован; ратификации: отказ write-пути БД новее бинаря, restore point под локом вне секундного неймспейса; поправка провенанса «зоны сошлись независимо» (платформа читала 13 из дерева движка) | ЖИВОЕ: строка 177 — гигиена restore point; дописки 93/146/176; платформе — PD-201 можно строить, мёртвый текст ошибки в deploy/README и П-1 (вход P7) | жив | бэкенд приёмка шов деплой | +| D39.135 | 15.08 | Приёмка фронта S4 (267aa35, панель 5 линз): контракт 0.2.3 в каноне байт-зеркалом; ратификации: PD-172 уточнён по коду платформы (стоп чтения на файле), title/reject_reason — форвард-контракт с носителем в P7, not_configured — словарь версии, verify_bank дефолт OFF до S5; фикс-лист ФС-1..12 → вход S5 (major: интейк-мир стартует прогон с total=0) | ЖИВОЕ: владельцу В-10/В-11 (фразы PD-173, кавеат not_configured)/Ф-62/Ф-63; поправки отчёта — запись приёмки в зонном журнале | жив | фронт контракт приёмка | diff --git a/docs/architecture/05-decisions-log.md b/docs/architecture/05-decisions-log.md index 079bef2f..43e4a110 100644 --- a/docs/architecture/05-decisions-log.md +++ b/docs/architecture/05-decisions-log.md @@ -1,4 +1,4 @@ -# Журнал решений оркестратора — контракт D1–D39.134 (живой файл: карта · эрраты · живые тела · голова D39.106+; тела закрытых эр — в слайсах `docs/archive/architecture/`, указатель ниже; реестр всех нот — `05-decisions-index.md`) +# Журнал решений оркестратора — контракт D1–D39.135 (живой файл: карта · эрраты · живые тела · голова D39.106+; тела закрытых эр — в слайсах `docs/archive/architecture/`, указатель ниже; реестр всех нот — `05-decisions-index.md`) > **⟶ КАРТА АКТУАЛЬНОСТИ (ревизия D31, продлена до D38.2 [12.07]; исторические записи ниже НЕ переписываются — дисциплина D23.3).** Работая с контрактом (греп номера: живой файл → слайсы, целиком НЕ читать — D39.125), держи под рукой, что чем перекрыто: > ⚠ **Эррата 09.08 (D39.125):** D39.111 п.1 предписывал промту S3 «максимум = баланс МИНУС открытые холды» — формула ОШИБОЧНА (вычитание дважды), исправлена D39.115 п.2(а): максимум = Balance КАК ЕСТЬ; тело D39.111 живёт ниже в этом файле (голова D39.106+). @@ -526,3 +526,13 @@ **3. Строки.** 174 ЗАКРЫТА (деадлок разорван; деплой-порядок «дренаж → новый бинарь → migrate ИМ → прогоны» записан платформой дофиксом P6 — их README уже верен, клейм §5(в) отчёта устарел к приёмке, не ошибочен). 175 ПЕРЕ-СКОУПЛЕНА: ближняя половина (типизированный mismatch у status + money-тест) исполнена паком, строка остаётся на дальний остаток (а)–(в). Новая 177 — гигиена restore point (находки панели ВНЕ карты отчёта: ретрай в ту же секунду после сорванного шага = exit 1 «backup already exists» на цикле самолечения · kill -9 посреди шва оставляет РВАНУЮ копию под легитимным именем · копии не подчищаются · SIGINT в migrate не прерывает). Дописки тем же касанием: 93 (`redrive --dry-run` на устаревшей БД мигрирует БЕЗ restore point), 146 (ценовой гейт держит и ДЕТЕКТОР самолечения: на протухших ценах `status` даёт 10, не 13 — цикл «поймал 13» не наступает), 176 (usage-строка invocation.go не знает migrate/backup/seed-lint — чинить разом тем же касанием exit-контракта). **4. Платформе (пинг в зонный журнал):** движковая половина финальна — PD-201 (самолечение «поймал 13 → migrate → повтор») можно строить; их хвосты: `deploy/README.md:131` и П-1 зонного бэклога несут МЁРТВЫЙ текст ошибки схемы («schema vN … expects vM» движок больше не печатает) · комментарий-образец `runs.go:45` зовёт голый `tmctl` из PATH (копипаст = тихий no-op старым бинарём при живом деадлоке). Всё — вход промта P7. (15.08.2026, оркестратор №17) ✅ + +## D39.135 — ПРИЁМКА ФРОНТА S4 ПРИНЯТА И ЗАЛЕНДЕНА (`267aa35`); КОНТРАКТ 0.2.3 В КАНОНЕ: PD-172 уточнён по коду платформы, title/reject_reason — форвард-контракт с носителем в P7 (15.08). ✅ + +**1. Приёмка исполнением (панель 5 линз в изолированных копиях; $0, только агент-токены).** Слепая линза по заказу+диффу — «принять» до чтения отчёта; пере-ран гейтов: `npm run check` 335/335 · `check:full` EXIT=0 (8 маршрутов · 11 сценариев · axe 0 блокирующих; «136 проверок» отчёта = фактически 134 — наивный греп ловил 2 строки vite) · spectral/типы/тест дрейфа зелёные · до-пакные числа арбитража (157 ключей · чанк 724130) подтверждены ОБРАТНЫМ применением диффа байт-в-байт · живые нарушения двух гейтов — красные · фикстура формы: обязательное поле за файлом = 400, необязательное = 201. Линза истинности спеки: PD-172/173/174/180 — ВЕРНО ПО КОДУ платформы (обе стороны цитатами). Механика, фикс-лист ФС-1..12 и поправки отчёта — запись приёмки в зонном журнале фронта 15.08 (состав — там). + +**2. Ратификации.** (а) **Контракт 0.2.3 — В КАНОНЕ**: `docs/architecture/14-api-contract/openapi.yaml` = байт-зеркало зонной копии (cmp пуст). (б) **PD-172 — формулировка спеки УТОЧНЕНА ПРОТИВ текста заказа, уточнение ратифицировано**: платформа останавливает чтение формы НА файле (`v0.go:349-361`) — обязательное поле после файла = 400 «как не слали», необязательное молча теряется (201); текст D39.130 п.2в «поле после файла = 400» амендирован кодом (сессия назвала отклонение вслух, две линзы сверили независимо). (в) **BookIntake.title и Book.reject_reason = ФОРВАРД-контракт**: платформа сегодня title НЕ читает (switch формы без case "title", имя всегда titleFrom) и reject_reason НЕ проецирует на провод (`v0.go:497` «never projected»); оба конформны (поля необязательные), но обещание без носителя — дефект класса «обязательство без адресата» ⇒ реализация обоих — ЯВНЫЙ вход промта P7. (г) `not_configured` сегодня недостижим на книге (не терминален — `waitsForTheDeployment`) — в enum оставлен осознанно как словарь версии. (д) **verify_bank дефолт OFF — временно, направлением**: с включённой галочкой прогон приходит в `awaiting_bank`, куда идти некуда до S5; дефолт возвращается при построенном пути подписи; отменяется словом владельца. (е) S4 = ПРИНЯТО с фикс-листом ФС-1..12 → вход промта S5 (тяжелейший ФС-1: интейк-мир стартует прогон с total=0 — общий прогресс 0/0 и ETA NaN, путь заказа §4 в мок-мире добить). + +**3. Владельцу (confirm-лист, сам не ратифицирую):** В-11 фразы PD-173 (⚠ кавеат панели: фраза not_configured «Сервис пока не готов принять эту книгу» говорит о приёме, а книга уже принята и отклонена позже) · В-10 спойлер (поиск по странице/печать обходят размытие) · Ф-62 (переименовать книгу нечем — у книги в контракте нет ни одной записи) · Ф-63 (рамка поля 1.20:1 — токен всей оболочки, вид принимает владелец). + +**4. Поправки к отчёту S4** (носитель — запись приёмки в зонном журнале): «словарь платформы — четыре значения» → пять (пропущен schema_mismatch) · «одна из трёх фраз недостижима» → сегодня недостижимы ВСЕ ТРИ (reject_reason не проецируется вовсе) · §1/§2 отчёта несут СНЯТОЕ правило PD-172 (противоречие с собственным §9а; тот же текст остался в докблоке upload.ts — ФС-5) · «31 строка DOM / 59 618px» — замер S2 04.08, не этого пака · «46 находок → 6 выжило» = 5 различных (одна — дубль). (15.08.2026, оркестратор №17) ✅ diff --git a/docs/architecture/14-api-contract/README.md b/docs/architecture/14-api-contract/README.md index 318369e2..fc2f6276 100644 --- a/docs/architecture/14-api-contract/README.md +++ b/docs/architecture/14-api-contract/README.md @@ -41,7 +41,7 @@ openapi.yaml РЯДОМ (байт-копия зонной frontend/docs/api-cont > каждое решение, чем оно обосновано, что осталось открытым. При расхождении по ФОРМЕ > побеждает YAML; при вопросе «почему так» — этот файл. > -> **Статус: РАТИФИЦИРОВАН — D39.99 (04.08), контракт 0.2.0 (D39.115, 08.08); 0.2.1 (D39.123, 09.08): += `503` на `POST /books/{bookId}/runs` — старт прогона на неукомплектованном деплое (шов движка не сконфигурирован) не выражается ни одним прежним кодом; закрывает PD-112 платформы; 0.2.2 (D39.129, 10.08): `BankTerm.sense` обязателен (Ф-47). Следующая правка — 0.2.3 (PD-172/173/174/180), задача S4-промта (D39.130).** Дом канона — этот каталог; `frontend/docs/api-contract/openapi.yaml` — байт-зеркало. ⚠ Испр. оркестратором №15 08.08: файл называл себя черновиком на ратификацию четверо суток ПОСЛЕ ратификации — тот же класс, что шапка `info` спеки. +> **Статус: РАТИФИЦИРОВАН — D39.99 (04.08), контракт 0.2.0 (D39.115, 08.08); 0.2.1 (D39.123, 09.08): += `503` на `POST /books/{bookId}/runs` — старт прогона на неукомплектованном деплое (шов движка не сконфигурирован) не выражается ни одним прежним кодом; закрывает PD-112 платформы; 0.2.2 (D39.129, 10.08): `BankTerm.sense` обязателен (Ф-47); **0.2.3 (D39.135, 15.08)**: PD-172 потоковое правило формы `createBook` (уточнено ПО КОДУ платформы против текста заказа: чтение останавливается НА файле — обязательное поле после файла = 400 «как не слали», необязательное молча теряется) · PD-173 `RejectReason` (enum версии: source_unreadable · not_configured · parser_unavailable; `Book.reject_reason` необязательное) · PD-174 404 интейка / 503 `resume` · PD-180 честный 201=`parsing` + отказы 400/408/413 · `BookIntake.title` необязательное. ⚠ Форвард-половина 0.2.3: платформа сегодня `title` не читает и `reject_reason` не проецирует — реализация обоих = явный вход P7 (D39.135 п.2в).** Дом канона — этот каталог; `frontend/docs/api-contract/openapi.yaml` — байт-зеркало. ⚠ Испр. оркестратором №15 08.08: файл называл себя черновиком на ратификацию четверо суток ПОСЛЕ ратификации — тот же класс, что шапка `info` спеки. > `docs/architecture/14-api-contract/`, зона оркестратора; перенос делает он, генерация типов > после ратификации идёт из перенесённой копии — контракт первичен, код вторичен. > diff --git a/docs/architecture/14-api-contract/openapi.yaml b/docs/architecture/14-api-contract/openapi.yaml index 842f1a44..8900e68f 100644 --- a/docs/architecture/14-api-contract/openapi.yaml +++ b/docs/architecture/14-api-contract/openapi.yaml @@ -2,7 +2,7 @@ openapi: 3.1.0 info: title: TextMachine API - version: 0.2.2 + version: 0.2.3 summary: Ratified contract between the frontend and the TextMachine platform (D39.99). description: | **RATIFIED contract (D39.99, 04.08.2026).** The canonical copy lives in @@ -114,8 +114,40 @@ paths: operationId: createBook summary: Add a book. description: | - Accepts the file and the properties declared by the user. Responds immediately; the book - enters `uploading` and parsing is a separate visible step. + Accepts the file and the properties declared by the user. + + **The `file` part MUST come LAST in the form** (0.2.3). The platform reads the form as a + STREAM, part by part, and stops at the file: the book's row — the record that makes an + upload visible while it arrives and findable when it dies halfway — cannot be written + before the languages that row requires. + + A part sent after the file is therefore NOT READ AT ALL. What that costs depends on the + part: a required one (`source_lang`, `target_lang`) is answered `400`, because to a reader + that streams "the languages came late" and "the languages never came" are the same thing; + an optional one is silently lost, and the book is created without it. A client that puts + anything after the file is a client whose form is partly ignored. + + **The `201` carries `parsing`, not `uploading`** (0.2.3). The answer is written after the + last byte has landed, so by the time a client can read it the file is in and the book has + moved on. `uploading` is a real state and is observable — by a SECOND read of the library + while the upload is still on the wire — but never as the answer to this call. + + Parsing is a separate visible step after that, and it has no numeric progress: no counter of + it exists on this contract, and a percentage would have to be invented. + + Refusals of the intake, all of them product states of the form rather than failures of the + service: + + - `400` — the form could not be read: more than 16 parts, a text field longer than a + kilobyte, a REQUIRED field that arrived after the file (or never), or no file at all; + - `404` — this deployment does not accept books at all. An instance with no place to put a + file and no engine to cut it with serves the library and refuses this path, which is a + property of the DEPLOYMENT and not of the request; + - `408` — the body did not finish inside the route's deadline: a slow client on a large + book. Retrying is the remedy, which is what separates it from `413`; + - `413` — the body is over the intake cap. The threshold belongs to the deployment and is + not stated here: a number in the contract would be a second copy of it, and the two would + disagree the day it changes. requestBody: required: true content: @@ -123,12 +155,14 @@ paths: schema: { $ref: '#/components/schemas/BookIntake' } responses: '201': - description: Book accepted. + description: Book accepted; it is being parsed. content: application/json: schema: { $ref: '#/components/schemas/Book' } '400': { $ref: '#/components/responses/BadRequest' } '401': { $ref: '#/components/responses/Unauthorized' } + '404': { $ref: '#/components/responses/NotFound' } + '408': { $ref: '#/components/responses/RequestTimeout' } '413': { $ref: '#/components/responses/TooLarge' } /books/{bookId}: @@ -412,6 +446,11 @@ paths: **Answers 409 while the set of bank decisions is incomplete** — the stop clears only on a complete set. + + **503 answers a deployment that cannot run at all** (0.2.3). Continuing a run is starting a + process, so it needs exactly what a start needs — the seam that tells the engine its ceiling + and the one that records how a run ended. 0.2.1 named that state for `startRun` only, and + the omission was in the SPEC and not in the wire: the two calls share one refusal. responses: '202': description: Resume accepted. @@ -421,6 +460,7 @@ paths: '401': { $ref: '#/components/responses/Unauthorized' } '404': { $ref: '#/components/responses/NotFound' } '409': { $ref: '#/components/responses/Conflict' } + '503': { $ref: '#/components/responses/ServiceUnavailable' } /usage: get: @@ -601,11 +641,20 @@ components: content: application/problem+json: schema: { $ref: '#/components/schemas/Problem' } + RequestTimeout: + description: | + The body did not arrive whole inside the route's deadline (added in 0.2.3): a slow client on + a large book. RFC 9110 §15.5.9 describes this case exactly, and it names RETRY as the + remedy — which is what a `413` and a `500` in its place would both hide. + content: + application/problem+json: + schema: { $ref: '#/components/schemas/Problem' } ServiceUnavailable: description: | - The deployment cannot perform this action right now (added in 0.2.1, D39.123): starting a - run requires the engine seam to be fully configured, and answering with any other code - would misname the state. Temporary by nature — retry later; no Retry-After is promised. + The deployment cannot perform this action right now (added in 0.2.1, D39.123): starting or + continuing a run requires the engine seam to be fully configured, and answering with any + other code would misname the state. Temporary by nature — retry later; no Retry-After is + promised. content: application/problem+json: schema: { $ref: '#/components/schemas/Problem' } @@ -725,6 +774,31 @@ components: - rejected - failed + RejectReason: + type: string + description: | + Machine reason a book was rejected (0.2.3). The platform's own closed vocabulary; as with + `PausedReason` the API carries STATE and the phrase the user reads is drawn by the client, + so no wording appears here. + + - `source_unreadable` — the file was read and is not a book this service can cut: it yields + no sections at all, or the reader refused it. TERMINAL, and the source does not survive + it — there is no path in this contract that re-reads a rejected book, so the remedy is to + add the book again; + - `not_configured` — this deployment has nothing to read the book AGAINST. It is a state of + the service, never of the file, and retrying by itself does not clear it; + - `parser_unavailable` — the service could not process the file, repeatedly, until it gave + up. A state of the service as well, and a temporary one. + + The three are two different NEXT ACTIONS for the user, and a client that told them apart by + colour alone would be telling them apart by nothing: the first means "the file is not one we + can read", the other two mean "not us, not now". + + A client MUST tolerate an unknown value arriving under a minor bump, and MUST render a + rejected book that carries no reason at all: a deployment older than this minor answers + exactly that. + enum: [source_unreadable, not_configured, parser_unavailable] + Book: type: object description: A book in the library. @@ -743,6 +817,18 @@ components: description: Size in characters. Not an engine field; the platform knows it from intake. added_at: { type: string, format: date-time } status: { $ref: '#/components/schemas/BookStatus' } + reject_reason: + oneOf: + - $ref: '#/components/schemas/RejectReason' + - type: 'null' + description: | + Why the book was rejected; meaningful only while `status` is `rejected` (0.2.3). + + OPTIONAL, unlike `Run.paused_reason`, and the asymmetry is deliberate: a rejection + reason is meaningful in exactly one of eleven states, and a deployment that predates + this minor sends nothing here at all. "Absent" and "null" therefore mean one and the + same thing — the reason is not known — and a client renders both the same way. That is + the opposite of the `sense` case (0.2.2), where the two shapes carried DIFFERENT facts. progress: { $ref: '#/components/schemas/Progress' } note_count: { type: integer, minimum: 0 } @@ -810,13 +896,29 @@ components: BookIntake: type: object - description: Add-a-book form. + description: | + Add-a-book form. + + ⚠ **Order matters here and nowhere else on this surface:** `file` is the LAST part, and + every other field precedes it — see `createBook`. An OpenAPI object has no ordering, so the + rule is stated in prose because it cannot be stated in the schema. required: [file, source_lang, target_lang] properties: + title: + type: string + maxLength: 200 + description: | + Title given by hand (0.2.3). OPTIONAL, and the two cases are told apart by the user + rather than guessed at: absent or empty means "the parse will name it" — today the + platform takes the name of the uploaded file — while a value present means the person + named the book themselves, and no later parse overwrites it. + + Bounded like the title the platform derives: the library lists it, and an unbounded + string on that screen is the client's problem to draw, not the server's to store. file: type: string format: binary - description: Book file. + description: Book file. The LAST part of the form. source_lang: { $ref: '#/components/schemas/LangCode' } target_lang: { $ref: '#/components/schemas/LangCode' } genre: { type: string }