From 4c94f7e8ff175c45c5567e391ee2447db2dc7597 Mon Sep 17 00:00:00 2001 From: "Claude (backend session)" Date: Fri, 21 Aug 2026 00:15:24 +0300 Subject: [PATCH] Finish the documentation sweep the P7 landing left half-done: closed working docs go to the zone archive, the P7 era is sliced out, and eight stale claims are corrected --- docs/PROGRESS.md | 14 +- docs/README.md | 2 +- docs/STACK.md | 4 +- docs/architecture/05-decisions-log.md | 10 +- docs/architecture/09-target-architecture.md | 2 +- docs/architecture/14-api-contract/README.md | 8 +- docs/glossary.md | 4 +- platform/docs/DEFECT_REGISTER.md | 2 +- platform/docs/STACK_DECISIONS.md | 4 + ...CONTRACT_SYNC_FROM_PLATFORM_2026-08-20.md} | 2 +- .../P7_ACCEPTANCE_HANDOFF_2026-08-17.md} | 5 + .../P7_ACT5_FIX_PLAN_2026-08-20.md} | 5 + platform/docs/archive/platform-PROGRESS-P7.md | 250 +++++++++++++++++ platform/docs/platform-PROGRESS.md | 263 +----------------- 14 files changed, 300 insertions(+), 275 deletions(-) rename platform/docs/{CONTRACT_SYNC_FROM_PLATFORM.md => archive/CONTRACT_SYNC_FROM_PLATFORM_2026-08-20.md} (97%) rename platform/docs/{P7_ACCEPTANCE_HANDOFF.md => archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md} (99%) rename platform/docs/{P7_ACT5_FIX_PLAN.md => archive/P7_ACT5_FIX_PLAN_2026-08-20.md} (98%) create mode 100644 platform/docs/archive/platform-PROGRESS-P7.md diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index e834edce..616f6174 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -1,9 +1,9 @@ # Журнал прогресса -> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-08-20, голова D39.153 — КУРС: движок и платформа до «работает и отдаёт результат», фронт ЗАМОРОЖЕН и P7 его НЕ размораживает (D39.147). **ОЧЕРЕДЬ №18** (единственный носитель — здесь): (а) **P7 платформы ПРИНЯТ С ФИКС-ЛИСТОМ и ЗАЛЕНДЕН, сессия закрыта владельцем 20.08** (D39.153; зонный фикс-лист из десяти пунктов — пинг №18 в `platform/docs/platform-PROGRESS.md`, первым `ContractVersion` 0.3.0 при формах 0.4.0) · (а1) **контракт API v0 0.4.0 РАТИФИЦИРОВАН** (D39.152; PD-327 закрыт; зеркало фронта отстаёт ратифицированно, при разморозке `cmp`) · (б) **лендинг петель полигона (фаза Д) — ОТКРЫТ**: приёмка ФАЗЫ у параллельного оркестратора, лендинг за этим; ⚠ в дереве живая незакоммиченная и частично ЗАСТЕЙДЖЕННАЯ работа полигона — не трогать и не «прибирать», состав выяснять у зоны · (в) **следующие работы платформы, по порядку:** дофикс-пак (фикс-лист пинга №18 + строка 199а — труба доставки правок банка + sqlc с разбором СОБРАННЫХ запросов) → ревью-пак четырёх осей, которых не смотрел никто (деньги/леджер · вход/сессии/CSRF · очередь/джобы · метрики) → живой прогон книги насквозь (строка 202, гейт — холодный прогон движка) · (г) **контракт:** сквозная полоса прогресса следующим минором (строка 200, слово владельца 20.08) вместе с хвостами релеев (203) · (д) свободные бэкенд: 160 Этап 0, фикс-лист ФЧ строкой 197 (носителя-сессии нет по слову владельца); ⚠ строки 176/181/187 СНЯТЫ с таблицы при лендинге 20.08 — они закрыты ещё D39.149, а очередь всё это время звала 181 свободной работой (поймано ревью доков; остатки живут строками 194/196/197) · (е) строка 148 после фраз владельца. **Открытые обязательства, которых нет больше нигде:** веса `pro` — строка 172-г НЕ закрыта, прогон мерил классификатор на flash; дешёвый вход — спросить полигон, говорят ли что-то данные фазы Д (там pro гоняется редактором), отдельный замер не покупать без этого · предложение внести норму «жалуйся владельцу, а не обходи молча» во ФРОНТОВЫЙ фрагмент pre-commit хука — не моя зона, нужен пинг в зонный журнал фронта, владелец не отвечал · `docs/experiments/00-provider-quirks.md` несёт протухшие цены DeepSeek («не изменились, flash $0.14/$0.28») — зона полигона, чинить пингом · санкция на платный прогон в архивном промте пака честности была РАЗОВОЙ · **вопрос платформы к ВЛАДЕЛЬЦУ, который её хендофф объявил несуществующим** (`P7_ACCEPTANCE_HANDOFF.md:46` пишет «вопросов на владельце нет», а `platform/docs/DEFECT_REGISTER.md:82` PD-255 просит именно решение владельца): норма ПЛОТНОСТИ комментариев в коде платформы — твоя норма 26.07 «одна-две строки почему» против того, что миграция на 250 строк наполовину проза; зона сама подрезала самое тяжёлое и просит сказать, где граница. Поймано ревьюером полноты выгрузки при лендинге P7. Оркестраторов ДВА (решение владельца 07.08): этот — движок/платформа/фронт/доки; параллельный (РОЛЬЮ, без номера — счётчик один, D39.112 п.6) — приёмка полигона. Одновременно не запускаются; CURRENT-STATE ведут оба, чужие строки не трогают. Норма изоляции панелей — D39.113, гардрейлы в CLAUDE.md.) +> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-08-20, голова D39.153 — КУРС: движок и платформа до «работает и отдаёт результат», фронт ЗАМОРОЖЕН и P7 его НЕ размораживает (D39.147). **ОЧЕРЕДЬ №18** (единственный носитель — здесь): (а) **P7 платформы ПРИНЯТ С ФИКС-ЛИСТОМ и ЗАЛЕНДЕН, сессия закрыта владельцем 20.08** (D39.153; зонный фикс-лист из десяти пунктов — пинг №18 в `platform/docs/platform-PROGRESS.md`, первым `ContractVersion` 0.3.0 при формах 0.4.0) · (а1) **контракт API v0 0.4.0 РАТИФИЦИРОВАН** (D39.152; PD-327 закрыт; зеркало фронта отстаёт ратифицированно, при разморозке `cmp`) · (б) **лендинг петель полигона (фаза Д) — ОТКРЫТ**: приёмка ФАЗЫ у параллельного оркестратора, лендинг за этим; ⚠ в дереве живая незакоммиченная и частично ЗАСТЕЙДЖЕННАЯ работа полигона — не трогать и не «прибирать», состав выяснять у зоны · (в) **следующие работы платформы, по порядку:** дофикс-пак (фикс-лист пинга №18 + строка 199а — труба доставки правок банка + sqlc с разбором СОБРАННЫХ запросов) → ревью-пак четырёх осей, которых не смотрел никто (деньги/леджер · вход/сессии/CSRF · очередь/джобы · метрики) → живой прогон книги насквозь (строка 202, гейт — холодный прогон движка) · (г) **контракт:** сквозная полоса прогресса следующим минором (строка 200, слово владельца 20.08) вместе с хвостами релеев (203) · (д) свободные бэкенд: 160 Этап 0, фикс-лист ФЧ строкой 197 (носителя-сессии нет по слову владельца); ⚠ строки 176/181/187 СНЯТЫ с таблицы при лендинге 20.08 — они закрыты ещё D39.149, а очередь всё это время звала 181 свободной работой (поймано ревью доков; остатки живут строками 194/196/197) · (е) строка 148 после фраз владельца. **Открытые обязательства, которых нет больше нигде:** веса `pro` — строка 172-г НЕ закрыта, прогон мерил классификатор на flash; дешёвый вход — спросить полигон, говорят ли что-то данные фазы Д (там pro гоняется редактором), отдельный замер не покупать без этого · предложение внести норму «жалуйся владельцу, а не обходи молча» во ФРОНТОВЫЙ фрагмент pre-commit хука — не моя зона, нужен пинг в зонный журнал фронта, владелец не отвечал · `docs/experiments/00-provider-quirks.md` несёт протухшие цены DeepSeek («не изменились, flash $0.14/$0.28») — зона полигона, чинить пингом · санкция на платный прогон в архивном промте пака честности была РАЗОВОЙ · **вопрос платформы к ВЛАДЕЛЬЦУ, который её хендофф объявил несуществующим** (`archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md:46` пишет «вопросов на владельце нет», а `platform/docs/DEFECT_REGISTER.md:82` PD-255 просит именно решение владельца): норма ПЛОТНОСТИ комментариев в коде платформы — твоя норма 26.07 «одна-две строки почему» против того, что миграция на 250 строк наполовину проза; зона сама подрезала самое тяжёлое и просит сказать, где граница. Поймано ревьюером полноты выгрузки при лендинге P7. Оркестраторов ДВА (решение владельца 07.08): этот — движок/платформа/фронт/доки; параллельный (РОЛЬЮ, без номера — счётчик один, D39.112 п.6) — приёмка полигона. Одновременно не запускаются; CURRENT-STATE ведут оба, чужие строки не трогают. Норма изоляции панелей — D39.113, гардрейлы в CLAUDE.md.) > - **Эра №15 закрыта — семь приёмок, все ПРИНЯТЫ и залендены**; лента, коммиты и разборы — D39.109–123 (D-лог) и реестр нот `architecture/05-decisions-index.md`; снимок прежних бюллетеней этой шапки — архив-слайс `-08-02-04`. -> - **ЖИВОЕ:** полигон — **фаза Д ИДЁТ** (заказ 10.08; деньги санкционированы 15.08 напрямую полигону — ⚠ числа потолка в носителях расходятся, фактическую цепь сверить при лендинге петель; ja-книга `enkan_no_hate_ja`; при ратификации фазы Д в D-ноту: декой-правило + обязательный кросс-семейный опровергатель приёмки — одобрены 10.08; свежие фриз-коммиты полигона в дереве — НЕ трогать) · **платформа — P7 ИСПОЛНЕН, ПРИНЯТ С ФИКС-ЛИСТОМ и ЗАЛЕНДЕН 20.08, сессия ЗАКРЫТА владельцем** (D39.153; промт с баннером-исходом — `platform/docs/archive/PLATFORM_P7_SESSION_PROMPT_2026-08-16.md`; зонный фикс-лист — пинг №18 в `platform/docs/platform-PROGRESS.md`; рантбук migrate прогнан живьём) · **фронт ЗАМОРОЖЕН** (D39.136 п.2 + **D39.147: морозится ДАЛЬШЕ лендинга P7 — слово владельца 17.08; P7 зону НЕ размораживает, S5-промт не выдаётся, разморозка отдельным словом по достижении сквозного пути**; перечень первого касания зоны — синк зеркала на ТЕКУЩИЙ канон (не на «0.3.0»: канон с тех пор ушёл на 0.4.0 и уйдёт дальше строкой 200; оба минора уедут в ОДНУ перегенерацию — D39.152 п.7) + перегенерация типов + моки + гейт утечки конвейера + ФС-1..12 + Ф-63/Ф-28 + фразы В-11 по словарю кодов — не отменён, ждёт разморозки) · **контракт: канон стоит на 0.4.0, РАТИФИЦИРОВАН 20.08** (D39.152 — синк с платформой, 14 пунктов; до него был финален 0.3.0: батч+дофикс D39.142/143 · модель подписи «один ОК» D39.144 · дочистка D39.145; зеркало фронта отстаёт ратифицированно, при разморозке `cmp`) · закрытые стройки эры — лентой нот: эмиттер D39.131 · P5/P6 D39.130/132 · migrate D39.134 · S4+0.2.3 D39.135 · DeepSeek-репин D39.137 (тела — D-лог и слайсы). -> - **Открыто на владельце:** **развязка git с origin** (локальная линия ИСТИННА, force-push его рукой; не пуллить) · Приложение А контракта (148: фразы — по словарю кодов 0.3.0, структура готова) · продуктовое слово «остановлена: лимиты» (В-3) · В-4/Ф-30 (глава без заголовка — движковая половина строка 160) · мини-проба флора 44 (одобрена, промт не выдан; число — после ре-пробы 188) · подпись денежного шага 46 · лист В-3+К-6 · авто-резюм paused (вопрос платформы) · **схема time-based DeepSeek** (доклад — архив-слайс `PROGRESS-2026-08-14-15`; рекомендация: пик оставить + операционное правило «прогоны в долины», scheduler не начинать без ответа вендора об отметке тарификации) · **вход ратификации фазы Д:** посылка «dspro дешевле glm» в пике ПЕРЕВЁРНУТА (×1.26 дороже, D39.137 п.4) · **возражение Sol по проходу `tier` эксп-23** (пере-судить починенным ригом или оставить с записанным возражением — секция «Полигон») · фронт-вопросы зонного журнала: В-7 (плотность; держит Ф-54) · В-8 (слово состояния в дереве) · В-9 (языки интерфейса — механизм готов, ПТ-36) · Ф-38 (вкладка «Замечания»). Закрытые пункты листа (PD-104 · В-10 · В-11-форма · Ф-56/57/61/62/63 · Ф-28 · ПТ-33-граница · 116 · 126 · 172-пин · PD-203 · санкции фазы Д · дизайн 160/161 · title) — в нотах D39.136–145, здесь не держатся. +> - **ЖИВОЕ:** полигон — **фаза Д ИДЁТ** (заказ 10.08; деньги санкционированы 15.08 напрямую полигону — ⚠ числа потолка в носителях расходятся, фактическую цепь сверить при лендинге петель; ja-книга `enkan_no_hate_ja`; при ратификации фазы Д в D-ноту: декой-правило + обязательный кросс-семейный опровергатель приёмки — одобрены 10.08; свежие фриз-коммиты полигона в дереве — НЕ трогать) · платформа и контракт — статус в строке выше, здесь НЕ дублируется (один носитель на факт) · **фронт ЗАМОРОЖЕН** (D39.136 п.2 + **D39.147: морозится ДАЛЬШЕ лендинга P7 — слово владельца 17.08; P7 зону НЕ размораживает, S5-промт не выдаётся, разморозка отдельным словом по достижении сквозного пути**; перечень первого касания зоны — синк зеркала на ТЕКУЩИЙ канон (не на «0.3.0»: канон с тех пор ушёл на 0.4.0 и уйдёт дальше строкой 200; оба минора уедут в ОДНУ перегенерацию — D39.152 п.7) + перегенерация типов + моки + гейт утечки конвейера + ФС-1..12 + Ф-63/Ф-28 + фразы В-11 по словарю кодов — не отменён, ждёт разморозки) · закрытые стройки эры — лентой нот: эмиттер D39.131 · P5/P6 D39.130/132 · migrate D39.134 · S4+0.2.3 D39.135 · DeepSeek-репин D39.137 (тела — D-лог и слайсы). +> - **Открыто на владельце:** **развязка git с origin** (локальная линия ИСТИННА, force-push его рукой; не пуллить) · Приложение А контракта (148: фразы — по словарю кодов 0.3.0, структура готова) · продуктовое слово «остановлена: лимиты» (В-3) · В-4/Ф-30 (глава без заголовка — движковая половина строка 160) · мини-проба флора 44 (одобрена, промт не выдан; число — после ре-пробы 188) · подпись денежного шага 46 · лист В-3+К-6 · авто-резюм paused (вопрос платформы) · **схема time-based DeepSeek** (доклад — архив-слайс `PROGRESS-2026-08-14-15`; рекомендация: пик оставить + операционное правило «прогоны в долины», scheduler не начинать без ответа вендора об отметке тарификации) · **вход ратификации фазы Д:** посылка «dspro дешевле glm» в пике ПЕРЕВЁРНУТА (×1.26 дороже, D39.137 п.4) · **возражение Sol по проходу `tier` эксп-23** (⚠ носители РАСХОДЯТСЯ: здесь пункт висит на владельце, а секция «Полигон» ниже пишет «возражение снято, и владелец назвал причину» — Sol судил своё семейство, что запрещено D13.3; сверить с полигоном при лендинге петель фазы Д и снять один из двух — поймано ревью доков 20.08) · фронт-вопросы зонного журнала: В-7 (плотность; держит Ф-54) · В-8 (слово состояния в дереве) · В-9 (языки интерфейса — механизм готов, ПТ-36) · Ф-38 (вкладка «Замечания»). Закрытые пункты листа (PD-104 · В-10 · В-11-форма · Ф-56/57/61/62/63 · Ф-28 · ПТ-33-граница · 116 · 126 · 172-пин · PD-203 · санкции фазы Д · дизайн 160/161 · title) — в нотах D39.136–145, здесь не держатся. > - **Сделано (сводно)** — снимок ленты закрытых эр в [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 залендены). @@ -141,8 +141,8 @@ | 200 | **Сквозная полоса прогресса вместо пофазной — требование владельца 20.08, сформулировано и ждёт исполнения.** Сегодня прогресс считается ПО ОТРЕЗКАМ и при снятии стопа начинается с нуля (канон §Progress: «When a stop is cleared the counter starts again from zero») ⇒ пользователь видит 100% после черновика и обнуление — владелец назвал это дефектом подписанного, не вкусовщиной. Форма решения: ОДНА доля на всю работу прогона, считает СЕРВЕР (иначе клиент снова начнёт знать про фазы), плюс подпись «что делается сейчас» и неопределённый индикатор там, где доли в главах нет. ⚠ Веса «условно 10/40/40» НЕ нужны для переводческой части: движок объявляет знаменатель каждого прохода и ноль для прохода, которого на деплое нет (`backend/internal/pipeline/events.go:297-323`) ⇒ доля = сделано по всем проходам ÷ запланировано, без подобранных констант, и на деплое без редактора честно доходит до 100%. Догадка остаётся только у банка: поток прогресса несёт лишь два переводческих прохода, майнинг знаменателя не объявляет — **вопрос движку: может ли майнинг объявлять знаменатель** (он идёт по главам). Цена: правит канон §Progress + `Book.chapters_done`, то есть новый минор; пока фронт заморожен, минор бесплатен | контракт → платформа + бэкенд | скоро (следующий минор контракта) | контрактная сессия + платформенная половина; вопрос движку о знаменателе майнинга | слово владельца 20.08, D39.153 | | 201 | **Движковое «Глава N» доезжает читателю ВНУТРИ текста, обходя дисциплину `heading: null`** (линза шва P7, пере-прочитано оркестратором): `backend/internal/pipeline/export.go:230` приклеивает детерминированный порядковый к экспортному тексту первой юнит-главы (`ce.FinalText = chunk.ApplyHeading(...)`), колонка `Source` при этом остаётся heading-stripped. Платформа переносит обе как есть и честно отдаёт `heading: null` — то есть клиент нарисует СВОЙ порядковый на языке своего интерфейса над абзацем, который уже начинается с русского «Глава N», а исходная колонка соответствующего маркера не несёт: пара визуально рассинхронизирована на каждой первой главе. Конкретное следствие открытого К-2 контракта; родня движковой строки **160** (глава без заголовка) | бэкенд | когда-нибудь (с 160) | отдельное решение | приёмка P7 (D39.153) | | 202 | **Живой перевод книги НАСКВОЗЬ через API платформы не гонялся НИ РАЗУ** (obstacle сессии P7, подтверждён приёмкой): всё после «прогон стартовал и остановился» — подпись банка, halt на потолке, резюм после пополнения — покрыто батареей против живого Postgres, но с движком-заглушкой; настоящий манифест, сайдкар банка и причины флагов будут ПЕРВЫМИ данными, форму которых платформа не сочинила сама. Форма проверки (решена): только через API, как ходил бы клиент — интейк → старт → живой движок с ключами провайдера → поток событий → подпись и продолжение → чтение глав/юнитов/замечаний/банка и сверка с тем, что движок реально произвёл; качество перевода НЕ предмет (полигон). Цена ≈ $0.05 на десятиглавую книгу. **Решение владельца 20.08: ПОСЛЕ холодного прогона движка** — гонять одну неготовую систему против другой смысла нет | платформа | скоро (гейт: холодный прогон движка) | короткая сессия по промту оркестратора | слово владельца 20.08, D39.153 | -| 203 | **Хвосты контракта после синка 0.4.0 — ОТКРЫТА ЧЕТВЕРТЬ, остальное исполнено** (тела релеев — `platform/docs/P7_ACCEPTANCE_HANDOFF.md` §7; сюда переписаны НЕ тела, а статус — один носитель на факт). ⚠ Сверено грепом при лендинге, потому что первая редакция этой строки уже разошлась с деревом: **(б) ИСПОЛНЕН** — срезанная фраза компаньона §2.14 стоит на месте (`14-api-contract/README.md:508`) · **(д) ИСПОЛНЕН** — клетка приложения А заполнена `unspecified` (`README.md:1391`) · **(г) наполовину** — `unspecified` ратифицирован в каноне (`openapi.yaml:1784-1787`), открыта только ГРАНИЦА ступеней замечаний (две ступени при девяти рангах движка) → это строка **148** · **(и)** закрыт полем `stop_requested` (D39.152) · (л)(м)(н)(о) закрыты контрактной сессией. **ОТКРЫТО РЕАЛЬНО:** (а) канон-половина про `/auth` — компаньон поверхность описывает (§2.14), а канон говорит только «Signing in is not part of this surface» (`openapi.yaml:35-36`) и НЕ предупреждает, что конверт вне `/v0` может прийти БЕЗ обязательного `code`; сгенерированный по канону клиент об это спотыкается · (з) расхождение семантики `--verify-bank`: D39.144 ратифицировал «подпись = ОДИН акт», движок держит пер-термный гейт полноты (`backend/internal/pipeline/mining.go:80-82,243`) — сегодня ОБОЙДЁН платформой, а не устранён (родня 191б); одно из двух должно уступить, это ратификация, не правка · (к) ключ `project_db` в `book.yaml`: договорить, кто им владеет — шаблон оператора его не содержит, движок делает необязательным. ⚠ **Следствие «на штатном деплое банк не читается» ОПРОВЕРГНУТО живым кодом** (проверено при лендинге): акт 5 внёс фолбэк `.db` и назвал прежний отказ багом (`platform/internal/runner/artifacts.go:82-90`); первая редакция этой строки повторила клейм хендоффа зоны, не сверив с деревом — остаток чисто договорной | контракт/доки | скоро (следующее касание контракта, вместе с 200) | контрактная сессия | приёмка P7 (D39.153) | -| 204 | **Движок не публикует причины флагов ДАННЫМИ — карта причин у платформы рукописная и расходится молча** (релей §7(в) хендоффа P7; зона платформы в чужой бэклог не пишет и просила строку сюда — `platform/docs/platform-PROGRESS.md:497`). Сегодня `platform/internal/ingest/notes.go` держит рукописную копию закрытого словаря ЧУЖОЙ зоны: 15 причин движка → коды замечаний контракта, сверено побайтно на 20.08 и верно СЕЙЧАС. Импортировать движок платформе нельзя (D39.85 — разные модули), поэтому расхождение появится молча в тот день, когда движок добавит причину: платформа отдаст `unspecified` и напишет ERROR в лог, то есть деградация честная, но карта протухнет незаметно. Лечение: движок публикует свой словарь причин артефактом-данными (тем же классом, что манифест и сайдкары банка), платформа читает его вместо копии. ⚠ Носителем был ТОЛЬКО регистр платформы (PD-246) — то есть обязательство к зоне движка жило внутри зоны автора; поймано ревьюером полноты выгрузки при лендинге | бэкенд | когда-нибудь (со следующим касанием эмиссии флагов) | отдельное решение | приёмка P7 (D39.153), релей §7(в) | +| 203 | **Хвосты контракта после синка 0.4.0 — ОТКРЫТА ЧЕТВЕРТЬ, остальное исполнено** (тела релеев — `platform/docs/archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md` §7; сюда переписаны НЕ тела, а статус — один носитель на факт). ⚠ Сверено грепом при лендинге, потому что первая редакция этой строки уже разошлась с деревом: **(б) ИСПОЛНЕН** — срезанная фраза компаньона §2.14 стоит на месте (`14-api-contract/README.md:508`) · **(д) ИСПОЛНЕН** — клетка приложения А заполнена `unspecified` (`README.md:1391`) · **(г) наполовину** — `unspecified` ратифицирован в каноне (`openapi.yaml:1784-1787`), открыта только ГРАНИЦА ступеней замечаний (две ступени при девяти рангах движка) → это строка **148** · **(и)** закрыт полем `stop_requested` (D39.152) · (л)(м)(н)(о) закрыты контрактной сессией. **ОТКРЫТО РЕАЛЬНО:** (а) канон-половина про `/auth` — компаньон поверхность описывает (§2.14), а канон говорит только «Signing in is not part of this surface» (`openapi.yaml:35-36`) и НЕ предупреждает, что конверт вне `/v0` может прийти БЕЗ обязательного `code`; сгенерированный по канону клиент об это спотыкается · (з) расхождение семантики `--verify-bank`: D39.144 ратифицировал «подпись = ОДИН акт», движок держит пер-термный гейт полноты (`backend/internal/pipeline/mining.go:80-82,243`) — сегодня ОБОЙДЁН платформой, а не устранён (родня 191б); одно из двух должно уступить, это ратификация, не правка · (к) ключ `project_db` в `book.yaml`: договорить, кто им владеет — шаблон оператора его не содержит, движок делает необязательным. ⚠ **Следствие «на штатном деплое банк не читается» ОПРОВЕРГНУТО живым кодом** (проверено при лендинге): акт 5 внёс фолбэк `.db` и назвал прежний отказ багом (`platform/internal/runner/artifacts.go:82-90`); первая редакция этой строки повторила клейм хендоффа зоны, не сверив с деревом — остаток чисто договорной | контракт/доки | скоро (следующее касание контракта, вместе с 200) | контрактная сессия | приёмка P7 (D39.153) | +| 204 | **Движок не публикует причины флагов ДАННЫМИ — карта причин у платформы рукописная и расходится молча** (релей §7(в) хендоффа P7; зона платформы в чужой бэклог не пишет и просила строку сюда — `platform/docs/archive/platform-PROGRESS-P7.md:206`). Сегодня `platform/internal/ingest/notes.go` держит рукописную копию закрытого словаря ЧУЖОЙ зоны: 15 причин движка → коды замечаний контракта, сверено побайтно на 20.08 и верно СЕЙЧАС. Импортировать движок платформе нельзя (D39.85 — разные модули), поэтому расхождение появится молча в тот день, когда движок добавит причину: платформа отдаст `unspecified` и напишет ERROR в лог, то есть деградация честная, но карта протухнет незаметно. Лечение: движок публикует свой словарь причин артефактом-данными (тем же классом, что манифест и сайдкары банка), платформа читает его вместо копии. ⚠ Носителем был ТОЛЬКО регистр платформы (PD-246) — то есть обязательство к зоне движка жило внутри зоны автора; поймано ревьюером полноты выгрузки при лендинге | бэкенд | когда-нибудь (со следующим касанием эмиссии флагов) | отдельное решение | приёмка P7 (D39.153), релей §7(в) | | 49 | **Этапы Б+В спеки D15.2** (content-addressed resume / `guard_hash` — D39.31 сознательно не строил) ; этап В = tmctl export-контракт D29.1 (annot-v1 · цвет-мап+rollup · политика красных fail-closed) + операторский протокол-документ релиза гендер-твиста (D5.1): сам механизм УЖЕ построен — until_ch-правка → точечный re-edit со сметой и $0-пере-пином (`repin.go`/`rebill.go`, D39.42 п.5/D39.45) | бэкенд | скоро (ПОДТЯНУТА D39.81: annot-v1 = источник замечаний для фронта — критический путь подключения) | отдельное решение (annot-половина — по контракту 14, D39.99) | D39.34(4), D33 п.5, D39.81 | | 49а | **ALTER-шаги миграций v8–v14 не идемпотентны вопреки шапке `migrate.go:9-11`** (полу-применённая БД не сходится; счётчик версий скрывает) — находка критика полноты пака-19 | бэкенд | когда-нибудь | отдельное решение | D39.56, PACK19_BUILD §6.9 | | 50 | F3-остаток идемпотентности | бэкенд | когда-нибудь | отдельное решение | D39.34(4) | @@ -280,7 +280,9 @@ ## Полигон -**ФАЗА Д — СТАТУС НА ВЕЧЕР 10.08 (сессия передана, хендофф `/home/ubuntu/CONTINUATION_PROMPT.md`).** +**⚠ Пинг оркестратора №18 — 20.08 (протухшие цены в квирках, чинить вашей рукой).** `docs/experiments/00-provider-quirks.md` до сих пор утверждает, что цены после катовера НЕ изменились («flash $0.14/$0.28»). Это опровергнуто пере-пином 13–15.08 (D39.137): таблица запинена ПИКОМ — flash 0.44/1.32, pro 1.32/3.96, кэш-хит 0.044 за 1M, и счёт шиппинга = 100% DeepSeek ⇒ ×4.2–4.4 в пике. Квирки — ваша зона, рукой не трогаю; поправьте при ближайшем касании, потому что по ним считают деньги проб. Тем же касанием сверьте пункт «возражение Sol по проходу `tier`»: шапка держит его на владельце, а ваша секция пишет, что оно снято и причина названа — один из двух носителей неверен. + +**ФАЗА Д — СТАТУС НА ВЕЧЕР 10.08 (сессия передана, хендофф `/home/ubuntu/CONTINUATION_PROMPT.md`).** ⚠ **Запись ПРОТУХЛА трижды и её надо срезать при лендинге петель** (свип доков 20.08): статус «на вечер 10.08» лежит поверх записей от 15.08, хендофф указывает ВНЕ репозитория (файл на месте, но от 10.08 и вне git — то есть не переживёт машину), а в дереве с 16.08 живёт незадокументированная работа (`eval/dovodka/PLAN-16-08.md`, `PLAN-17-08.md`, `HANDOFF-21-08.md`, `ja6.py`, `naklon.py`), которой в этой секции нет вовсе. Три поколения записей в одном месте — именно то, из-за чего состояние фазы Д сегодня нельзя прочитать. Куплено: арм A1 (флаговый edit-контур) 30/30 платных клеток, **$0.226944**; A3 (смысловой критик, ставка владельца H-2б) в работе. Пакет **$0.234846 из $4.50**. Четыре коммита: правки ригов 22/23 по приёмке №16 и трём линиям ревью · фриз пре-рега Д0 · фриз харнесса контура · починка тихого diff --git a/docs/README.md b/docs/README.md index db918f5c..2fff5bb3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -17,7 +17,7 @@ - `research/` — фактура ресёрчей 01–28; у принятых — ревью-шапки, часть тел под ⚠ 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: записка-план, сниппеты хендоффов, карта «уже делаем/перенять») · **28 контракт-ревью API v0 (ПРИНЯТ D39.138: решения владельца 16.08 — §8, состав батча 0.3.0 — §5; НОСИТЕЛЬ для исполняющих сессий, читать оригинал, не пересказ)**. - [PROGRESS.md](PROGRESS.md) — журнал: CURRENT-STATE + **ЕДИНЫЙ БЭКЛОГ** (единственный трекер) + живой хвост хроники. НЕ источник решений. - `scripts/counts.py` — **производные числа доков считаются им, а не руками** (голова по трём носителям · счёт очереди и зон · вес открытых строк регистра платформы · полнота реестра нот); `--check` даёт ненулевой код на расхождении; `--lint` — линтер file:line-якорей живых доков (D39.126). Его же зовёт зонный хук `scripts/githooks/pre-commit`: **`--lint` якорей — при коммите, задевающем ЛЮБОЙ док или `CLAUDE.md`; `--check` чисел и головы — при коммите с D-логом или PROGRESS** (оба `--from-index`, предупреждает, не блокирует; вплетение линта — ревизия D39.148). Заведено по D39.112 п.5б: голова отставала трижды у трёх разных оркестраторов. -- Активные хендофф-промты сессий (состав обновляется при каждом лендинге — норма D39.80): [ORCHESTRATOR_SESSION_PROMPT.md](ORCHESTRATOR_SESSION_PROMPT.md) (роль/нормы; состояния не дублирует) · **Контракт: активного промта НЕТ — канон стоит на 0.4.0, РАТИФИЦИРОВАН 20.08 (D39.152)**; батч 0.3.0 отработан целиком (D39.142+D39.143), промт в `archive/prompts/`, отчёт — `archive/reports/CONTRACT_BATCH_0.3.0_REPORT.md`; синк 0.4.0 сделан ОТДЕЛЬНОЙ контрактной сессией по записке зоны платформы (`platform/docs/CONTRACT_SYNC_FROM_PLATFORM.md`, разбор — §6в компаньона), следующий минор — сквозная полоса прогресса, строка 200 · **Полигон: [POLYGON_EXP2223_REDO_SESSION_PROMPT.md](POLYGON_EXP2223_REDO_SESSION_PROMPT.md)** — фаза Д доводки эксп-22/23 ИДЁТ (заказ владельца 10.08; потолки фазы поднимал владелец напрямую — числа в CURRENT-STATE; выводы 22/23 заморожены до неё), хендофф живой сессии — [POLYGON_PHASE_D_HANDOFF.md](POLYGON_PHASE_D_HANDOFF.md) (испр. оркестратором №18: файл заленден `67e3260`, в составе не значился) · [POLYGON_PACKAGE4_SESSION_PROMPT.md](POLYGON_PACKAGE4_SESSION_PROMPT.md) (отложен). **Фронт: ЗОНА ЗАМОРОЖЕНА (D39.136 п.2)** — S4 ИСПОЛНЕН и ПРИНЯТ (D39.135, лендинг `267aa35`; контракт 0.2.3 в каноне; промт в `frontend/docs/archive/`); ⚠ **разморозка БОЛЬШЕ НЕ привязана к P7** — слово владельца 17.08 (D39.147): зона морозится дальше лендинга P7, S5-промт не выдаётся, курс — движок и платформа до «работает и отдаёт результат»; разморозка отдельным словом. Перечень первого касания (синк зеркала на ТЕКУЩИЙ канон — версия к моменту разморозки, не «0.3.0» · типы · моки · гейт утечки · ФС-1..12 · Ф-63/Ф-28 · фразы В-11 по словарю кодов; ~~В-10~~ закрыт «вежливость») не отменён, ждёт разморозки; живой smoke против дев-стенда легитимен и во фризе; фикс-лист ФС — запись приёмки 15.08 в зонном журнале · **Платформа: активного промта НЕТ** — P6 + дофикс ИСПОЛНЕНЫ и ПРИНЯТЫ (D39.132, промты в `platform/docs/archive/`); **P7 ИСПОЛНЕН (пять актов 16–20.08), ПРИНЯТ С ФИКС-ЛИСТОМ и ЗАЛЕНДЕН, сессия ЗАКРЫТА владельцем 20.08** (D39.153; промт с баннером-исходом — `platform/docs/archive/PLATFORM_P7_SESSION_PROMPT_2026-08-16.md`); зонный фикс-лист из десяти пунктов и то, что ушло в единый бэклог (198–203), — **пинг оркестратора №18 в `platform/docs/platform-PROGRESS.md`**; следующие работы зоны по порядку — дофикс-пак, ревью-пак четырёх непросмотренных осей, живой прогон насквозь (гейт — холодный прогон движка) · **Бэкенд: активного промта НЕТ** — пак «честные числа и статусы» ИСПОЛНЕН и ПРИНЯТ С ФИКС-ЛИСТОМ (D39.149, лендинг `f840867`; промт с баннером-исходом — `archive/prompts/BACKEND_HONESTY_PACK_SESSION_PROMPT_2026-08-17.md`); остаток — фикс-лист ФЧ-1…ФЧ-8 строкой бэклога **197**, носителя-сессии пока нет по слову владельца** (оба рубежа D39.141 закрыты: механическая сверка 11/11 блоков + ДВА прохода опровергателя другой моделью + узкая сверка вливания находок; первый проход сам принёс ошибку атрибуции — она вскрыта автором и подтверждена вторым проходом) (пак «честные числа и статусы»: строки 176 · 181 · 172-г · 187; п.5 живой вахты весов исполняется ТОЛЬКО при названной владельцем сумме) — ранее: пере-пин цен DeepSeek ИСПОЛНЕН и ПРИНЯТ (D39.137, лендинг `76049bb`; промт в `archive/prompts/`), потолки снова защищают; `tmctl migrate` — D39.134 (`d55edd4`), деплой эмиттер-бинаря разблокирован. Эмиттер шва ИСПОЛНЕН и ПРИНЯТ (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) (роль/нормы; состояния не дублирует) · **Контракт: активного промта НЕТ — канон стоит на 0.4.0, РАТИФИЦИРОВАН 20.08 (D39.152)**; батч 0.3.0 отработан целиком (D39.142+D39.143), промт в `archive/prompts/`, отчёт — `archive/reports/CONTRACT_BATCH_0.3.0_REPORT.md`; синк 0.4.0 сделан ОТДЕЛЬНОЙ контрактной сессией по записке зоны платформы (`platform/docs/archive/CONTRACT_SYNC_FROM_PLATFORM_2026-08-20.md`, разбор — §6в компаньона), следующий минор — сквозная полоса прогресса, строка 200 · **Полигон: [POLYGON_EXP2223_REDO_SESSION_PROMPT.md](POLYGON_EXP2223_REDO_SESSION_PROMPT.md)** — фаза Д доводки эксп-22/23 ИДЁТ (заказ владельца 10.08; потолки фазы поднимал владелец напрямую — числа в CURRENT-STATE; выводы 22/23 заморожены до неё), хендофф живой сессии — [POLYGON_PHASE_D_HANDOFF.md](POLYGON_PHASE_D_HANDOFF.md) (испр. оркестратором №18: файл заленден `67e3260`, в составе не значился) · [POLYGON_PACKAGE4_SESSION_PROMPT.md](POLYGON_PACKAGE4_SESSION_PROMPT.md) (отложен). **Фронт: ЗОНА ЗАМОРОЖЕНА (D39.136 п.2)** — S4 ИСПОЛНЕН и ПРИНЯТ (D39.135, лендинг `267aa35`; контракт 0.2.3 в каноне; промт в `frontend/docs/archive/`); ⚠ **разморозка БОЛЬШЕ НЕ привязана к P7** — слово владельца 17.08 (D39.147): зона морозится дальше лендинга P7, S5-промт не выдаётся, курс — движок и платформа до «работает и отдаёт результат»; разморозка отдельным словом. Перечень первого касания (синк зеркала на ТЕКУЩИЙ канон — версия к моменту разморозки, не «0.3.0» · типы · моки · гейт утечки · ФС-1..12 · Ф-63/Ф-28 · фразы В-11 по словарю кодов; ~~В-10~~ закрыт «вежливость») не отменён, ждёт разморозки; живой smoke против дев-стенда легитимен и во фризе; фикс-лист ФС — запись приёмки 15.08 в зонном журнале · **Платформа: активного промта НЕТ** — P6 + дофикс ИСПОЛНЕНЫ и ПРИНЯТЫ (D39.132, промты в `platform/docs/archive/`); **P7 ИСПОЛНЕН (пять актов 16–20.08), ПРИНЯТ С ФИКС-ЛИСТОМ и ЗАЛЕНДЕН, сессия ЗАКРЫТА владельцем 20.08** (D39.153; промт с баннером-исходом — `platform/docs/archive/PLATFORM_P7_SESSION_PROMPT_2026-08-16.md`); зонный фикс-лист из десяти пунктов и то, что ушло в единый бэклог (198–203), — **пинг оркестратора №18 в `platform/docs/platform-PROGRESS.md`**; следующие работы зоны по порядку — дофикс-пак, ревью-пак четырёх непросмотренных осей, живой прогон насквозь (гейт — холодный прогон движка) · **Бэкенд: активного промта НЕТ** — пак «честные числа и статусы» ИСПОЛНЕН и ПРИНЯТ С ФИКС-ЛИСТОМ (D39.149, лендинг `f840867`; промт с баннером-исходом — `archive/prompts/BACKEND_HONESTY_PACK_SESSION_PROMPT_2026-08-17.md`); остаток — фикс-лист ФЧ-1…ФЧ-8 строкой бэклога **197**, носителя-сессии пока нет по слову владельца** (оба рубежа D39.141 закрыты: механическая сверка 11/11 блоков + ДВА прохода опровергателя другой моделью + узкая сверка вливания находок; первый проход сам принёс ошибку атрибуции — она вскрыта автором и подтверждена вторым проходом) (пак «честные числа и статусы»: строки 176 · 181 · 172-г · 187; п.5 живой вахты весов исполняется ТОЛЬКО при названной владельцем сумме) — ранее: пере-пин цен DeepSeek ИСПОЛНЕН и ПРИНЯТ (D39.137, лендинг `76049bb`; промт в `archive/prompts/`), потолки снова защищают; `tmctl migrate` — D39.134 (`d55edd4`), деплой эмиттер-бинаря разблокирован. Эмиттер шва ИСПОЛНЕН и ПРИНЯТ (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..П-18) + `docs/` (зонный журнал `platform-PROGRESS.md` · регистр дефектов · архив промтов P0–P7). - `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/STACK.md b/docs/STACK.md index d0d07f2b..4e1c91bf 100644 --- a/docs/STACK.md +++ b/docs/STACK.md @@ -8,7 +8,7 @@ | **+ банкнота** (WHAT-канал драфта) | та же flash, промпт `translator-banknote.md` | как draft | ⚠ НЕ в shipping-c1 — ран-локальный конфиг книги: `~/books/gu-zhenren/coldrun-b/pipeline.yaml` (`gates.banknote` + `prompt_override`) | ⚠0731; включение в c1 = СТОП-решение владельца (строка 140: двигает RequestHash) | те же | | **терминолог** | `deepseek-v4-flash` | thinking ON, `gates.terminology.reasoning:"low"` (одна ручка на обе бэнк-роли) | ран-локальный `~/books/gu-zhenren/coldrun-b/reprobe/bank-low/pipeline.yaml:68-78`; схема — `internal/config/pipeline.go:298` (TerminologyGate); в shipping-c1 гейта НЕТ (opt-in OFF) | боевой по факту прогонов; носитель — конфиг книги | quirks §0731 п.3а: пустой `reasoning` = вендор-`high` → 4/5 `length` с пустым телом; экран `target_script: Cyrillic` обязателен при гейте ON | | **классификатор** (типы кандидатов) | flash (`classify_model` пуст ⇒ = model) | та же ручка | там же: `classify_types: true` + `classify_budget_usd` | проба/полигон; в shipping выключен ВЕЗДЕ | латентный мис-вердикт `cjk_artifact` — `13-tech-debt-anchors.md` §Б-105 | -| **editor** | `deepseek-v4-pro` **БИЛИНГВ** | thinking ON; `reasoning:"off"` = осознанный NO-OP (ReasoningNone); ручки эффорта у pro НЕТ (`low`→`high`) | `configs/pipeline-c1.yaml:61-85`; floor 16000 — `models.yaml:178` | боевой ИНТЕРИМ (D30.1/D39.22); D39.117: топология 2-прохода ПОДТВЕРЖДЕНА (`A/F3` +2.50 Holm 0.0004), жильцы dspro/glm-5 неразличимы ⇒ выбор = цена; закон-блок ОБЯЗАТЕЛЕН (строка 134) | quirks §0731 п.3а (маппинг pro), п.3б (замер `low` на pro ОТОЗВАН — НЕ УСТАНОВЛЕНО); вахта смены маппинга «early August 2026» — §Б-108 | +| **editor** | `deepseek-v4-pro` **БИЛИНГВ** | thinking ON; `reasoning:"off"` = осознанный NO-OP (ReasoningNone); ⚠ ручка эффорта у pro ПОЯВИЛАСЬ 13.08 (low/high/max — D39.137; прежнее «ручки нет» протухло, испр. 20.08), маппинг поведением пере-проверяет полигон | `configs/pipeline-c1.yaml:61-85`; floor 16000 — `models.yaml:178` | боевой ИНТЕРИМ (D30.1/D39.22); D39.117: топология 2-прохода ПОДТВЕРЖДЕНА (`A/F3` +2.50 Holm 0.0004), жильцы dspro/glm-5 неразличимы ⇒ выбор = цена; закон-блок ОБЯЗАТЕЛЕН (строка 134) | quirks §0731 п.3а (маппинг pro), п.3б (замер `low` на pro ОТОЗВАН — НЕ УСТАНОВЛЕНО); вахта смены маппинга «early August 2026» — §Б-108 | | **editor-резерв** | `glm-5` | thinking OFF ЯВНО (`extra_body {thinking:{type:disabled}}`, иначе таймауты ×3) | `configs/pipeline-arm-glm.yaml:42` + `models.yaml:184-195` | резерв; флип = один арм-конфиг. mistral-арм есть, но mistral ИСКЛЮЧЁН как редактор (D39.20) | quirks thinking-таблица (glm-5); эхо-экспозиция билингва при thinking-OFF НЕ измерена (`sourceEchoExposure`) | | **судья Ф2** | Gemini (нативный адаптер — Ф2, строка 33); в C2-скелете провизорно `glm-5` | Gemini: thinking mandatory | `models.yaml:95-108,240-255`; `pipeline-c2.yaml:33-44` (select; «DO NOT FLIP») | Ф2/полигон — в движке НЕ построен; C2 неисполняем | quirks: `thinking_budget:0` → HTTP 400; учёт `additive_total`; судья ЭРОТИКИ непригоден (PROHIBITED_CONTENT неконфигурируем, D22.6) → первичный судья 18+ = grok | | **канал B (18+)** | `mistral-large-2512` (переводчик-дефолт, D19.1) + `grok-4.3` (эскалация reasoning-ON + судья 18+) | mistral: не-reasoning; grok: OFF только явным `reasoning_effort:"none"` | `models.yaml:118-131,257-273` (accepts_labels, rate_limit) · `:63-87,221-238` · c1 `chains.adult:[grok-4.3]` | данные заведены; полный wiring — Ф2; `content_policy` пуст во всех shipping (сознательно) | quirks §Транспорт: mistral rate-limiter (~48% retry-fails → `max_concurrency:2`); grok: вложенная форма эффорта молча глотается; additive-биллинг (think-ON только за резервом D6.2) | @@ -18,5 +18,5 @@ ## Примечания - **⚠0731 (D39.61):** flash пере-обучен под тем же слагом; `/models` молчал. Развилка решена вариантом (б): явный `reasoning_effort:"low"` черновику + ручка эффорта бэнк-ролям (код `553f1a3`). Версию модели проверять ПОВЕДЕНИЕМ. - **Вахта эффорта pro:** реестр загейченных триггеров — `architecture/13-tech-debt-anchors.md` §Б-108; статус ручки `low` на pro = НЕ УСТАНОВЛЕНО (quirks §3б). -- **Цена:** ~$0.85/ранобэ (D30.4; тело — `archive/architecture/05-decisions-D1-D38.md`, карта — шапка D-лога); пере-калибровка при следующем платном прогоне (112 залендена, D39.97). Edit-волна не гонялась НИ РАЗУ (строка 16); ставка платформы $0.03/глава (D39.123 п.2г). Цены слагов — `models.yaml` (`prices_checked: 2026-07-10`; катовер 0731 цен не менял). +- **Цена:** ~$0.85/ранобэ (⚠ число ДО пере-пина цен 13–15.08: таблица запинена ПИКОМ, счёт шиппинга = 100% DeepSeek ⇒ ×4.2–4.4 в пике и ×2.1–2.2 в долине — D39.137; пере-калибровать первым же платным прогоном. D30.4; тело — `archive/architecture/05-decisions-D1-D38.md`, карта — шапка D-лога); пере-калибровка при следующем платном прогоне (112 залендена, D39.97). Edit-волна не гонялась НИ РАЗУ (строка 16); ставка платформы $0.03/глава (D39.123 п.2г). Цены слагов — `models.yaml` (`prices_checked: 2026-07-10`; катовер 0731 цен не менял). - **Ключи API:** список env-ключей — `docs/README.md` §«Доступные ключи» (7 шт.); резолв per-провайдер — `models.yaml api_key_env`. **`.env` НЕ читать** (гардрейл CLAUDE.md), `.env.example` можно. diff --git a/docs/architecture/05-decisions-log.md b/docs/architecture/05-decisions-log.md index d35b0b91..a7f60a62 100644 --- a/docs/architecture/05-decisions-log.md +++ b/docs/architecture/05-decisions-log.md @@ -519,9 +519,9 @@ **4. Почему срочности нет.** Под контрактом D39.150 («гарантируется НАПРАВЛЕНИЕ ошибки, не точность») ни один исход нынешнего механизма не занижает молча: нормальный случай точен, недостача несётся историческими деньгами С РАСКРЫТИЕМ, пойманный откат откатывается к устаревшей цене ВСЛУХ. Остаточные нарушения контракта чинятся БЕЗ схемы и уже имеют носителей — **197** (прибить гарантии тестами и довести раскрытие до `status`) и **194** (деньги банковых ролей в число согласия). ⚠ Уточнение цены 194, сверенное оркестратором: миграция ей НЕ нужна — `store.RoleSpentUSD` уже ключуется по РОЛИ чекпоинта, а не по колонке класса (`internal/store/ledger.go:105-118`, докстринг прямо: «a new call class needs no migration to become countable»). (17.08.2026, оркестратор №18) ✅ -## D39.152 — КОНТРАКТ API v0 **0.4.0 РАТИФИЦИРОВАН** (синк с платформой, 14 пунктов; author≠ratifier соблюдён сессией); четыре текстовые правки внесены при ратификации; клейм «ломающая правка одна» верен для типов и неточен поведенчески (20.08). ✅ +## D39.152 — КОНТРАКТ API v0 **0.4.0 РАТИФИЦИРОВАН** (лендинг `6e84574`) (синк с платформой, 14 пунктов; author≠ratifier соблюдён сессией); четыре текстовые правки внесены при ратификации; клейм «ломающая правка одна» верен для типов и неточен поведенчески (20.08). ✅ -**1. Что ратифицируется.** `docs/architecture/14-api-contract/openapi.yaml` + компаньон, `info.version: 0.4.0`. Автор — ОТДЕЛЬНАЯ контрактная сессия (20.08) в ответ на записку зоны платформы `platform/docs/CONTRACT_SYNC_FROM_PLATFORM.md` (14 пунктов A–N); разбор каждого — §6в компаньона. Сессия ратификацию за собой не записала и сдала текст оркестратору — норма author≠ratifier исполнена ею самой, отмечаю как правильное поведение. **0.3.0 действовал до этой ноты**; зависимость зоны (PD-327) закрывается ею. +**1. Что ратифицируется.** `docs/architecture/14-api-contract/openapi.yaml` + компаньон, `info.version: 0.4.0`. Автор — ОТДЕЛЬНАЯ контрактная сессия (20.08) в ответ на записку зоны платформы `platform/docs/archive/CONTRACT_SYNC_FROM_PLATFORM_2026-08-20.md` (14 пунктов A–N); разбор каждого — §6в компаньона. Сессия ратификацию за собой не записала и сдала текст оркестратору — норма author≠ratifier исполнена ею самой, отмечаю как правильное поведение. **0.3.0 действовал до этой ноты**; зависимость зоны (PD-327) закрывается ею. **2. Рубеж перед ратификацией исполнен** (норма: тяжёлая ратификация — контракт — смотрится ревьюером другой модели, мнение владельцу ДО). Fable-5, чтение обеих версий ЦЕЛИКОМ: вердикт «ратифицировать с правками». Пере-проверено ИМ независимо дважды: структурный дифф схем и дифф генерённых типов дают ровно одну строку `stop_requested`. Корневой `ErrorCode` — 16 значений, байт-в-байт не тронут; все открытые уровни (`ErrorCause`, `ErrorItem.code`, `Note.code`, три reason-словаря) объявлены открытыми явно. Все 14 пунктов записки имеют диспозицию, остатков прежних формулировок ноль (грепы по снятым фразам = 0). @@ -535,11 +535,11 @@ **7. Почему следующий минор не втиснут сюда.** Требование сквозной полосы прогресса (строка 200, слово владельца 20.08) — новое обязательное поле, то есть ещё один минор и ещё одна перегенерация клиента. Пока фронт заморожен и не потребляет ничего, миноры бесплатны: оба уедут в ОДНУ перегенерацию при разморозке. Значит нет причины вскрывать уже принятый пак платформы и заставлять зону доделывать на ходу. Зеркало фронта отстаёт ратифицированно (D39.142 п.5), при разморозке сверяется `cmp`. (20.08.2026, оркестратор №18) ✅ -## D39.153 — ПРИЁМКА И ЛЕНДИНГ P7 ПЛАТФОРМЫ (пять актов, читающая поверхность): **ПРИНЯТ С ФИКС-ЛИСТОМ**; шесть линз + собственные посадки, одна дыра пинов найдена оркестратором; новые строки 198–203; сессия закрыта владельцем (20.08). ✅ +## D39.153 — ПРИЁМКА И ЛЕНДИНГ P7 ПЛАТФОРМЫ (пять актов, читающая поверхность; лендинг `9b23e8c`, записи `6e84574`): **ПРИНЯТ С ФИКС-ЛИСТОМ**; шесть линз + собственные посадки, одна дыра пинов найдена оркестратором; новые строки 198–203; сессия закрыта владельцем (20.08). ✅ **1. Приёмка исполнением.** Панель шести линз в изолированных копиях, каждой свой каталог, бэкап чужого незакоммиченного ДО запуска (D39.113): слепая (заказ+дифф ДО отчёта) · контракт-конформность (пофайловый дифф wire-структур против ОБЕИХ версий канона) · деньги (два независимых пути из сырого леджера + живой стенд) · шов (инвентарь ВСЕХ каналов движка чтением чужого кода) · вне карты · ревью канона 0.4.0 другой моделью. Ни одной REJECT, регрессов против HEAD нет. **Пере-проверено рукой оркестратора:** `make check` с обоими гейтами — 18 пакетов, EXIT=0, **скипов 0**, линтер 0 issues · реестр 327 строк / 65 открытых (13 minor, 52 info), major и BLOCKER нет · оба док-гейта зелёные · миграционный манифест сходится, released-миграции не тронуты · `tmplatformctl books --migratable` живой. ⚠ Тестовых функций **532**, не 533 (команда — `grep -rh '^func Test' platform --include='*_test.go' | wc -l`; норма «дифф `^func Test` исполнением, не памятью» — `docs/ORCHESTRATOR_SESSION_PROMPT.md` §кодовый промт, со ссылкой на D39.121; в теле самой D39.121 команды нет — испр. при проверке записей); удалённых имён семь — каждое проверено, у каждого есть преемник, и преемники СИЛЬНЕЕ либо перевёрнуты по ратифицированному решению (гейт подписи банка → `TestResumeLiftsABankStopWithTheDecisionsAsTheyStand` плюс НОВЫЙ встречный `TestTheReconcilerDoesNotLiftABankStopNobodySigned`). -**2. Замер, обосновавший разворот схемного решения ВНУТРИ пака (00016 → 00022), пере-выведен независимо.** Свой бенчмарк на трёх вариантах в копии дерева: джойн **14.6 мс** · счётчик **5.3 мс** · без счётчика **2.9 мс**. Порядок и вывод подтверждаются, разворот законен: 00016 снёс колонку с доводом «её никто не пишет», 00022 вернул её ВМЕСТЕ с писателем. ⚠ Процент назван ЧЕТЫРЬМЯ носителями (журнал зоны 83% · `platform/internal/pgstore/perf_test.go:13` 96% · миграция 00022 «16.8 против 3.4, джойн сам 9 мс» · регистр PD-306 повторяет 83% и 16.8/3.4) — распад нормы «один носитель на факт» (D39.112) внутри одного пака. ⚠ **Первая редакция этой ноты писала «96% не выводится ни из чего» — ЭТО НЕВЕРНО и снято проверкой записей при лендинге:** число выводится точно, просто из ДРУГОГО замера — `platform/docs/P7_ACT5_FIX_PLAN.md:439-441`, «636 мс против 24 мс» на холодном корпусе акта 4, (636−24)/636 = 96.2%. То есть носители меряли разное (холодный корпус против вакуумированного) и оба честны; сводить их надо указанием УСЛОВИЙ замера, а не удалением одного как фантома — иначе следующая сессия снесёт верное число. +**2. Замер, обосновавший разворот схемного решения ВНУТРИ пака (00016 → 00022), пере-выведен независимо.** Свой бенчмарк на трёх вариантах в копии дерева: джойн **14.6 мс** · счётчик **5.3 мс** · без счётчика **2.9 мс**. Порядок и вывод подтверждаются, разворот законен: 00016 снёс колонку с доводом «её никто не пишет», 00022 вернул её ВМЕСТЕ с писателем. ⚠ Процент назван ЧЕТЫРЬМЯ носителями (журнал зоны 83% · `platform/internal/pgstore/perf_test.go:13` 96% · миграция 00022 «16.8 против 3.4, джойн сам 9 мс» · регистр PD-306 повторяет 83% и 16.8/3.4) — распад нормы «один носитель на факт» (D39.112) внутри одного пака. ⚠ **Первая редакция этой ноты писала «96% не выводится ни из чего» — ЭТО НЕВЕРНО и снято проверкой записей при лендинге:** число выводится точно, просто из ДРУГОГО замера — `platform/docs/archive/P7_ACT5_FIX_PLAN_2026-08-20.md:439-441`, «636 мс против 24 мс» на холодном корпусе акта 4, (636−24)/636 = 96.2%. То есть носители меряли разное (холодный корпус против вакуумированного) и оба честны; сводить их надо указанием УСЛОВИЙ замера, а не удалением одного как фантома — иначе следующая сессия снесёт верное число. **3. Собственные посадки ВНЕ списка автора — 8, поймано 7.** Долг не поставлен третьей концовкой · `edit_wave` не монотонен · снят `Vary` · HEAD лишён валидатора · `reopen` снимает стоп банка кому угодно · погашение долга без сверки метки · вынос метки долга из закрывающей транзакции во второй оператор (техника `xmin` из их §36 работает — проверено исполнением, а не принято на слово). **НЕ поймано:** снятие `structure_version` И `revision` из `emitFrame` проходит ВСЮ батарею — два поля, которые канон требует на КАЖДОМ кадре `EventBase`. По норме самой зоны (PD-1) свойство без пинящего теста считается незакрытым. @@ -553,7 +553,7 @@ **8. ВТОРОЙ РУБЕЖ — приёмка приёмки (слово владельца 20.08: «сначала приёмка твоей же работы, потом коммит»).** Четыре линзы прочитали не пак, а РАБОТУ ОРКЕСТРАТОРА: широкий инвентарь доков (другая модель, чтение всей документации четырёх зон целиком) · claim-fidelity обеих нот и всех сегодняшних записей · поиск того, что панель пропустила · полнота выгрузки долга и зонная дисциплина. Результат оправдал остановку коммита. -**(а) Пять овер-атрибуций в первой редакции ЭТИХ нот — снято, каждая проверена автором лично.** «96% не выводится ни из чего» — неверно: число выводится точно из ДРУГОГО замера зоны (`P7_ACT5_FIX_PLAN.md:439-441`, 636 мс против 24 мс на холодном корпусе), и удаление его как фантома снесло бы верное измерение · расхождений с 0.3.0 не четыре, а ПЯТЬ (пятое — семантика `410 Gone`, носитель PD-253) · «четыре рантайм-ошибки» проверяемого носителя не имеют, репозиторий несёт две · клейм «оговорка расширена на всю ручку» опережал текст канона — оговорка внесена только сейчас (D39.152 п.6) · «фикс-лист из восьми пунктов» устарел на собственной правке. **Класс один и тот же — верное утверждение приписано не тому источнику**, и это ровно тот провал, против которого написана дисциплина «эрудиция ≠ улика». +**(а) Пять овер-атрибуций в первой редакции ЭТИХ нот — снято, каждая проверена автором лично.** «96% не выводится ни из чего» — неверно: число выводится точно из ДРУГОГО замера зоны (`archive/P7_ACT5_FIX_PLAN_2026-08-20.md:439-441`, 636 мс против 24 мс на холодном корпусе), и удаление его как фантома снесло бы верное измерение · расхождений с 0.3.0 не четыре, а ПЯТЬ (пятое — семантика `410 Gone`, носитель PD-253) · «четыре рантайм-ошибки» проверяемого носителя не имеют, репозиторий несёт две · клейм «оговорка расширена на всю ручку» опережал текст канона — оговорка внесена только сейчас (D39.152 п.6) · «фикс-лист из восьми пунктов» устарел на собственной правке. **Класс один и тот же — верное утверждение приписано не тому источнику**, и это ровно тот провал, против которого написана дисциплина «эрудиция ≠ улика». **(б) Долг, живший только внутри зоны автора, вынесен наружу.** Строка в бэклог ДВИЖКА про публикацию причин флагов данными (релей §7в) жила только в регистре платформы, который движок не читает — заведена строка **204** · вопрос платформы К ВЛАДЕЛЬЦУ про норму плотности комментариев (PD-255) был объявлен несуществующим её же хендоффом («вопросов на владельце нет») — вынесен в обязательства CURRENT-STATE · норма «жалуйся владельцу, не обходи молча» для фронтового фрагмента хука жила только в моей прозе — написан пинг в зонный журнал фронта. Плюс сняты три строки бэклога (**176/181/187**), закрытые ещё D39.149: очередь всё это время звала 181 свободной работой, то есть направляла сессию чинить построенное. diff --git a/docs/architecture/09-target-architecture.md b/docs/architecture/09-target-architecture.md index 850aa367..66c4fed9 100644 --- a/docs/architecture/09-target-architecture.md +++ b/docs/architecture/09-target-architecture.md @@ -7,7 +7,7 @@ > > Это карта «куда и почему», а не пошаговая спека. Спеки — в хендофф-промтах сессий; контракт — в D-логе. -> **⟶ СТАТУС СТРОЙКИ (освежён 16.08 оркестратором №17: контракт-ревью ПРИНЯТО (research/28, D39.138), ломающий батч 0.3.0 ИСПОЛНЕН и принят с дофиксом (D39.142–145: конвейер снят с провода, машинная модель ошибок, /capabilities, поток на книгу, подпись банка = один ОК D39.144; жанр из продукта ВЫКИНУТ — строка 184); P7 платформы ЗАПУЩЕН по финальному канону. Ранее 15.08: эмиттер шва ПОСТРОЕН И ПРИНЯТ — `events.jsonl` StreamVersion 1.1, exit 4/5 + полоса отказов 10–19 (D39.131); платформа P6 + дофикс приняты — потребительская половина шва, интейк формы Б, дев-стенд, PD-113/PD-196 закрыты (D39.132); `tmctl migrate` принят — exit 13 финализирован, деадлок деплоя v15 разорван (D39.134); фронт S4 принят — путь «файл → загрузка → запуск → прогресс» в мире моков, контракт **0.2.3** в каноне (D39.135). Ранее 14.08 №16: платформа достроена до интейка книг P5 — `POST /books` с сентинелом хранилища, стоп/резюм с намерением, Prometheus, Go-floor 1.26.6 (D39.130); фронт — S3.5–S3.7 приняты (оболочка · слой данных · i18n; D39.127/129). Ранее 09.08, пост-D39.125: шов движок↔платформа ратифицирован — транзиентный systemd-юнит на прогон + `events.jsonl`-outbox в каталоге книги, платформа НЕ родитель (D39.106); платформа достроена до раннера P4 (D39.109/114/123 — River-очередь, холд-до-спавна, реконсилятор; дефекты — `platform/docs/DEFECT_REGISTER.md`); фронт — слой данных S3, контракт 0.2.0→0.2.1 (D39.115/123); движок отдал блокеры контракта — `tm-manifest-v2`, `unit.id` с тегом разреза, пофазные счётчики на главу, `--ceiling-usd` (D39.122); слой 4 добит фикс-паком банка — семьи термов со-батчатся юнитами, bankdata-плоскость (D39.118). Ранее 04.08, пост-D39.105: слои 4/5 добраны паками банка/чекеров D39.69/78/82; репо на стандартах — `make battery`, tmvet/archguard, D39.96/97; контракт API v0 = `14-api-contract/` (D39.99), платформа = зона `platform/`, открыта D39.100. Баннер — не переписывание, тело ниже = замысел арх-ресета 13.07).** Карта «слой → статус → пак/D»: +> **⟶ СТАТУС СТРОЙКИ (освежён 20.08 оркестратором №18: **пак P7 платформы ПРИНЯТ и ЗАЛЕНДЕН** — читающая поверхность построена целиком (главы · юниты · замечания · проекция банка · SSE · модель ошибок · условные чтения · идемпотентность), D39.153; **канон контракта — 0.4.0**, ратифицирован D39.152; пак движка «честные числа и статусы» принят с фикс-листом, D39.149. Предыдущий срез — 16.08 оркестратором №17: контракт-ревью ПРИНЯТО (research/28, D39.138), ломающий батч 0.3.0 ИСПОЛНЕН и принят с дофиксом (D39.142–145: конвейер снят с провода, машинная модель ошибок, /capabilities, поток на книгу, подпись банка = один ОК D39.144; жанр из продукта ВЫКИНУТ — строка 184); P7 платформы ЗАПУЩЕН по финальному канону. Ранее 15.08: эмиттер шва ПОСТРОЕН И ПРИНЯТ — `events.jsonl` StreamVersion 1.1, exit 4/5 + полоса отказов 10–19 (D39.131); платформа P6 + дофикс приняты — потребительская половина шва, интейк формы Б, дев-стенд, PD-113/PD-196 закрыты (D39.132); `tmctl migrate` принят — exit 13 финализирован, деадлок деплоя v15 разорван (D39.134); фронт S4 принят — путь «файл → загрузка → запуск → прогресс» в мире моков, контракт **0.2.3** в каноне (D39.135). Ранее 14.08 №16: платформа достроена до интейка книг P5 — `POST /books` с сентинелом хранилища, стоп/резюм с намерением, Prometheus, Go-floor 1.26.6 (D39.130); фронт — S3.5–S3.7 приняты (оболочка · слой данных · i18n; D39.127/129). Ранее 09.08, пост-D39.125: шов движок↔платформа ратифицирован — транзиентный systemd-юнит на прогон + `events.jsonl`-outbox в каталоге книги, платформа НЕ родитель (D39.106); платформа достроена до раннера P4 (D39.109/114/123 — River-очередь, холд-до-спавна, реконсилятор; дефекты — `platform/docs/DEFECT_REGISTER.md`); фронт — слой данных S3, контракт 0.2.0→0.2.1 (D39.115/123); движок отдал блокеры контракта — `tm-manifest-v2`, `unit.id` с тегом разреза, пофазные счётчики на главу, `--ceiling-usd` (D39.122); слой 4 добит фикс-паком банка — семьи термов со-батчатся юнитами, bankdata-плоскость (D39.118). Ранее 04.08, пост-D39.105: слои 4/5 добраны паками банка/чекеров D39.69/78/82; репо на стандартах — `make battery`, tmvet/archguard, D39.96/97; контракт API v0 = `14-api-contract/` (D39.99), платформа = зона `platform/`, открыта D39.100. Баннер — не переписывание, тело ниже = замысел арх-ресета 13.07).** Карта «слой → статус → пак/D»: > | Слой | Статус | Пак / D | > |---|---|---| > | 1 Сегментация | ✅ ПОСТРОЕН: бюджет в выходных токенах снапшот-folded (`chunk.SegBudget`), edit-единицы декаплены; когезия/carryover — НЕ строится (D39.7/8: эффекты под floor 0.126; кнобы `STMDepth`/`OverlapTokens` УДАЛЕНЫ, WS2 §2а), граница `logical` — не рычаг (exp15), greedy остался | пак-11 (D39.13 WS2 · D39.17 волны · D39.18 c-lite) | diff --git a/docs/architecture/14-api-contract/README.md b/docs/architecture/14-api-contract/README.md index c1868653..d64ab4b1 100644 --- a/docs/architecture/14-api-contract/README.md +++ b/docs/architecture/14-api-contract/README.md @@ -9,7 +9,7 @@ openapi.yaml РЯДОМ. ⚠ Зонная копия frontend/docs/api-contract/ первое касание зоны при разморозке; после него правило прежнее: расхождение = дефект лендинга. Генерация типов фронта после этой ратификации идёт из ЭТОЙ копии. -20.08.2026: СИНК С ПЛАТФОРМОЙ (запрос platform/docs/CONTRACT_SYNC_FROM_PLATFORM.md, 14 пунктов) — +20.08.2026: СИНК С ПЛАТФОРМОЙ (запрос platform/docs/archive/CONTRACT_SYNC_FROM_PLATFORM_2026-08-20.md, 14 пунктов) — канон 0.3.0 → 0.4.0, разбор и диспозиция КАЖДОГО пункта в §6в, отдельным пунктом §6в п.0 — сверка 0.2.3 → 0.3.0 на молча срезанные при резке прозы правила (найдена одна, восстановлена). Ратификацию этой редакции контрактная сессия за собой НЕ записывает — это акт оркестратора: @@ -893,7 +893,7 @@ the original request was never applied». Каждый `POST /books` созда ## 6в. Синк с платформой 20.08 → канон 0.4.0: что решено и почему -Вход — `platform/docs/CONTRACT_SYNC_FROM_PLATFORM.md`, четырнадцать мест, где провод сообщает +Вход — `platform/docs/archive/CONTRACT_SYNC_FROM_PLATFORM_2026-08-20.md`, четырнадцать мест, где провод сообщает состояние и не даёт клиенту действия. Записка честно разделяет ФАКТ / ⚠ МНЕНИЕ ПЛАТФОРМЫ / ГРАНИЦА, и разбор шёл по этой границе: ФАКТы перепроверены исполнением, МНЕНИЯ проверялись на ПОСЫЛКУ, а не только на предложенную форму. Два мнения посылку не выдержали (B, часть A), одно оказалось @@ -951,7 +951,7 @@ the original request was never applied». Каждый `POST /books` созда `resumeRun`). `paused` до этой ветки не доходит — он отказан выше, поэтому молчаливый `202` живёт ровно на `stopped` и `awaiting_bank`. Худший из двух — `awaiting_bank`: человек подписал банк, нажал «продолжить», получил «принято», а `ReleaseBankStop` не вызывался (зона это записала сама, -`P7_ACCEPTANCE_HANDOFF.md` §7(и)). +`archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md` §7(и)). ⚠ **Номера строк в чужой зоне в этом разделе сняты намеренно** (находка ревью): дерево платформы на 20.08 держит незакоммиченные правки, поэтому одна и та же строка в HEAD и в рабочем дереве @@ -1149,7 +1149,7 @@ announce-once-леджер: ключ `unit::::` не ### J. «Остановлено по вашей просьбе» — ПОЛЕ ЗАВЕДЕНО; форма отличается от предложенной зоной Решение владельца 17.08 принято, форму делегировали контрактной сессии -(`P7_ACCEPTANCE_HANDOFF.md:452`). Заведено `Run.stop_requested` — **обязательное булево, а не +(`archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md:452`). Заведено `Run.stop_requested` — **обязательное булево, а не необязательное.** Довод: функция тотальна — прогон, который никто не просил остановить, это `false`, а не «поля нет»; необязательность дала бы два написания одного факта, и это ровно тот дефект, который контракт уже чинил у `sense` (0.2.2), у `reject_reason` и у `kind`. Ценой стал ломающий минор — diff --git a/docs/glossary.md b/docs/glossary.md index e2db81e7..a8bd9f0c 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -8,7 +8,7 @@ - **Хендофф(-промт)** — передача роли новой сессии файлом-промтом; аддендумы к бегущей сессии доезжают только релеем владельца. - **Владелец** — человек; ратифицирует деньги, скоуп-сдвиги, продукт, 18+; связной между сессиями. - **Ф0–Ф3** — фазы: Ф0 скелет · Ф1 инфраструктура · Ф2 качество (судья/гейты) · Ф2.5 пилот · Ф3 продукт (веб-фронт, ридер-IDE). -- **S0–S7 / P0–P7** — нумерация кодовых сессий зон: S-этапы фронта (S0–S4 приняты, S4 — путь «файл→прогресс», D39.135; зона ЗАМОРОЖЕНА, и с 17.08 морозится ДАЛЬШЕ лендинга P7 — D39.147: P7 её не размораживает, S5 не выдаётся, разморозка отдельным словом владельца) · P-этапы платформы (P0 бутстрап D39.100 … P6 потребительская половина шва D39.132 · **P7 читающая поверхность — ЗАПУЩЕН 16.08**); не путать с фазами Ф0–Ф3. +- **S0–S7 / P0–P7** — нумерация кодовых сессий зон: S-этапы фронта (S0–S4 приняты, S4 — путь «файл→прогресс», D39.135; зона ЗАМОРОЖЕНА, и лендинг P7 её НЕ разморозил — D39.147: P7 её не размораживает, S5 не выдаётся, разморозка отдельным словом владельца) · P-этапы платформы (P0 бутстрап D39.100 … P6 потребительская половина шва D39.132 · **P7 читающая поверхность — ЗАПУЩЕН 16.08**); не путать с фазами Ф0–Ф3. - **Зонный журнал / зонный бэклог** — `frontend/docs/frontend-PROGRESS.md` · `platform/docs/platform-PROGRESS.md` и BACKLOG зоны: прогресс/пинги фронта и платформы живут ТОЛЬКО там (D39.100); их строки единый бэклог не принимает (D39.84). - **Полигон** — eval-зона платных/бесплатных экспериментов (`eval/`; отчёты — `docs/experiments/`, статус эксп-а — его баннер/D-лог). @@ -26,7 +26,7 @@ - **Строка N** — стабильный ID строки единого бэклога (PROGRESS §Бэклог; не перенумеровывается); **вес** — блокер-очереди / скоро / когда-нибудь; **носитель** — артефакт, в котором обязательство живёт; **хвост** — незакрытый остаток; **петля** — вопрос, обязанный получить диспозицию; **слот** — зарезервированное место в будущем пакете/замере. - **Гвоздь** — регрессионный тест, прибивающий контракт (негативный гвоздь — тест на ОТСУТСТВИЕ поведения). - **Реестр 108 / «жилец реестра»** — строка 108 единого бэклога: реестр ЗАГЕЙЧЕННЫХ ТРИГГЕРОВ (отложенных реопенов с условием «когда вернуться»); «жилец» = такой реопен. «Каждое отложено получает строку бэклога или жильца реестра 108» — норма D39.66/D39.90. -- **Контракт 14 (API v0)** — ратифицированный контракт фронт↔платформа: `architecture/14-api-contract/` — нормативная спека OpenAPI 3.1 + компаньон-README; зонная копия `frontend/docs/api-contract/` — байт-зеркало (D39.99; ⚠ временно ОТСТАЁТ на 0.2.3 при каноне 0.3.0 — ратифицировано D39.142 п.5 на фриз фронта, синк при разморозке). **Провенанс ✓/◆/○** — классы утверждений компаньона: выведено из кода/ратификации · предложено (подтверждает названная зона) · открыто (К-вопросы). **spectral / openapi-typescript** — линт спеки и генерация типов фронта с дрифт-тестом (⚠ 3.1-условия генератор игнорирует — К-11). +- **Контракт 14 (API v0)** — ратифицированный контракт фронт↔платформа: `architecture/14-api-contract/` — нормативная спека OpenAPI 3.1 + компаньон-README; зонная копия `frontend/docs/api-contract/` — байт-зеркало (D39.99; ⚠ временно ОТСТАЁТ на 0.2.3 при каноне **0.4.0** (ратифицирован D39.152, 20.08) — ратифицировано D39.142 п.5 на фриз фронта, синк при разморозке). **Провенанс ✓/◆/○** — классы утверждений компаньона: выведено из кода/ратификации · предложено (подтверждает названная зона) · открыто (К-вопросы). **spectral / openapi-typescript** — линт спеки и генерация типов фронта с дрифт-тестом (⚠ 3.1-условия генератор игнорирует — К-11). - **ПТ-N** — стабильный ID требования в `product-requirements.md`; не путать со строками единого бэклога. **paused / лимиты «как Claude Code»** — статус книги при стопе по потолку + страница статуса использования в настройках, сумм на экране нет (ПТ-35, D39.100). ## Пайплайн и код diff --git a/platform/docs/DEFECT_REGISTER.md b/platform/docs/DEFECT_REGISTER.md index dc3c2ee1..581e0d1d 100644 --- a/platform/docs/DEFECT_REGISTER.md +++ b/platform/docs/DEFECT_REGISTER.md @@ -364,7 +364,7 @@ | PD-270 | bug | info | `internal/httpapi/problem.go` `WriteProblem` | **`Problem` без `Code` уходил как 500 БЕЗ обязательного `code`.** Канон требует код на каждом ответе `/v0`, 500 включая; `omitempty` существует ради поверхности, которую канон не описывает, и протекал обратно. Живого вызова не было — латентная ловушка, бьющая по принципу самого файла («расходящаяся пара непредставима») — **закрыто:** пустой код → `internal_error`; пин `httpapi.TestAProblemWithNoCodeStillAnswersOne` | fixed(приёмка P7, дерево сессии) | приёмка P7 (воркфлоу 12 осей + кросс-модель) | | PD-271 | bug | info | `internal/httpapi/conditional.go` `acceptsGzip`, `writeJSON` | **Договорённость о кодировании решалась по ПЕРВОМУ токену** (`*, gzip;q=0` читалось как согласие) и **HEAD не получал ни ETag, ни 304**, хотя маршрутизатор отдаёт ему тот же обработчик (Go 1.22+) — **закрыто:** именованное кодирование выигрывает у `*` в любом порядке; валидатор отвечает и на HEAD; пины `TestTheNamedCodingOutranksTheWildcardInEitherOrder`, `TestHeadCarriesTheSameValidatorAsGet` | fixed(приёмка P7, дерево сессии) | приёмка P7 (воркфлоу 12 осей + кросс-модель) | | PD-272 | bug | info | `internal/pgstore/readmodel.go` `scope.tag`, `SubmitBankDecisions` | **Курсор не был привязан к КНИГЕ** (только к версии структуры) и принимался на другой книге; **решения банка** брали блокировки строк в порядке клиентского массива, и два пересекающихся сабмита взаимно блокировались — **закрыто:** книга входит в тег области; решения применяются в порядке `term_id`, отказ по-прежнему называет клиентский индекс; пин `pgstore.TestACursorMintedForOneBookIsRefusedOnAnother` | fixed(приёмка P7, дерево сессии) | приёмка P7 (воркфлоу 12 осей + кросс-модель) | -| PD-273 | standards | info | `internal/runs/reconcile.go` `outcome`, контракт §Run | **ЗАКРЫТ решением владельца 17.08: статус остаётся `awaiting_bank`, лечение — в КОНТРАКТЕ.** Разбор: нажать «стоп» на прогоне, УЖЕ стоящем в `awaiting_bank`, нельзя (`RequestStop` требует `finished_at is null`) ⇒ случай ровно один — гонка: стоп запрошен во время перевода, а движок в этом окне домайнил банк и вышел кодом 3. Оба состояния продолжаемы, но ярлык несёт ПРОВОДКУ: `ReleaseBankStop` вызывается только при `l.Status == "awaiting_bank"`, поэтому переименование в `stopped` оставило бы `bank_released = false`, вернуло бы `--verify-bank` на resume и **пере-открыло бы PD-277**. Плюс `awaiting_bank` информативнее: работа стоит на самой дешёвой точке — черновик и майнинг оплачены, редакторская волна не начата. **Настоящая дыра — ПРОВОД: `Run` не умеет сказать «остановлено по вашей просьбе»** (`status` + `stop_for_signing` = опция запуска, а не состояние), поэтому честную фразу клиент нарисовать не может. Строка бэклога для оркестратора — `P7_ACCEPTANCE_HANDOFF.md` §7(и) | closed (решение владельца 17.08) | приёмка P7 | +| PD-273 | standards | info | `internal/runs/reconcile.go` `outcome`, контракт §Run | **ЗАКРЫТ решением владельца 17.08: статус остаётся `awaiting_bank`, лечение — в КОНТРАКТЕ.** Разбор: нажать «стоп» на прогоне, УЖЕ стоящем в `awaiting_bank`, нельзя (`RequestStop` требует `finished_at is null`) ⇒ случай ровно один — гонка: стоп запрошен во время перевода, а движок в этом окне домайнил банк и вышел кодом 3. Оба состояния продолжаемы, но ярлык несёт ПРОВОДКУ: `ReleaseBankStop` вызывается только при `l.Status == "awaiting_bank"`, поэтому переименование в `stopped` оставило бы `bank_released = false`, вернуло бы `--verify-bank` на resume и **пере-открыло бы PD-277**. Плюс `awaiting_bank` информативнее: работа стоит на самой дешёвой точке — черновик и майнинг оплачены, редакторская волна не начата. **Настоящая дыра — ПРОВОД: `Run` не умеет сказать «остановлено по вашей просьбе»** (`status` + `stop_for_signing` = опция запуска, а не состояние), поэтому честную фразу клиент нарисовать не может. Строка бэклога для оркестратора — `archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md` §7(и) | closed (решение владельца 17.08) | приёмка P7 | | PD-274 | doc | **major** | `deploy/README.md:80`, `docs/PLATFORM_DIRECTION.md:68` | **Деплой-нота включала обратно грант, который PD-104 выключил.** В копируемом блоке окружения стояло `TM_PLATFORM_SIGNUP_GRANT_USD=5`, то есть развёртывание по ноте давало каждой новой личности безлимитный самообслуживаемый грант; в `PLATFORM_DIRECTION.md` §2 «Дефолт $5» пережил правку первого абзаца. Плюс `TM_PLATFORM_LANGUAGE_PAIRS` не назван вовсе, а пустой список делает `/capabilities` и интейк противоположными — **закрыто:** строка снята с объяснением, пары внесены, оба текста актуализированы | fixed(приёмка P7, дерево сессии) | приёмка P7 (воркфлоу 12 осей + кросс-модель) | | PD-275 | standards | minor | `internal/pgstore/readmodel_test.go`, `httpapi/reading_test.go`, `httpapi/problem_test.go` | **Три пина не проверяли того, что объявляли.** `TestAMissingBankReadOutSavesNothing` падал на шаг раньше (нет `book.yaml`) и в ветку `ErrNoBank` не входил; `TestALimitIsClampedOrIgnoredButNeverRefused` не мог наблюдать подрезку (фейк выбрасывал `limit`); `title(code) == ""` недостижимо ни для одного кода. Плюс подсистема `Idempotency-Key` целиком без тестов — **закрыто:** три пина переписаны на наблюдаемое свойство, подсистема ключей закрыта семью тестами, карта замечаний (`ingest/notes.go`) — тремя | fixed(приёмка P7, дерево сессии) | приёмка P7 (воркфлоу 12 осей + кросс-модель) | | PD-276 | bug | info | `internal/books/parse.go` `Parse` | **Материализация на границе интейка шла на контексте задачи,** уже потраченном разбором: на большой книге `Refresh` (ещё два процесса движка) не укладывался, и дерево оставалось пустым, а свип этого не повторяет — **закрыто:** свой отвязанный бюджет, как на границе прогона. Бэкстоп-свип для книг с `chapter_count > 0` и пустым деревом **построен доработкой 20.08** (`books.materializeMissingTrees`, `pgstore.BooksWithNoTree`; пин `TestABookWhoseTreeNeverLandedIsMaterializedByTheSweep`) ⚠ **ЭРРАТА (акт 5): названный здесь бэкстоп и его пин БОЛЬШЕ НЕ СУЩЕСТВУЮТ.** `books.materializeMissingTrees`, `pgstore.BooksWithNoTree` и `TestABookWhoseTreeNeverLandedIsMaterializedByTheSweep` удалены вместе с механизмом, который их заменил: долг на материализацию стал колонкой (PD-302), и он покрывает не только «дерева нет вовсе», но и «дерево на границу старше». Свойство закрыто, доказательство переехало: `books.TestAParsedBookOwesAReadingSurfaceUntilOneIsMaterialized` (плюс проверка, что метка ставится ТОЙ ЖЕ транзакцией, что и конец разбора) | fixed(приёмка P7 + доработка 20.08, дерево сессии) | приёмка P7 (воркфлоу 12 осей + кросс-модель) | diff --git a/platform/docs/STACK_DECISIONS.md b/platform/docs/STACK_DECISIONS.md index c54f619a..6b93bd15 100644 --- a/platform/docs/STACK_DECISIONS.md +++ b/platform/docs/STACK_DECISIONS.md @@ -424,6 +424,10 @@ export TM_PLATFORM_TEST_DSN='postgres://postgres@/postgres?host=/tmp&port=55432& - **Красный `runner.TestARunIsBoundedByItsOwnCgroup` — обычно НЕ регрессия кода:** у `tm.slice` опустел `cgroup.subtree_control`. Лечение без root: `echo "+memory +pids" > /sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/tm.slice/cgroup.subtree_control`. +- **Демон нельзя убивать `pkill -f <путь к бинарю>`** — шаблон совпадает с собственной командной + строкой оболочки, и она убивает сама себя (exit 144). Убивать по PID. +- **Postgres стенда переживает не всё:** сокет живёт в `/tmp`, и уборка `/tmp` (или smart shutdown) + роняет соединение — `pg_ctl … status` скажет «no server running». Поднимать заново по разделу выше. - **Замер страницы библиотеки** (когда трогаете проекции книги): `go test ./internal/pgstore/ -bench LibraryPage -run xxx` — корпус 40 книг × 500 глав собирается сам, `vacuum analyze` внутри. diff --git a/platform/docs/CONTRACT_SYNC_FROM_PLATFORM.md b/platform/docs/archive/CONTRACT_SYNC_FROM_PLATFORM_2026-08-20.md similarity index 97% rename from platform/docs/CONTRACT_SYNC_FROM_PLATFORM.md rename to platform/docs/archive/CONTRACT_SYNC_FROM_PLATFORM_2026-08-20.md index 5a9dde97..c939e00f 100644 --- a/platform/docs/CONTRACT_SYNC_FROM_PLATFORM.md +++ b/platform/docs/archive/CONTRACT_SYNC_FROM_PLATFORM_2026-08-20.md @@ -1,6 +1,6 @@ # Промт: контрактная сессия — синк с платформой по API v0 -> ✅ **ОТВЕЧЕНА ЦЕЛИКОМ 20.08 контрактной сессией; канон стал 0.4.0 (в дереве контрактной зоны, НЕ ратифицирован).** Все 14 пунктов имеют диспозицию; работа, которая пришла зоне (A · E · G · J), исполнена актом 5. Документ ИСТОРИЧЕСКИЙ — это вход другой сессии, а не задача. Что из ответа стало кодом — `platform-PROGRESS.md`, шапка; зависимость от ратификации — PD-327. +> ✅ **ОТВЕЧЕНА ЦЕЛИКОМ 20.08 контрактной сессией; канон 0.4.0 РАТИФИЦИРОВАН 20.08 — D39.152** (испр. оркестратором №18 при архивации: баннер писался до ратификации). Все 14 пунктов имеют диспозицию; работа, которая пришла зоне (A · E · G · J), исполнена актом 5. Документ ИСТОРИЧЕСКИЙ — это вход другой сессии, а не задача. Что из ответа стало кодом — `platform-PROGRESS.md`, шапка; зависимость от ратификации — PD-327. > Составила зона «Платформа» 20.08.2026 по слову владельца. Это ЗАПРОС, не проект правки: зона > называет места, где провод не даёт клиенту сделать то, что нужно пользователю, и говорит, что она diff --git a/platform/docs/P7_ACCEPTANCE_HANDOFF.md b/platform/docs/archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md similarity index 99% rename from platform/docs/P7_ACCEPTANCE_HANDOFF.md rename to platform/docs/archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md index edf7da49..4c92a2dd 100644 --- a/platform/docs/P7_ACCEPTANCE_HANDOFF.md +++ b/platform/docs/archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md @@ -1,5 +1,10 @@ # Пак P7 — приёмка, правки, приёмка правок, доработка. Хендофф +> ⚠ **АРХИВ (оркестратор №18, 20.08).** Пак P7 принят и заленден (D39.153, `9b23e8c`), сессия закрыта владельцем. Документ ИСТОРИЧЕСКИЙ — рабочий процесс приёмки актов 1–4; инструкции НЕ исполнять. +> +> Живое из него ВЫНЕСЕНО, чтобы не держать второй носитель: рецепт стенда и грабли (§2) живут в `platform/docs/STACK_DECISIONS.md` (две уникальные грабли дописаны туда при архивации) · релеи §7 — строка **203** единого бэклога, статус каждого сверен грепом и половина исполнена · строка про «остановлено по вашей просьбе» (§7и) закрыта полем `stop_requested` канона 0.4.0 · строка в бэклог движка (§7в) заведена как **204**. ⚠ §0 этого файла объявляет «вопросов на владельце нет» — это НЕВЕРНО и поймано ревью: PD-255 просит именно решение владельца, оно вынесено в CURRENT-STATE. + + > ⚠ **РАБОЧИЙ ДОКУМЕНТ СЕССИИ, ОРКЕСТРАТОРУ ЧИТАТЬ НЕ НУЖНО.** Это мой процесс: как я шёл, что проверял, что передумал. Для лендинга нужны три вещи, и все они в других местах — что сделано и зачем: шапка `platform-PROGRESS.md` · статус каждого дефекта: `DEFECT_REGISTER.md` · правила, переживающие пак: `STACK_DECISIONS.md` §33–36. > > Составлен 17.08.2026 сессией приёмки платформы; **акт 4 — доработка 20.08** (этот же документ). diff --git a/platform/docs/P7_ACT5_FIX_PLAN.md b/platform/docs/archive/P7_ACT5_FIX_PLAN_2026-08-20.md similarity index 98% rename from platform/docs/P7_ACT5_FIX_PLAN.md rename to platform/docs/archive/P7_ACT5_FIX_PLAN_2026-08-20.md index 841f23a4..2c859bc8 100644 --- a/platform/docs/P7_ACT5_FIX_PLAN.md +++ b/platform/docs/archive/P7_ACT5_FIX_PLAN_2026-08-20.md @@ -1,5 +1,10 @@ # Пак P7, акт 5 — исполнение фиксов по ревью акта 4 +> ⚠ **АРХИВ (оркестратор №18, 20.08).** Задача закрыта целиком: акт 5 исполнен, пак P7 принят с фикс-листом и заленден (D39.153, `9b23e8c`). Документ ИСТОРИЧЕСКИЙ — рабочий процесс сессии; инструкции НЕ исполнять. +> +> Живое из него переехало: замер «636 мс против 24 мс» (§ про `note_count`) — единственный носитель числа 96% в `perf_test.go`, разбор — D39.153 п.2; фикс-лист приёмки — пинг оркестратора №18 в `platform-PROGRESS.md`. + + > ⚠ **РАБОЧИЙ ДОКУМЕНТ СЕССИИ, ОРКЕСТРАТОРУ ЧИТАТЬ НЕ НУЖНО.** Это мой процесс: как я шёл, что проверял, что передумал. Для лендинга нужны три вещи, и все они в других местах — что сделано и зачем: шапка `platform-PROGRESS.md` · статус каждого дефекта: `DEFECT_REGISTER.md` · правила, переживающие пак: `STACK_DECISIONS.md` §33–36. > > Составлен 20.08.2026 сессией платформы ДЛЯ СЕБЯ ЖЕ после компакции контекста. diff --git a/platform/docs/archive/platform-PROGRESS-P7.md b/platform/docs/archive/platform-PROGRESS-P7.md new file mode 100644 index 00000000..b68cc4e1 --- /dev/null +++ b/platform/docs/archive/platform-PROGRESS-P7.md @@ -0,0 +1,250 @@ +# Архив журнала зоны «Платформа» — эра пака P7 (16–20.08.2026) + +> ⚠ **СРЕЗ, выселен оркестратором №18 при лендинге P7 (20.08, D39.153)** — по образцу срезов `platform-PROGRESS-P0-P3.md` и `-P4-P6.md`. Эра ЗАКРЫТА: пак исполнен пятью актами, принят с фикс-листом и заленден (`9b23e8c`), сессия закрыта владельцем. +> +> **Не читать при онбординге.** Живое состояние зоны — шапка `platform-PROGRESS.md`; статус каждого дефекта — `DEFECT_REGISTER.md` (источник истины); правила, пережившие пак, — `STACK_DECISIONS.md` §33–36; фикс-лист приёмки и то, что ушло в единый бэклог, — пинг оркестратора №18 там же в живом журнале. + +## Сессия P7 (16–17.08): читающая поверхность контракта 0.3.0 + +Промт — `PLATFORM_P7_SESSION_PROMPT.md`. Ниже: записка-план по §4 (каждый пункт с диспозицией), +команды, живые пробы, находки, obstacle. + +### Записка-план: пункт → исполнено / отказ → улика + +| § | Пункт | Статус | Улика | +|---|---|---|---| +| 0 | Рантбук деплоя живым `migrate` | **исполнен** | БД проекта отведена на v14 при бинаре v15 → `tmctl status --json` = exit 13, токен `schema_mismatch found=14 expected=15`; `tmctl migrate` → бэкап + v14→v15; тот же `status` = exit 0. Мёртвая цитата вычищена (`deploy/README.md`, П-1 бэклога), пример в `tmplatformctl/runs.go` переписан на ВЕРСИОНИРОВАННЫЙ путь | +| 0 | `tmplatformctl books --migratable` → `tmctl migrate` end-to-end | **исполнен** | 5 книг стенда, все `MIGRATE=yes`, цикл из деплой-ноты отработал | +| 1а | Читать `BookIntake.title` | **исполнен** | `books.Intake.Title`; пустая строка = «назови по файлу» (`books.title()`), непустая не перезаписывается разбором | +| 1б | Проецировать `reject_reason` | **исполнен** | `httpapi.contractRejectReason`; `parser_unavailable` → `processing_failed` (ФБ-9: имя значения — то, на что клиент вешает фразу) | +| 2 | PD-104: грант → 0 + тест | **исполнен** | `config.go` дефолт 0; пин `config.TestSignupGrantIsParsedNotGuessed` пинит ИМЕННО ноль; протухшие «$5» вычищены из `PLATFORM_DIRECTION.md` §2, `BACKLOG.md` П-7, регистра | +| 3 | Модель ошибок по карте А-2 | **исполнен** | `httpapi/problem.go`: 16 корневых кодов, статус ВЫВОДИТСЯ из кода (пара «код+статус» непредставима расходящейся), `cause` открытый, `errors[]`, `request_id` из `reqid`; `WWW-Authenticate` на 401; две причины 403 разведены в `cause` при одном корневом `forbidden`; класс 2 — один код без вариации | +| 4 | `listChapters` · `listUnits` (пер-главно, 410) · `listNotes` · `listBankTerms` · `submitBankDecisions` · дельты · SSE · `structure_version` · gzip · ETag/304 | **исполнен** | `httpapi/{reading,stream,conditional}.go`, `pgstore/{readmodel,events}.go`; ручки «вся книга юнитами» НЕТ; `Unit.notes` массивом; агрегаты банка на ПЕРВОЙ странице; дельты ВКЛЮЧИТЕЛЬНЫЕ; `version_too_old` и `cursor_invalid` — причинами | +| 4 | Ловушка `heading` | **исполнен** | поле не декодируется ВОВСЕ (`ingest.ManifestChapter`), колонка `chapters.heading` удалена миграцией, проекция отдаёт `null`; пин `readmodel.TestTheManifestsRenderedHeadingHasNowhereToLand` | +| 4 | Демонтаж построенного гейта полноты банка | **исполнен** | `runs/reconcile.go`: `awaiting_bank` продолжается при ЛЮБОМ состоянии решений; пин `TestResumeLiftsABankStopWithTheDecisionsAsTheyStand`. Граница паузы движка сверена чтением (`pipeline/mining.go`: авто-продолжение с неподписанным банком — дефолт) | +| 4 | Пофазность у главы НЕ строить | **соблюдён** | у главы один счётчик `units_done`; пин «фазовый счётчик не доехал до строки главы» | +| 4 | `Note.code` из ◆-карты | **исполнен с ОДНИМ отступлением** | `httpapi/notes.go`; отступление — незнакомая причина проецируется как `unspecified` (в карте колонка кода пуста, а поле обязательно). Заведена строка PD-246, ждёт ратификации вместе с фразами | +| 5 | `Progress` с книги на `Run`, одна полоса в ГЛАВАХ | **исполнен** | `pgstore.Progress{Done,Total,ETASeconds}`, знаменатель — `ceiling_chapters`; сегмент выбирается `verify_bank && !bank_released` | +| 5 | `Book`: +`revision`, +`chapters_done`, −`progress`, −`genre` | **исполнен** | `genre` снят и с ПРОВОДА, и из формы интейка, и из колонки: платформа его больше не знает, значение шаблона оператора остаётся его | +| 5 | `Run`: +`book_id`, +`failure_reason`, `verify_bank`→`stop_for_signing` | **исполнен** | словарь из трёх значений мапится с полосы 10–19 и веток `outcome()` (`runs.failureReason`) | +| 5 | `Usage`: `halt_reason` со своим словарём | **исполнен** | `httpapi.contractHaltReason`; прогонная причина больше не может доехать до аккаунтного поля | +| 5 | `GET /capabilities` | **исполнен** | все шесть полей; пары — из конфигурации (`TM_PLATFORM_LANGUAGE_PAIRS`), не список в Go | +| 5 | `limit` подрезать, а не отвергать | **исполнен** | `pgstore.clampPage`; отвергается только значение, которое не является размером страницы | +| 5 | Трейлинг-части интейка → 400 | **исполнен, с находкой** | сначала книга ОСТАВАЛАСЬ при 400 (живая проба); теперь часть после файла ПРОВАЛИВАЕТ чтение, и интейк откатывает загрузку своим же путём | +| 5 | `Location` на 201 | **исполнен** | `/v0/books/` | +| 5 | `Idempotency-Key` на `createBook` и `startRun` | **исполнен** | таблица 00017, повтор отдаёт ИСХОДНЫЙ ответ, другой запрос — 409 `key_reused`, гонка — `key_in_flight` + `Retry-After`, >255 → 400 | +| 5 | `blocked {code, book_id}` на run-options и 409 | **исполнен** | `pgstore.CreditHeldBy` + `runs.CreditHeldError` | +| 5 | Отказ по неподдерживаемой паре на интейке | **исполнен** | `books.ErrUnsupportedPair` → `errors[].code: unsupported_pair`; пустой список пар = деплой не объявляет ничего и пару не проверяет | +| 5 | `finalizing` вон из словарей | **исполнен** | Go-свитчи и CHECK-констрейнты обеих таблиц | +| 6 | PD-172/173/174/180/199 привести · PD-201 · PD-241 | **исполнен** | все закрыты либо сужены с уликой; PD-241 — перевёрнутый порядок в `outcome()` с пином | +| 6 | Кандидаты PD-219/217/162 | **отсуждены** | PD-217 — половина ЗАКРЫТА (paused больше не блокирует апгрейд движка); PD-219 и PD-162 — не брались, с названной причиной | +| 6 | Находки §9 research/28 | **отсуждены** | три взяты строками (PD-249/250/251/252), две сведены к существующим (PD-203, PD-162/244) | +| 6 | Инструменты: sqlc / oapi-codegen | **отказ с доводом** | оба НЕ взяты; довод — `PLATFORM_DIRECTION.md` §3, и он опирается на замер этого пака, а не на вкус | + +### Команды (каждое число отчёта — этой командой) + +```sh +# батарея, оба гейта, -race +export TM_PLATFORM_TEST_DSN='postgres://postgres@/postgres?host=/tmp&port=55433&sslmode=disable' +export TM_PLATFORM_TEST_ENGINE_BIN=<путь к tmctl> TM_PLATFORM_TEST_BOOK_TEMPLATE=<шаблон> +make check # EXIT=0, 18 пакетов, скипов 0, линтер 0 issues +grep -rh '^func Test' --include='*_test.go' . | wc -l # 458 (HEAD: 416) +git diff --stat platform | tail -1 # 46 файлов, +2329 −646 +python3 docs/scripts/counts.py # регистр: 256 строк, 63 открытых +``` + +⚠ Стенд Postgres на этой машине пришлось поднять с нуля (его не было): рецепт `STACK_DECISIONS.md` +§«Postgres без root», micromamba + `postgresql=18.4` в `~/.local/pgsql`, порт 55433 — отработал +дословно. + +### Живые пробы на дев-стенде (демон + сид + настоящий `tmctl`) + +Сид P6 отработал целиком: дев-вход → грант → загрузка через ЖИВОЙ `POST /v0/books` → разбор → +`not_started, 3 главы`. Дальше — курлом по новым ручкам: + +- `GET /capabilities` → все шесть полей, `contract_version: 0.3.0`, пары `zh>ru available` + + `ja>ru unavailable`; +- `GET /books` → `revision · reject_reason: null · structure_version: 1 · chapters_done: 0 · + character_count: 987`, **никакого `progress` и никакого `genre`**; +- `GET /books/{id}/chapters` → три главы, `heading: null` у каждой; +- `GET /books/{id}/chapters/{ch}/units` → пара с ИСХОДНЫМ ТЕКСТОМ (канал `tmctl export --pairs` + работает), `target: ""`, `state: pending`, `notes: []`; +- `GET /books/{id}/notes`, `/bank` → пустые с агрегатами и `structure_version`; +- SSE на книге в покое → `hello id=4` → `end id=4` → закрытие; реконнект с `Last-Event-ID: 6` → **204**; +- `ETag` → `304` на `If-None-Match`; `Accept-Encoding: gzip` → `Content-Encoding: gzip` + `Vary`; + тот же заголовок на `/events` → **не сжато**; +- ошибки: 404 → `code: not_found` + `request_id`; 401 → `WWW-Authenticate: Bearer realm="textmachine"`; + POST без `X-TM-Client` → 403 `forbidden` · `cause.code: client_header_missing`; +- интейк: пара `ja→ru` → 400 `unsupported_pair` на обоих полях; часть после файла → 400 + `missing_or_late` **и книга не остаётся** (проверено счётом библиотеки до/после); +- `Idempotency-Key`: тот же ключ дважды → один и тот же `Location`; тот же ключ с другим `title` → + 409 `idempotency_conflict` · `cause.code: key_reused`. + +### Что нашли ПРОБЫ, чего не нашли тесты + +**Часть формы после файла оставляла книгу.** Отказ 400 приезжал (правило соблюдалось), но +`intake.Accept` к тому моменту уже создал строку и каталог — пользователь получал ошибку И книгу в +библиотеке. Починено не новым кодом отката, а ПРОВАЛОМ чтения: часть после файла возвращает ошибку +из ридера, и интейк отменяет загрузку тем же путём, которым отменяет оборванную. Пин +`httpapi.TestAPartAfterTheFileIsRefusedAndTheBookIsNotKept`, пере-проверено живьём. + +### Адверсариальное селф-ревью финалом: три ревьюера, таблица находок + +Механизм по §5 промта: три независимых субагента по ФИНАЛЬНОМУ диффу, author≠reviewer, **два из +трёх — другой модели** (кросс-семейная линза, а не вторая своя). Ноль находок не случился — и это +хорошо: две HIGH нашли ОБА контрактных ревьюера независимо, что и есть подтверждение. + +| # | Линза | Находка | Вердикт | Что сделано | +|---|---|---|---|---| +| Р-1 | контракт (кросс-модель) · деньги/шов | **Кадр `note` уносил движковую причину** (`glossary_miss`, `hard_refusal`) и не нёс обязательных `severity`/`code`; `unit_id: null` вместо отсутствия | ПОДТВЕРЖДЕНА, HIGH | Карта переехала в `internal/ingest/notes.go` — один дом на оба потребителя; кадр строится через неё; `unit_id` опускается. Пин `TestTheNoteFrameCarriesTheContractsNoteAndNotTheEnginesReason` | +| Р-2 | контракт (кросс-модель) | **Кадр `status` уносил внутренние словари** (`daily_ceiling`, `parser_unavailable`): та же величина читалась `null` на карточке и внутренним словом в потоке | ПОДТВЕРЖДЕНА, HIGH | Переводы переехали в `internal/ingest/vocabulary.go`, кадр строит `emitStatus`; при ошибке чтения кадр НЕ шлётся (вместо `status: null` вне схемы). Пин `TestTheStatusFrameCarriesTheContractsVocabularyOrNothing` | +| Р-3 | деньги/шов | **DOWN-путь миграции неисполним при первой же строке банка** (воспроизведено живым PG): три словаря переписывались без перевода данных, а goose гоняет миграцию одной транзакцией | ПОДТВЕРЖДЕНА, HIGH | Порядок drop → перевод → add в ОБЕ стороны (UP тоже: он должен переживать пере-накат после отката). Пин `TestARollbackSurvivesTheDataTheNewVocabulariesWrote` — откат до документированного пола (версия 5) на базе С данными | +| Р-4 | деньги/шов | **Четыре писателя меняли статус без кадра** (`RestartRun`, `PauseRun`, `FinishUnspawnedStop`, `ReleaseBankStop`); двое из них ставят `finished_at`, то есть книга «в покое» — и следующий реконнект получает **204 «не переподключайся»** при устаревшем статусе у клиента | ПОДТВЕРЖДЕНА, HIGH | Кадр у всех трёх писателей статуса; четвёртый (`ReleaseBankStop`) перестал быть отдельным писателем — см. Р-5 | +| Р-5 | деньги/шов | **`ReleaseBankStop` коммитился ДО `reopen`**: резюм, который ничего не сделал (расчёт в полёте, бюджет исчерпан), всё равно переключал полосу с N/N на 0/N | ПОДТВЕРЖДЕНА, MED | Снятие стопа перенесено ПОСЛЕ успешного `reopen` | +| Р-6 | деньги/шов | **`Refresh` тратил бюджет прохода ПЕРЕД `settle`**: на большой книге два полных ре-чанка съедали проход, расчёт уходил в «отложено», холд висел свип | ПОДТВЕРЖДЕНА, MED | Деньги первыми: `settle` → затем `refreshReadModel` на СВОЁМ ограниченном контексте, ошибка громкая | +| Р-7 | деньги/шов | **`failureReason` игнорировал маркер**, который ему передавали: OOM и kill по стоп-таймауту приезжали `interrupted` («повтори») | ПОДТВЕРЖДЕНА, MED | Читает `m.Result`; пин `TestWhyARunFailedDecidesWhetherARetryIsWorthOffering` (7 веток) | +| Р-8 | контракт (кросс-модель) | **Квитанции `Run` несли нулевую полосу** (`202` на старт/стоп/резюм) со свежей ревизией — клиентский гард пропускал её и полоса откатывалась к 0/0 | ПОДТВЕРЖДЕНА, MED | `StartRun`/`RequestStop`/`ReadRun` считают ту же полосу, что карточка | +| Р-9 | контракт (кросс-модель) | **Полоса ВТОРОГО прогона считала главы всей книги**: дробь стартовала выше нуля и могла превысить единицу | ПОДТВЕРЖДЕНА, MED | Колонка `runs.chapters_before` — база сегмента, снимается в том же стейтменте, что создаёт прогон; `least(…, ceiling_chapters)` закрывает второй край. Пин `TestASecondRunsBarStartsAtZeroOverAHalfFinishedBook` | +| Р-10 | контракт (кросс-модель) | **`Last-Event-ID: 0` после подрезки буфера молча пропускал дыру** — а `0` это легальный id, который сервер сам выдаёт | ПОДТВЕРЖДЕНА, MED | Условие `last+1 < Oldest` вместо `last > 0 && last < Oldest` | +| Р-11 | контракт (кросс-модель) · скоуп | **Склейка кадров `chapter` шла по имени события**, теряя счётчик соседней главы внутри одного соединения | ПОДТВЕРЖДЕНА, MED | Склейка по (событие, id сущности) | +| Р-12 | контракт (кросс-модель) | **Порядок банка** был `(src, id)` — то есть по ХЕШУ, а канон объявляет «по поверхности, затем по окну» | ПОДТВЕРЖДЕНА, MED | Порядок и кейсет приведены к канону (`src, since, until, id`) | +| Р-13 | контракт (кросс-модель) | **`limit` всё ещё отвергался снизу** (0, отрицательный, нечисло), тогда как канон освобождает параметр от отказа | ПОДТВЕРЖДЕНА, MED | Никогда не отвергается: сверху подрезка, всё прочее — дефолт деплоя. Пин переписан | +| Р-14 | контракт (кросс-модель) | **Неверная пара языков и слишком длинное поле отказывали без `errors[]`** | ПОДТВЕРЖДЕНА, MED | `ErrMalformedLanguage` и `too_long` с указателем на поле | +| Р-15 | контракт (кросс-модель) | **`SweepIdempotency` не имел вызывающего**: ключи не забывались никогда | ПОДТВЕРЖДЕНА, LOW | Подключён в свип демона, окно 25 часов | +| Р-16 | контракт (кросс-модель) | **Курсор замечаний нёс движковое слово волны** в открытом виде | ПОДТВЕРЖДЕНА, LOW | Пакуется порядковым номером | +| Р-17 | скоуп (кросс-модель) | `acceptsGzip` игнорировал `*`; `pump` спал такт даже после полной пачки; `unknownTermPointer` парсил текст ошибки; алиас `itoa` | ПОДТВЕРЖДЕНЫ, LOW | Все четыре починены (типизированная `UnknownTermError` вместо парсинга строки) | +| Р-18 | скоуп (кросс-модель) | **`sqlc` был привязан к этому паку ратификацией**, а пак от него отказался — это отступление, а не решение зоны | СПРАВЕДЛИВО | Отказ с доводом записан в `PLATFORM_DIRECTION.md` §3 и вынесен ВОПРОСОМ оркестратору (ниже) | +| Р-19 | скоуп (кросс-модель) | **`unspecified` — изобретённый код** там, где промт требовал пинг | ЧАСТИЧНО: разбор с владельцем 17.08 показал, что находка верна по форме и неверна по существу | Значение отдано ветке, которую канон УЖЕ ратифицировал («нейтральная фраза для незнакомого кода»), а не заводит новое правило; настоящий предмет — рукописная копия чужого словаря без гейта, PD-246 пере-сформулирован, движку — пинг про публикацию причин данными | +| Р-20 | контракт (кросс-модель) | `410` отвечает и на главу, которой никогда не было: различение 410/404 без надгробий неисполнимо | ПРИНЯТО КАК ЕСТЬ | Лечение у обоих одно (перечитать дерево); строка PD-253 | +| Р-21 | скоуп (кросс-модель) | **Масса комментариев** выросла против нормы зоны (миграция на 250 строк — половина проза) | ЧАСТИЧНО ПРИНЯТО | Подрезано самое тяжёлое; остальное — предмет пинга, а не тихой правки | +| Р-22 | скоуп (кросс-модель) | **Два писателя ошибок** (`WriteProblem` + `WriteStatusProblem`/`codeForStatus`), три одинаковых структуры пары | НЕ БРАЛОСЬ | Второй писатель обслуживает НЕконтрактную поверхность (`/auth`, `/readyz`), где кода версии нет; сведение в один требует ратификации формы для 405/429 — вопрос оркестратору | + +**Что ревьюеры подтвердили как ВЕРНОЕ** (важно не меньше находок): ни одной денежной величины на +проводе ни в каком виде · порядок блокировок не тронут, `emitFrame` не берёт НОВЫХ локов ни в одной +из 14 точек · кадр не может быть выпущен для откаченного состояния · демонтаж гейта банка +соответствует таблице канона дословно · словари шва (шесть значений банка, полоса отказов 10–19, +все семь типов событий) сверены по коду движка и полны · `finalizing` снят безопасно · оба гейта +миграций пере-считаны и совпадают. + +### Живые пробы ПОСЛЕ фикс-раунда (стенд пере-создан) + +Стенд пришлось пере-создать, и это отдельная улика: миграция 00016 правилась ПОСЛЕ того, как была +применена, а goose ключуется номером — отредактированный файл не перезапускается никогда. На стенде +лечится сносом базы; в проде именно от этого стоит гейт `migrations.sha256` (обе строки пере-считаны). + +- `limit=0 | -3 | abc | 100000` → **200 во всех четырёх** (канон освобождает параметр от отказа); +- квитанция старта: `status: translating`, `progress {done:0, total:2}`, `book_id`, `failure_reason: null` + — полоса едет с квитанцией, а не только с карточкой; +- поток при ЖИВОМ прогоне: `hello id=5` → `status id=7` с `failure_reason: "service_error"` и + `paused_reason: null` — кадр несёт КОНТРАКТНЫЙ словарь (внутреннего слова в кадре нет); +- карточка после отказа: книга `failed`, прогон `failed` + `service_error` (на стенде нет ключей + провайдера — движок отказывает конфигурацией, и это ровно тот класс, который «повтор не лечит»); +- `resume` упавшего прогона → `run_not_resumable` без `cause` (канон: это не остановленный прогон); +- неверный код языка → `invalid_request` + `errors[]` на оба поля; +- `/usage` → `halt_reason: null` (свой словарь, не прогонный). + +### Obstacle: что НЕ удалось и что не проверено + +1. **Отложено в P8 явно** (заказ промта): `updateBook` · `deleteBook` · `getRun` · `createExport` + /`getExport` · эскроу (П-18). +2. **`Note.code` для незнакомой причины — отступление**, не решение: `unspecified` (PD-246). +3. **Ни одного живого ЗАМЕЧАНИЯ и ни одного термина банка через настоящий прогон не прошло** — + прогон стоит денег, а сессия $0. Проекции замечаний и банка проверены тестами на живом PG и + ручными строками `unit_resolutions`, но не сквозным прогоном движка. +4. **SSE с ЖИВЫМ прогоном не гонялся** по той же причине: проверены книга в покое, реконнект, 204, + склейка и `resync_required` — тестами и на стенде, но не под настоящим потоком кадров. +5. **Стоимость материализации не замерена на большой книге** (PD-248): два полных ре-чанка на + границу работы; на демо-книге в 3 главы это миллисекунды, на 2283 главах — секунды CPU. +6. **`structure_version` на РЕАЛЬНОЙ пере-нарезке** проверен тестом (смена ключа манифеста), но не + настоящей сменой чанкера движка. +7. **Опрос потока — 2 запроса/с на соединение** (PD-247): `LISTEN/NOTIFY` не строился. +8. **Кадр `note` живьём не наблюдался**: он рождается только на помеченной единице настоящего + прогона. Проверен тестом на живом PG через настоящий `RunSink.Apply` (полный путь материализатора), + но не в потоке под браузером. +9. **Полоса под настоящей работой не наблюдалась**: `progress {0,2}` — это старт; движения счётчика + на стенде без ключей провайдера не бывает. + +### Вопросы оркестратору (канал вопросов промта, НЕ тихая интерпретация) + +1. **Словарь флаг-причин — рукописная копия чужой зоны без гейта** (PD-246; формулировка исправлена + после разбора с владельцем 17.08 — прежняя, «в карте контракта дыра», была неверной). + Проверено чтением движка: локализованных фраз там НЕТ вовсе — `refusal.go` и `status.go` несут + машинные классы, русских пользовательских строк в продовом коде движка ноль. То есть движок и + контракт построены на одном принципе, и переделывать под «гугловский словарик в движке» нечего: + фраза всегда на языке ИНТЕРФЕЙСА, которого не знает ни движок, ни платформа, а движок ОДИН на все + пары — русская строка в нём была бы таргет-спецификой в общем слое (тот же инвариант, что снял + `ruby` с провода). + **Проводу окно закрыто:** причина вне карты едет кодом `unspecified`, а канон уже предписывает + клиенту нейтральную фразу для незнакомого кода — значение отдано РАТИФИЦИРОВАННОЙ ветке, а не + изобретено правило. На подпись остаются две строки продуктового текста: фраза для `unspecified` и + граница ступеней `attention`/`glance` (сегодня — догадка платформы, колонка «Ступень» в + приложении А пуста у всех 15 строк). Это не блокер. + **Правка контракта — предлагаю, зона не моя (готовые формулировки, вставить как есть).** + *Обязательный минимум — КОМПАНЬОН, приложение А, последняя строка (`README.md:899`).* Пустая + клетка кода в ней и есть то, что заставило платформу выбирать значение самой: + + > `| незнакомая причина | 8 (по умолчанию) | `unspecified` — стабильный плейсхолдер деплоя: не значение словаря, а ОБЯЗАННОСТЬ сервера ответить одним и тем же кодом на причину, которой его сборка карты не знает (носитель — PD-246 платформы) | ⬜ нейтральная, НЕ «ошибка» | ⬜ |` + + *Желательное — ОДНА фраза в канон*, к описанию `Note.code` (`openapi.yaml:1693-1700`), после + абзаца про нейтральную фразу: + + > A deployment that meets a reason its build of the map cannot name answers the stable placeholder `unspecified` rather than the producer's own word, so the branch above is exercised by a real value in ordinary operation and not only in theory. + + Форма выбрана намеренно: это ОБЯЗАННОСТЬ СЕРВЕРА, а не запись словаря — канон отказывается + перечислять `Note.code` («freezing a list in the schema before the words exist would make it a + second copy»), и перечисление начинать нельзя. Ценность ровно одна и она процессная: без строки в + нормативном документе значение живёт только в Go платформы, и следующая сессия изобретёт своё. + **Бампа версии не требует, и вот почему точно:** `Note.code` объявлен `type: string`, не enum, — + ни один генерённый тип не сужается и не расширяется; а сама фраза описывает поведение, которое + ЕДИНСТВЕННЫЙ потребитель 0.3.0 (этот пак) уже реализует, то есть сломать клиента, сгенерированного + по 0.3.0, она не может. ⚠ Прецедент D39.144 (микро-правка канона без бампа) здесь опорой НЕ + служит: там довод был «спека ещё никем не потреблена», и он больше не верен. Цена, которую надо + назвать: описания компилируются в исходники клиента, значит фраза доедет до `schema.ts` — то есть + зеркало фронта и регенерация типов при разморозке. И пара «код нормативен, фраза ⬜» должна + остаться видимой, иначе следующий читатель решит, что карта опять сломана. + + **⚠ ПИНГ ОРКЕСТРАТОРУ — строка в бэклог ДВИЖКА (сама зона в чужой бэклог не пишет):** публиковать + список флаг-причин ДАННЫМИ — артефакт рядом с манифестом либо `tmctl flag-reasons --json` ($0, + таблица `flagReasonSeverity` уже существует). Тогда тест платформы читает его и ПАДАЕТ, если в + карте нет строки, и класс «словарь разъехался тихо» закрывается насовсем. Со стороны платформы + гейт невозможен: импорт `backend/internal` запрещён ревью-гардом модулей (D39.85). Обратный + вариант — чтобы движок эмитил сразу контрактный код — отвергнут: это зеркальная утечка, + продуктовое слово поехало бы в движок, который о контракте знать не должен. +2. **`sqlc` — ОТЛОЖЕН СЛОВОМ ВЛАДЕЛЬЦА 17.08** («отложим»), строка PD-44 дополнена разбором. + Фиксирую честно, включая довод против себя: пак был обязан его взять (D39.132 п.2б), и sqlc + поймал бы ровно тот класс, который дважды укусил этот пак в рантайме (`stop_for_signing`, + `chapters_before`) — батарея его поймала, но на цикл позже компилятора. Что мешает в read-модели: + запросы собраны склейкой общих фрагментов (одна проекция книги на четыре пути), а sqlc требует + литерального SQL на запрос, и страница с её ревизией — транзакция, которую он не моделирует. + Предложение зоны: взять в P8 на отложенных однооператорных ручках, по итогам решить про + read-модель. +3. **Поверхность входа: РЕШЕНО контрактной сессией 17.08 (релей владельца), механизм исполнен.** + Вердикт — вариант A уточнённый: `/auth/*` отвечает тем же конвертом и **без машинного `code` + вовсе**; клиент показывает одну нейтральную фразу, а единственный пользовательски осмысленный + случай — `429` — уже машинный без всякого словаря, потому что лечение едет в `Retry-After` + (платформа его отдаёт: `login.go:173,233`, `dev.go:138`). Отвергнуты: расширение `ErrorCode` + (значения, недостижимые на поверхности, которую этот словарь описывает, ломают инвариант «код + называет свой статус») и собственный словарь в компаньоне (сделал бы НЕнормативный документ + нормативным с чёрного хода — канон в шапке объявляет нормативным для ФОРМЫ только себя). + **Исполнено в этом дереве:** `codeForStatus` и обратная функция удалены — писатель входа берёт + статус в точке вызова и кода не эмитит, поэтому инвертировать больше нечего. Пин + `httpapi.TestTheSignInSurfaceAnswersTheSameEnvelopeWithoutAVersionedCode` (шесть статусов: конверт + и `request_id` есть, `code` нет ни у одного). PD-254 закрыт. + **Остаётся зоне контракта (релей, не пере-проектирование):** две фразы — в канон рядом с + существующей про вход (`:36-37`): поверхность механики сессии отвечает тем же конвертом без + `code`, клиент диспетчеризует по статусу, особый случай `429` с `Retry-After`, серверный текст не + показывает никогда; и в компаньон §2.14 — восстановить срезанное правило и таблицу шести статусов. + Триггер пересмотра назван явно: второй пользовательски осмысленный случай на входе → своя + маленькая нормативная спека на `/auth/*`, а не рост таблицы в спутнике. + +4. **⚠ НАХОДКА КОНТРАКТНОЙ СЕССИИ, которая дороже самого вопроса — передать оркестратору отдельно.** + Правило про вход было РАТИФИЦИРОВАНО и потеряно молча: в компаньоне 0.2.3 §2.14 стояло «Отказ + входа — problem+json, как везде; **различать причины отказа клиент не может по замыслу**», а в + сегодняшней редакции осталась только первая половина — вторую срезал коммит лендинга батча 0.3.0 + (`8d82096`, проверено `git log -S`). То есть P7 не переоткрывал спор, а восстанавливал решение, + которое кто-то выкинул. **Класс потери структурно непроверяем существующей приёмкой:** сверка + батча шла по мультимножеству модальных глаголов (MUST/SHOULD/MAY), а в этой фразе модального + глагола нет. Стоит отдельного разбора приёмки — не как дефект контракта, а как дыра в МЕТОДЕ + проверки резки прозы. +5. **Плотность комментариев** (PD-255): пак вышел за норму «одна-две строки почему». Часть прозы + несущая, часть — эссе; прошу решение владельца о норме, а не тихую подрезку в следующем паке. diff --git a/platform/docs/platform-PROGRESS.md b/platform/docs/platform-PROGRESS.md index 6ecb9451..447dfeef 100644 --- a/platform/docs/platform-PROGRESS.md +++ b/platform/docs/platform-PROGRESS.md @@ -55,7 +55,7 @@ продолжить». Ломающая правка ровно одна — `Run.stop_requested` (0.3.0 такого поля не объявляет); `cause.code: credit_unavailable` легален и по 0.3.0, второй уровень там открыт. Зависимость записана строкой **PD-327** и закрывается лендингом канона, а не работой зоны. Если форма - сдвинется словом владельца — правки отделимы, карта в `P7_ACT5_FIX_PLAN.md` §5б. + сдвинется словом владельца — правки отделимы, карта в `archive/P7_ACT5_FIX_PLAN_2026-08-20.md` §5б. - **Тесты на АТОМАРНОСТЬ сверяют `xmin`** (транзакцию, последней писавшей строку). Это не экзотика ради экзотики: два пина акта проходили под мутацией «вынести метку из транзакции во второй оператор» — конечное состояние она не меняет, меняет окно, и утверждать про окно иначе @@ -92,9 +92,9 @@ появление класса в паке, и он назван в плане §3 п.2 ещё до того, как повторился. - **P7, акт 5 (начало) — исполнение фиксов по ревью акта 4 + ответ контрактной сессии.** - План и рабочий список — **`platform/docs/P7_ACT5_FIX_PLAN.md`** (читать первым; §5а — что пришло из + План и рабочий список — **`platform/docs/archive/P7_ACT5_FIX_PLAN_2026-08-20.md`** (читать первым; §5а — что пришло из контракта). - ⚠ **Контрактная сессия ответила 20.08 на записку зоны `CONTRACT_SYNC_FROM_PLATFORM.md`: канон стал + ⚠ **Контрактная сессия ответила 20.08 на записку зоны `archive/CONTRACT_SYNC_FROM_PLATFORM_2026-08-20.md`: канон стал 0.4.0** (лежит в дереве контрактной зоны, НЕ ратифицирован — до лендинга в силе 0.3.0). Все три вопроса, висевшие на владельце, закрыты. Зоне пришла работа: `resume` исчерпанного прогона — 409 с двумя РАЗНЫМИ причинами (`ceiling_reached` против нового `credit_unavailable`); «глава сделана» = @@ -117,8 +117,8 @@ регистронезависимо. Батарея: 18 пакетов, exit 0, скипов 0, тестов **503**. - **P7, акт 4 — доработка 20.08: сверка ВСЕХ находок против дерева + триаж §8.2.** - (Пакет релеев `P7_ACCEPTANCE_HANDOFF.md` §7; три вопроса владельцу §8.1а; вопросы контракта - вынесены в `platform/docs/CONTRACT_SYNC_FROM_PLATFORM.md` для отдельной контрактной сессии.) + (Пакет релеев `archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md` §7; три вопроса владельцу §8.1а; вопросы контракта + вынесены в `platform/docs/archive/CONTRACT_SYNC_FROM_PLATFORM_2026-08-20.md` для отдельной контрактной сессии.) Все 74 позиции обеих приёмок сверены поштучно с ТЕКУЩИМ деревом — каждая с цитатой живого кода, исход «не проверено» отдельно от «опровергнуто». ⚠ **Три места числились закрытыми и закрыты не были — правка не закрывала собственный сценарий:** @@ -144,7 +144,7 @@ **Осей, которых не смотрел никто:** деньги и леджер · вход/сессии/CSRF · очередь и джобы · метрики. - **P7: приёмка → правки → приёмка правок (17.08).** - ⚠ Полный хендофф под сессию без контекста — **`platform/docs/P7_ACCEPTANCE_HANDOFF.md`** (читать §0–§3, + ⚠ Полный хендофф под сессию без контекста — **`platform/docs/archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md`** (читать §0–§3, дальше по нужде). Там же: принципы приёмки, сверка с исходным промтом, техдолг, план следующей сессии. Категорийное ревью по 12 осям с адверсариальной верификацией: 80 находок, **54 подтверждено, 16 правдоподобно, 10 опровергнуто**; после дедупа **46 уникальных дефектов** — 3 блокирующих класса, @@ -172,11 +172,11 @@ «стоп был запрошен» в контракте; готовая строка для единого бэклога — хендофф §7(и), вставляет оркестратор (зона `docs/` не наша). **Разбор, план, обязательства через оркестратора и команды воспроизведения — - `platform/docs/P7_ACCEPTANCE_HANDOFF.md`.** + `platform/docs/archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md`.** ⚠ Заявки раздела «Сессия P7» ниже приёмку НЕ прошли — читать их вместе с хендоффом, не вместо. - **P7 ПОСТРОЕН — заявка САМОЙ сессии написания (17.08).** ⚠ **Приёмку эта заявка НЕ прошла** — см. - верхнюю запись и `P7_ACCEPTANCE_HANDOFF.md`: 46 уникальных дефектов, три блокирующих класса, из них + верхнюю запись и `archive/P7_ACCEPTANCE_HANDOFF_2026-08-17.md`: 46 уникальных дефектов, три блокирующих класса, из них ни один батарея не видела. Читать ниже как исходную позицию, а не как состояние дерева. Читающая поверхность контракта **0.3.0**: главы · пары с текстом · замечания · банк и подпись · SSE на КНИГЕ · `GET /capabilities` · @@ -295,250 +295,9 @@ *(Записи паков P4–P6 с дофиксами (08–15.08) — в [archive/platform-PROGRESS-P4-P6.md](archive/platform-PROGRESS-P4-P6.md); вынесено 16.08 по слову владельца.)* -## Сессия P7 (16–17.08): читающая поверхность контракта 0.3.0 +## Эра пака P7 (16–20.08) — в архиве -Промт — `PLATFORM_P7_SESSION_PROMPT.md`. Ниже: записка-план по §4 (каждый пункт с диспозицией), -команды, живые пробы, находки, obstacle. - -### Записка-план: пункт → исполнено / отказ → улика - -| § | Пункт | Статус | Улика | -|---|---|---|---| -| 0 | Рантбук деплоя живым `migrate` | **исполнен** | БД проекта отведена на v14 при бинаре v15 → `tmctl status --json` = exit 13, токен `schema_mismatch found=14 expected=15`; `tmctl migrate` → бэкап + v14→v15; тот же `status` = exit 0. Мёртвая цитата вычищена (`deploy/README.md`, П-1 бэклога), пример в `tmplatformctl/runs.go` переписан на ВЕРСИОНИРОВАННЫЙ путь | -| 0 | `tmplatformctl books --migratable` → `tmctl migrate` end-to-end | **исполнен** | 5 книг стенда, все `MIGRATE=yes`, цикл из деплой-ноты отработал | -| 1а | Читать `BookIntake.title` | **исполнен** | `books.Intake.Title`; пустая строка = «назови по файлу» (`books.title()`), непустая не перезаписывается разбором | -| 1б | Проецировать `reject_reason` | **исполнен** | `httpapi.contractRejectReason`; `parser_unavailable` → `processing_failed` (ФБ-9: имя значения — то, на что клиент вешает фразу) | -| 2 | PD-104: грант → 0 + тест | **исполнен** | `config.go` дефолт 0; пин `config.TestSignupGrantIsParsedNotGuessed` пинит ИМЕННО ноль; протухшие «$5» вычищены из `PLATFORM_DIRECTION.md` §2, `BACKLOG.md` П-7, регистра | -| 3 | Модель ошибок по карте А-2 | **исполнен** | `httpapi/problem.go`: 16 корневых кодов, статус ВЫВОДИТСЯ из кода (пара «код+статус» непредставима расходящейся), `cause` открытый, `errors[]`, `request_id` из `reqid`; `WWW-Authenticate` на 401; две причины 403 разведены в `cause` при одном корневом `forbidden`; класс 2 — один код без вариации | -| 4 | `listChapters` · `listUnits` (пер-главно, 410) · `listNotes` · `listBankTerms` · `submitBankDecisions` · дельты · SSE · `structure_version` · gzip · ETag/304 | **исполнен** | `httpapi/{reading,stream,conditional}.go`, `pgstore/{readmodel,events}.go`; ручки «вся книга юнитами» НЕТ; `Unit.notes` массивом; агрегаты банка на ПЕРВОЙ странице; дельты ВКЛЮЧИТЕЛЬНЫЕ; `version_too_old` и `cursor_invalid` — причинами | -| 4 | Ловушка `heading` | **исполнен** | поле не декодируется ВОВСЕ (`ingest.ManifestChapter`), колонка `chapters.heading` удалена миграцией, проекция отдаёт `null`; пин `readmodel.TestTheManifestsRenderedHeadingHasNowhereToLand` | -| 4 | Демонтаж построенного гейта полноты банка | **исполнен** | `runs/reconcile.go`: `awaiting_bank` продолжается при ЛЮБОМ состоянии решений; пин `TestResumeLiftsABankStopWithTheDecisionsAsTheyStand`. Граница паузы движка сверена чтением (`pipeline/mining.go`: авто-продолжение с неподписанным банком — дефолт) | -| 4 | Пофазность у главы НЕ строить | **соблюдён** | у главы один счётчик `units_done`; пин «фазовый счётчик не доехал до строки главы» | -| 4 | `Note.code` из ◆-карты | **исполнен с ОДНИМ отступлением** | `httpapi/notes.go`; отступление — незнакомая причина проецируется как `unspecified` (в карте колонка кода пуста, а поле обязательно). Заведена строка PD-246, ждёт ратификации вместе с фразами | -| 5 | `Progress` с книги на `Run`, одна полоса в ГЛАВАХ | **исполнен** | `pgstore.Progress{Done,Total,ETASeconds}`, знаменатель — `ceiling_chapters`; сегмент выбирается `verify_bank && !bank_released` | -| 5 | `Book`: +`revision`, +`chapters_done`, −`progress`, −`genre` | **исполнен** | `genre` снят и с ПРОВОДА, и из формы интейка, и из колонки: платформа его больше не знает, значение шаблона оператора остаётся его | -| 5 | `Run`: +`book_id`, +`failure_reason`, `verify_bank`→`stop_for_signing` | **исполнен** | словарь из трёх значений мапится с полосы 10–19 и веток `outcome()` (`runs.failureReason`) | -| 5 | `Usage`: `halt_reason` со своим словарём | **исполнен** | `httpapi.contractHaltReason`; прогонная причина больше не может доехать до аккаунтного поля | -| 5 | `GET /capabilities` | **исполнен** | все шесть полей; пары — из конфигурации (`TM_PLATFORM_LANGUAGE_PAIRS`), не список в Go | -| 5 | `limit` подрезать, а не отвергать | **исполнен** | `pgstore.clampPage`; отвергается только значение, которое не является размером страницы | -| 5 | Трейлинг-части интейка → 400 | **исполнен, с находкой** | сначала книга ОСТАВАЛАСЬ при 400 (живая проба); теперь часть после файла ПРОВАЛИВАЕТ чтение, и интейк откатывает загрузку своим же путём | -| 5 | `Location` на 201 | **исполнен** | `/v0/books/` | -| 5 | `Idempotency-Key` на `createBook` и `startRun` | **исполнен** | таблица 00017, повтор отдаёт ИСХОДНЫЙ ответ, другой запрос — 409 `key_reused`, гонка — `key_in_flight` + `Retry-After`, >255 → 400 | -| 5 | `blocked {code, book_id}` на run-options и 409 | **исполнен** | `pgstore.CreditHeldBy` + `runs.CreditHeldError` | -| 5 | Отказ по неподдерживаемой паре на интейке | **исполнен** | `books.ErrUnsupportedPair` → `errors[].code: unsupported_pair`; пустой список пар = деплой не объявляет ничего и пару не проверяет | -| 5 | `finalizing` вон из словарей | **исполнен** | Go-свитчи и CHECK-констрейнты обеих таблиц | -| 6 | PD-172/173/174/180/199 привести · PD-201 · PD-241 | **исполнен** | все закрыты либо сужены с уликой; PD-241 — перевёрнутый порядок в `outcome()` с пином | -| 6 | Кандидаты PD-219/217/162 | **отсуждены** | PD-217 — половина ЗАКРЫТА (paused больше не блокирует апгрейд движка); PD-219 и PD-162 — не брались, с названной причиной | -| 6 | Находки §9 research/28 | **отсуждены** | три взяты строками (PD-249/250/251/252), две сведены к существующим (PD-203, PD-162/244) | -| 6 | Инструменты: sqlc / oapi-codegen | **отказ с доводом** | оба НЕ взяты; довод — `PLATFORM_DIRECTION.md` §3, и он опирается на замер этого пака, а не на вкус | - -### Команды (каждое число отчёта — этой командой) - -```sh -# батарея, оба гейта, -race -export TM_PLATFORM_TEST_DSN='postgres://postgres@/postgres?host=/tmp&port=55433&sslmode=disable' -export TM_PLATFORM_TEST_ENGINE_BIN=<путь к tmctl> TM_PLATFORM_TEST_BOOK_TEMPLATE=<шаблон> -make check # EXIT=0, 18 пакетов, скипов 0, линтер 0 issues -grep -rh '^func Test' --include='*_test.go' . | wc -l # 458 (HEAD: 416) -git diff --stat platform | tail -1 # 46 файлов, +2329 −646 -python3 docs/scripts/counts.py # регистр: 256 строк, 63 открытых -``` - -⚠ Стенд Postgres на этой машине пришлось поднять с нуля (его не было): рецепт `STACK_DECISIONS.md` -§«Postgres без root», micromamba + `postgresql=18.4` в `~/.local/pgsql`, порт 55433 — отработал -дословно. - -### Живые пробы на дев-стенде (демон + сид + настоящий `tmctl`) - -Сид P6 отработал целиком: дев-вход → грант → загрузка через ЖИВОЙ `POST /v0/books` → разбор → -`not_started, 3 главы`. Дальше — курлом по новым ручкам: - -- `GET /capabilities` → все шесть полей, `contract_version: 0.3.0`, пары `zh>ru available` + - `ja>ru unavailable`; -- `GET /books` → `revision · reject_reason: null · structure_version: 1 · chapters_done: 0 · - character_count: 987`, **никакого `progress` и никакого `genre`**; -- `GET /books/{id}/chapters` → три главы, `heading: null` у каждой; -- `GET /books/{id}/chapters/{ch}/units` → пара с ИСХОДНЫМ ТЕКСТОМ (канал `tmctl export --pairs` - работает), `target: ""`, `state: pending`, `notes: []`; -- `GET /books/{id}/notes`, `/bank` → пустые с агрегатами и `structure_version`; -- SSE на книге в покое → `hello id=4` → `end id=4` → закрытие; реконнект с `Last-Event-ID: 6` → **204**; -- `ETag` → `304` на `If-None-Match`; `Accept-Encoding: gzip` → `Content-Encoding: gzip` + `Vary`; - тот же заголовок на `/events` → **не сжато**; -- ошибки: 404 → `code: not_found` + `request_id`; 401 → `WWW-Authenticate: Bearer realm="textmachine"`; - POST без `X-TM-Client` → 403 `forbidden` · `cause.code: client_header_missing`; -- интейк: пара `ja→ru` → 400 `unsupported_pair` на обоих полях; часть после файла → 400 - `missing_or_late` **и книга не остаётся** (проверено счётом библиотеки до/после); -- `Idempotency-Key`: тот же ключ дважды → один и тот же `Location`; тот же ключ с другим `title` → - 409 `idempotency_conflict` · `cause.code: key_reused`. - -### Что нашли ПРОБЫ, чего не нашли тесты - -**Часть формы после файла оставляла книгу.** Отказ 400 приезжал (правило соблюдалось), но -`intake.Accept` к тому моменту уже создал строку и каталог — пользователь получал ошибку И книгу в -библиотеке. Починено не новым кодом отката, а ПРОВАЛОМ чтения: часть после файла возвращает ошибку -из ридера, и интейк отменяет загрузку тем же путём, которым отменяет оборванную. Пин -`httpapi.TestAPartAfterTheFileIsRefusedAndTheBookIsNotKept`, пере-проверено живьём. - -### Адверсариальное селф-ревью финалом: три ревьюера, таблица находок - -Механизм по §5 промта: три независимых субагента по ФИНАЛЬНОМУ диффу, author≠reviewer, **два из -трёх — другой модели** (кросс-семейная линза, а не вторая своя). Ноль находок не случился — и это -хорошо: две HIGH нашли ОБА контрактных ревьюера независимо, что и есть подтверждение. - -| # | Линза | Находка | Вердикт | Что сделано | -|---|---|---|---|---| -| Р-1 | контракт (кросс-модель) · деньги/шов | **Кадр `note` уносил движковую причину** (`glossary_miss`, `hard_refusal`) и не нёс обязательных `severity`/`code`; `unit_id: null` вместо отсутствия | ПОДТВЕРЖДЕНА, HIGH | Карта переехала в `internal/ingest/notes.go` — один дом на оба потребителя; кадр строится через неё; `unit_id` опускается. Пин `TestTheNoteFrameCarriesTheContractsNoteAndNotTheEnginesReason` | -| Р-2 | контракт (кросс-модель) | **Кадр `status` уносил внутренние словари** (`daily_ceiling`, `parser_unavailable`): та же величина читалась `null` на карточке и внутренним словом в потоке | ПОДТВЕРЖДЕНА, HIGH | Переводы переехали в `internal/ingest/vocabulary.go`, кадр строит `emitStatus`; при ошибке чтения кадр НЕ шлётся (вместо `status: null` вне схемы). Пин `TestTheStatusFrameCarriesTheContractsVocabularyOrNothing` | -| Р-3 | деньги/шов | **DOWN-путь миграции неисполним при первой же строке банка** (воспроизведено живым PG): три словаря переписывались без перевода данных, а goose гоняет миграцию одной транзакцией | ПОДТВЕРЖДЕНА, HIGH | Порядок drop → перевод → add в ОБЕ стороны (UP тоже: он должен переживать пере-накат после отката). Пин `TestARollbackSurvivesTheDataTheNewVocabulariesWrote` — откат до документированного пола (версия 5) на базе С данными | -| Р-4 | деньги/шов | **Четыре писателя меняли статус без кадра** (`RestartRun`, `PauseRun`, `FinishUnspawnedStop`, `ReleaseBankStop`); двое из них ставят `finished_at`, то есть книга «в покое» — и следующий реконнект получает **204 «не переподключайся»** при устаревшем статусе у клиента | ПОДТВЕРЖДЕНА, HIGH | Кадр у всех трёх писателей статуса; четвёртый (`ReleaseBankStop`) перестал быть отдельным писателем — см. Р-5 | -| Р-5 | деньги/шов | **`ReleaseBankStop` коммитился ДО `reopen`**: резюм, который ничего не сделал (расчёт в полёте, бюджет исчерпан), всё равно переключал полосу с N/N на 0/N | ПОДТВЕРЖДЕНА, MED | Снятие стопа перенесено ПОСЛЕ успешного `reopen` | -| Р-6 | деньги/шов | **`Refresh` тратил бюджет прохода ПЕРЕД `settle`**: на большой книге два полных ре-чанка съедали проход, расчёт уходил в «отложено», холд висел свип | ПОДТВЕРЖДЕНА, MED | Деньги первыми: `settle` → затем `refreshReadModel` на СВОЁМ ограниченном контексте, ошибка громкая | -| Р-7 | деньги/шов | **`failureReason` игнорировал маркер**, который ему передавали: OOM и kill по стоп-таймауту приезжали `interrupted` («повтори») | ПОДТВЕРЖДЕНА, MED | Читает `m.Result`; пин `TestWhyARunFailedDecidesWhetherARetryIsWorthOffering` (7 веток) | -| Р-8 | контракт (кросс-модель) | **Квитанции `Run` несли нулевую полосу** (`202` на старт/стоп/резюм) со свежей ревизией — клиентский гард пропускал её и полоса откатывалась к 0/0 | ПОДТВЕРЖДЕНА, MED | `StartRun`/`RequestStop`/`ReadRun` считают ту же полосу, что карточка | -| Р-9 | контракт (кросс-модель) | **Полоса ВТОРОГО прогона считала главы всей книги**: дробь стартовала выше нуля и могла превысить единицу | ПОДТВЕРЖДЕНА, MED | Колонка `runs.chapters_before` — база сегмента, снимается в том же стейтменте, что создаёт прогон; `least(…, ceiling_chapters)` закрывает второй край. Пин `TestASecondRunsBarStartsAtZeroOverAHalfFinishedBook` | -| Р-10 | контракт (кросс-модель) | **`Last-Event-ID: 0` после подрезки буфера молча пропускал дыру** — а `0` это легальный id, который сервер сам выдаёт | ПОДТВЕРЖДЕНА, MED | Условие `last+1 < Oldest` вместо `last > 0 && last < Oldest` | -| Р-11 | контракт (кросс-модель) · скоуп | **Склейка кадров `chapter` шла по имени события**, теряя счётчик соседней главы внутри одного соединения | ПОДТВЕРЖДЕНА, MED | Склейка по (событие, id сущности) | -| Р-12 | контракт (кросс-модель) | **Порядок банка** был `(src, id)` — то есть по ХЕШУ, а канон объявляет «по поверхности, затем по окну» | ПОДТВЕРЖДЕНА, MED | Порядок и кейсет приведены к канону (`src, since, until, id`) | -| Р-13 | контракт (кросс-модель) | **`limit` всё ещё отвергался снизу** (0, отрицательный, нечисло), тогда как канон освобождает параметр от отказа | ПОДТВЕРЖДЕНА, MED | Никогда не отвергается: сверху подрезка, всё прочее — дефолт деплоя. Пин переписан | -| Р-14 | контракт (кросс-модель) | **Неверная пара языков и слишком длинное поле отказывали без `errors[]`** | ПОДТВЕРЖДЕНА, MED | `ErrMalformedLanguage` и `too_long` с указателем на поле | -| Р-15 | контракт (кросс-модель) | **`SweepIdempotency` не имел вызывающего**: ключи не забывались никогда | ПОДТВЕРЖДЕНА, LOW | Подключён в свип демона, окно 25 часов | -| Р-16 | контракт (кросс-модель) | **Курсор замечаний нёс движковое слово волны** в открытом виде | ПОДТВЕРЖДЕНА, LOW | Пакуется порядковым номером | -| Р-17 | скоуп (кросс-модель) | `acceptsGzip` игнорировал `*`; `pump` спал такт даже после полной пачки; `unknownTermPointer` парсил текст ошибки; алиас `itoa` | ПОДТВЕРЖДЕНЫ, LOW | Все четыре починены (типизированная `UnknownTermError` вместо парсинга строки) | -| Р-18 | скоуп (кросс-модель) | **`sqlc` был привязан к этому паку ратификацией**, а пак от него отказался — это отступление, а не решение зоны | СПРАВЕДЛИВО | Отказ с доводом записан в `PLATFORM_DIRECTION.md` §3 и вынесен ВОПРОСОМ оркестратору (ниже) | -| Р-19 | скоуп (кросс-модель) | **`unspecified` — изобретённый код** там, где промт требовал пинг | ЧАСТИЧНО: разбор с владельцем 17.08 показал, что находка верна по форме и неверна по существу | Значение отдано ветке, которую канон УЖЕ ратифицировал («нейтральная фраза для незнакомого кода»), а не заводит новое правило; настоящий предмет — рукописная копия чужого словаря без гейта, PD-246 пере-сформулирован, движку — пинг про публикацию причин данными | -| Р-20 | контракт (кросс-модель) | `410` отвечает и на главу, которой никогда не было: различение 410/404 без надгробий неисполнимо | ПРИНЯТО КАК ЕСТЬ | Лечение у обоих одно (перечитать дерево); строка PD-253 | -| Р-21 | скоуп (кросс-модель) | **Масса комментариев** выросла против нормы зоны (миграция на 250 строк — половина проза) | ЧАСТИЧНО ПРИНЯТО | Подрезано самое тяжёлое; остальное — предмет пинга, а не тихой правки | -| Р-22 | скоуп (кросс-модель) | **Два писателя ошибок** (`WriteProblem` + `WriteStatusProblem`/`codeForStatus`), три одинаковых структуры пары | НЕ БРАЛОСЬ | Второй писатель обслуживает НЕконтрактную поверхность (`/auth`, `/readyz`), где кода версии нет; сведение в один требует ратификации формы для 405/429 — вопрос оркестратору | - -**Что ревьюеры подтвердили как ВЕРНОЕ** (важно не меньше находок): ни одной денежной величины на -проводе ни в каком виде · порядок блокировок не тронут, `emitFrame` не берёт НОВЫХ локов ни в одной -из 14 точек · кадр не может быть выпущен для откаченного состояния · демонтаж гейта банка -соответствует таблице канона дословно · словари шва (шесть значений банка, полоса отказов 10–19, -все семь типов событий) сверены по коду движка и полны · `finalizing` снят безопасно · оба гейта -миграций пере-считаны и совпадают. - -### Живые пробы ПОСЛЕ фикс-раунда (стенд пере-создан) - -Стенд пришлось пере-создать, и это отдельная улика: миграция 00016 правилась ПОСЛЕ того, как была -применена, а goose ключуется номером — отредактированный файл не перезапускается никогда. На стенде -лечится сносом базы; в проде именно от этого стоит гейт `migrations.sha256` (обе строки пере-считаны). - -- `limit=0 | -3 | abc | 100000` → **200 во всех четырёх** (канон освобождает параметр от отказа); -- квитанция старта: `status: translating`, `progress {done:0, total:2}`, `book_id`, `failure_reason: null` - — полоса едет с квитанцией, а не только с карточкой; -- поток при ЖИВОМ прогоне: `hello id=5` → `status id=7` с `failure_reason: "service_error"` и - `paused_reason: null` — кадр несёт КОНТРАКТНЫЙ словарь (внутреннего слова в кадре нет); -- карточка после отказа: книга `failed`, прогон `failed` + `service_error` (на стенде нет ключей - провайдера — движок отказывает конфигурацией, и это ровно тот класс, который «повтор не лечит»); -- `resume` упавшего прогона → `run_not_resumable` без `cause` (канон: это не остановленный прогон); -- неверный код языка → `invalid_request` + `errors[]` на оба поля; -- `/usage` → `halt_reason: null` (свой словарь, не прогонный). - -### Obstacle: что НЕ удалось и что не проверено - -1. **Отложено в P8 явно** (заказ промта): `updateBook` · `deleteBook` · `getRun` · `createExport` - /`getExport` · эскроу (П-18). -2. **`Note.code` для незнакомой причины — отступление**, не решение: `unspecified` (PD-246). -3. **Ни одного живого ЗАМЕЧАНИЯ и ни одного термина банка через настоящий прогон не прошло** — - прогон стоит денег, а сессия $0. Проекции замечаний и банка проверены тестами на живом PG и - ручными строками `unit_resolutions`, но не сквозным прогоном движка. -4. **SSE с ЖИВЫМ прогоном не гонялся** по той же причине: проверены книга в покое, реконнект, 204, - склейка и `resync_required` — тестами и на стенде, но не под настоящим потоком кадров. -5. **Стоимость материализации не замерена на большой книге** (PD-248): два полных ре-чанка на - границу работы; на демо-книге в 3 главы это миллисекунды, на 2283 главах — секунды CPU. -6. **`structure_version` на РЕАЛЬНОЙ пере-нарезке** проверен тестом (смена ключа манифеста), но не - настоящей сменой чанкера движка. -7. **Опрос потока — 2 запроса/с на соединение** (PD-247): `LISTEN/NOTIFY` не строился. -8. **Кадр `note` живьём не наблюдался**: он рождается только на помеченной единице настоящего - прогона. Проверен тестом на живом PG через настоящий `RunSink.Apply` (полный путь материализатора), - но не в потоке под браузером. -9. **Полоса под настоящей работой не наблюдалась**: `progress {0,2}` — это старт; движения счётчика - на стенде без ключей провайдера не бывает. - -### Вопросы оркестратору (канал вопросов промта, НЕ тихая интерпретация) - -1. **Словарь флаг-причин — рукописная копия чужой зоны без гейта** (PD-246; формулировка исправлена - после разбора с владельцем 17.08 — прежняя, «в карте контракта дыра», была неверной). - Проверено чтением движка: локализованных фраз там НЕТ вовсе — `refusal.go` и `status.go` несут - машинные классы, русских пользовательских строк в продовом коде движка ноль. То есть движок и - контракт построены на одном принципе, и переделывать под «гугловский словарик в движке» нечего: - фраза всегда на языке ИНТЕРФЕЙСА, которого не знает ни движок, ни платформа, а движок ОДИН на все - пары — русская строка в нём была бы таргет-спецификой в общем слое (тот же инвариант, что снял - `ruby` с провода). - **Проводу окно закрыто:** причина вне карты едет кодом `unspecified`, а канон уже предписывает - клиенту нейтральную фразу для незнакомого кода — значение отдано РАТИФИЦИРОВАННОЙ ветке, а не - изобретено правило. На подпись остаются две строки продуктового текста: фраза для `unspecified` и - граница ступеней `attention`/`glance` (сегодня — догадка платформы, колонка «Ступень» в - приложении А пуста у всех 15 строк). Это не блокер. - **Правка контракта — предлагаю, зона не моя (готовые формулировки, вставить как есть).** - *Обязательный минимум — КОМПАНЬОН, приложение А, последняя строка (`README.md:899`).* Пустая - клетка кода в ней и есть то, что заставило платформу выбирать значение самой: - - > `| незнакомая причина | 8 (по умолчанию) | `unspecified` — стабильный плейсхолдер деплоя: не значение словаря, а ОБЯЗАННОСТЬ сервера ответить одним и тем же кодом на причину, которой его сборка карты не знает (носитель — PD-246 платформы) | ⬜ нейтральная, НЕ «ошибка» | ⬜ |` - - *Желательное — ОДНА фраза в канон*, к описанию `Note.code` (`openapi.yaml:1693-1700`), после - абзаца про нейтральную фразу: - - > A deployment that meets a reason its build of the map cannot name answers the stable placeholder `unspecified` rather than the producer's own word, so the branch above is exercised by a real value in ordinary operation and not only in theory. - - Форма выбрана намеренно: это ОБЯЗАННОСТЬ СЕРВЕРА, а не запись словаря — канон отказывается - перечислять `Note.code` («freezing a list in the schema before the words exist would make it a - second copy»), и перечисление начинать нельзя. Ценность ровно одна и она процессная: без строки в - нормативном документе значение живёт только в Go платформы, и следующая сессия изобретёт своё. - **Бампа версии не требует, и вот почему точно:** `Note.code` объявлен `type: string`, не enum, — - ни один генерённый тип не сужается и не расширяется; а сама фраза описывает поведение, которое - ЕДИНСТВЕННЫЙ потребитель 0.3.0 (этот пак) уже реализует, то есть сломать клиента, сгенерированного - по 0.3.0, она не может. ⚠ Прецедент D39.144 (микро-правка канона без бампа) здесь опорой НЕ - служит: там довод был «спека ещё никем не потреблена», и он больше не верен. Цена, которую надо - назвать: описания компилируются в исходники клиента, значит фраза доедет до `schema.ts` — то есть - зеркало фронта и регенерация типов при разморозке. И пара «код нормативен, фраза ⬜» должна - остаться видимой, иначе следующий читатель решит, что карта опять сломана. - - **⚠ ПИНГ ОРКЕСТРАТОРУ — строка в бэклог ДВИЖКА (сама зона в чужой бэклог не пишет):** публиковать - список флаг-причин ДАННЫМИ — артефакт рядом с манифестом либо `tmctl flag-reasons --json` ($0, - таблица `flagReasonSeverity` уже существует). Тогда тест платформы читает его и ПАДАЕТ, если в - карте нет строки, и класс «словарь разъехался тихо» закрывается насовсем. Со стороны платформы - гейт невозможен: импорт `backend/internal` запрещён ревью-гардом модулей (D39.85). Обратный - вариант — чтобы движок эмитил сразу контрактный код — отвергнут: это зеркальная утечка, - продуктовое слово поехало бы в движок, который о контракте знать не должен. -2. **`sqlc` — ОТЛОЖЕН СЛОВОМ ВЛАДЕЛЬЦА 17.08** («отложим»), строка PD-44 дополнена разбором. - Фиксирую честно, включая довод против себя: пак был обязан его взять (D39.132 п.2б), и sqlc - поймал бы ровно тот класс, который дважды укусил этот пак в рантайме (`stop_for_signing`, - `chapters_before`) — батарея его поймала, но на цикл позже компилятора. Что мешает в read-модели: - запросы собраны склейкой общих фрагментов (одна проекция книги на четыре пути), а sqlc требует - литерального SQL на запрос, и страница с её ревизией — транзакция, которую он не моделирует. - Предложение зоны: взять в P8 на отложенных однооператорных ручках, по итогам решить про - read-модель. -3. **Поверхность входа: РЕШЕНО контрактной сессией 17.08 (релей владельца), механизм исполнен.** - Вердикт — вариант A уточнённый: `/auth/*` отвечает тем же конвертом и **без машинного `code` - вовсе**; клиент показывает одну нейтральную фразу, а единственный пользовательски осмысленный - случай — `429` — уже машинный без всякого словаря, потому что лечение едет в `Retry-After` - (платформа его отдаёт: `login.go:173,233`, `dev.go:138`). Отвергнуты: расширение `ErrorCode` - (значения, недостижимые на поверхности, которую этот словарь описывает, ломают инвариант «код - называет свой статус») и собственный словарь в компаньоне (сделал бы НЕнормативный документ - нормативным с чёрного хода — канон в шапке объявляет нормативным для ФОРМЫ только себя). - **Исполнено в этом дереве:** `codeForStatus` и обратная функция удалены — писатель входа берёт - статус в точке вызова и кода не эмитит, поэтому инвертировать больше нечего. Пин - `httpapi.TestTheSignInSurfaceAnswersTheSameEnvelopeWithoutAVersionedCode` (шесть статусов: конверт - и `request_id` есть, `code` нет ни у одного). PD-254 закрыт. - **Остаётся зоне контракта (релей, не пере-проектирование):** две фразы — в канон рядом с - существующей про вход (`:36-37`): поверхность механики сессии отвечает тем же конвертом без - `code`, клиент диспетчеризует по статусу, особый случай `429` с `Retry-After`, серверный текст не - показывает никогда; и в компаньон §2.14 — восстановить срезанное правило и таблицу шести статусов. - Триггер пересмотра назван явно: второй пользовательски осмысленный случай на входе → своя - маленькая нормативная спека на `/auth/*`, а не рост таблицы в спутнике. - -4. **⚠ НАХОДКА КОНТРАКТНОЙ СЕССИИ, которая дороже самого вопроса — передать оркестратору отдельно.** - Правило про вход было РАТИФИЦИРОВАНО и потеряно молча: в компаньоне 0.2.3 §2.14 стояло «Отказ - входа — problem+json, как везде; **различать причины отказа клиент не может по замыслу**», а в - сегодняшней редакции осталась только первая половина — вторую срезал коммит лендинга батча 0.3.0 - (`8d82096`, проверено `git log -S`). То есть P7 не переоткрывал спор, а восстанавливал решение, - которое кто-то выкинул. **Класс потери структурно непроверяем существующей приёмкой:** сверка - батча шла по мультимножеству модальных глаголов (MUST/SHOULD/MAY), а в этой фразе модального - глагола нет. Стоит отдельного разбора приёмки — не как дефект контракта, а как дыра в МЕТОДЕ - проверки резки прозы. -5. **Плотность комментариев** (PD-255): пак вышел за норму «одна-две строки почему». Часть прозы - несущая, часть — эссе; прошу решение владельца о норме, а не тихую подрезку в следующем паке. +Пять актов, приёмка, фикс-раунды и таблицы селф-ревью выселены срезом в [`archive/platform-PROGRESS-P7.md`](archive/platform-PROGRESS-P7.md) (норма: закрытая эра не живёт в журнале). Итог и то, что пережило пак, — шапка выше и пинг оркестратора №18 ниже. ## Закрытые эры P0–P3 — в архиве @@ -609,7 +368,7 @@ python3 docs/scripts/counts.py # регистр: 256 6. **Труба доставки решений банка в движок** — единый бэклог, строка **199(а)**: перед resume писать решения в `mined_delta`/`mined_rejects`. Сегодня `action`/`dst` — write-only колонки (единственный SELECT `readmodel.go:336` проверяет лишь наличие строки), а воркер описан в комментарии вашей же миграции `00002_readmodel.sql:172-174` и не построен. 7. **Мусор:** пустой `platform/ru` (0 байт, обрубок редиректа) — в лендинг не взят, снесён оркестратором. `books.go:234-235` — задвоенная первая строка доккомментария, класс PD-310/326. 8. **Ревью-пак четырёх осей, которых не смотрел НИКТО** (ваш же obstacle): деньги и леджер целиком · вход/сессии/CSRF · очередь и джобы · метрики. Это не дофикс и не довесок — первый взгляд, отдельной работой. -9. **Один носитель на факт для замера 00016→00022 — но НЕ удалением числа.** Выигрыш назван ЧЕТЫРЬМЯ носителями: шапка этого журнала «83%» · `internal/pgstore/perf_test.go:13` «96%» · миграция 00022 «16.8 против 3.4, джойн сам 9 мс» · регистр PD-306 (повторяет 83% и 16.8/3.4). ⚠ Я сперва записал, что «96%» ни из чего не выводится — **это была моя ошибка, снята проверкой записей**: оно выводится точно из ВАШЕГО же замера в `P7_ACT5_FIX_PLAN.md:439-441` («636 мс против 24 мс», холодный корпус акта 4) = 96.2%, тогда как 83% и мой независимый ≈80% — с вакуумированного корпуса. То есть носители меряли РАЗНОЕ и все честны. Свести указанием УСЛОВИЙ замера при каждом числе, оставив нормативным один (миграция 00022 — она их и несёт); удалять «96%» как фантом НЕЛЬЗЯ. +9. **Один носитель на факт для замера 00016→00022 — но НЕ удалением числа.** Выигрыш назван ЧЕТЫРЬМЯ носителями: шапка этого журнала «83%» · `internal/pgstore/perf_test.go:13` «96%» · миграция 00022 «16.8 против 3.4, джойн сам 9 мс» · регистр PD-306 (повторяет 83% и 16.8/3.4). ⚠ Я сперва записал, что «96%» ни из чего не выводится — **это была моя ошибка, снята проверкой записей**: оно выводится точно из ВАШЕГО же замера в `archive/P7_ACT5_FIX_PLAN_2026-08-20.md:439-441` («636 мс против 24 мс», холодный корпус акта 4) = 96.2%, тогда как 83% и мой независимый ≈80% — с вакуумированного корпуса. То есть носители меряли РАЗНОЕ и все честны. Свести указанием УСЛОВИЙ замера при каждом числе, оставив нормативным один (миграция 00022 — она их и несёт); удалять «96%» как фантом НЕЛЬЗЯ. 11. **У материализатора нет ПОЛА на пустой манифест — латентная потеря всего текста книги.** `internal/readmodel/readmodel.go:215-232` строит `in.Chapters` только из `manifest.Chapters` и ни разу не сверяется со счётчиками того же документа (`ChaptersTotal`/`UnitsTotal` лежат рядом и печатаются в лог строкой ниже). Пустой список едет в `SaveStructure`, где `pgstore/readmodel.go:193-196` выполняет `delete from chapters where book_id = $1 and not (id = any($2))` — на пустом массиве предикат истинен для ВСЕХ глав, и каскад `chapters → units` сносит текст; при пустом `Key` вдобавок срабатывает `changed` и уходят все `unit_resolutions` (родня строки 198). Сегодняшним движком недостижимо (`buildManifest` всегда наполняет главы, файл пишется атомарно) ⇒ фикс-лист, не блокер. **Асимметрия и есть находка:** на ИНТЕЙКЕ ровно этот случай отловлен явно и прибит мутацией (`internal/books/parse.go:134-142`, `books_test.go:1296`) — «нет глав, но работа считается» там не признаётся правдой о книге. У материализатора такого пола нет, и теста на нулевой манифест в `readmodel_test.go` тоже нет. Лечится одной сверкой `len(manifest.Chapters)` против `manifest.ChaptersTotal`. 10. **`PD-327` в регистре стоит `open`, а канон 0.4.0 РАТИФИЦИРОВАН** (D39.152) — то есть условие её закрытия наступило. Закрыть строку регистра явно; сегодня расхождение видно скриптом (`counts.py --check` печатает PD-327 среди открытых), и это ровно тот класс, ради которого регистр объявлен источником истины по статусу.