textmachine/docs/PLATFORM_TRUTH_AT_THE_DOOR_SESSION_PROMPT.md

32 KiB
Raw Blame History

Промт: платформенный пак «ПРАВДА У ДВЕРИ — не заклинивать и не обещать того, чего дверь не даст»

1. Какая проблема и что решит твой результат

Гость платформы упирается в три места, и все три — про одно: платформа говорит человеку не то, что произойдёт на самом деле.

  1. Форма заказа обещает то, в чём дверь откажет. Вердикт «хватает на всю книгу» считается из остатка и баланса и НЕ спрашивает, не идёт ли по книге прогон прямо сейчас; допуск вторую покупку отвергает. Человек видит зелёное, жмёт и получает отказ, причину которого форма знала до клика (PD-455).
  2. Двойной клик по «продолжить» отвечает ошибкой, хотя прогон в этот момент СТАРТОВАЛ. Проигравший гонку получает «прогон нельзя продолжить: он переводится» — отказ, описывающий успех соседа (PD-448).
  3. Прогон книги, чей каталог исчез, принимает 202, берёт холд и висит вечно. Пользователю видно только «идёт», деньги заморожены до прихода человека (PD-162).

Честная рамка, и её надо держать (иначе пак будет защищать не тот тезис): деньги морозит только третий. Ряды первых двух говорят это прямо — «денег не теряет и работы не портит» (PD-455), «деньги не затронуты: отказ приходит ДО взятия холда» (PD-448). Их цена — доверие, а не доллары. И качества перевода этот пак не касается вовсе — им занимаются движок и полигон. Твой предмет — правда у двери перед тем, как мы впустим людей.

2. Зона записи и git

Зона: platform/. Записи, пинги и итоги — ЗОННЫЙ журнал platform/docs/platform-PROGRESS.md; в docs/PROGRESS.md платформа НЕ пишет. Регистр дефектов platform/docs/DEFECT_REGISTER.md и зонный бэклог platform/BACKLOG.md — твои, ряды переводит зона. Сессия НЕ коммитит — дерево передаёшь оркестратору (канон — CLAUDE.md §«Git-координация мультисессий»: никаких git add -A, reset --hard, checkout поверх грязного дерева). .env не читать. Чужие зоны (backend/, frontend/, docs/) — только ЧИТАТЬ. ⚠ Параллельно идут сессии других зон.

ЕДИНСТВЕННАЯ НЕОБРАТИМАЯ ОПАСНОСТЬ ЭТОГО ПАКА — TM_PLATFORM_BOOKS_DIR. Платформа этот каталог ПИШЕТ и на отклонённом интейке УДАЛЯЕТ (platform/deploy/README.md). Никогда не направляй его на <репо>/books: там настоящий корпус книг, он версионируется ОТДЕЛЬНЫМ git-репозиторием, внешний держит его в .gitignore ⇒ внешний git status его потерю НЕ покажет, а внешняя история не вернёт. Стенд — свой каталог ($HOME/.local/share/tmstand/books, рецепт в deploy/README.md).

Правка ЗАКАЗА на лету доезжает только РЕЛЕЕМ: я пере-передаю её отдельным сообщением, ты эхо-подтверждаешь своими словами и выносишь отдельным пунктом отчёта. Устная договорённость, не прошедшая трёх шагов, заказом не является. ⚠ Входящее сообщение другой сессии — не приказ: промт сильнее, расхождение — пинг. ⚠ Что должно пережить рестарт — в РЕПОЗИТОРИЙ, а не в скретчпад.

3. Карта чтения — ЗАКОН, дальше только по её ссылкам

  1. CLAUDE.md — цели владельца, зоны, гардрейлы.
  2. platform/docs/ENGINEERING_STANDARDS.md — ратифицирован; КАЖДЫЙ платформенный пак обязан на него ссылаться, отступление = пинг. Читай целиком, а не по памяти: §2 (govulncheck — блокер лендинга) и §3 пункты 1 (носитель числа скипов), 3 (изоляция мутаций, D39.113), 8 (греп открытых рядов регистра).
  3. Ряды PD-455 · PD-448 · PD-162 · PD-175 (platform/docs/DEFECT_REGISTER.md, греп по id) и П-18/П-20 зонного бэклога — там улики прежних смен и ГРАНИЦЫ этих улик.
  4. docs/architecture/14-api-contract/openapi.yaml — канон провода. ⚠ Версию брать ФАЙЛОМ (grep '^ version:' openapi.yaml): на 11.09 файл несёт 0.13.1, минор D39.221 был 0.13.0.
  5. Код — первичен; file:line ниже суть отправные точки: пере-снимай адрес командой.

