textmachine/platform/docs/PLATFORM_RUNNER_SESSION_PROMPT.md

13 KiB
Raw Blame History

Промт платформа-сессии: РАННЕР — транзиентные юниты · реконсилятор · очередь · первые ручки /v0

Выдан 08.08.2026, оркестратор №15, по слову владельца 08.08 (D39.119; санкция направления — D39.107 п.3(3)). Ты — платформа-сессия. Зона записи: platform/ + зонный журнал platform/docs/platform-PROGRESS.md (итоги/пинги ТОЛЬКО туда, в docs/PROGRESS.md не пишешь — D39.100). НЕ коммитишь — дерево готовишь, лендит оркестратор; своё в git-индексе не держи (стейдж = риск чужого коммита). Деньги: $0 — LLM-вызовов нет; PostgreSQL стенда — рецепт без root в platform/docs/STACK_DECISIONS.md. ⚠ Живые соседи по дереву: полигон эксп-22 (eval/, docs/experiments/22-*) и, возможно, бэкенд-пак «блокеры контракта» (см. §Координация) — чужого не трогать и не «прибирать» (инцидент D39.113: откачено семь файлов, шесть потеряны). Пространства имён: «строка N» = ЕДИНЫЙ БЭКЛОГ docs/PROGRESS.md (таблица «Бэклог») · «PD-N» = platform/docs/DEFECT_REGISTER.md · «П-N» = platform/BACKLOG.md.

Первый деливерабл — эхо-блок ≤10 строк ПЕРВЫМ СООБЩЕНИЕМ сессии (скоуп · инварианты · не-делать; подтверждения не жди — работай дальше). ⚠ Все file:line/якоря промта — ОТПРАВНЫЕ ТОЧКИ, код первичен: протухший якорь — сверка, не блокер.

Онбординг: какую проблему решаем и что решит твой результат

Платформа — SaaS control plane над движком перевода: пользователи/кредиты/HTTP уже стоят (P0P3 приняты, D39.107/109/114), но ПРОГОН движка платформа пока умеет запускать только дев-пайпом (internal/ingest/supervisor.go — явный DEV MODE). Ратифицированная форма шва — D39.106: движок = транзиентный systemd-юнит на прогон (платформа НЕ родитель), события — events.jsonl каталога книги (эмиттер движка ещё НЕ построен — строка 103, промт будет отдельно), платформа ТЕЙЛИТ с курсором, а ремонт-канал — tmctl status --json (уже существует и читается твоим resync.go). Твой пак строит ПРОДОВУЮ половину раннера и первые контрактные ручки — после него фронт сможет говорить с живой платформой, а не моками, не дожидаясь эмиттера.

Карта чтения (≤5): platform/README.md + зонный журнал (шапка; там же — отчёты P0P3, вкл. замер PD-91) → docs/research/25-*.md (§Форма · §Обязательные механизмы, включая абзац «Опс:» внутри неё — читать ПЕРЕД любым кодом стыка) → D-лог грепом: D39.106 · D39.110 · D39.115 п.4 (форма run-options/CeilingBounds) → контракт docs/architecture/14-api-contract/ (openapi 0.2.0 + компаньон 2.142.16) → реестр platform/docs/DEFECT_REGISTER.md (открытые PD-строки твоих поверхностей; счёт — python3 docs/scripts/counts.py).

