22 KiB
Бэклог платформы (зонный)
Ведёт зона
platform/(решение владельца 02.08, D39.84: фронт и платформа держат СВОИ бэклоги; единый бэклогdocs/PROGRESS.mdостаётся трекером движка/полигона/доков и фронт/платформа-строк не принимает). Нормы те же: ID стабилен навсегда, каждая петля получает диспозицию. Запросы к ДВИЖКУ сюда не пишутся — они заходят строками единого бэклога через оркестратора (пример: строки 99–102). Засеян оркестратором при лендинге D39.84 — дальше правит платформа-сессия.
Диспозиции после P1 (05.08) — раздел «Диспозиции бэклога зоны» архив-слайса зонного журнала (
docs/archive/platform-PROGRESS-P0-P3.md). Коротко: П-6 и П-8 ЗАКРЫТЫ, П-7 закрыт по схеме и операциям (постановка холда воркером — часть П-1), П-4 отменён и поглощён П-7, П-5 переопределён под кредитную модель и ждёт правки спеки, П-1 продолжена, П-2/П-3 не трогали. Дублировать их здесь не стали — у строки один источник истины. ⚠ Сводка датирована 05.08 и задним числом не переписывается, но по П-5 она УСТАРЕЛА: спека с тех пор правлена, ручка построена — актуальное состояние в самой строке П-5 ниже. Адрес слайса file-относительный:platform/docs/archive/platform-PROGRESS-P0-P3.md:1086=## Диспозиции бэклога зоны.
| ID | Хвост | Вес | Источник |
|---|---|---|---|
| П-1 | HTTP/SSE-слой и сервисная обвязка (экс-строка 96 единого бэклога) — ⚠ ЗАКРЫТА, живого хвоста нет (диспозиция 22.08, аудит доков). Что именно построено — platform/README.md §«Что здесь будет»; последний остаток, читающая поверхность, вынесен строкой П-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 (довод — STACK_DECISIONS §19), одновременность по книге закрыта не лизами, а частичным уникальным индексом runs_one_live_per_book в БД. ОСТАЮТСЯ ровно те части, которые нужны только со ВТОРЫМ хостом: пиннинг книги к хосту и лизы book_leases с heartbeat — сегодня хост один, и лиза без второго хоста охраняет от самой себя |
до второго хоста | STACK_DECISIONS §5 и §19, D39.84 |
| П-4 | Учёт токенов/денег per-user + бюджет-гейт ДО старта задачи — ⚠ ОТМЕНЁН и поглощён П-7 (диспозиция P1, шапка выше). ⚠ Оговорка жива и после поглощения: леджер = НИЖНЯЯ граница траты (строка 78 единого) | отменён | platform/README, D39.84 |
| П-6 | OAuth-вход популярных провайдеров (Google первым) + модель аккаунта (направление владельца 04.08) — ⚠ ЗАКРЫТ P1: authorization code + PKCE, собственная серверная сессия сохраняется (D39.84 — OAuth даёт только СОБЫТИЕ входа), ключ личности (provider, subject); код — internal/login/, состав и живой остаток — диспозиция из шапки. Писатель куки с __Host-атрибутами и dev-профиль — PD-8 |
P1, вместе с П-1 | владелец 04.08 |
| П-7 | Кредитный баланс и фри-тир (решения владельца 05.08; ПРОДАЖИ НЕТ — бета на предоплаченных ключах владельца): append-only леджер в целых микро-долларах, грант фри-тира из админки (дефолт НОЛЬ, начисление руками — tmplatformctl grant), холд ДО спавна прогона + пер-книжный потолок движку (жёсткий стоп исполняет движок), расчёт на границе попытки. ⚠ Прежний «дефолт $5» ОТМЕНЁН словом владельца 16.08 (D39.138 п.2л, PD-104); возврат $5 идёт вместе с суточным агрегатным потолком. ⚠ Окон с обнулением НЕТ — баланс, а не подписка: черновик usage_windows в подписочной форме заменяется. Платёжный провайдер не проектируется до решения продавать. Разбор — docs/PLATFORM_DIRECTION.md §2 |
P1+, после П-6 | владелец 04–05.08 |
| П-8 | Минимальная админ-поверхность: начислить/списать кредиты аккаунту (одна запись леджера), посмотреть баланс и состояние прогонов — ⚠ ЗАКРЫТ P1 формой CLI: tmplatformctl grant/adjust/balance/logins/revoke (cmd/tmplatformctl/) |
вместе с П-7 | владелец 05.08 |
| П-5 | API лимитов/использования + оповещение стопа по потолку (решение владельца 04.08, D39.100/ПТ-35, механизм «как Claude Code»): страница лимитов в настройках читает СТАТУС использования (не суммы — деньги на провод не идут, D39.84); стоп по потолку → статус paused + оповещение «перевод остановлен: лимиты исчерпаны». ⚠ ПЕРЕОПРЕДЕЛЁН под кредитную модель (диспозиция P1, шапка выше): окон и resets_at нет, ручка ПОСТРОЕНА, спека правлена — канон несёт docs/architecture/14-api-contract/openapi.yaml:815=operationId: getUsage с прямым «no period, no resets_at», маршрут смонтирован (platform/internal/httpapi/v0.go:89=path: "/usage", греп "/usage"; хендлер — символ func (h *v0) usage). Диспозиция П-5 с тремя поправками (колонка Run.paused_reason · скоуп revision · трактовка D39.84) — platform/docs/archive/platform-PROGRESS-P0-P3.md:861=потолок поднимает платформа) — ПРИНЯТ |
Ф3, вместе с П-1 | D39.100, ПТ-35, контракт К-8 |
| П-9 | Загрузка книги POST /books (multipart) — ИСПОЛНЕНО P5 (11.08): состав в platform/README.md §«Что здесь будет»; 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): продуктовых КВОТ НЕТ и не будет, фри-тир-лимиты не проектируются, живём на покупке 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); правила шаблона и его отказов — deploy/README.md §«Шаблон книги», требования к полям — 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 и дев-вход TM_PLATFORM_DEV_LOGIN с четырьмя гардами непроходимости в проде — рецепт и разбор гардов в deploy/README.md §«Дев-стенд». Прогнано на стенде целиком |
владелец 14.08 |
| П-17 | ИСПОЛНЕНО P7 (16–17.08). Читающая поверхность — остаток П-1, названный отдельной строкой | ИСПОЛНЕНО P7 по канону 0.3.0; состав поверхности — platform/README.md §«Что здесь будет» и §«Карта зоны» (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 |