diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 31e66e8d..e64c3811 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -1,6 +1,6 @@ # Журнал прогресса -> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 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) · (е) фронтовый фрагмент pre-commit хука получает норму «жалуйся владельцу» — **решение владельца 21.08: ДА**, исполняется первым касанием зоны (пинг в её журнале). **Открытые обязательства, которых нет больше нигде:** веса `pro` — строка 172-г НЕ закрыта, прогон мерил классификатор на flash; дешёвый вход — спросить полигон, говорят ли что-то данные фазы Д (там pro гоняется редактором), отдельный замер не покупать без этого · `docs/experiments/00-provider-quirks.md` несёт протухшие цены DeepSeek («не изменились, flash $0.14/$0.28») — зона полигона, чинить пингом · санкция на платный прогон в архивном промте пака честности была РАЗОВОЙ · **норма плотности комментариев — ОТВЕЧЕНА владельцем 21.08:** режем ВОДУ, а не длину — счёт строк «пиши одну-две» негодный гейт и снят; уходит пересказ решений, провенанс и изложение исследования вместо ссылки, остаётся всё, что из одной функции не выводится, сколько бы строк ни заняло (норма переписана — `12-go-style-notes` §1; PD-255 платформы этим закрывается). ⚠ Метод-урок: её хендофф объявил «вопросов на владельце нет», а строка регистра просила именно решения — вопрос был закрыт ОБЪЯВЛЕНИЕМ, поймано ревьюером полноты выгрузки. Оркестраторов ДВА (решение владельца 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`) · (б) **лендинг петель полигона (фаза Д) — ОТКРЫТ**: приёмка ФАЗЫ у параллельного оркестратора, лендинг за этим; ⚠ в дереве живая незакоммиченная и частично ЗАСТЕЙДЖЕННАЯ работа полигона — не трогать и не «прибирать», состав выяснять у зоны · (в) **следующие работы платформы, порядок ПЕРЕСТАВЛЕН 21.08 при выдаче промтов:** ревью-пак четырёх осей (`platform/docs/PLATFORM_P8_REVIEW_SESSION_PROMPT.md`) → дофикс-пак (`PLATFORM_P8_FIX_SESSION_PROMPT.md`: фикс-лист пинга №18 + строка 199а + sqlc с разбором СОБРАННЫХ запросов) → живой прогон книги насквозь (строка 202, гейт — холодный прогон движка). **Почему ревью первым:** он read-only и дёшев, а дофикс тогда берёт известное И найденное одним заходом вместо двух. ⚠ **Цена перестановки, названная вслух:** блокер свипа (расчёт денег и допуск прогонов встают для всей инсталляции, ручки нет) остаётся живым на всё время читающего пака. Принято потому, что **первого выката ещё не было** — рантбук деплоя был предусловием, а не фактом, — то есть блокер сегодня пред-продовый, а не действующий отказ. Появится реальный деплой раньше, чем дофикс — порядок пересматривается · (г) **контракт:** сквозная полоса прогресса следующим минором (строка 200, слово владельца 20.08) вместе с хвостами релеев (203) · (д) свободные бэкенд: 160 Этап 0, фикс-лист ФЧ строкой 197 (носителя-сессии нет по слову владельца); ⚠ строки 176/181/187 СНЯТЫ с таблицы при лендинге 20.08 — они закрыты ещё D39.149, а очередь всё это время звала 181 свободной работой (поймано ревью доков; остатки живут строками 194/196/197) · (е) фронтовый фрагмент pre-commit хука получает норму «жалуйся владельцу» — **решение владельца 21.08: ДА**, исполняется первым касанием зоны (пинг в её журнале). **Открытые обязательства, которых нет больше нигде:** веса `pro` — строка 172-г НЕ закрыта, прогон мерил классификатор на flash; дешёвый вход — спросить полигон, говорят ли что-то данные фазы Д (там pro гоняется редактором), отдельный замер не покупать без этого · `docs/experiments/00-provider-quirks.md` несёт протухшие цены DeepSeek («не изменились, flash $0.14/$0.28») — зона полигона, чинить пингом · санкция на платный прогон в архивном промте пака честности была РАЗОВОЙ · **норма плотности комментариев — ОТВЕЧЕНА владельцем 21.08:** режем ВОДУ, а не длину — счёт строк «пиши одну-две» негодный гейт и снят; уходит пересказ решений, провенанс и изложение исследования вместо ссылки, остаётся всё, что из одной функции не выводится, сколько бы строк ни заняло (норма переписана — `12-go-style-notes` §1; PD-255 платформы этим закрывается). ⚠ Метод-урок: её хендофф объявил «вопросов на владельце нет», а строка регистра просила именно решения — вопрос был закрыт ОБЪЯВЛЕНИЕМ, поймано ревьюером полноты выгрузки. Оркестраторов ДВА (решение владельца 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; свежие фриз-коммиты полигона в дереве — НЕ трогать) · платформа и контракт — статус в строке выше, здесь НЕ дублируется (один носитель на факт) · **фронт ЗАМОРОЖЕН** (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, здесь не держатся. @@ -136,7 +136,7 @@ | 196 | **Остаточный класс строки 176: неперехватываемые `fatal error` Go** (конкурентная запись в map, OOM, стек-оверфлоу) по-прежнему дают exit 2, то есть читаются платформой как «завершено с флагами» — `recover` их не ловит по устройству языка (подтверждено линзой шва исполнением). Строка 176 закрыта для ПАНИК, не для fatal. Лечение — вне exit-контракта: сторож процесса у платформы либо маркер живости в артефакте прогона | бэкенд/платформа | когда-нибудь | отдельное решение | приёмка №18, линза шва | | 197 | **Фикс-лист приёмки пака честности ФЧ-1…ФЧ-8** (D39.149; тело — запись приёмки №18 в секции «Бэкенд»): три НЕПРИБИТЫЕ гарантии (снятие фильтра по книге в `CheckpointUsageForBook` не валит ни один тест — воспроизведено оркестратором · ключ ячейки без `chunk_idx` съедает деньги соседнего чанка · ветка «строка не пере-оценена» не ловится на продовом пути) · два докстринга `reprice.go` описывают НЕ то, что делает код · 187 исполнен наполовину (тот же снятый закон в докстринге теста и `backend/docs/D15.2-*.md:317`) · `HistoricalRows` не доезжает до `status`/`--json`, второй операторский текст (`--accept-rebill`) без basis · **ФЧ-5 РЕШЁН владельцем 17.08 (D39.150): прайсить по модели, которую стадия резолвит СЕЙЧАС, + округление вверх и оговорка в тексте согласия** · `Status()` жёстко падает при ошибке репрайсера против соседней политики деградации · паника поверх ceiling-стопа даёт `failed` вместо `paused` (PD-113) · три стейл-докстринга. Носителя-сессии НЕТ — по слову владельца 17.08 пока только записано | бэкенд | скоро (следующее касание денежного пути; ФЧ-5 обязателен до первого пере-прогона со сменой модели) | дофикс-промт ЛИБО попутно ближайшим паком | **D39.149**, **D39.150** | | 198 | **Апгрейд движка стирает замечания и счётчики книги БЕЗВОЗВРАТНО — композиция двух половин, каждая известна по отдельности** (приёмка P7, линза «вне карты», обе половины пере-прочитаны оркестратором). Платформа при смене `manifest_key` сносит ВСЕ `unit_resolutions` книги (`platform/internal/pgstore/readmodel.go:164-165`), рассчитывая, что поток их пере-наполнит; движок анонсирует юнит РОВНО ОДИН РАЗ за жизнь книги — ключ `unit::::` БЕЗ метки нарезки (`backend/internal/pipeline/events.go:399-400`), а леджер анонсов переживает прогоны (`backend/internal/store/outbox.go:96` «already announced… by one that ran before it») ⇒ совпавшие координаты не переанонсируются НИКОГДА. Обостряется порядком: долг на материализацию ставится только на ГРАНИЦАХ работы, поэтому первая зачистка после апгрейда случается в КОНЦЕ первого пост-апгрейдного прогона и сносит замечания ТОГО ЖЕ прогона, за который заплачено. Следствия на проводе: «0 из N» на переведённой книге навсегда · шкала снова предлагает купить переведённое · замечания читателя исчезают. **Лечится с обеих сторон:** движковая половина — метка нарезки в ключе анонса (решение зоны движка), платформенная — не сносить вслепую либо восстанавливать из экспорта. ⚠ Гейт холодного прогона: смысл упражнения — гонять книгу против МЕНЯЮЩЕГОСЯ движка, то есть первый же апгрейд обнулит библиотеку | бэкенд + платформа | **скоро (до первого реального пользователя И до холодного прогона с апгрейдами)** | связка: решение по ключу анонса в движке → правка платформы | приёмка P7 (D39.153) | -| 199 | **Канал доставки правок банка в движок НЕ построен — цепь «поправить/добавить термин → перегенерация» рвётся на шве платформа→движок** (расследование 20.08 по слову владельца; грепы пере-проверены оркестратором). По краям обе половины ЕСТЬ: сверху пользователь может впечатать исправленный перевод (`submitBankDecisions`, поле `dst`), снизу движок умеет точечную ре-редактуру по вхождениям за $0 на незатронутых юнитах со сметой и порогом согласия (`stagerun.go:88-107`, `repin.go`/`rebill.go`). Носителя между ними нет: колонки `action`/`dst` не читает НИ ОДИН SELECT (единственная выборка `readmodel.go:336` проверяет лишь факт наличия строки) · `mined_delta|mined_rejects` по Go платформы = **0** вхождений · воркер, который должен переносить решения в эти файлы перед resume, описан в комментарии её же миграции (`00002_readmodel.sql:172-174`) и НЕ построен. **Делится надвое:** (а) **труба, строится сейчас** — перед resume платформа пишет решения в два файла, которые движок и так читает; контракт файлов существует, проектировать нечего; закрывает и честность `decline` (PD-277); (б) **отложенное владельцем** — правки ПОСЛЕ прочтения уже переведённой книги: там правка банка двигает снапшот, движок падает громко без явного согласия на пере-оплату, а `resnapshot|accept-rebill` по Go платформы = 0 ⇒ прогон не перегенерирует, а УПАДЁТ (сегодня не кусает только потому, что до движка не доезжает ничего). Половина (б) — территория строки **192** | платформа + бэкенд | (а) скоро · (б) гейчена 192 | (а) дофикс-пак платформы · (б) с циклом чтения | расследование 20.08, D39.153 | +| 199 | **Канал доставки правок банка в движок НЕ построен — цепь «поправить/добавить термин → перегенерация» рвётся на шве платформа→движок** (расследование 20.08 по слову владельца; грепы пере-проверены оркестратором). По краям обе половины ЕСТЬ: сверху пользователь может впечатать исправленный перевод (`submitBankDecisions`, поле `dst`), снизу движок умеет точечную ре-редактуру по вхождениям за $0 на незатронутых юнитах со сметой и порогом согласия (`stagerun.go:88-107`, `repin.go`/`rebill.go`). Носителя между ними нет: колонки `action`/`dst` не читает НИ ОДИН SELECT (единственная выборка `readmodel.go:336` проверяет лишь факт наличия строки) · `mined_delta|mined_rejects` по Go платформы = **0** вхождений · воркер, который должен переносить решения в эти файлы перед resume, описан в комментарии её же миграции (`00002_readmodel.sql:172-174`) и НЕ построен. **Делится надвое:** (а) **труба** — платформа пишет решения в два файла, которые движок читает. ⚠ **«Контракт файлов существует, проектировать нечего» — ОПРОВЕРГНУТО КОДОМ 21.08** (опровергатель промта, пере-проверено оркестратором построчно): движок читает `mined_delta`/`mined_rejects`, ТОЛЬКО если их путь объявлен в `book.yaml` (`backend/internal/pipeline/mining.go:855-858`=`if r.Book.MinedDelta == ""`), а объявленный ключ с НЕсуществующим файлом валит загрузку конфига целиком (`backend/internal/config/book.go:199-207`=`is not readable`). Ключей нет ни в шаблоне оператора, ни в дев-стенде (`backend/example/book.yaml` — ноль вхождений), и добавить их платформа не может молча: она пишет `book.yaml` ОДИН раз под `O_EXCL` и «никогда не перезаписывает» (`platform/internal/books/render.go:106-109`=`writes the file once and never again`), а схему движка знать не должна — это ратифицированная форма Б (D39.110 §2б). **Значит развилка есть и она упирается в ратифицированную границу владения `book.yaml`:** объявляет ли ключи платформа при рождении книги (и создаёт ли два пустых файла сразу, иначе движок не стартует) · несёт ли их шаблон оператора · двигается ли граница владения. Решать её — ратификацией, не паком. Закрывает и честность `decline` (PD-277 — его текст сегодня относит работу к отложенной 192, пере-диспозиция нужна тем же решением); (б) **отложенное владельцем** — правки ПОСЛЕ прочтения уже переведённой книги: там правка банка двигает снапшот, движок падает громко без явного согласия на пере-оплату, а `resnapshot|accept-rebill` по Go платформы = 0 ⇒ прогон не перегенерирует, а УПАДЁТ (сегодня не кусает только потому, что до движка не доезжает ничего). Половина (б) — территория строки **192** | платформа + бэкенд | (а) скоро · (б) гейчена 192 | (а) дофикс-пак платформы · (б) с циклом чтения | расследование 20.08, D39.153 | | 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 | diff --git a/platform/docs/PLATFORM_P8_FIX_SESSION_PROMPT.md b/platform/docs/PLATFORM_P8_FIX_SESSION_PROMPT.md new file mode 100644 index 00000000..5a9f261c --- /dev/null +++ b/platform/docs/PLATFORM_P8_FIX_SESSION_PROMPT.md @@ -0,0 +1,112 @@ +# Промт: платформа, пак P8-FIX — фикс-лист приёмки P7 + труба доставки правок банка + +> Выдан №18 21.08.2026. **Запуск — по слову владельца и ПОСЛЕ пака P8-REVIEW**: его находки вливаются +> в состав этого пака отдельным релеем (см. §4.7). Читающий пак — `PLATFORM_P8_REVIEW_SESSION_PROMPT.md`. + +## 0. Зачем + +Платформа — control plane между веб-фронтом и движком перевода книг. Пак P7 построил её читающую поверхность и был **принят с фикс-листом** (D39.153): дефекты пака починены, но приёмка и последующий аудит оставили тринадцать пунктов, которые зона починить не успела, плюс один блокер выката, который в паке не рождался — он прожил два пака помеченным в регистре как закрытый. + +Твой пак закрывает этот долг. Самое тяжёлое в нём — не количество пунктов, а два свойства: **деплой сегодня объявляет клиенту версию контракта, которую не отдаёт**, и **двух медленных прогонов достаточно, чтобы расчёт денег встал для всей инсталляции без способа выйти**. + +Отдельно — строка **199(а)** единого бэклога: сегодня пользователь может впечатать исправленный перевод термина, и это не доезжает до движка НИЧЕМ. Экран подписи работает как журнал, а не как управление. + +## 1. Нормативные источники + +- **Фикс-лист — пинг оркестратора №18** в `platform/docs/platform-PROGRESS.md` (раздел «Фикс-лист приёмки», тринадцать нумерованных пунктов плюс врезанный первым блокер свипа). Тела пунктов там; сюда они НЕ переписаны намеренно — копия разошлась бы с оригиналом (норма «один носитель на факт»). +- **Канон контракта** — `docs/architecture/14-api-contract/openapi.yaml`, `info.version: 0.4.0`, **ратифицирован D39.152**. Не та версия → стоп, пинг. +- **Статус дефектов** — `platform/docs/DEFECT_REGISTER.md`. ⚠ Строка `fixed` — это КЛЕЙМ: `PD-169` стоял закрытым, пока дефект был жив, потому что пин доказывал свойство слабее, чем читается. Закрывая строку, проверь, что твой пин доказывает именно объявленное. + +## 2. Зона и git + +Пишешь только в `platform/`. Отчёт и вопросы — `platform/docs/platform-PROGRESS.md`; статусы дефектов — `DEFECT_REGISTER.md`; свои строки — `platform/BACKLOG.md`. **Ты не коммитишь** — лендит оркестратор (канон — `CLAUDE.md`, таблица зон). Чужие зоны read-only; живой полигон (`eval/`, `docs/experiments/`) не трогать; `.env` не читать; git не трогать вовсе — ни `add`, ни `commit`, ни `reset`/`checkout`/`restore`/`clean`/`stash`/`rebase`/`push`; файлы застейдженными не оставлять. Путь Go-модуля не вкладывать под путь движка (D39.85). + +## 3. Читать (≤5) + +1. **Пинг оркестратора №18** — хвост `platform/docs/platform-PROGRESS.md`: фикс-лист целиком, плюс раздел «Ратификации, которые вас касаются». +2. **`platform/docs/DEFECT_REGISTER.md`** — строки, которые ты закрываешь, и их пины. +3. **`platform/docs/STACK_DECISIONS.md`** — §22 (порядок блокировок), §33–36 (долг материализации с арендой, `edit_wave`, техника `xmin`), «Стенд разработчика». +4. **Канон контракта** `docs/architecture/14-api-contract/` — для пункта 1 фикс-листа (`ContractVersion`) и §`BankDecision` для строки 199(а). +5. **`CLAUDE.md`** + **`docs/architecture/12-go-style-notes.md` §1** — норматив кода; жаргон — `docs/glossary.md`. + +Код достаёшь САМ; `file:line` в фикс-листе — отправные точки, не пересказ. **Код первичен**: расходится с доком — верен код, расхождение это находка. + +## 4. Состав + +### 4.1 «Делай РОВНО так» — пункты фикс-листа + +Пункты **1–7 и 9–13** плюс врезанный первым блокер свипа. ⚠ **Пункт 8 — НЕ твой**: это заказ читающего пака (`PLATFORM_P8_REVIEW_SESSION_PROMPT.md`), там он и исполняется. ⚠ Счёт в пинге неоднороден и это нормально: п. 7 наполовину уже исполнен оркестратором (пустой `platform/ru` снесён при лендинге), п. 5 — замер, п. 9 — док-работа, пп. 12–13 нашёл аудит 21.08 уже ПОСЛЕ закрытия сессии P7, то есть «зона не успела» к ним не относится. Тела — в пинге; здесь только то, что задаёт РАМКУ и в пинге не сказано: + +- **Блокер свипа (врезан первым).** Лечение — НЕ «поднять константу». Это класс «терминальное состояние после N неудач», родня эскроу (строка 136 единого бэклога) и `PD-162`. Форму решаешь ты и аргументируешь; но ручка обязана существовать у ОПЕРАТОРА, а не только в коде: сегодня наблюдаемость есть (`tm_platform_sweep_unfinished_total` растёт), а сделать нельзя ничего. ⚠ Тем же пунктом **пере-открой `PD-169`** — он единственная строка регистра, которая солгала приёмке. +- **Пункт 1, `ContractVersion`.** Одна строка, но она обязана уехать вместе с пониманием: константа — единственное место, где не-стриминговый клиент узнаёт версию, и клиент, сгенерированный под другую, ОТКАЗЫВАЕТСЯ работать. Канон уже 0.4.0 и ратифицирован. +- **Пункты 12 и 13 (непойманные мутации).** Это не «дописать тест»: сначала воспроизведи посадку сам и убедись, что батарея её пропускает, и только потом пиши пин. Пин, написанный без воспроизведения, — ровно тот класс, что дал `PD-169`. +- **Пункт 4, sqlc — БЕРЁМ (слово владельца 20.08).** ⚠ Твоё же прежнее предложение «взять на однооператорных ручках P8» покупает инструмент туда, где не болит: рантайм-ошибки «нет такой колонки» случались в СКЛЕЕННОМ SQL read-модели, куда sqlc по построению не дойдёт. Поэтому тем же пунктом — **гейт, который туда дойдёт**: разбор КАЖДОГО собранного запроса Postgres'ом (prepare/describe) против мигрированной схемы. Склейка ему не мешает — он получает финальную строку. + ⚠ **Объём — «реши сам и аргументируй», и выбор обязан быть явным в отчёте.** Твой же `PD-44` говорит, что read-модель для sqlc недостижима по построению (склейка фрагментов плюс транзакции), а конверсия пятнадцати транзакционных запросов — «отдельный пак, не довесок». Между «две тривиальные ручки» и «отдельный пак» промт за тебя не выбирает: назови границу, обоснуй, и если вывод «в этом паке sqlc берётся только сюда, остальное отдельным паком» — это законный ответ, а не отказ. + +### 4.2 Строка 199(а) — труба доставки решений банка. ⚠ ПОСЫЛКА ПРОВЕРЕНА И ОПРОВЕРГНУТА, ЧИТАЙ ЦЕЛИКОМ + +Сегодня пользователь может впечатать исправленный перевод термина, и это не доезжает до движка ничем: колонки `action`/`dst` не читает ни один SELECT, а файлов, которые читает движок, платформа не пишет. + +⚠ **Первая редакция этого промта говорила «контракт файлов существует, проектировать нечего». Это НЕВЕРНО, снято опровергателем и пере-проверено построчно:** + +- движок читает `mined_delta`/`mined_rejects`, **только если путь объявлен в `book.yaml`** — `backend/internal/pipeline/mining.go:855-858`=`if r.Book.MinedDelta == ""` возвращает пусто без единого чтения; +- объявленный ключ с НЕсуществующим файлом **валит загрузку конфига целиком** — `backend/internal/config/book.go:199-207`=`is not readable`. То есть «объявим ключ, файл создадим потом» не работает: движок не стартует; +- ключей нет ни в шаблоне оператора, ни в шаблоне дев-стенда: `backend/example/book.yaml` — ноль вхождений. Значит зелень на стенде без правки шаблона НИЧЕГО не докажет: труба будет писать файлы, которых движок не читает; +- добавить ключи молча платформа не может: она пишет `book.yaml` **один раз** под `O_EXCL` и `platform/internal/books/render.go:106-109`=`writes the file once and never again`, подставляя фиксированный набор ключей, а схему движка знать не должна — это ратифицированная форма Б (D39.110 §2б). + +**Отсюда «РОВНО так»:** развилку **не решай сам** — она упирается в ратифицированную границу владения `book.yaml`. Твоя работа: назвать варианты с ценой каждого (ключи объявляет платформа при рождении книги и сразу создаёт два пустых файла · ключи несёт шаблон оператора · граница владения двигается) и **сдать это вопросом через владельца**, а строить — после ратификации. Если ратификация придёт по ходу пака, она доедет релеем (§4.7). + +**Границы, если строить разрешат:** +- ⚠ Писать **не «перед resume»**, а только на том резюме, которое СНИМАЕТ стоп подписи: `Resume` в платформе один на все случаи (`internal/runs/reconcile.go`, ручка `internal/httpapi/v0.go`), а снятие стопа отличает `bank_released` (`internal/runs/spawn.go:166`=`l.VerifyBank && !l.BankReleased`). Безусловная запись — это и есть уезд в отложенную владельцем половину (б). +- Пост-ридинговые правки уже переведённой книги — территория строки **192**, владелец отложил её явно. Признак, что уехал: понадобился `--resnapshot` или согласие на пере-оплату. +- ⚠ **Регистр скажет тебе обратное, и это известно:** `PD-277` относит эту работу к отложенной 192. Пере-диспозиция живёт в строке 199(а) единого бэклога и приедет вместе с ратификацией развилки; сам регистр правь только после неё. +- ⚠ **`--verify-bank` не трогать.** Расхождение «D39.144 ратифицировал подпись как ОДИН акт, а движок держит пер-термный гейт полноты» сегодня ОБОЙДЕНО платформой, а не устранено (строка **203(з)**). Как только пойдут файлы решений, соблазн вернуть флаг на resume возникнет сам — **это ратификация, не правка**, и решать её тебе запрещено. + +### 4.3 «Реши сам и аргументируй» + +Порядок пунктов · форма лечения блокера свипа · брать ли `PD-297` (замер round-trip на корпусной книге) в этот пак или назвать причину отказа · нужен ли отдельный пин на каждый пункт или один на класс · как делить работу между субагентами. + +### 4.4 Предметные оси ревью (1–3, вправе заменить с аргументом) + +**Код — исполнением:** батарея + СОБСТВЕННЫЕ адверсариальные посадки ВНЕ списка, который ты сам себе составил. **Шов** — если тронешь канал движка (а строка 199(а) его трогает), сначала инвентарь ВСЕХ его каналов и форматов **чтением чужого кода**, не по памяти и не по нашим докам. ⚠ Инвентарь — АРТЕФАКТ в сдаче: таблица «канал движка (`file:line`) → читатель/писатель платформы → согласовано или расходится». «Я прочитал код движка» исполнением не является. **Деньги** — пак их формально не двигает, но блокер свипа лежит на пути расчёта: коснулся — два независимых пути счёта из сырого леджера. + +- **Норма комментариев — решение владельца 21.08, и она СМЕНИЛАСЬ.** Счёт строк («пиши одну-две») снят как негодный гейт: комментарий на три строки может быть нужен, на одну — достаточен. Режем ВОДУ — пересказ решений («владелец решил… и поехали»), провенанс, изложение исследования вместо краткой ссылки. Остаётся всё, что из одной функции НЕ выводится: порядок блокировок, инварианты между таблицами, цена забывания, вендор-квирк, — сколько бы строк ни заняло. Формулировка — `12-go-style-notes` §1. ⚠ **Тем же пунктом закрой `PD-255`**: он открыт со СТАРОЙ формулой и этим решением снимается. + +### 4.5 Отложенное — только явно, списком с причинами + +Всё, что не влезло, называется в отчёте с причиной. Тихо не сделанное — дефект сдачи. + +### 4.5а Чем паку доказывать, что труба работает + +⚠ **Живого перевода через платформу не было НИ РАЗУ, и в этом паке его не будет:** строка **202** гейчена холодным прогоном движка — решение владельца 20.08. Значит доказательством трубы служит не «прогнали книгу», а: пробы против ЖИВОГО Postgres и настоящего `tmctl` на стенде · сверка формата записанных файлов с тем, что читает `membank.LoadGlossarySeed` · и честная запись в obstacle, что сквозного подтверждения нет. Не пытайся добрать доказательство платным вызовом. + +### 4.6 Что НЕ делать + +Не трогать отложенное в P8 по заказу P7 (`updateBook`/`deleteBook`/`getRun`, экспорт, эскроу П-18) — если считаешь, что что-то из этого стало блокером, это вопрос, а не решение. Не проектировать пост-ридинговый цикл (см. §4.2). + +### 4.7 Аддендум от пака P8-REVIEW + +Читающий пак сдаёт находки по четырём осям, которых не смотрел никто. **Они доедут до тебя ТОЛЬКО релеем оркестратора с эхо-подтверждением** — не читай его отчёт сам и не догадывайся: состав пака определяет оркестратор. Релей получит отдельный пункт в твоём отчёте: что пришло, что взято, что отложено и почему. + +## 5. Нормы + +- **Самопроверка ИСПОЛНЕНИЕМ — механизмом.** ≥2 независимых ревьюера по ФИНАЛЬНОМУ диффу, author≠reviewer, **субагенты РАЗРЕШЕНЫ, спавнь** (иначе дефолт-запрет харнесса тихо победит). ⚠ **Изоляция каждому — жёстко (D39.113, норма куплена инцидентом отката чужих файлов):** СВОЙ каталог песочницы КАЖДОМУ агенту, выданный явным путём — «работай в копии» без выданного пути есть приглашение к инциденту; запрет state-changing git ПЕРЕЧИСЛЕНИЕМ (`reset` · `checkout` · `restore` · `clean` · `stash` · `add` · `commit` · `rebase` · `push` · `merge` · `switch` · `rm` · `mv`); мандат читающий. В дереве живёт незакоммиченная и частично ЗАСТЕЙДЖЕННАЯ работа полигона — любая правка вне твоей зоны её уничтожает: (а) контракт-конформность построенного против канона 0.4.0 с пере-раном живых проб; (б) шов и деньги — свой инвентарь каналов, не твой список. Плюс СВОИ посадки в новые гейты и пины, не из ожидаемого тобой списка. Артефакт: таблица находок и посадок с диспозициями, **с именами агентов и по одной команде или цитате из отчёта каждого** — иначе факт спавна ничем не подтверждён. ⚠ **Ноль находок — законный результат, если получен исполнением**; «ноль находок = не верить» было бы давлением на фабрикацию. Не верить надо прогону, который ноль ОБЪЯВИЛ, ничего не исполнив. Рамка ревьюерам (анти-оверфлаг): флагай бьющее по корректности, деньгам, безопасности или по объявленным требованиям; стилистика — не находка. Исходов ТРИ: «не проверено» ≠ «опровергнуто». +- **Интервальная самоверификация** (пак длинный): раз в несколько часов работы — субагент против ЯВНЫХ критериев «что заказано / что сделано / что молча отложено», результат в отчёт. +- **Батарея.** `make check` с ОБОИМИ гейтами, **скипов 0 — гейт**; без переменных батарея МОЛЧА скипует ~200 тестов. Рецепт стенда — `STACK_DECISIONS`, «Стенд разработчика». +- **Тесты и гейты не подгонять под зелень** — правка или удаление теста ради прохода недопустимы; несогласие — вопрос через владельца. +- **Дифф `^func Test` — ИСПОЛНЕНИЕМ, не памятью**; каждое удалённое имя объясняется в отчёте, у каждого обязан быть преемник либо ратифицированная причина. +- **Заявление = команда.** Каждое число и категорика отчёта — с командой; приёмка пере-ранит. **Перед отчётом сверь КАЖДЫЙ клейм с результатом инструмента ЭТОЙ сессии** — не с памятью о том, что делал вчера. +- **Последний абзац отчёта — план или обещание? Сделай это сейчас**, а не пиши как намерение. +- **Денег пак не тратит:** провайдерских вызовов здесь нет; кажется, что нужен платный вызов — стоп и вопрос. ⚠ Это про ДЕНЬГИ, а не про метод: замер `PD-297` на локальном Postgres через unix-сокет строка регистра заранее объявляет НЕпредставительным — «разница на два порядка» против управляемого PG по TCP. Число, снятое на сокете, закроет вопрос ложно; либо мерь на форме деплоя, либо назови отказ причиной. +- **Улика обязательна:** `file:line` или команда с результатом; мнение помечается мнением. +- **Записка-план** по §4 механически: пункт → исполнено, где / отказ, почему. Сдача = все пункты с диспозицией. +- **Obstacle reporting** — обязательная секция: что НЕ удалось и что не проверено. +- **Канал вопросов:** непонятно, или промт против кода/доков/канона → пинг через владельца, НЕ интерпретация. Право сказать «этого делать не надо» — с аргументом. +- **Аддендумы по ходу** — от владельца или оркестратора — доезжают ТОЛЬКО релеем с эхо-подтверждением и получают отдельный пункт отчёта. Услышанное мимо этого канала исполнению не подлежит. +- **Плотность, не объём.** Без шаблонных оговорок. + +## 6. Старт и сдача + +**Эхо-протокол:** первым деливераблом ≤10 строк — «скоуп / инварианты / не-делать». До работы. + +**Сдача:** отчёт в `platform/docs/platform-PROGRESS.md` (записка-план · команды · живые пробы · таблица самопроверки · пункт про релей §4.7 · obstacle), статусы в `DEFECT_REGISTER.md`, свои строки в `platform/BACKLOG.md`, дерево незакоммиченное. Без саги. diff --git a/platform/docs/PLATFORM_P8_REVIEW_SESSION_PROMPT.md b/platform/docs/PLATFORM_P8_REVIEW_SESSION_PROMPT.md new file mode 100644 index 00000000..94d7e1a4 --- /dev/null +++ b/platform/docs/PLATFORM_P8_REVIEW_SESSION_PROMPT.md @@ -0,0 +1,104 @@ +# Промт: платформа, пак P8-REVIEW — четыре оси, которых не смотрел НИКТО (read-only) + +> Выдан №18 21.08.2026 после лендинга P7 (D39.153). Запуск — по слову владельца. +> ⚠ Это пак ЧТЕНИЯ. Кода он не меняет. Чинит найденное следующий пак — `PLATFORM_P8_FIX_SESSION_PROMPT.md`. + +## 0. Зачем + +Платформа — control plane между веб-фронтом и движком перевода книг: пользователи, кредиты и холды, очередь, HTTP API, запуск движка процессами. Она построена и заленджена, батарея зелёная. + +Но **четыре её оси не смотрел никто и никогда**: деньги и леджер целиком · вход, сессии и CSRF · очередь и джобы · метрики. Не потому, что они хороши, а по построению: каждая приёмка смотрела ДИФФ очередного пака, а эти оси ни в один дифф не входили. + +21.08 первый серьёзный взгляд на ОДНУ из них — очередь — дал жёсткий блокер выката: двух медленных прогонов достаточно, чтобы расчёт денег и допуск новых прогонов встали для всей инсталляции, и ручки, чтобы выйти, нет. Он прожил два пака, и **в регистре был помечен закрытым**. + +Твой результат — находки с воспроизведением. Не правки. Их возьмёт следующий пак и починит разом, а не двумя заходами. + +## 1. Нормативный источник и одна оговорка к нему + +**`platform/docs/DEFECT_REGISTER.md` — источник истины по СТАТУСУ каждого дефекта.** Открытые печатает `python3 docs/scripts/counts.py --check` (от корня репозитория). + +⚠ **И он умеет врать.** `PD-169` стоял `fixed(P5)`, пока дефект был жив: его пин доказывал свойство СЛАБЕЕ, чем читается — гонял свип вообще без дедлайна прохода, то есть мерил пер-прогонный бюджет, а не выживание прохода. Поэтому строка `fixed` — это КЛЕЙМ, а не факт: если ось, которую ты смотришь, опирается на закрытую строку, открой её пин и проверь, то ли он доказывает. + +## 2. Зона и git + +Пишешь только в `platform/`. Отчёт и вопросы — `platform/docs/platform-PROGRESS.md`; строки находок — `platform/docs/DEFECT_REGISTER.md` (это твой файл). **Ты не коммитишь** — лендит оркестратор (канон — `CLAUDE.md`, таблица зон). Чужие зоны read-only; живой полигон (`eval/`, `docs/experiments/`) не трогать; `.env` не читать; git не трогать вовсе — ни `add`, ни `commit`, ни `reset`/`checkout`/`restore`/`clean`/`stash`/`rebase`/`push`/`merge`/`switch`/`rm`/`mv`; файлы застейдженными не оставлять. ⚠ В дереве живёт незакоммиченная и частично ЗАСТЕЙДЖЕННАЯ работа полигона — не трогать и не «прибирать». + +**⚠ РОВНО: кода не менять.** Ни одной правки `.go`, ни «заодно поправил очевидное». Причина не бюрократическая: правка, внесённая тем же, кто нашёл, лишает следующий пак независимой проверки, а тебя — чистого измерения «сколько тут дефектов». Исключение одно — временные правки в КОПИИ дерева ради посадки мутаций (см. §5), в репозиторий они не возвращаются. + +## 3. Читать (≤5) + +1. **`platform/docs/DEFECT_REGISTER.md`** — открытые строки целиком; закрытые по твоим осям — выборочно, с оговоркой §1. +2. **`platform/docs/STACK_DECISIONS.md`** — правила, которые не выводятся из одной функции: §22 (порядок блокировок), §33–36 (долг материализации, `edit_wave`, техника `xmin`), раздел «Стенд разработчика» (сборка, ОБА гейта батареи, грабли). +3. **`platform/docs/platform-PROGRESS.md`** — шапка (что построено и зачем) + **пинг оркестратора №18** в хвосте: там фикс-лист приёмки P7, и его **пункт 8 — это ты**. +4. **`platform/docs/ENGINEERING_STANDARDS.md`** §3 — норма посадок мутаций зоны. + ⚠ Твой продукт — это ДЕСЯТКИ новых `file:line` в регистре, а гейт якорей с 21.08 видит `platform/docs` и умеет сверять по СОДЕРЖИМОМУ: `python3 docs/scripts/counts.py --lint` (от корня). Якорь может нести токен ожидания — `` `путь:12-14`=`подстрока` `` — и на строках, которые ты трогаешь, токен ТРЕБУЕТСЯ. Токен списывается из цели дословно, не по памяти: автор этого промта на этом попадался трижды за сутки. +5. **`CLAUDE.md`**; жаргон — `docs/glossary.md`. + +Всё остальное — код, и его ты достаёшь САМ: `file:line` ниже — отправные точки, а не пересказ. **Код первичен**: если док и код расходятся, верен код, а расхождение — находка. + +## 4. Состав: четыре оси. Скоуп — «делай РОВНО так», глубина и метод — «реши сам» + +**РОВНО:** осей ровно четыре, они ниже; кода не менять; у каждой находки — воспроизведение. +**Решаешь сам и аргументируешь:** порядок осей, глубина по каждой, сколько и куда сажать мутаций, звать ли субагентов и как делить между ними. Всё, что ниже помечено «приор» — опровергается аргументом или замером, это не задание. + +### Ось 1 — ДЕНЬГИ И ЛЕДЖЕР ЦЕЛИКОМ (приоритетная) + +Приор: здесь дефект стоит денег. ⚠ **Уточнение базовой линии:** «не смотрел никто» — про СИСТЕМНЫЙ разбор оси; точечно её трогали, и в регистре есть строки со ссылками на `credits.go` и на прежние денежные линзы. Смотри их как известное, не переоткрывай. ⚠ **И два денежных дефекта уже найдены, но в регистр ещё НЕ заведены** — пункты 12 и 13 фикс-листа в пинге №18: изоляция `inReadTx` без пина и оговорка `book_id <> $2` в `CreditHeldBy`, чей пин её ни разу не исполняет. Их не переоткрывай; ищи их класс. Предмет: резерв → расчёт → возврат холда · потолки (книжный и дневной) · арифметика микро-долларов и округления · `spend_baseline`/`SpendBound` · кэп расхода холдом · путь «расход провайдера случился, а строка в леджер не легла» · `adjust` и доля в `/usage`. + +Отправные точки: `internal/pgstore/credits.go`, `internal/money/`, `internal/runs/reconcile.go` (`settle`, `restart`), миграции `00007_credits.sql`, `00019`. + +**Норма, обязательная к исполнению (канон приёмок).** ⚠ Обязателен САМ ЗАМЕР, а не оформление уже найденного: сессия, ничего не нашедшая, чисел не производит — и норма «каждое число двумя путями» не связала бы ничего. Поэтому минимум: сведи на стенде баланс аккаунта, сумму леджера и открытые холды двумя путями ДО всякого поиска — расхождение здесь и есть первая находка. Дальше каждое число — из СЫРОГО леджера **двумя независимыми путями** (чтение кода/SQL и прямой `SELECT` по стенду). Пути обязаны сойтись или расхождение называется числом. ⚠ И вторая половина той же нормы, без которой первая обманывает: **леджер = НИЖНЯЯ граница**. Сходимость двух путей доказывает согласованность, а НЕ полноту: вызов, за который провайдер списал, а строка не легла, сойдётся в обоих путях одинаково неверно. Для оси, у которой этот путь прямо в предмете, ищи его отдельно. + +### Ось 2 — ВХОД, СЕССИИ, CSRF + +Приор: приёмка P7 смотрела на этой оси только владение ресурсами — кто чью книгу читает. ⚠ Носитель этого утверждения — obstacle-секции отчётов панели приёмки, которые в репозиторий не попали; в дереве его нет, и как факт он не проверяем. Считай это ориентиром, а не установленным покрытием: если найдёшь следы более глубокой проверки — тем лучше, скажи об этом. Предмет: генерация и сравнение токена сессии · ротация при логине · атрибуты куки и их граничные значения · привязка CSRF-токена · OIDC `state`/`return_to` · абсолютный и idle-потолок сессии · журнал входов. + +Отправные точки: `internal/auth/`, `internal/login/`, `internal/pgstore/sessions.go`, `internal/pgstore/identity.go`. + +⚠ В регистре по этой оси уже есть открытые строки (`PD-6`, `PD-86`, `PD-87`, `PD-88`, `PD-101`, `PD-103`) — они ИЗВЕСТНЫ, повторно их не открывай; их наличие означает, что ось трогали точечно, а не смотрели. + +### Ось 3 — ОЧЕРЕДЬ И ДЖОБЫ + +⚠ **Блокер здесь УЖЕ НАЙДЕН — не ищи его заново, ищи его СИБЛИНГОВ.** Найденное: бюджет прохода свипа 2 минуты против бюджета одного прогона 60 секунд (`cmd/tmplatformd/runner.go:189` и `internal/runs/reconcile.go:70`) ⇒ двух медленных прогонов хватает, чтобы проход кончился до `UnsettledRuns` — единственного ретрая отложенного расчёта; `ListLiveRuns` сортирует по `started_at`, поэтому заклиненный прогон стоит в голове и голодит хвост детерминированно; ручки нет — `runs.Config.RunBudget` объявлен и в проде не присваивается. + +Приор: это класс «арифметика двух констант в разных пакетах, ни одна не покрыта тестом». Ищи такие же: где ещё поведение задаётся парой чисел, живущих врозь, и где у функции нет ни одного теста. Предмет шире: River-задания и их повторы · идемпотентность обработчиков · крэш-окна между сигналом и записью · свипы (интейк, идемпотентность, материализация) и их взаимное голодание. + +Отправные точки: `internal/jobs/`, `internal/runs/reconcile.go` (`Sweep`), `cmd/tmplatformd/runner.go` (`sweep`, `pass`). + +### Ось 4 — МЕТРИКИ + +Приор: самая дешёвая из четырёх, но у неё есть острый вопрос — **наблюдаемость без ручки**. Блокер оси 3 виден метрикой `tm_platform_sweep_unfinished_total`, и оператор увидит, что проход не дошёл, и не сможет сделать НИЧЕГО. Предмет: что вообще можно понять по метрикам в момент отказа · есть ли метрика, растущая молча · кардинальность лейблов · соответствие практикам именования, объявленным зоной (`STACK_DECISIONS` §24). + +Отправные точки: `internal/metrics/`, `cmd/tmplatformd/main.go`. + +**Механизм — исполнением, не чтением:** подними дев-демон по рецепту стенда, сними `/metrics` в покое, ВЫЗОВИ отказ (например заклинь книгу так, чтобы проход свипа не дошёл до конца) и сними снова. Ось закрывается диффом двух снимков и ответом «что оператор понял бы по этой дельте», а не прозой по чтению кода. + +### 4.5 Предметные оси ревью по характеру работы (вправе заменить с аргументом) + +Пак читающий, поэтому из таблицы приёмок применимы две. **Код — исполнением:** батарея, живые пробы и СОБСТВЕННЫЕ посадки мутаций; сверка с индустриальным первоисточником прежде велосипеда (RFC для сессий и кук, практики именования метрик, объявленные `STACK_DECISIONS` §24); у ШВА — инвентарь ВСЕХ каналов другой стороны чтением ЧУЖОГО кода, не по памяти. **Деньги — пере-выводом чисел из СЫРЬЯ** двумя независимыми путями. Третью ось, если считаешь нужной, назови и аргументируй в эхо-протоколе. + +## 5. Нормы + +- **Самопроверка ИСПОЛНЕНИЕМ — механизмом, а не перечтением.** Названный механизм: (а) **посадки мутаций** по норме зоны — портишь инвариант ровно так, как его называет комментарий или строка регистра, и смотришь, краснеет ли пин; непойманная мутация в несущем инварианте — находка, а не примечание; (б) прямые `SELECT` по стенду для денежных чисел; (в) **субагенты РАЗРЕШЕНЫ и рекомендуются** — четыре оси независимы и делятся между ними без потерь (иначе дефолт-запрет харнесса тихо победит). Артефакт самопроверки — таблица «**ось** → что посадил → какой пин обязан был упасть → упал ли». ⚠ **Пол — не меньше одной посадки НА КАЖДУЮ ось**: без него буква промта удовлетворяется одной посадкой на весь пак и четырьмя непрочитанными осями. +- **Мутации — в КОПИИ дерева**, не в репозитории, и КАЖДОМУ агенту своя: `cp -a platform ~/tm-p8-review/<имя-агента>/platform`, путь выдаётся агенту ЯВНО в его задании — «работай в копии» без выданного пути есть приглашение к инциденту (D39.113). Каждому агенту — тот же запрет state-changing git ПЕРЕЧИСЛЕНИЕМ, что и тебе. В дереве живут незакоммиченные работы параллельных сессий; правка = их потеря (норма изоляции D39.113). +- **Батарея.** `make check` с ОБОИМИ гейтами (`TM_PLATFORM_TEST_DSN` + `TM_PLATFORM_TEST_ENGINE_BIN`/`_BOOK_TEMPLATE`), **скипов 0 — гейт**; без переменных батарея МОЛЧА скипует ~200 тестов, и её зелень тогда не значит ничего. Рецепт стенда — `STACK_DECISIONS`, раздел «Стенд разработчика». +- **Тесты и гейты не подгонять под зелень.** Правка или удаление теста ради прохода недопустимы; несогласие с тестом — вопрос через владельца, не правка. +- **Заявление = команда.** Каждое число и каждая категорика отчёта — с командой, которой они получены; приёмка пере-ранит и сверит. **Перед отчётом сверь КАЖДЫЙ клейм с результатом инструмента ЭТОЙ сессии**, а не с памятью о том, что видел час назад — у пака, чей единственный продукт это утверждения, цена неверного клейма выше, чем у кода. +- **Последний абзац отчёта — план или обещание? Сделай это сейчас**, а не пиши как намерение. +- **Интервальная самоверификация** (четыре оси — длинная работа): раз в несколько часов субагент против ЯВНЫХ критериев «какая ось закрыта, какая объявлена закрытой без исполнения, что молча выпало», результат в отчёт. +- **Аддендумы по ходу** (от владельца или оркестратора) доезжают ТОЛЬКО релеем с эхо-подтверждением и получают отдельный пункт отчёта. ⚠ Норма «дифф `^func Test` исполнением» к этому паку НЕ применяется сознательно: он не пишет тестов; если по ходу окажется, что пин всё-таки нужен — это вопрос, а не самодеятельность. +- **Рамка находки (анти-оверфлаг):** флагай бьющее по КОРРЕКТНОСТИ, ДЕНЬГАМ, БЕЗОПАСНОСТИ или по объявленным зоной требованиям. Стилистика и «можно было бы красивее» — не находки. **Ноль находок по оси — законный результат**, если он получен исполнением; ревью, обязанное что-то найти, находит выдуманное. +- **Улика обязательна.** `file:line` или команда с результатом. Эрудиция уликой не является: где это мнение — так и пиши «мнение». +- **Записка-план** против §4 механически: ось → что смотрел → чем проверял → находки/чисто. Сдача = все четыре оси с диспозицией. +- **Денег пак не тратит:** провайдерских вызовов здесь нет вовсе. Если тебе кажется, что нужен платный вызов — стоп и вопрос, не трать. +- **Obstacle reporting** — обязательная секция: что НЕ удалось, что не проверено и почему. Пустой она не бывает. +- **Канал вопросов:** непонятно, или промт против кода/доков → пинг через владельца, НЕ интерпретация. Право сказать «этого делать не надо» — с аргументом; если считаешь, что ось надо заменить или порядок другой, скажи это в эхо-протоколе. +- **Плотность, не объём.** Без шаблонных оговорок и без пересказа того, что уже есть в доках. + +## 6. Старт и сдача + +**Эхо-протокол:** первым деливераблом ≤10 строк — «скоуп / инварианты / не-делать», как ты их понял. До работы. + +**Артефакты для СЛЕДУЮЩЕЙ сессии — на durable АБСОЛЮТНЫЙ путь `~/tm-handoff/p8-review/`, не в scratchpad и не в копию дерева:** скрипты и патчи, которыми находка воспроизводится, обязаны пережить твою сессию — иначе «воспроизведение» остаётся только текстом строки регистра. В строке регистра ссылайся на этот путь. + +**Сдача:** отчёт в `platform/docs/platform-PROGRESS.md` (записка-план по четырём осям · команды · таблица посадок · obstacle) + строки находок в `DEFECT_REGISTER.md` с воспроизведением. Дерево незакоммиченное, кода не тронуто. Без саги.