Работы

  1. Транзиентный systemd-юнит на прогон: Restart=no, SIGTERM (D39.106 §2); щедрый TimeoutStopSec (research/25 §Форма); cgroup-лимиты прогона — ответ PD-13 живёт здесь (D39.106 §3). Privilege-модель реши ДО постройки — research/25 называет два варианта: linger-пользователь либо узкое polkit-правило; зафиксируй выбор в STACK_DECISIONS. Свойства юнита меряй исполнением на стенде без root — метод замера systemd-run --user уже отработан на PD-91 (P3, зонный журнал). Пиннинг прогона к версионированному пути бинаря движка + резюм другой версией только явным флагом (строка 139).
  2. Очередь River + воркер (П-3/П-7): пин подтверждён — добавь в go.mod; гард «один живой прогон на книгу» (runs_one_live_per_book) — исполнением; холд ДО спавна на сумму потолка (PD-79 закрыт в P3 — путь открыт), интеграция с юнитом п.1.
  3. Реконсилятор (строка 138): на КАЖДЫЙ выход юнита (ExecStopPost-маркер/D-Bus — реши сам) и на БУТЕ — перезапуск прерванных прогонов; источник истины на буте = каталоги книг + Postgres, НЕ состояние systemd (research/25). До появления эмиттера live-статус добирается периодическим status --json-резюнком (твой resync.go) — честно, с меткой давности.
  4. Тейлер events.jsonl — строится против словаря platform/internal/ingest/events.go (словарь = ПРЕДЛОЖЕНИЕ платформы движку; сам ТРАНСПОРТ ратифицирован D39.106) и лежит наготове: курсор (engine_run_id, seq) коммитится в ОДНОЙ транзакции с эффектом (контракт Sink + run_attempts.last_seq уже это предвосхищают); файла пока нет — тейлер обязан спокойно ждать его появления. Ратификация PD-105 (этим промтом, D39.119): доставка at-least-once, ДУБЛЬ seq = НОРМА повторного чтения — декодер принимает его идемпотентно, БЕЗ фатала; тот же seq с ДРУГИМ payload = карантин прогона (research/25). Реестр предписывал ратифицировать это «вместе с промтом эмиттера» — девиация осознанная (тейлер-сторона строится сейчас); строку PD-105 реестра обнови этим паком. Дев-пайп platform/internal/ingest/supervisor.go не удаляется — остаётся дев-режимом; resync.go — твой резюнк-канал.
  5. Первые ручки /v0 по контракту 0.2.0 (П-1/П-5; гейт «ждёт ратификации» снят D39.115): библиотека/карточка книги · GET /books/{id}/run-optionsCeilingBounds (максимум = Balance КАК ЕСТЬ — ⚠ НЕ «минус Reserved», это вычитание дважды, D39.115 п.2а; max_chapters отдаётся УЖЕ подрезанным, клиенту подрезать второй раз запрещено) · старт прогона с обязательным ceiling_chapters (потолок в USD передаётся движку аргументом прогона — см. §Координация) · GET /usage · статус/прогресс прогона из read-model. Формы ответов — СТРОГО спека; расхождение спеки с твоим кодом = вопрос оркестратору, не правка спеки. Две границы, размеченные явно: (а) интейк книг — библиотека обязана читать книги, заведённые ЛЮБЫМ путём (дев-скрипт/руками в каталоге + строка read-model; заведи такой скрипт как дев-инструмент); сам POST /books (multipart-загрузка) бери ТОЛЬКО если ложится чисто, иначе — явная строка зонного бэклога с обоснованием, ручки сдаются без него; (б) пересчёт «главы→доллары»: движковой поверхности оценки $/глава НЕ СУЩЕСТВУЕТ — на бету источник = конфиг-константа платформы (правит оператор; дефолт возьми из cost-model docs/experiments/08-cost-model-v2.md, поделив на главы, с комментом-провенансом), НЕ выдумывай движковую поверхность и НЕ ходи в SQLite движка; потребность в честной движковой оценке — строкой зонного бэклога, оркестратор заведёт её движку.
  6. Реестр PD: возьми строки, чья латентность снимается ЭТИМ паком (PD-99 — argv с деньгами/book-id на INFO при появлении воркера — обязательно; остальные сверь сам по реестру и возьми/оставь с обоснованием). Строки эмиттер-стороны (PD-60/61) НЕ трогать — они задание движку.

Вне скоупа: эмиттер (движок, строка 103) · uncertain-эскроу/ночная сверка (строки 136/137 — следующий денежный промт) · SSE на фронт · SPA-отдача. Инварианты: движок дёргается ТОЛЬКО процессами (никаких импортов backend) · живой SQLite движка не читать (D39.85) · book.yaml платформа НЕ правит (D39.110).

§Координация с бэкенд-паком (живой шов)

Параллельно (возможно) идёт бэкенд-пак «блокеры контракта» (промт docs/BACKEND_CONTRACT_BLOCKERS_SESSION_PROMPT.md): он строит потолок-аргумент прогона (строка 145), пофазный прогресс в status --json (99), манифест глав (100) и экспорт банка (125). Правило до его лендинга: свою логику доводи ДО шва целиком, сам шов — за узким интерфейсом с дев-стабом и пометкой TODO(145)/TODO(99)… (стаб = заглушка твоего интерфейса, НЕ имитация wire-формы движка — форму молча не выдумывай). Ручка старта прогона сдаётся полной, передача потолка движку — через такой интерфейс. Форму ПРИНИМАТЬ только из HEAD (залендённого); чужое незакоммиченное дерево backend/ читать для сверки МОЖНО (норма D39.115 п.3), но копировать его форму нельзя — расхождение твоего стаба с их черновиком = вопрос, не молчаливая подгонка. Писать в backend/ нельзя.

Самопроверка и СТОП

Мандат 12.07: ревью ИСПОЛНЕНИЕМ (код + живые пробы на собранном бинаре + systemd-run-замеры). Дифф ^func Test до/после — исполнением, не памятью; батарея make check зелёная целиком с живым PG (скипов ноль — рецепт в STACK_DECISIONS); make vuln чист. По правилу зоны: закрытая PD-строка = запиненное свойство (тест поимённо). Канал вопросов: непонятно / конфликт промта с кодом-доками-спекой / privilege-модель упирается в стенд → СТОП по ЭТОМУ пункту (остальные продолжай), вопрос — строкой в зонный журнал плюс устно владельцу (он релеит оркестратору); НЕ тихая интерпретация. Отчёт в зонный журнал: по работам с file:line · девиации · открытые PD-строки после пака (счёт скриптом) · каждое ЧИСЛО отчёта — с командой, которой получено (приёмка пере-ранит). СТОП — приёмка оркестратора (адверсариальная, со своими посадками).