115 KiB
Журнал зоны «Платформа»
Весь прогресс платформы — ЗДЕСЬ (решение владельца 04.08): пинги, итоги сессий, открытые вопросы, предложения на ратификацию. В
docs/PROGRESS.mdплатформа не пишет; оркестратор читает этот журнал при каждом лендинге зоны (свип «решений владельца» — норма D39.99 п.4).
Текущее состояние
-
P7, акт 5 — ЗАКРЫТ. Дерево готово к приёмке и лендингу. Батарея: 18 пакетов, exit 0, скипов 0, линтер 0 issues, тестовых функций 532 (⚠ было «533» — испр. оркестратором №18 20.08: канонической командой D39.121
grep -rh '^func Test' platform --include='*_test.go' | wc -lвыходит 532; расхождение на единицу, ни на что не влияет, но число было заявлено без команды). Регистр — 327 строк, открытых 65 (13 minor, 52 info), major и BLOCKER нет. Дерево не закоммичено и не застейджено. Миграции пака: 00019–00024.Что построено и зачем
- Долг на материализацию — колонка с арендой (
books.read_model_owed_at, 00019). Ставится в ТОЙ ЖЕ транзакции, что закрывает границу работы (конец разбора и все три конца прогона), гасится сверкой метки, берётся в аренду тем, кто платит. Зачем: очередь жила в памяти процесса — упавшийRefreshеё терял, рестарт демона терял её всю, и оплаченный текст не доезжал до читателя НИКОГДА. Плюс «в покое» для потока теперь значит «и материализация не должна» — это Ф-56: книга, только что нарезанная, получалаendи 204 «не переподключайся» ровно в те секунды, пока дерево ещё не легло. Почему отошёл от прежней реализации: удалены очередь в памяти (runs.deferRefresh/DrainRefresh/Reader) и бэкстоп «дерева нет вовсе» (books.materializeMissingTrees,pgstore.BooksWithNoTree) — оба покрывались одним механизмом, а бэкстоп к тому же не видел книгу, у которой дерево есть, но на границу старше. Дрейн переехал вreadmodel.Drain— в пакет, чья это работа. - «Глава сделана» = последний проход, который книга на ЭТОМ деплое реально получает
(
books.edit_wave, 00024). Зачем: счёт шёл по волнеedit, и на деплое без редактора ни одна глава не была сделана никогда — шкала покупки не подрезалась, сервис бесконечно предлагал купить уже переведённое. Форму объявляет сам движок (пайплайн без редактора даёт волнеeditзнаменатель ноль). Почему на КНИГЕ, а не на прогоне: прочитанная с последнего прогона, она ронялаchapters_doneв ноль в момент допуска нового прогона — счётчик ходил назад, что канон запрещает. Флаг монотонный: книга, прошедшая редактирующий пайплайн, остаётся такой. - У клейма идемпотентности появился владелец (
claim_token, 00020) и тождество интейка решается дайджестом файла (content_sha256, 00023). Зачем: строка ключа не несла, какая попытка её держит — застрявшая попытка удаляла строку преемника (пользователь получал вторую книгу) или писала свою квитанцию поверх чужой (клиент реплеилLocationнесуществующей книги); а тождество поContent-Lengthне различало две РАЗНЫЕ книги с одинаковым объявлением. - Остановка АККАУНТА читается с аккаунта, а не с потолка одного прогона;
resumeразличает «прогон закончен, нужен новый» (ceiling_reached) и «пополните счёт» (credit_unavailable);blockedназывает холд, который реально освободит шкалу. Зачем: всё это — «у вас нет денег» пользователю, у которого деньги есть, и отправка его делать не то. - Счётчик замечаний вернулся на главу (
chapters.note_count, 00022),chapters.units_doneснесён (00021). Почему это разворот решения 00016 того же пака: 00016 снёс колонку с доводом «её никто не пишет» — здесь она возвращается ВМЕСТЕ с писателем, которого ей не хватало. Основание замерено: джойн, которым её заменяли, стоил 83% времени страницы библиотеки (16.8 мс против 3.4 мс на корпусе 40 книг × 500 глав); со счётчиком — 6.6 мс. Бенчмарк оставлен в дереве:go test ./internal/pgstore/ -bench LibraryPage -run xxx.
Что форсировано и почему
- Работа по канону 0.4.0 лежит в дереве до его ратификации. Основание: ответ контрактной
сессии на записку зоны плюс слово владельца 20.08 про «кончились деньги → сообщить и дать
продолжить». Ломающая правка ровно одна —
Run.stop_requested(0.3.0 такого поля не объявляет);cause.code: credit_unavailableлегален и по 0.3.0, второй уровень там открыт. Зависимость записана строкой PD-327 и закрывается лендингом канона, а не работой зоны. Если форма сдвинется словом владельца — правки отделимы, карта вP7_ACT5_FIX_PLAN.md§5б. - Тесты на АТОМАРНОСТЬ сверяют
xmin(транзакцию, последней писавшей строку). Это не экзотика ради экзотики: два пина акта проходили под мутацией «вынести метку из транзакции во второй оператор» — конечное состояние она не меняет, меняет окно, и утверждать про окно иначе тест не может.
Что осталось, названо и не спрятано
- PD-327 — ждёт лендинга канона 0.4.0 (не работа зоны).
- PD-297 — round-trip на строку в
SaveStructureпод эксклюзивной блокировкой книги. Не взят осознанно: путь самый опасный на запись, инструмент штатный (tx.SendBatch), но правку надо мерить на корпусной книге до и после. - Четыре оси не смотрел никто и никогда: деньги и леджер целиком · вход/сессии/CSRF · очередь и джобы · метрики. Пак их не менял, а все приёмки смотрели дифф. Это отдельный пак.
- Живого перевода на стенде не было ни разу — движку нужны ключи провайдера и деньги. Всё после «прогон стартовал и остановился» (подпись банка, halt на потолке, резюм после пополнения) покрыто батареей против живого Postgres, а не живым движком.
Как это проверялось
make checkс гейтами (скипов 0) · каждая правка проверена ПОСАДКОЙ МУТАЦИИ: код испорчен именно так, как называет комментарий пина, пин обязан упасть, код возвращён (40 проб, все поймались) · живые пробы по ручкам на стенде: интейк и реплей,409 key_reusedна другой файл под тем же ключом, часть после файла на реплее,/chapters/units/notes/bank, ETag→304 и разные теги у страниц, 410 на чужой id главы,after_versionиз прошлой жизни,unsupported_pair,/usageна пустом счету и послеadjust, старт и стоп прогона соstop_requestedна проводе, SSE в покое и SSE с непогашенным долгом (Ф-56 на проводе), 400 вместо 413 на длинном теле.Самопроверка
Акт закрыт адверсариальным ревью СОБСТВЕННОГО диффа (9 линз × 2 рефутера + критик полноты, 84 агента, 0 ошибок): 37 находок, 18 пережили рефутеров, и почти все — дефекты, внесённые правками самого акта. Строки PD-315…PD-327, каждая с механизмом и пином. Два из них — собственные пины акта, проходившие под мутацией, которую сами называют (PD-318): это третье появление класса в паке, и он назван в плане §3 п.2 ещё до того, как повторился.
- Долг на материализацию — колонка с арендой (
-
P7, акт 5 (начало) — исполнение фиксов по ревью акта 4 + ответ контрактной сессии. План и рабочий список —
platform/docs/P7_ACT5_FIX_PLAN.md(читать первым; §5а — что пришло из контракта). ⚠ Контрактная сессия ответила 20.08 на записку зоныCONTRACT_SYNC_FROM_PLATFORM.md: канон стал 0.4.0 (лежит в дереве контрактной зоны, НЕ ратифицирован — до лендинга в силе 0.3.0). Все три вопроса, висевшие на владельце, закрыты. Зоне пришла работа:resumeисчерпанного прогона — 409 с двумя РАЗНЫМИ причинами (ceiling_reachedпротив новогоcredit_unavailable); «глава сделана» = последний реально пройденный проход, и это ДЕНЬГИ —ChaptersLeftна деплое без волны редактора не подрезается вовсе, сервис бесконечно предлагает купить уже переведённое; отпечаток интейка — по содержимому,Content-Lengthиз нормы вышел, а невозможность установить тождество обязана давать 409, а не реплей;Run.stop_requestedобязательным булевым (единственная ломающая правка). Отклонены: слово под суточный потолок движка (решение владельца 15.08) и предложенный зоной признак «прогон продолжаем» (три лишних чтения на карточке, которую перечитывают на каждый кадр). Акт 4 закрылся адверсариальным ревью СОБСТВЕННОГО диффа (9 линз × 2 рефутера, 75 агентов): 33 находки, 27 пережили рефутеров, и часть из них внесли сами правки акта 4. Тяжелейшая — четыре независимые линзы сошлись на том, что реконсилятор снимал стоп подписи банка, которого никто не подписывал, и доспавнивал движок без--verify-bank: складывая снятие стопа внутрь общегоreopen, акт 4 не проверил, чтоreopenзовёт не толькоresume, но и свип. Нарушение согласия пользователя; починено ключом на вызывающего, пин проверен посадкой мутации. ⚠ Первый написанный на это пин ПРОШЁЛ под мутацией — фикстура не доходила до кода, потому что часы сервиса захвачены при конструировании иf.nowих не двигает. Урок в плане, §3. Закрыто также: загрузочная проверка пар — на ДОСТУПНОЙ половине (деплой с одними:unavailableбольше не стартует), интейк не трактует пустой список как «пускать всё», теги сравниваются регистронезависимо. Батарея: 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для отдельной контрактной сессии.) Все 74 позиции обеих приёмок сверены поштучно с ТЕКУЩИМ деревом — каждая с цитатой живого кода, исход «не проверено» отдельно от «опровергнуто». ⚠ Три места числились закрытыми и закрыты не были — правка не закрывала собственный сценарий: (1) подрезка буфера потока сверялась ПОСЛЕ того, как водяной знак перепрыгнул дыру, поэтому условие не срабатывало никогда и кадрыnoteтерялись молча (PD-283); (2)CompleteIdempotencyписала квитанцию в строку, которая попытке уже не принадлежит — воспроизведено живым PG, клиент получал квитанцию ЧУЖОГО запроса (PD-284); (3) пин на снятие--verify-bankбыл ПУСТЫМ: фикстура стартовала прогон безstop_for_signing(PD-285). Все три «подтверждались» зелёной батареей. Ещё закрыто: HEAD на потоке больше не держит горутину и ошибкаFlushне выдаётся за отправленный кадр (PD-286) ·blockedназывает чужую книгу только когда её холд укорачивает шкалу (PD-287, пина не было вовсе) ·note_countиGET /notesописывают одно множество (PD-288) · устаревшая доставка не рождает кадр (PD-289) · чтения на одном снапшоте (PD-290) · флаг «текст прочитан» переехал на ПАРУ (PD-291) · снятие стопа банка внутри транзакции переоткрытия, отдельного писателя больше нет (PD-292) · проход материализации подрезается своим бюджетом (PD-293) · блокировка книги в решениях банка (PD-294) · дубликат индекса снят (PD-295) · маршруты и коды ошибок — по ОДНОЙ таблице, тесты ходят по ней (PD-296) · бэкстоп-свип для книги без дерева (PD-276 дозакрыт) · интейк не платит за третью ре-нарезку (PD-248 актуализирован). Триаж §8.2: 17 сделано, 5 отклонено с причиной, 1 релей. Батарея: 18 пакетов, exit 0, скипов 0, линтер 0 issues, тестов 458 → 501; каждая правка проверена посадкой мутации, не рассуждением. ⚠ Осознанно НЕ сделано, с причиной: PD-297 (round-trip на строку под блокировкой книги — мерить прежде правки) · PD-202 (draft-only, вопрос владельцу) · PD-282 (канон §resumeRun не покрывает «денег не осталось») · PD-298 (сперва сверка у движка) · PD-299. Осей, которых не смотрел никто: деньги и леджер · вход/сессии/CSRF · очередь и джобы · метрики. -
P7: приёмка → правки → приёмка правок (17.08). ⚠ Полный хендофф под сессию без контекста —
platform/docs/P7_ACCEPTANCE_HANDOFF.md(читать §0–§3, дальше по нужде). Там же: принципы приёмки, сверка с исходным промтом, техдолг, план следующей сессии. Категорийное ревью по 12 осям с адверсариальной верификацией: 80 находок, 54 подтверждено, 16 правдоподобно, 10 опровергнуто; после дедупа 46 уникальных дефектов — 3 блокирующих класса, 15 HIGH, 17 MEDIUM. Батарея была зелёная, потому что все три блокирующих дефекта живут в путях, которые тесты проходили только в безопасной форме. Починено в зоне (регистр PD-257…PD-281): пере-нарезка книги больше не валит читающую модель навсегда (отложенный констрейнт, миграция 00018) · упавшийtmctl exportбольше не затирает текст пустотой · весь блок идемпотентности (гонка первых попыток 500→409, область ключа, отпечаток с размером файла, закрытие ключа вне контекста запроса) · база полосы прогресса считает тот же проход, что числитель · SSE (подрезанные кадры →resync_required, дедлайн записи, id из будущего) · материализация не голодает свип · банк читается на штатном деплое · деплой-нота больше не включает обратно грант, который PD-104 выключил. Батарея: 18 пакетов, exit 0, скипов 0, линтер 0 issues, тестов 458 → 490. ⚠ Приёмка ПРАВОК (9 осей + fable-5) нашла, что восемь дефектов внесли сами правки — батарея не увидела ни одного, три были запинены под ошибку автора. Все исправлены; разбор — хендофф §0. Б-1 ПОЧИНЕН разбором с владельцем 17.08 (PD-277). Рамка приёмки была неверна: это не «нужен новый канал в движок», а невыполненная половина строки единого бэклога 191(в) (слово владельца 16.08, D39.144) — «проводкаresume = снятие стопадо движка». Движок при выключенном--verify-bankуже делает модель владельца: неподписанное едет авто-строками с пометкой ⟨проверить⟩ (mining.go:211-231, D39.42 п.3), а платформа передавала флаг обратно и роняла прогон в тот же стоп. Снято:l.VerifyBank && !l.BankReleased; пинTestAResumedRunIsSpawnedWithoutTheSigningStop. ⚠ Остаток:declineпользователя до движка не доезжает (движок читаетmined_rejects) — строка бэклога 192, отложена владельцем. PD-273 закрыт решением владельца 17.08: статус остаётсяawaiting_bank, лечение — признак «стоп был запрошен» в контракте; готовая строка для единого бэклога — хендофф §7(и), вставляет оркестратор (зонаdocs/не наша). Разбор, план, обязательства через оркестратора и команды воспроизведения —platform/docs/P7_ACCEPTANCE_HANDOFF.md. ⚠ Заявки раздела «Сессия P7» ниже приёмку НЕ прошли — читать их вместе с хендоффом, не вместо. -
P7 ПОСТРОЕН — заявка САМОЙ сессии написания (17.08). ⚠ Приёмку эта заявка НЕ прошла — см. верхнюю запись и
P7_ACCEPTANCE_HANDOFF.md: 46 уникальных дефектов, три блокирующих класса, из них ни один батарея не видела. Читать ниже как исходную позицию, а не как состояние дерева. Читающая поверхность контракта 0.3.0: главы · пары с текстом · замечания · банк и подпись · SSE на КНИГЕ ·GET /capabilities· машинная модель ошибок (code+request_id) · условные чтения и сжатие ·Idempotency-Key·structure_version. Плюс форварды (title,reject_reason), PD-104 (грант → 0), демонтаж построенного гейта полноты банка (D39.144), PD-241, конформность построенного по §5 промта и рантбук деплоя, прогнанный ЖИВЫМmigrate. Батарея на стенде~/.local/pgsql(порт 55433) под-raceс ОБОИМИ гейтами: EXIT=0, 18 пакетов, скипов 0, линтер 0 issues, тестовых функций 416 → 458. Дифф: 46 файлов, +2329/−646. Селф-ревью финалом — ТРИ независимых ревьюера, два из них другой модели: 22 находки, 17 подтверждены и починены (две HIGH нашли оба контрактных ревьюера независимо), 5 — диспозиция с аргументом. Разделы ниже — записка-план, живые пробы, таблица селф-ревью, obstacle, вопросы оркестратору. -
Запись оркестратора, 15.08 — P6 + ДОФИКС ПРИНЯТЫ И ЗАЛЕНДЕНЫ (D39.132). Приёмка двумя раундами: панель 5 адверсариальных верификаторов по P6 (две линзы — другой моделью; исполнением, включая живой демон и живой PG) → фикс-лист ФП-1…ФП-8 → дофикс → финальная верификация исполнением: батарея
make checkпод-raceс живым PG и ОБОИМИ гейтами пере-прогнана оркестратором — EXIT=0, 17 пакетов, скипов 0; тестов 416 (grep -rh '^func Test' platform --include='*_test.go' | wc -l; HEAD = 359); деньги пере-считаны из сырого леджера стендовой БД двумя путями (сошлись до цента); живая проба рендера пере-снята своим tmctl из HEAD; 2 собственные посадки приёмки на дофикс — обе пойманы (TestAFlaggedBookStillAnswersAboutItsMoney·TestEachOfTheThreeBlockersAloneKeepsABookOutOfTheMigrationList— вторая до дофикса переживала всю батарею). Исправлено оркестратором при лендинге: откачено переименование закрытой строки PD-198 → PD-199 и удалена заведённая под PD-198 строка-дубль с ложным обоснованием (регистр 246 → 245 слиянием; «ID стабилен навсегда»); PD-200 перенесена в «Закрытые — эра P6», PD-180 — в «Открытые — info». Ратификации и диспозиция вопроса PD-241 — тело D39.132. -
ДОФИКС P6 ЗАКРЫТ — дерево передаётся на лендинг одним пакетом с P6 (15.08). Фикс-лист приёмки ФП-1…ФП-8, раздел «Дофикс P6» ниже. Ни одна находка не опровергнута, но две подтвердились не так, как их описала приёмка. Самая тяжёлая — денежная и на ОБЫЧНОМ пути: движок отвечает exit 2 из
status --jsonпро любую книгу с помеченной единицей, а платформа читала это как «движок не ответил», из-за чего расчёт такого прогона откладывался вечно и следующий прогон книги не стартовал. Плюс аддендум владельца 15.08:day_usdубран из ПРИМЕРА шаблона книги. Батарея под-raceс обоими гейтами: EXIT=0, 17 пакетов, скипов 0, линтер 0 issues,make vulnчист, 359 (HEAD) → 416 тестовых функций — счёт командами в разделе. Посадки 15 из 15. -
P6 ПОСТРОЕН — дерево передаётся на лендинг (14.08). Потребительская половина шва эмиттера (П-15) · интейк формы Б (П-14) · дев-стенд с сидом и дев-входом (П-16) · порядок апгрейда движка против деадлока v15 · попутные PD · гигиена зонных доков. PD-113 закрыт — открытых major в регистре НЕТ. Батарея на стенде
~/.local/pgsql(порт 55433) под-race: EXIT=0, 17 пакетов, линтер 0 issues, скипов 0,make vulnчист, тестов зоны 359 → 401 (числа P6; счёт — команды в разделе «Дофикс P6», прежний базис «396 → 403» не воспроизводился, PD-234). Посадки: 20 из 20 в первом круге (три переписаны после разбора переживших) + 6 из 6 на находки адверсариальной панели, одна названа НЕПИНЯЕМОЙ по построению. Живые пробы на настоящемtmctlи на фейке движка с правилом потолка — разделы ниже. ⚠ Три вопроса на ратификацию оркестратору (подробности в разделе P6): внутренняя причинаdaily_ceilingНЕ проецируется на провод (контракт знает одно значение — PD-199, спек-правка за S4) · направлениеPLATFORM_DIRECTION§3 предложено ПЕРЕ-ПОДПИСАТЬ (oapi-codegen и sqlc не исполнены, срок «до первого хендлера» пройден) · батарея получила ВТОРОЙ гейт окружения (TM_PLATFORM_TEST_ENGINE_BIN+_BOOK_TEMPLATE), без него один тест честно скипается. -
P5 ПОСТРОЕН и ДОФИКШЕН по приёмке — дерево передаётся на лендинг (11.08). (→ принят в три раунда и заленден D39.130,
69d485a— запись оркестратора 14.08 ниже.)POST /v0/booksпотоково с пер-маршрутным потолком тела и своим дедлайном чтения · статусыuploading → parsing → not_started | rejectedполучили писателей, разбор — $0-команда движкаtmctl manifest·POST /v0/runs/{id}/stop|resumeс намерением стопа в Postgres ДО сигнала · метрики Prometheus на отдельном слушателе · печать эффективной конфигурации. -
Приёмка 11.08 (8 находок) → дофикс → кросс-семейное ревью дофикса (5 находок) → ре-чек оркестратора (3 находки, 2 high) → ТРЕТИЙ РАУНД ЗАКРЫТ (14.08): разделы «Третий раунд», «Дофикс-2» и «Дофикс P5» ниже, движение — записками-планами. Батарея на стенде
~/.local/pgsql(порт 55433) под-race: EXIT=0, 16 пакетов, линтер 0 issues, скипов 0,make vulnчист, тестов 261 → 359. Посадки: 10/10 · 6/6 · 6/6 (две пережившие за все раунды — оба раза виноват был слепой пин, переписан пин, не мутация); списки — в журнале. ⚠ Тулчейн 1.26.6 НА РАТИФИКАЦИЮ (→ ратифицирован D39.130), и вчерашний клейм про него был ЛОЖЕН: гейт принимал 1.26.5 (регекс вместо сравнения). Теперь floor держат два механизма —make version-checkсравнивает версии,go.modнесётtoolchain go1.26.6, который читает всякая сборка; приGOTOOLCHAIN=autoхост скачает нужный тулчейн, при=localостановится. Само сравнение запинено (internal/gates). ВОПРОС на ратификацию — кто пишетbook.yamlпри интейке: половина П-9 стоит на нём, раздел «Развилка» ниже. (→ решено D39.130: бета = форма Б, стройка = П-14; движковая форма В = строка 170 единого.) -
Запись оркестратора, 14.08 — P5 ПРИНЯТ И ЗАЛЕНДЕН (
69d485a, D39.130). Финальная верификация исполнением: батарея EXIT=0 на том же стенде · гейт версий живьём отказывает 1.26.5 иgo1.27rc1, принимает 1.26.6 и 1.26.10 (sort -V честный) ·toolchain go1.26.6в go.mod · сентинел.tmplatform-booksна месте ·revision+1остался ровно у двух заявленных прогресс-писателей синка (мотивированное исключение ратифицировано) · тестов 359, регистр 198, удалённых имён тестов против HEAD нет. Ратифицировано (D39.130): Go-floor 1.26.6 с toolchain-директивой (цена офлайн-хоста с=localназвана и принята) ·book.yamlпри интейке — форма Б (рендер из деплой-шаблона; интерпретация D39.110 §2b с аудит-следом, стройка — следующим касанием зоны), форма В (tmctl init) — строка 170 единого бэклога движку · контракт-диспозиции PD-172/173/174/180 — спек-правкой 0.2.3 задачей S4-промта · PD-196 → дописка строки 165 (различимость классов отказаmanifest). -
Пинг оркестратора, 14.08 (второй) — ЭМИТТЕР ДВИЖКА ЗАЛЕНДЕН (D39.131,
9cfe080):events.jsonlначнёт появляться в каталогах книг. Словарь = вашevents.goс диффом движка (принят приёмкой):StreamVersion1.1 ·Ceiling.Scope: book|day·Finished.outcome += ceiling|stopped·eta_seconds= темп ТЕКУЩЕГО прогона ·unit_done.unit= лидерныйfirst_chunk_idx. Ваша половина — П-15 зонного бэклога (маппинг exit 4/5/10–19 ·unit_doneприсваиванием · scope · dev-супервизор · порядок деплоя против деадлока v15 — строка 174 единого, РЕШИТЬ ДО деплоя нового бинаря). PD-113/PD-196 в регистре остаются open до П-15 — движковая половина построена, потребительская нет. -
Пинг оркестратора, 14.08 — гигиена зонных доков по аудит-свипу корпуса, закрыть следующим касанием зоны (вместе с П-14):
README.md:85«тулчейн ≥1.26.5» → 1.26.6 c toolchain-директивой ·README.md:87«River не подключена — П-3» иSTACK_DECISIONS.md:23«River в go.mod НЕ добавлен» — противоречат go.mod и построенной P4-очереди ·README.md:47-48вопрос book.yaml → решён D39.130 (форма Б) ·PLATFORM_DIRECTION.md: oapi-codegen «взять — доказано» противENGINEERING_STANDARDS:59«кандидат при P1» — оба не исполнены (ручки P4/P5 рукописные), sqlc «до первого хендлера» не случился (PD-44 открыт), «River в go.mod не заводить» отстал — направление пере-подписать честно ·DEFECT_REGISTER.md: PD-172/173/174/180 не несут диспозицию D39.130 (спек-правка 0.2.3 задачей S4) · открытые PD-180/185/196 живут в секциях «Закрытые…» · PD-178 стоит после PD-191 (порядок номеров) · PD-99 (fixed кодом) лежит в «Закрытых ратификацией» · путьdocs/scripts/counts.pyв шапке регистра исполним только от корня репо · весаhigh/medium-highсекций дофиксов против объявленных major/minor/info ·STACK_DECISIONS.md:17называет гейт «make tools-check», хотяversion-checkотделён (FP5-9) · П-1/П-3 зонного бэклога не знают построенного P4 (вес «Ф3, после контракта» отстал) · хвост (г) третьего раунда — перечислительность мета-пина systemd-гейта — носителя не имеет: завести PD-строку или закрыть явно. -
P4 «раннер» + дофикс + V2 ПРИНЯТЫ и ЗАЛЕНДЕНЫ — D39.123, код
d29e30c(ревью-шапка ниже): транзиентный systemd-юнит на прогон · очередь River с холдом-до-спавна в одной транзакции · реконсилятор с базовой линией расчёта · тейлерevents.jsonlс карантином проекции · пять ручек/v0контракта 0.2.1 · дев-интейк. Батарея с живым PG 18.4 под-raceзелёная, скипов 0, тестов зоны 261. Формула аргумента потолка —committed + прирост(PD-158, ратифицирована ПОПРАВКОЙ к пингу оркестратора). -
Регистр — 245 строк (
python3 docs/scripts/counts.pyот корня репо; было 246 — лендинг слил строку-дубль PD-198, испр. оркестратором №16 15.08): 178 закрыто · 1 закрыт ратификацией (PD-59) · 4 риском · 62 открыто (17 minor, 45 info), из них 0 major — PD-113 закрыт P6 вместе с приходом эмиттера. Форма — 15 секций (добавлены эра P6 и дофикс P6). -
Промт P5 ВЫДАН оркестратором 10.08 (
PLATFORM_P5_SESSION_PROMPT.md, D39.128): П-9POST /books(+PD-72 потолок тела; развилка «кто пишет book.yaml при интейке» — вопросом в этот журнал ДО стройки той половины) · стоп/резюм-ручки PD-140 (различение «потолок vs авария» — за эмиттером движка, строки 103/165, его промт выдан параллельно) · наблюдаемость П-11 + печать конфигурации PD-114 · DEFECT_REGISTER секциями (пинг №16). Запуск — по слову владельца. (→ исполнен сессией P5 11–14.08, принят D39.130; промт с баннером-исходом —archive/PLATFORM_P5_SESSION_PROMPT_2026-08-10.md.) Эскроу/uncertain (строка 136) — следующим денежным промтом, НЕ в P5. -
Эры P0–P3 (вход OIDC · кредиты · админ-CLI · деплой · фикс-паки) — исполнены и залендены (D39.107/109/112/114); разделы — в archive/platform-PROGRESS-P0-P3.md. Стек и рецепт стенда —
STACK_DECISIONS.md; критерии приёмки —ENGINEERING_STANDARDS.md.
(Записи паков P4–P6 с дофиксами (08–15.08) — в archive/platform-PROGRESS-P4-P6.md; вынесено 16.08 по слову владельца.)
Сессия 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/<id> |
| 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, и он опирается на замер этого пака, а не на вкус |
Команды (каждое число отчёта — этой командой)
# батарея, оба гейта, -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→ 403forbidden·cause.code: client_header_missing; - интейк: пара
ja→ru→ 400unsupported_pairна обоих полях; часть после файла → 400missing_or_lateи книга не остаётся (проверено счётом библиотеки до/после); Idempotency-Key: тот же ключ дважды → один и тот жеLocation; тот же ключ с другимtitle→ 409idempotency_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: что НЕ удалось и что не проверено
- Отложено в P8 явно (заказ промта):
updateBook·deleteBook·getRun·createExport/getExport· эскроу (П-18). Note.codeдля незнакомой причины — отступление, не решение:unspecified(PD-246).- Ни одного живого ЗАМЕЧАНИЯ и ни одного термина банка через настоящий прогон не прошло —
прогон стоит денег, а сессия $0. Проекции замечаний и банка проверены тестами на живом PG и
ручными строками
unit_resolutions, но не сквозным прогоном движка. - SSE с ЖИВЫМ прогоном не гонялся по той же причине: проверены книга в покое, реконнект, 204,
склейка и
resync_required— тестами и на стенде, но не под настоящим потоком кадров. - Стоимость материализации не замерена на большой книге (PD-248): два полных ре-чанка на границу работы; на демо-книге в 3 главы это миллисекунды, на 2283 главах — секунды CPU.
structure_versionна РЕАЛЬНОЙ пере-нарезке проверен тестом (смена ключа манифеста), но не настоящей сменой чанкера движка.- Опрос потока — 2 запроса/с на соединение (PD-247):
LISTEN/NOTIFYне строился. - Кадр
noteживьём не наблюдался: он рождается только на помеченной единице настоящего прогона. Проверен тестом на живом PG через настоящийRunSink.Apply(полный путь материализатора), но не в потоке под браузером. - Полоса под настоящей работой не наблюдалась:
progress {0,2}— это старт; движения счётчика на стенде без ключей провайдера не бывает.
Вопросы оркестратору (канал вопросов промта, НЕ тихая интерпретация)
-
Словарь флаг-причин — рукописная копия чужой зоны без гейта (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
unspecifiedrather 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). Обратный вариант — чтобы движок эмитил сразу контрактный код — отвергнут: это зеркальная утечка, продуктовое слово поехало бы в движок, который о контракте знать не должен. -
sqlc— ОТЛОЖЕН СЛОВОМ ВЛАДЕЛЬЦА 17.08 («отложим»), строка PD-44 дополнена разбором. Фиксирую честно, включая довод против себя: пак был обязан его взять (D39.132 п.2б), и sqlc поймал бы ровно тот класс, который дважды укусил этот пак в рантайме (stop_for_signing,chapters_before) — батарея его поймала, но на цикл позже компилятора. Что мешает в read-модели: запросы собраны склейкой общих фрагментов (одна проекция книги на четыре пути), а sqlc требует литерального SQL на запрос, и страница с её ревизией — транзакция, которую он не моделирует. Предложение зоны: взять в P8 на отложенных однооператорных ручках, по итогам решить про read-модель. -
Поверхность входа: РЕШЕНО контрактной сессией 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/*, а не рост таблицы в спутнике. -
⚠ НАХОДКА КОНТРАКТНОЙ СЕССИИ, которая дороже самого вопроса — передать оркестратору отдельно. Правило про вход было РАТИФИЦИРОВАНО и потеряно молча: в компаньоне 0.2.3 §2.14 стояло «Отказ входа — problem+json, как везде; различать причины отказа клиент не может по замыслу», а в сегодняшней редакции осталась только первая половина — вторую срезал коммит лендинга батча 0.3.0 (
8d82096, провереноgit log -S). То есть P7 не переоткрывал спор, а восстанавливал решение, которое кто-то выкинул. Класс потери структурно непроверяем существующей приёмкой: сверка батча шла по мультимножеству модальных глаголов (MUST/SHOULD/MAY), а в этой фразе модального глагола нет. Стоит отдельного разбора приёмки — не как дефект контракта, а как дыра в МЕТОДЕ проверки резки прозы. -
Плотность комментариев (PD-255): пак вышел за норму «одна-две строки почему». Часть прозы несущая, часть — эссе; прошу решение владельца о норме, а не тихую подрезку в следующем паке.
Закрытые эры P0–P3 — в архиве
Разделы сессий P0–P3 и их ратификаций (04–08.08) вынесены в
archive/platform-PROGRESS-P0-P3.md (D39.124).
Решения оттуда живут в D-логе и DEFECT_REGISTER.md.
Пинги оркестратора (живые ссылки для следующих сессий)
Пинг оркестратора №15 (09.08, D39.122): движковый пак «блокеры контракта» ПРИНЯТ и заленден 0e69bc1 — пять поверхностей для платформы существуют. ФИНАЛЬНЫЕ формы (менялись трижды за приёмку — старые в переписке игнорировать):
- Манифест глав:
<project_db>.manifest.json,manifest_version: "tm-manifest-v2"(v1 движок сам отклоняет); id главы = 16 hex (стабилен через пере-нарезку);unit.id = <chapterID>:<cutTag>:<firstChunkIdx>— тег разреза 8 hex, при любой смене нарезки/данных пары unit.id УМИРАЮТ намеренно (id жив ⇒ якорь цел); полеheading— ВРЕМЕННЫЙ рендер движка «Глава N», НЕ метка книги (решение владельца 09.08; настоящие заголовки — строка 160 бэклога движка). $0-командаtmctl manifestстроит дерево до первого прогона (первое касание создаёт БД проекта — то же поведение, что у status). - Прогресс:
status --json→progress: {draft:{done,total}, edit:{done,total}}на книге и в каждом элементеchapters;done= «разрешено волной» (ok/flagged/skipped); волна, которой нет, —total: 0; процент не отгружается — собирает клиент. - Банк:
<project_db>.bank.json(весь банк тремя статусами; id термов — длино-префиксированный хеш ключа уникальности, стабилен через пересборку) и<project_db>.bank-stop.json(полная таблица подписи;conf: null≠ 0). ⚠ ИСПРАВЛЕНО оркестратором №18 (20.08, линза шва P7): «ВСЕ сайдкары атомарно» — НЕВЕРНО. Атомарны (temp+Sync+rename,backend/internal/pipeline/artifact.go:24-59) ровно три —manifest.json,bank.json,bank-stop.json, — и читать во время прогона можно ИХ.bank-stop.txt,mined-signature.yaml,auto-bank.yamlпишутсяos.WriteFileс усечением первым делом: читателей у них сегодня нет, и сессия, взявшая любой по прежней формулировке, получила бы усечённый документ на живом прогоне. - Потолок (строка 145):
tmctl translate|redrive --ceiling-usd <usd>— это КНИЖНЫЙ ПОТОЛОК В СИЛЕ, не бюджет прогона (ратифицировано D39.122): леджер сравнивает значение с накопленным committed+reserved книги. Пересчёт пользовательского «прирост в главах» (D39.110) в абсолют — ОБЯЗАННОСТЬ платформы. ⚠ АМЕНДИРОВАНО D39.123 (PD-158): формула =committed_usd + прирост×оценка, БЕЗ reserved — read-onlystatusпоказывает leftover-reserved, которыйstore.Openзануляет до первой судимой резервации; включение переплачивало бы запасом сверх холда (исполнено обеими формулами против гейта).reserved_usdчитается обязательным полем как гард присутствия и улика leftover. Значение ниже уже потраченного откажет первой же резервации. День-потолок не перекрывается. Опция по желанию зоны: движок готов провести--ceiling-usdи вstatus, чтобы мониторинг видел действующий потолок capped-прогона (сегодня status показывает книжный) — скажите, заведём строку.
Пинг оркестратора №16 — 09.08.2026 (форма DEFECT_REGISTER, строка 167)
Реестр дефектов дорос до 171 строки одной таблицей; докс-аудит D39.125 (worksheet docs/archive/reports/DOC_AUDIT_INVENTORY_2026-08-09.md, жалоба «зонная изоляция прячет половины тем») просит форму: разложить таблицу на СЕКЦИИ (open по весу · accepted-risk · fixed по эрам паков), сохранив построчную форму | PD-N | … | — docs/scripts/counts.py ключуется формой строки, не позицией, секции его не ломают. Заведите П-строкой в свой BACKLOG, исполнение — попутно следующим паком, НЕ срочно. Вопросы — через владельца.
Пинг оркестратора №17 — 15.08.2026 (migrate принят, D39.134 — движковая половина самолечения ФИНАЛЬНА)
Бэкенд-пак tmctl migrate принят и заленден (d55edd4): exit 13 = schema_mismatch финализирован, токен schema_mismatch found=N expected=M на stderr стабилен, write-путь тоже отказывает БД новее бинаря. Ваш PD-201 (самолечение «поймал 13 → migrate → повтор») теперь можно строить — движок больше не сдвинется под ногами; строку реестра, ссылающуюся на «движкового migrate ещё нет», обновите. Хвосты вашей зоны, найденные приёмкой (вход промта P7, исполнение попутно): (1) deploy/README.md:131 цитирует МЁРТВЫЙ текст ошибки схемы («schema vN … expects vM») — движок его больше не печатает; (2) та же мёртвая цитата и уплывший якорь store.go:135-143 в строке П-1 вашего BACKLOG; (3) комментарий-образец в tmplatformctl (runs.go:45) зовёт голый tmctl из PATH — копипаст воспроизводит тихий no-op СТАРЫМ бинарём при живом деадлоке, ваш же README:139-141 требует версионированный путь. Вопросы — через владельца.
Пинг оркестратора №17 (второй) — 15.08.2026 (S4 принят, контракт 0.2.3 в каноне — пять строк вашего регистра протухли; аудит корпуса)
Фронт S4 принят и заленден (D39.135), контракт 0.2.3 в каноне. Для вашего регистра: (1) PD-172 · PD-173 · PD-174 · PD-180 — диспозиция «спек-правка 0.2.3 задачей S4» (D39.130 п.2в) ИСПОЛНЕНА — правила стоят в openapi.yaml §createBook (PD-172 при этом уточнён ПО ВАШЕМУ коду: чтение останавливается на файле, обязательное после файла = 400 «как не слали», необязательное молча теряется — D39.135 п.2б); обновите статусы. (2) PD-199 ратифицирован закрытым ещё D39.132 п.2а («null на проводе подтверждён»), в регистре до сих пор open — привести. (3) Ваше НОВОЕ обязательство в P7 (D39.135 п.2в): читать BookIntake.title (сегодня падает в «unknown field is IGNORED», v0.go:369-376) и проецировать books.reject_reason на провод (сегодня «kept for an operator and never projected», v0.go:497) — без этого 0.2.3 остаётся обещанием без носителя. (4) Кандидаты в P7 по аудиту корпуса 15.08: PD-219 (упавший дрейн теряет хвост unit_resolutions навсегда — зона сама вешала его на читающую поверхность) · PD-217 (книга на вечном холде блокирует апгрейд движка — вторая половина после D39.132) · PD-162 (удалённый каталог книги = вечный прогон с открытым холдом). (5) ⚠ Ваш же журнал честно фиксирует: «tmctl migrate живьём не гонялся» — команда теперь СУЩЕСТВУЕТ и принята (D39.134); мнение оркестратора: прогнать деплой-рантбук end-to-end на дев-стенде настоящим migrate — обязательное предусловие первого выката, дешевле любого пака. Вопросы — через владельца.
Пинг оркестратора №17 (третий) — 16.08.2026 (контракт-ревью принято D39.138: ваша половина батча 0.3.0, PD-104 закрыт, попутные находки)
Контракт-ревью API v0 отработало отдельной сессией и ПРИНЯТО (отчёт — docs/research/28-contract-review.md; решения владельца — его §8, ратификация D39.138). ⚠ Читать ОРИГИНАЛ отчёта, не этот пересказ — он и есть носитель.
- PD-104 ЗАКРЫТ словом владельца 16.08 (§8 п.14):
SignupGrantMicroUSD→ 0 на бете, начисление руками; возврат $5 — вместе с суточным агрегатным потолком, когда появятся платежи. Исполнение — P7-однострочник конфига + тест (грант при неверифицированном email уже 0,login.go:306-308). Обновите регистр. - Ваша половина батча 0.3.0 — ПОСЛЕ лендинга спеки; состав — §5 отчёта:
wireProgress→ один счётчик (Б-0; ваши колонки и словарь шва НЕ трогаются — фазы остаются внутренним делом); словарь машинныхcode+request_idвProblem(Б-1/§8а: класс 1 — конкретика максимальная, класс 2 модельный — ОДИН грубый код без вариации);GET /capabilities(Б-2: пары/порог интейка/форматы/страницы/версия — всё уже есть в конфиге и константах);WWW-Authenticateна 401 и две причины 403 (Б-15); трейлинг-части интейка → 400 вместо тихой потери +Locationна 201 +Idempotency-Key(Б-3); подрезаниеlimitдо максимума вместо сброса к дефолту (Б-10,books.go:509-511);PATCH /books/{id}title-only +DELETE+GET /runs/{id}+Run.failure_reason(Б-5/Б-8 — словарь исхода у движка уже есть);blocked: {code, book_id}на run-options/409 (В-6); отказ по неподдерживаемой паре кодом на интейке (сегодня ja/en-книга умираетfailed-ом на валидации конфига движка в КОНЦЕ пути — денег не сгорает, но причина не доезжает). - Сеть (§5б; вход до первой живой книги под фронтом, строка 186): gzip на текстовых ответах (НЕ на SSE) и
ETag/If-None-Match→304 на списочных GET — ваше же требованиеPLATFORM_DIRECTION.md:202-205, батчем оно уезжает В КОНТРАКТ. Числа: дерево 2283 глав = 250 КБ на кадрstatus, фокус-рефетч 12 вкладок = 562 КБ. - К-10 (пофазность у главы): НЕ СТРОИТЬ — поправка приёмки: вердикт §6 отчёта («правка проекции») противоречит Б-0; фазы уходят с провода и у главы.
- Попутные находки §9 (сессия их адверсариально НЕ судила — проверьте у себя, заведите П/PD-строки по месту): (а) расчёт может висеть навсегда в двух легаси-путях (
reconcile.go:660-670— попытка без базовой отметки; дев-путь без движка) — бюджета «сколько холд может висеть» не существует; (б) флаг «аккаунт остановлен» выводится сканом последних прогонов ВСЕХ книг (pgstore/books.go:720-724) — одна книга зажигает аккаунт; после PD-203 перечитать; (в)ReadRunForSpawnлинеен по живым прогонам (pgstore/runs.go:712); (г)/metricsбез аутентификации, защита — только 127.0.0.1 (main.go:200-202); (д) лимитер входа один на процесс (login.go:128-129,165) — один клиент упирает вход всем (выбор объяснён комментарием, следствие стоит записать); (е) сырой Go-текст ошибки лежит причиной карантина в БД (reconcile.go:320) — на провод не идёт. Вопросы — через владельца.
Аддендум к пингу №17-третьему (16.08, свип планировочных доков D39.139): (1) docs/PLATFORM_DIRECTION.md §2 и BACKLOG.md П-7 держат «фри-тир дефолт $5» — ПРОТУХЛО против PD-104 (слово владельца 16.08: грант 0 на бете, начисление руками; D39.138 п.2л) — поправить тексты при P7. (2) Баннер §3 PLATFORM_DIRECTION («ратификация за оркестратором») закрыт ещё D39.132 п.2б: oapi-codegen — кандидат при P7, sqlc — привязан к P7, River-факт поправлен; баннер снять/заменить ссылкой на ноту. (3) §4 п.5 («сервер ВПРАВЕ склеивать события») сузится батчем 0.3.0: склейка только снимкам, note не склеивать (research/28 Б-6в). Вопросы — через владельца.
Дозакладка к §4.6 промта P7 (16.08, аудит готовности зоны; релей владельца — подтверди эхом): к списку протухших текстов зоны добавь: PLATFORM_DIRECTION.md §4 п.8 («живого канала до-прогонных состояний нет») — решено книжным SSE 0.3.0, опрос запрещён нормой · §4 п.10 («персист манифеста — недостающий») — построен D39.122 · :184 ссылка на несуществующий §3.3 стандартов · platform/README.md:3-4 шапка «зона на P1» и «один тест-гейт» (гейта два) · BACKLOG.md П-17 — состав пака у́же промта (промт первичен). Расхождение ENGINEERING_STANDARDS:59 против DIRECTION:128 по oapi-codegen решаешь ты (промт §4.6). Всё — попутно, не отдельным заходом.
Пинг оркестратора №18 — 20.08.2026 (P7 акт 5 ПРИНЯТ С ФИКС-ЛИСТОМ и ЗАЛЕНДЕН; контракт 0.4.0 ратифицирован; тело — D39.152/D39.153)
Вердикт: ПРИНЯТЬ С ФИКС-ЛИСТОМ. Панель шести линз в изолированных копиях (слепая · контракт-конформность · деньги · шов · вне карты · ревью канона 0.4.0 другой моделью) + пере-раны и собственные посадки оркестратора. Регрессов против HEAD нет, ни одной линзы с REJECT.
Пере-проверено МОЕЙ рукой (заявление = команда): make check с обоими гейтами — 18 пакетов, EXIT=0, скипов 0, линтер 0 issues · реестр 327 строк / 65 открытых (13 minor, 52 info), major и BLOCKER нет — python3 docs/scripts/counts.py --check · оба док-гейта зелёные · tmplatformctl books --migratable живой (exit 0, «resumable run» на стендовой книге) · миграционный манифест сходится, released-миграции не тронуты, комментарий про пере-отпечаток 00016 честный.
Замер, обосновавший разворот 00016→00022, пере-выведен независимо (свой бенчмарк на трёх вариантах в копии дерева): джойн 14.6 мс · счётчик 5.3 мс · без счётчика 2.9 мс. Порядок и вывод подтверждаются, разворот законен. ⚠ Процент назван в ТРЁХ носителях тремя разными числами (журнал «83%», perf_test.go:13 «96%», миграция 00022 «16.8 против 3.4, джойн сам по себе 9 мс»); мой замер даёт ≈80%, а «96%» ни из чего не выводится — один носитель на факт, остальные указывают.
Собственные посадки мутаций ВНЕ вашего списка — 8, поймано 7: долг не поставлен третьей концовкой ✅ · edit_wave не монотонен ✅ (⚠ сообщение пина печатает указатель вместо значения — readmodel_test.go:918) · снят Vary: Accept-Encoding ✅ · HEAD лишён валидатора ✅ · reopen снимает стоп банка кому угодно ✅ · погашение долга без сверки метки ✅ · вынос метки долга из закрывающей транзакции во второй оператор ✅ (техника xmin §36 работает, проверено исполнением).
⚠ НЕ поймано — дыра: снятие structure_version И revision из emitFrame (pgstore/events.go:72-73) проходит ВСЮ батарею. Это два поля, которые канон требует на КАЖДОМ кадре (EventBase), и ваш же комментарий это утверждает. По вашей норме PD-1 свойство без пинящего теста считается НЕ закрытым.
Фикс-лист приёмки — завести строками СВОЕГО бэклога и регистра (зона моя не пишет)
⚠ ПЕРВЫМ — не из пака P7, но найдено вторым рубежом приёмки и проверено мной построчно: Sweep останавливается для ВСЕЙ инсталляции на двух медленных прогонах, и выхода нет. cmd/tmplatformd/runner.go:189 — sweepBudget = 2 * time.Minute на ВЕСЬ проход; internal/runs/reconcile.go:70 — defaultRunBudget = 60 * time.Second на ОДИН прогон. 120/60 = 2: два прогона, выбравшие свой бюджет, съедают проход целиком, и тогда ctx.Err() (reconcile.go:39,48) обрывает цикл — UnsettledRuns, единственный ретрай отложенного расчёта, не вызывается вообще, а живые прогоны, стоящие ниже, не реконсилируются и не спавнятся. ListLiveRuns сортирует order by r.started_at (pgstore/runs.go:249), то есть заклиненный прогон — по построению самый старый — стоит в голове и голодит остальных КАЖДЫЙ проход, детерминированно. Ручки нет: runs.Config.RunBudget объявлен (internal/runs/runs.go:62-65), но startRunner его НЕ присваивает (cmd/tmplatformd/runner.go:74-83), переменной окружения нет ни для одного из двух чисел, а tmplatformctl не умеет ни закрыть прогон, ни вернуть холд. Цена: прогон вечно finished_at is null ⇒ холд не возвращается ⇒ runs_one_live_per_book не даёт запустить новый прогон этой книги. Деньги заморожены, книга заморожена, пользователю видно «идёт».
Достижимо буднично, без экзотики: RunSink.Apply берёт транзакцию с блокировкой книги на КАЖДУЮ строку журнала (pgstore/sink.go:80-104), поэтому после часа простоя демона две книги с бэклогом выбирают проход целиком — и всё время догона деньги всей инсталляции не считаются.
⚠ PD-169 в вашем регистре стоит fixed(P5) и этим ЛЖЁТ приёмке: его пин гоняет Sweep вообще без дедлайна прохода, то есть доказывает пер-прогонный бюджет, а не выживание прохода. Пере-открыть. Код приехал в P6 и в дифф P7 не входил (Sweep против HEAD — identical), поэтому ни одна диффовая линза его увидеть не могла: тот же класс «композиция известных фактов», что и строка 198. ⚠ Наблюдаемость при этом ЕСТЬ и она ваша: tm_platform_sweep_unfinished_total растёт — то есть оператор увидит, что проход не дошёл до конца, и не сможет ничего сделать. Метрика без ручки — половина механизма.
ContractVersion= "0.3.0" при формах 0.4.0 (internal/httpapi/capabilities.go:13, он же в каждомhello—stream.go:100). Ратификация 0.4.0 состоялась (D39.152) ⇒ константа обязана подняться. Комментарий над ней сам это требует: «raised in the same commit as the code that implements a new minor». Сегодня практического вреда нет (фронт заморожен на 0.2.3), но деплой объявляет версию, которую не отдаёт. Первым пунктом.- Пины на два поля
EventBase(см. выше). - Бюджет попыток материализации. У долга нет предела и канала «признать безнадёжным»: claim → fail → defer(
now()) → следующий свип через 15 с, вечно (pgstore/books.go:538,557-564). У интейка предел есть (parseAttempts=5). Три следствия: до 5 мин движковых процессов на проход бесконечно · поток такой книги НЕ заканчивается никогда (AtRestтребуетread_model_owed_at is null,events.go:125) · при живом манифесте и падающем экспортеSaveStructureкоммитится каждый проход ⇒revision++и кадр каждые 15 с. - sqlc — БЕРЁМ, слово владельца 20.08 («я вообще за»). Отступление P7 закрыто, PD-44 переоткрыть исполнением. ⚠ Ваше предложение «взять на однооператорных ручках P8» покупает инструмент туда, где не болит: все ЧЕТЫРЕ рантайм-ошибки «нет такой колонки» случились в СКЛЕЕННОМ SQL read-модели (
chapters_before/stop_for_signing—readmodel.go:441,446, там жеnote_countи сломанный алиасb), куда sqlc по построению не дойдёт. Тем же паком — гейт, который туда дойдёт: прогонять КАЖДЫЙ собранный запрос через разбор Postgres (prepare/describe) против мигрированной схемы; склейка ему не мешает, он получает финальную строку. И ответить попутно на вопрос, которого мы не знаем: есть ли в read-модели запрос, которого не касается ни один тест — если есть, это не «медленная обратная связь», а дыра. ⚠ Половина ответа УЖЕ получена вторым рубежом приёмки (собранный SQL извлечён из пакета черезgo/typesи прогнанEXPLAIN (GENERIC_PLAN)против мигрированной схемы): 141 запрос, все планируются чисто, остаточных «нет такой колонки» НЕТ; тестом недостижимы десять —RefundParseAttempt·StuckIntake·OpenReservations·ReleaseUnspawned·DeleteOldLoginEvents·UserByIdentity·Observe·SpendBound·AttemptReservationOpen·RunPausedReason, и ни один из них не трогает схему 00016–00024. То есть дыры сегодня нет, а гейт нужен как ПОСТОЯННЫЙ — именно он и делает этот ответ воспроизводимым. - PD-297 — round-trip на строку в
SaveStructureпод эксклюзивной блокировкой книги; мерить на корпусной книге до и после (корпусная книга появится на холодном прогоне движка). - Труба доставки решений банка в движок — единый бэклог, строка 199(а): перед resume писать решения в
mined_delta/mined_rejects. Сегодняaction/dst— write-only колонки (единственный SELECTreadmodel.go:336проверяет лишь наличие строки), а воркер описан в комментарии вашей же миграции00002_readmodel.sql:172-174и не построен. - Мусор: пустой
platform/ru(0 байт, обрубок редиректа) — в лендинг не взят, снесён оркестратором.books.go:234-235— задвоенная первая строка доккомментария, класс PD-310/326. - Ревью-пак четырёх осей, которых не смотрел НИКТО (ваш же obstacle): деньги и леджер целиком · вход/сессии/CSRF · очередь и джобы · метрики. Это не дофикс и не довесок — первый взгляд, отдельной работой.
- Один носитель на факт для замера 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%» как фантом НЕЛЬЗЯ. - У материализатора нет ПОЛА на пустой манифест — латентная потеря всего текста книги.
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. PD-327в регистре стоитopen, а канон 0.4.0 РАТИФИЦИРОВАН (D39.152) — то есть условие её закрытия наступило. Закрыть строку регистра явно; сегодня расхождение видно скриптом (counts.py --checkпечатает PD-327 среди открытых), и это ровно тот класс, ради которого регистр объявлен источником истины по статусу.
Что ушло в ЕДИНЫЙ бэклог (движок/шов/контракт — ваши строки туда не заходят, D39.84)
198 апгрейд движка стирает замечания и счётчики безвозвратно (ваша зачистка при ре-кате × announce-once движка — композиция, гейт холодного прогона) · 199 канал доставки правок банка · 200 сквозная полоса прогресса вместо пофазной (слово владельца 20.08) · 201 «Глава N» внутри текста экспорта · 202 живой прогон насквозь через API — ПОСЛЕ холодного прогона движка (слово владельца 20.08) · 203 хвосты контракта · 204 движок публикует причины флагов данными (релей §7в, ваш PD-246 — строка заведена в бэклоге ДВИЖКА, как вы и просили). ⚠ По релеям §7 сверено грепом при лендинге, а не по вашему списку: (б) и (д) уже ИСПОЛНЕНЫ синком 0.4.0, (г) наполовину (unspecified ратифицирован, открыта граница ступеней), (и) закрыт полем stop_requested. Реально открыты только (а)-канон-половина, (з) и договорная часть (к).
Ратификации, которые вас касаются
Контракт 0.4.0 РАТИФИЦИРОВАН (D39.152) — PD-327 закрывается лендингом канона, он состоялся. ⚠ Ваш клейм «ломающая правка ровно одна» верен для диффа генерённых ТИПОВ и неточен поведенчески: против 0.3.0 расходятся ЧЕТЫРЕ места (stop_requested · тождество интейка по содержимому против дословного «never over the bytes themselves» · 409 там, где таблица резюма говорит 202 · валидатор на двух ручках сверх объявленных). Все четыре 0.4.0 благословляет, поэтому цена уплачена ратификацией — но клейм в отчёте стоит поправить, чтобы следующая приёмка не опёрлась на него.
Оговорка про пер-термные решения расширена на ВСЮ ручку (была только на decline): инертны одинаково и approve, и dst. Оговорка временная — снимается исполнением строки 199(а).
⚠ Исправление МОЕГО же пинга №15 (испр. оркестратором №18): «Все сайдкары пишутся атомарно (temp+rename)» — НЕВЕРНО. Атомарны три из шести (manifest.json, bank.json, bank-stop.json — backend/internal/pipeline/artifact.go:24-59); bank-stop.txt, mined-signature.yaml, auto-bank.yaml пишутся os.WriteFile с усечением. Сегодня безвредно (читателей нет), но сессия, взявшая любой из них по той строке, получит усечённый документ на живом прогоне.
Сессия P7 ЗАКРЫТА владельцем 20.08. Промт отработан → platform/docs/archive/. Дальше — другие сессии.