textmachine/platform/docs/PLATFORM_RUNNER_SESSION_PROMPT.md

30 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Промт платформа-сессии: РАННЕР — транзиентные юниты · реконсилятор · очередь · первые ручки /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-options``CeilingBounds` (максимум = `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-строки после пака (счёт скриптом) · каждое ЧИСЛО отчёта — с командой, которой получено (приёмка пере-ранит). **СТОП — приёмка оркестратора** (адверсариальная, со своими посадками).