23 KiB
Бэклог платформы (зонный)
Ведёт зона
platform/(решение владельца 02.08, D39.84: фронт и платформа держат СВОИ бэклоги; единый бэклогdocs/PROGRESS.mdостаётся трекером движка/полигона/доков и фронт/платформа-строк не принимает). Нормы те же: ID стабилен навсегда, каждая петля получает диспозицию. Запросы к ДВИЖКУ сюда не пишутся — они заходят строками единого бэклога через оркестратора (пример: строки 99–102). Засеян оркестратором при лендинге D39.84 — дальше правит платформа-сессия.
Диспозиции после P1 (05.08) — в журнале зоны, раздел «Диспозиции бэклога зоны» (
docs/platform-PROGRESS.md). Коротко: П-6 и П-8 ЗАКРЫТЫ, П-7 закрыт по схеме и операциям (постановка холда воркером — часть П-1), П-4 отменён и поглощён П-7, П-5 переопределён под кредитную модель и ждёт правки спеки, П-1 продолжена, П-2/П-3 не трогали. Дублировать их здесь не стали — у строки один источник истины.
| ID | Хвост | Вес | Источник |
|---|---|---|---|
| П-1 | HTTP/SSE-слой и сервисная обвязка (экс-строка 96 единого бэклога) — ⚠ ЗАКРЫТА, живого хвоста нет (диспозиция 22.08, аудит доков). Аутентификация, сессии и CSRF — P1; тейлер events.jsonl с курсором и карантином проекции, реконсилятор и пять ручек /v0 — P4/P5; потребительская половина шва (коды выхода, фолд присваиванием, потолки) — P6. Последний остаток, читающая поверхность, был вынесен отдельной строкой П-17 и исполнен паком P7 (D39.153), после чего «часть исполнена» перестало что-либо значить. Форма потока и аутентификации ратифицирована D39.84/D39.85 (docs/research/23-engine-platform-seam.md); порядок деплоя против schema-mismatch движка — deploy/README.md, §«Апгрейд ДВИЖКА» |
закрыта | D39.81, D39.84, D39.85, STACK_DECISIONS §5 |
| П-2 | Глобальный брокер рейт-лимитов провайдеров (экс-строка 97): гарды движка per-процесс (pipeline/ratelimit.go:11, mistral ~48% отказов под параллелизмом), а лимит провайдера — на ВЕСЬ аккаунт: N прогонов = N независимых гардов против общего лимита; воркер отпрашивается у платформы перед вызовом |
ДО второго параллельного пользователя | D39.81, D39.84 |
| П-3 | Очередь и конкурентность по книге — ⚠ ИСПОЛНЕНО P4 в той форме, которая была нужна: River на том же Postgres, MaxAttempts: 1 (повтор не доделывает работу, а спавнит второй движок — работу восстанавливает реконсилятор), одновременность по книге закрыта не лизами, а частичным уникальным индексом runs_one_live_per_book в БД: двух живых прогонов на книге не бывает, потому что движок держит эксклюзивный лок на файле проекта. ОСТАЮТСЯ ровно те части, которые нужны только со ВТОРЫМ хостом: пиннинг книги к хосту и лизы book_leases с heartbeat — сегодня хост один, и лиза без второго хоста охраняет от самой себя |
до второго хоста | STACK_DECISIONS §5 и §19, D39.84 |
| П-4 | Учёт токенов/денег per-user + бюджет-гейт ДО старта задачи (сырьё уже считает движок: request_log + internal/ledger; помнить: леджер = нижняя граница — строка 78 единого) |
Ф3-пак платформы | platform/README, D39.84 |
| П-6 | OAuth-вход популярных провайдеров (Google первым) + модель аккаунта (направление владельца 04.08): authorization code + PKCE, валидация ID-токена, связывание аккаунта по ПОДТВЕРЖДЁННОЙ почте; собственная серверная сессия сохраняется (D39.84) — OAuth даёт только СОБЫТИЕ входа. Форма и библиотеки — по ресёрч-пакету направления (ратифицирует оркестратор); писатель куки с __Host-атрибутами и dev-профиль — здесь же (PD-8) |
P1, вместе с П-1 | владелец 04.08 |
| П-7 | Кредитный баланс и фри-тир (решения владельца 05.08; ПРОДАЖИ НЕТ — бета на предоплаченных ключах владельца): append-only леджер в целых микро-долларах, грант фри-тира из админки (дефолт $5, настраиваемый), холд ДО спавна прогона + пер-книжный потолок движку (жёсткий стоп исполняет движок), расчёт на границе попытки. ⚠ «дефолт $5» ПРОТУХ: слово владельца 16.08 (D39.138 п.2л, PD-104) — грант по умолчанию НОЛЬ, начисление руками; возврат $5 идёт вместе с суточным агрегатным потолком. ⚠ Окон с обнулением НЕТ — баланс, а не подписка: черновик usage_windows в подписочной форме заменяется. Платёжный провайдер не проектируется до решения продавать. Разбор — docs/PLATFORM_DIRECTION.md §2 |
P1+, после П-6 | владелец 04–05.08 |
| П-8 | Минимальная админ-поверхность: начислить/списать кредиты аккаунту (одна запись леджера), посмотреть баланс и состояние прогонов. Защищённая ручка либо CLI — форму предлагает сессия. Без неё фри-тир неуправляем | вместе с П-7 | владелец 05.08 |
| П-5 | API лимитов/использования + оповещение стопа по потолку (решение владельца 04.08, D39.100/ПТ-35, механизм «как Claude Code»): страница лимитов в настройках читает СТАТУС использования (не суммы — деньги на провод не идут, D39.84); стоп по потолку → статус paused + оповещение «перевод остановлен: лимиты исчерпаны»; сырьё у движка есть (request_log/ledger, потолки конфига), форму API предлагает P0 |
Ф3, вместе с П-1 | D39.100, ПТ-35, контракт К-8 |
| П-9 | Загрузка книги POST /books (multipart) — ИСПОЛНЕНО P5 (11.08): ручка построена потоково (r.MultipartReader, пер-маршрутный потолок тела, свой дедлайн чтения), хранилище — каталог книги под TM_PLATFORM_BOOKS_DIR, статусы uploading → parsing → not_started | rejected получили писателей, разбор зовёт tmctl manifest, PD-72 закрыт своим тестом. Развилка «кто пишет стартовый book.yaml при интейке» (D39.110 §2b, шов books.ErrNotProvisioned) РЕШЕНА D39.130: бета = форма Б (стройка — П-14); движковая форма В (tmctl init) = строка 170 единого |
Ф3, следующий пак | сессия P4 (границей промта D39.119 §5а), исполнено P5 |
| П-10 | Честная оценка «$/глава» от ДВИЖКА. Сейчас ставка — константа платформы ($0.03, провенанс exp08 v2 через D30.4, STACK_DECISIONS §20), и это осознанная бета-мера: движковой поверхности оценки не существует, а выдумывать её запрещено. Ставка решает только ДЛИНУ шкалы (деньги защищены холдом и потолком движка), но на книге, которая заметно дороже или дешевле средней, шкала врёт пользователю о том, сколько глав он покупает. Нужна оценка от движка по конкретной книге — запрос уходит строкой ЕДИНОГО бэклога через оркестратора, не сюда |
когда-нибудь (до первого платящего) | сессия P4 |
| П-11 | Наблюдаемость раннера — ИСПОЛНЕНО P5 (11.08): prometheus/client_golang v1.24.1 на отдельном слушателе TM_PLATFORM_METRICS_ADDR; глубина очереди · возраст самого старого открытого холда · карантины · отставание тейлера · книги в интейке · длительность свипа и счётчик недоведённых проходов · запросы и задержки по паттерну маршрута. Ось наблюдаемости получила внешний эталон (практики именования Prometheus + золотые сигналы, ENGINEERING_STANDARDS §2) — половина PD-115, вторая половина строки остаётся открытой |
Ф3 | сессия P4, исполнено P5 |
| П-12 | Квота интейка и ретеншен отклонённых книг. POST /books даёт аутентифицированному аккаунту писать на диск оператора: один аплоад ограничен (64 МиБ), число аплоадов — ничем. Отклонённая по вине источника книга каталог теряет, отклонённая по вине деплоя — сохраняет намеренно, и не чистит их никто. Строка регистра — PD-175 ⚠ ПРОДУКТОВАЯ ПОЛОВИНА СНЯТА ЦЕЛИКОМ — D39.176 п.1 (слово владельца 30.08), диспозиция записана паком P12 31.08: продуктовых КВОТ НЕТ и не будет, фри-тир-лимиты не проектируются, живём на покупке API и зачислениях из админки. То есть «сколько книг входит во фри-тир» — больше НЕ развилка и НЕ ждёт владельца; вопроса нет. Остаётся ИНЖЕНЕРНАЯ гигиена, решаемая зоной без чьего-либо слова: ретеншен отклонённых (rejected) книг · свип каталогов-сирот · потолок диска. Гейт у неё один и он не продуктовый — открытая регистрация, которой в закрытой бете нет. |
инженерная гигиена, до открытой регистрации | сессия P5; продуктовая половина снята D39.176 |
| П-13 | Оценка размера книги в символах — у ДВИЖКА. character_count контракта платформа считает потоково на приёме (байты, не являющиеся продолжением UTF-8), что точно для UTF-8 и приблизительно для GB18030/UTF-16, которые движок принимает и декодирует сам. Манифест несёт source_bytes и encoding, но не число символов. Запрос уходит строкой ЕДИНОГО бэклога через оркестратора; строка регистра — PD-177 → строка 171 единого заведена 14.08 |
когда-нибудь | сессия P5 |
| П-15 | ИСПОЛНЕНО P6 (14.08). Платформенная половина шва эмиттера (движковая залендена D39.131, 9cfe080) |
ИСПОЛНЕНО P6: коды выхода движка 4/5/10–19 через ingest.OutcomeOf, потолок = paused двумя каналами (PD-113 закрыт), интейк судит по коду (PD-196 закрыт), exit 5 без намерения = прерывание и перезапуск (PD-152 закрыт); фолд unit_done ПРИСВАИВАНИЕМ по тройке (chapter, unit, wave) через unit_resolutions (миграция 00015; ратифицировано D39.131 п.2г, at-least-once); StreamVersion 1.1, Ceiling.Scope (book|day), внутренняя причина daily_ceiling, резюм дневного потолка = 409 (PD-157 половина); dev-супервизор читает ту же таблицу; foreign-hello adoption воспроизведён и закрыт (PD-200); порядок деплоя — deploy/README.md + tmplatformctl books --migratable. ⚠ Граница присваивания (PD-219): оно самолечит ПОВТОРНУЮ доставку, а не пропущенную — недодрейненный хвост новая попытка не перечитывает, её курсор начинается с размера журнала на допуске |
приёмка D39.131 |
| П-14 | ИСПОЛНЕНО P6 (14.08). Стройка интейка формы Б (ратификация D39.130) | ИСПОЛНЕНО P6: рендер в ОДНОМ месте (books.provision), TM_PLATFORM_BOOK_TEMPLATE, работа с YAML-узлом (комментарии и незнакомые ключи оператора живы, значения — строки), O_EXCL (никогда не перезаписываем), битый шаблон = класс, который ЖДЁТ. Требования к полям — backend/internal/config/book.go как справочник; шаблон — деплой-артефакт оператора, не код. При приходе формы В (строка 170 единого, tmctl init) рендер заменяется вызовом движка. Проверено настоящим tmctl manifest (3 главы) |
ратификация D39.130 (приёмка P5) |
| П-16 | ИСПОЛНЕНО P6 (14.08). Дев-сид стенда: тестовый пользователь, чтобы фронт разрабатывался на живой платформе, а не на своих моках (слово владельца 14.08). Границы: фикстуры фронта остаются батарее его гейтов (детерминированные состояния — не работа стенда); полный снос frontend/src/mock/ — триггер Ф-29, после читающей поверхности |
ИСПОЛНЕНО P6: tmplatformctl seed (дев-вход → аккаунт → грант → загрузка через ЖИВОЙ POST /v0/books → ожидание конца интейка), дев-вход TM_PLATFORM_DEV_LOGIN с четырьмя гардами непроходимости в проде, рецепт страницей в deploy/README.md. Прогнано на стенде целиком |
владелец 14.08 |
| П-17 | ИСПОЛНЕНО P7 (16–17.08). Читающая поверхность — остаток П-1, названный отдельной строкой | ИСПОЛНЕНО P7: listChapters/listUnits/listNotes/listBankTerms/streamBookEvents/getCapabilities по канону 0.3.0 · модель ошибок с машинным code · условные чтения и сжатие · Idempotency-Key · structure_version · материализатор internal/readmodel (манифест + экспорт + сайдкар банка). ⚠ submitBankDecisions СНЯТ 22.08 вместе с пер-термной моделью подписи — D39.144, слово владельца; см. PD-370. НЕ вошло и отложено в P8: updateBook/deleteBook/getRun, экспорт (createExport/getExport), эскроу (П-18) |
П-1, D39.84/85, контракт 14 |
| П-18 | Эскроу денег шва: write-ahead intent · uncertain · closing (строка 136 единого бэклога) — денежный промт, сознательно НЕ взятый ни P5, ни P6. Здесь же закрывается PD-154 (settled_at между Settle и MarkSettled): половина эскроу рядом с проектируемым целым — второй, более слабый ответ на тот же вопрос |
денежный промт | строка 136, PD-154 |
| П-19 | Конверсия свободного от склейки блока под sqlc (решение владельца 20.08 «БЕРЁМ»; граница названа P8-FIX, PD-44). Пять файлов без единой склейки — credits.go(15) · identity.go(13) · idempotency.go(7) · sessions.go(5) · observe.go(1) = 42 места / 41 текст / 40 КОНВЕРТИРУЕМЫХ (⚠ испр. D39.172: observe.go структурно не конвертируется — River мигрирует river_job сам; худший позиционный дрейф набора, семь int64 подряд, остался рукописным): это весь кусок пакета, где инструмент силён и ничего не ломает. Остальные 25 склеенных мест недостижимы по построению (lastRun — девять потребителей, nextRevisionOfThisBooksLibrary — восемь), и это ровно та часть, где рантайм-ошибки и случались. Состав пака: sqlc.yaml + пин версии инструмента (как у golangci-lint) + генерённый код в дереве + гейт «сгенерённое актуально» + WithTx для одиннадцати денежных запросов, идущих внутри ЧУЖОЙ транзакции. ⚠ Класс «нет такой колонки» УЖЕ закрыт постоянным гейтом (TestEverySQLStatementParsesAgainstTheMigratedSchema, 162 оператора, включая склеенные), поэтому этот пак покупает типизированные скан-структуры и раннюю обратную связь, а не корректность. РЕШЕНО владельцем 22.08: ОТДЕЛЬНОЙ СЕССИЕЙ, не внутри пака — изменений много, мешать их с чем-либо нельзя |
отдельная сессия | PD-44, фикс-лист приёмки P7 п. 4, решение владельца 22.08 |
| П-20 | Хвост PD-162 после P8-FIX: холд прогона, чей движок не ответит НИКОГДА, возвращается только рукой. Пак дал оператору и диагноз (tmplatformctl runs --stalled, гейдж tm_platform_runs_stalled), и терминальный вердикт (run abandon [--release-hold]), и это сознательная граница: автоматически решать про деньги прогона, о котором нельзя спросить, — та же ошибка «я не смог спросить = его нет», только со счётчиком впереди. Автоматический ответ на этот вопрос и есть эскроу — write-ahead intent · uncertain · closing (строка 136 единого бэклога, П-18). Пока эскроу нет, ручка остаётся ручной, и это записано, а не подразумевается |
вместе с П-18 | P8-FIX |
| П-21 | Ключ идемпотентности под конкуренцией даёт 500 (PD-369). ⚠ Не работа пака P8-FIX и файл им не тронут — найдено попутно, прогоном батареи: собственный тест TestAClaimThatLostARaceToAReleaseIsRetriedAndNotAnError ФЛЕЙКОВЫЙ, 1–2 падения на ~80 прогонов. Причина не в тесте: ClaimIdempotency ретраит проигранную гонку ровно claimRounds = 3 раза, а восемь одновременных попыток одного ключа, каждая из которых сразу отдаёт ключ назад (как делает любой 4xx), могут отобрать гонку у одного проигравшего трижды подряд — и он получает внутреннюю ошибку вместо одного из четырёх контрактных ответов. Направление, а не решение: граница по ВРЕМЕНИ вместо числа раундов либо ErrKeyInFlight при исчерпании — это решение о контрактном поведении |
до первого чужого пользователя | попутная находка сессии P8-FIX |