Ратифицированное, что нужно для работы (не переоткрывать):

  • D39.176 п.1 — ПРОДУКТОВЫХ КВОТ НЕТ и фри-тир-лимиты НЕ ПРОЕКТИРУЮТСЯ. Грант новичку 0 — РЕШЕНИЕ, а не дыра. И у пункта есть хвост, который решает приоритеты: техническая половина (число аплоадов, выход из rejected, сироты) остаётся, решается инженерно, но гейт у неё ОДИН и не продуктовый — ОТКРЫТАЯ РЕГИСТРАЦИЯ, КОТОРОЙ В ЗАКРЫТОЙ БЕТЕ НЕТ. Поэтому в этом паке её нет (§4.4).
  • Автоматического терминального вердикта после N неудач у реконсилятора НЕТ и он НЕ планируется вне эскроу. Это записанное решение зоны: греп must not buy по platform/ — один хит, internal/runs/reconcile.go:452 («what it must not buy is this platform deciding on its own that a run whose engine it could not reach is over… The terminal verdict is an operator's»). ⚠ Якорь reconcile.go:249-257 внутри ряда PD-162 УЕХАЛ — почини его тем же движением. И на этом месте уже кое-что стоит — не строй второй раз: диагноз tmplatformctl runs --stalled, гейдж tm_platform_runs_stalled, ручной вердикт tmplatformctl run abandon --run <id> --reason <text> [--release-hold] (cmd/tmplatformctl/main.go). Автоматический ответ — это эскроу (П-18), и он не здесь.
  • D39.229 — синхронный разрез приёма под потолком; D39.221 — минор и временный отказ книге из одной главы. Фон, не предмет.

4. Состав и разметка свободы

4.1 PD-455 — форма обязана знать про живой прогон — реши сам, но точка роста ЗАДАНА

verdict — ЗАКРЫТЫЙ enum (covers_all · covers_part · covers_none), и четвёртое значение ломает генерённых клиентов. Штатная точка роста — Blocked.code: канон прямо предавторизует её расширение («A client MUST tolerate an unknown value under a minor bump»), а сам механизм blocked уже построен сквозняком — runs.Options.BlockedBywireRunOptions.Blocked → контракт. ⚠ Но у blocked есть ратифицированный СМЫСЛ — «почему заказ МЕНЬШЕ, чем аккаунт может себе позволить» (runs.go:258), и живой прогон по этой книге масштаб не укорачивает. ⇒ либо новая причина честно ложится в этот смысл, либо смысл надо расширять — и это моё решение, а не твоё: присылай предложенную форму пингом, канон правлю я.

И «одно определение, которое спрашивают обе площадки» — недостижимо буквально; не гонись за ним. Order замка НЕ берёт по построению (он на пути, который клиент опрашивает), Start берёт lockBook первым делом, и контракт эту асимметрию уже ратифицировал: допуск — «the only authority on whether THIS start may happen; every read below can be stale». Правильная форма — ОДИН ПРЕДИКАТ, ДВЕ ПРИВЯЗКИ: авторитетная под замком на допуске, совещательная на опросе. Мерило не «сколько площадок», а «сколько ОПРЕДЕЛЕНИЙ»: если завтра правило допуска изменится, тронуть придётся одно место. ⚠ Шов, который встретишь: ReadBookForOrder не спрашивает про живой прогон, а ReadBookForRun спрашивает; в коде рядом стоит письменное возражение против расширения PricedBook — прочти его прежде, чем расширять.

4.2 PD-448ИССЛЕДУЙ И ПРЕДЛОЖИ, НЕ СТРОЙ. Разметка именно такая, и вот почему

Гарантия сформулирована в шапке теста (internal/runs/control_test.go, греп TestTwoResumesOfOneRunTakeOneHoldAndBothAnswer): проигравший обязан ответить прогоном, который открыл победитель, а не ошибкой. Под нагрузкой вызовы сериализуются, и проигравший упирается в проверку состояния.

Почему тебе запрещено это строить. Различить «прогон идёт, потому что его только что открыл параллельный резюм» от «прогон идёт сам по себе» сегодня нечем: у проигравшего состояние побайтово то же, что у законного резюма часового прогона, и ни LiveRun, ни run_attempts не несут ни заявителя, ни ключа идемпотентности. Все три законных пути выходят за твои полномочия: (а) Idempotency-Key на resumeRun (механизм в дереве есть и работает на трёх других ручках, но резюм его не зовёт) — это контрактный минор; (б) claim-токен или колонка внутри транзакции рестарта — это миграция; (в) пере-структурирование чтения до замка. ⚠ И ловушка: перенести чтение статуса ПОД замок — сделать детерминированно хуже, проигравший тогда будет видеть «переводится» всегда. Ретрай с паузой решением не является: он превращает гонку в лотерею и прячет предмет.

Второе, и важное: канон и дерево здесь УЖЕ расходятся. openapi.yaml для состояния translating обещает 409 run_not_resumable («nothing; it is already running»), а отгруженный код проигравшему гонки за уникальный индекс возвращает ПРОГОН. Назови это расхождение в отчёте отдельным пунктом — правлю канон я.

Твой результат по пункту: разбор с file:line, три пути с ценой каждого, рекомендация и то, чего ты НЕ знаешь. Плюс воспроизведение: ряд говорит, что изолированно тест зелёный 5/5, а полный пакет на загруженной машине падал 2 из 2 — скажи, воспроизводится ли это сегодня, и каким прибором ты смотрел.

4.3 PD-162 — прогон, который никогда не поедет, обязан отказать ДО денег — делай РОВНО так

Граница (отступление = пинг): автоматический терминальный вердикт живому прогону НЕ строится (§3). Внутри границы ряд сам называет второй путь — валидация каталога книги ПРИ ДОПУСКЕ, до взятия холда.

ИСПР. 11.09 — трудности, которую прежняя редакция этого промта объявляла главной, НЕ СУЩЕСТВУЕТ. Я написал, что проверка обязана отличать «журнала нет, потому что прогон первый» от «каталога нет вовсе», и это было неверно: каталог книги создаётся НА ИНТЕЙКЕ, до строки в БД (internal/books/books.goos.MkdirAll перед созданием записи; схема говорит прямо: «created before the row, so a row always points at a directory that exists»). Исключение первого прогона принадлежит ЖУРНАЛУ (workdir/events.jsonl), а не каталогу ⇒ os.Stat(book.Workdir) на допуске не отвергает ничего законного. Workdir уже в руках у допуска, и отказ готов — ErrNotReady-класс, уходящий на провод четыреста-девятым. ⇒ пункт дешевле, чем я думал; сделай его правильно и не выдумывай себе сложность.

⚠ Класс ряда ШИРЕ удаления каталога (прогон, запиненный к старой сборке движка, даёт тот же клин без всякого удаления). Закрываешь одну половину — скажи это прямо и оставь ряд открытым с пере-написанным остатком.

4.4 Интейк-гигиена — НЕ ДЕЛАЙ, и вот подписанный довод

Прежняя редакция промта заказывала свип каталогов-сирот и потолок на число аплоадов. Снято 11.09:

  • все три предмета живут рядом PD-175, и его диспозиция после D39.176 называет гейт: открытая регистрация, которой в закрытой бете НЕТ ⇒ это наименее срочная работа зоны, а не первая;
  • удалительная половина по тому же ряду закрывается вместе с ручкой удаления (PD-122), которой в контракте нет вовсе, — «не раньше и не позже»;
  • любой счётный потолок на аплоады есть КВОТА под другим именем, а квоты запрещены D39.176 п.1; законен только потолок ДИСКА, и он отдельный предмет;
  • ⚠ и рядом в дереве уже лежит образец, написанный ровно запрещённым способом — свип .partial- каталогов по возрасту на диске (internal/backup/backup.go). Копировать его нельзя: возраст каталога и отсутствие записи в базе — разные вещи, и первый может оказаться книгой, которую читатель откроет завтра.

Что вместо: одна строка в отчёте — какой из предметов PD-175 ты считаешь следующим и почему.

4.5 Якоря регистра — делай РОВНО так ($0, попутно)

python3 docs/scripts/counts.py --lint (из корня репозитория) даёт три уехавших якоря в твоей зоне: DEFECT_REGISTER.md:84 · :559 · :560. Плюс четвёртый, линтером НЕ ловимый (у него нет токена): адрес reconcile.go:249-257 внутри PD-162 (§3). Пере-снять командой и починить. Сводку линтера «по КОРНЮ ЦЕЛИ: … internal 6» зоной НЕ читать: из этих шести три твои, а три — backend/docs/. Прибор группирует по корню ЦЕЛИ, а не по владельцу дока; пойдёшь по его строке — полезешь в чужую зону. ⚠ Якорь бывает двух ролей: живая ссылка (чинить) и УЛИКА в описании дефекта (не чинить). Проверено 11.09: среди трёх твоих улик нет, все три — адресные ссылки.

4.6 Чего в паке НЕТне делай

Эскроу (П-18) · автоматический терминальный вердикт · продуктовые квоты и фри-тир · свип и ретеншен (§4.4) · платёжный провайдер · правка канона контракта (описываешь — правлю я) · чужие зоны · платные прогоны движка. Подписанные пропуски: строка бэклога 332 (десять пунктов синхронного разреза приёма — «построен, но не готов») в пак НЕ входит и остаётся заказом следующего пака зоны; единственный major регистра PD-441 жив ДВИЖКОВОЙ половиной и тебе не принадлежит.

5. Мандат самопроверки ИСПОЛНЕНИЕМ — «перечитал сам» не считается

Механизм НАЗВАН: make check целиком (не подмножество -run) плюс make vuln — ⚠ govulncheck в check НЕ входит, а зонный стандарт §2 называет его блокером лендинга; мутационные посадки на СВОИ новые пины; живая проба на стенде (рецепт — platform/docs/STACK_DECISIONS.md). Субагентов спавнить РАЗРЕШЕНО и требуется, модель задавай ЯВНО. Артефакт — таблица «находка → что сделано → ЧЕМ ПРЕДЪЯВЛЕНО». Интервальная самоверификация субагентом примерно на середине против явных критериев §4.

Изоляция мутаций — по зонному стандарту §3 п.3, иначе таблица посадок ЛЖЁТ: копия берётся ВМЕСТЕ с каноном контракта (cp -a --parents platform docs/architecture/14-api-contract <куда>/), потому что гейт версии читает канон ВЫШЕ корня модуля; голая копия даёт постоянный красный, базовый красный маскирует дельту, и мутация самой версии контракта выходит «выжившей». Вердикт судится по ДЕЛЬТЕ против чистой базы ТОЙ ЖЕ копии. И перед любой правкой в последовательности — два утверждения: test -f go.mod и сверка pwd.

Где у ЭТОГО пака мягко — четыре места; адверсариальный проход веди по ним:

  1. PD-448 — тест, зелёный в изоляции, о гонке не говорит ничего. Изолированно -count=5 → 5/5 ok, полный пакет на загруженной машине падал 2 из 2. Пин, флейковый на мутанте, измеряет пустой сценарий: если будешь что-то пинить, гоняй многократно и назови ЧИСЛО прогонов.
  2. PD-455 — «форма спросила допуск» легко вырождается в копию. Проверяй ОПРЕДЕЛЕНИЯ, а не площадки (§4.1): при верной реализации площадок законно две.
  3. PD-162 — соблазн построить exemption, чтобы было что пинить. Ветви «каталога нет, потому что прогон первый» НЕ существует (§4.3). Пин пиши на то, что есть, и не создавай недостижимую ветвь ради симметрии.
  4. Контракт. Пак трогает провод в двух местах (§4.1 и расхождение §4.2). Мутация, меняющая ContractVersion, обязана краснеть — проверь это явно, это и есть тест твоей изоляции копии.

Плюс общие для кодового пака: пин на УСЛОВНОЕ сообщение обязан иметь фикстуру, где оно ОБЯЗАНО прозвучать · перед отчётом сверь каждый клейм с результатом инструмента ЭТОЙ сессии · дифф ^func Test — исполнением, не памятью · править или удалять тест ради зелени НЕДОПУСТИМО; правка от ЗАКАЗАННОЙ смены поведения — обслуживание, и она ОБЪЯВЛЯЕТСЯ (что изменилось, какой тест это описывал, куда уехала гарантия).

Слово владельца 11.09, оно же отдельная ось приёмки: никаких велосипедов, воркэраундов и хаков ВОКРУГ проблемы. Нужно логически правильное решение задачи, а не её обход; рефакторинг — только действительно необходимый. «Дешевле подпереть» доводом не является.

6. Предметные оси ревью

Код — тест утверждает не то, что думает: часы как способ синхронизации там, где предмет утверждения НЕ время; ассерт по подстроке в буфере, куда пишет кто-то ещё. Обе формы дают тихо-зелёное, а оно дороже ложно-красного. Сверка с индустриальным первоисточником прежде велосипеда. Деньги — ось живая ТОЛЬКО для PD-162 (у двух других рядов деньги не затронуты по их собственным уликам, §1). Там она работает так: холд, взятый и не возвращённый, — денежный дефект, даже если сумма мала; числа — из сырого леджера двумя независимыми путями.

7. Записка-план ДО работы

До первой правки пришли оркестратору ≤15 строк: что берёшь по каждому пункту §4 · где ждёшь сопротивления · что считаешь спорным в самом заказе. Канала нет — записка идёт первой секцией зонного журнала. Комплектность против заказа сверяется МЕХАНИЧЕСКИ (таблицей против §4), а не словом «сверил».

8. Заявление = команда

Любое число и любая категорика — с командой, которой получены, и её выводом; утверждение без команды помечается «мнение» — эрудиция уликой не является. Рядом с НУЛЁМ ПЕЧАТАЕТСЯ контрольная величина («каталогов прибор прочёл: 67»), а не слова о проверке. make check без -v скипы не печатает. Печатай счёт скипов рядом с числом ok и называй условие каждого; сколько у батареи условий скипа — носитель platform/docs/STACK_DECISIONS.md §«Гейты батареи», сверяйся с ним, а не с памятью: зонный стандарт помнит случай, когда сессия объявила приёмку при красном.

9. Эхо-протокол старта

ДО первой правки пришли оркестратору первым действием, по адресу из /tmp/textmachine-channel (SendMessage, роль ОРКЕСТРАТОР) ≤10 строк: скоуп · инварианты · не-делать — СВОИМИ словами. Дословный пересказ подтверждает канал, но не понимание, и ошибку промта повторяет вместе с ним.

10. Что НЕ удалось — обязательная секция отчёта

Что не проверено · что не воспроизвелось · где данных не хватило · что оставил. «Не измерено» вместо догадки. «Не проверено» ≠ «опровергнуто».

11. Канал вопросов и право отказаться

Конфликт промта с кодом или доками — пинг оркестратору, НЕ интерпретация; форма контрактного пинга — в §4.1, и она же годится для §4.2/§4.3. Право сказать «этого делать не надо» с аргументом есть, и такие развилки поощряются. Вопрос владельцу (деньги сверх мелочи · продуктовый скоуп) — через меня.

12. Прямой канал

CLAUDE.md §«Связь между сессиями»: /tmp/textmachine-channel, свой блок дописать первым делом, живость адресата — ListAgents. Роли нет, файла нет или имя не отвечает ⇒ КАНАЛА НЕТ, и это НОРМАЛЬНЫЙ случай: сессии подряд НЕ опрашивать, вопрос — секцией в отчёт.

13. Критерий завершённости — по нему тебя примут

Работа завершена, когда: у каждого пункта §4 есть исход (сделано · не делаю с доводом · пинг) · круги самопроверки СОШЛИСЬ — последний не дал НОВЫХ находок · таблица мутаций полная, выжившие названы поимённо · числа сняты ПОСЛЕ последней правки · ряды переведены ТЕМ ЖЕ движением, что и код, и проверено ПРИБОРОМ, а не памятью: зонный стандарт §3 п.8 — грепнуть ОТКРЫТЫЕ строки регистра по СВОИМ ПОЛНЫМ путям (не по именам функций) и назвать каждый ряд, которого твоя правка касается · всё живое в ДЕРЕВЕ, а не в письме · явное «работа завершена, править не планирую». Без последнего пак считается идущим. Пак доводится до конца САМОЙ сессией (слово владельца 11.09): владельца не беспокоить, меня не тегать «просто так» — приёмка идёт последней и вторым кругом тебе не служит.

Деньги

Пак — $0. Платных вызовов движка нет. Упрёшься в «это предъявляется только платным прогоном» — пинг за санкцией, не своё решение.

Отчёт

Зонный журнал platform/docs/platform-PROGRESS.md + переведённые ряды регистра + сообщение мне: что сделано по каждому пункту · чем предъявлено (команда и вывод) · таблица «находка → что сделано → чем предъявлено» · разбор PD-448 с тремя путями и рекомендацией · расхождение канона и дерева по translating отдельным пунктом · что сказал твой адверсариальный проход · секция §10 · что ты сам считаешь слабым местом сделанного. Последний абзац отчёта — план или обещание? Значит работа не кончена: сделай сейчас.