textmachine/docs/COLD_RUN_B_SESSION_PROMPT.md

49 KiB
Raw Blame History

Промт: сквозной пак «ХОЛОДНЫЙ ПРОГОН B — платформа → бэкенд → ФАЙЛ, ВТОРОЙ раз»

Выдан оркестратором №23 (сессия textmachine-11) 11.09. Пак ПЛАТНЫЙ, санкция владельца получена дословно («разрешаю») на прямой вопрос с числами: ждём ≈$0.42, машинный кап ≈$2.5 холда. Носитель санкции — docs/NEAR_TERM_PLAN.md §«Решения владельца, уже полученные».

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

Месяц назад движок умел переводить, но никто не видел, как платформа ведёт настоящую книгу от двери до файла. 11.09 это увидели один раз — прогон A: три главы 蛊真人, 27 платных вызовов, $0.419423, книга дошла до EPUB. Один прогон дал знак, но не величину.

Твой прогон B покупает четыре вещи, которых нет ни у кого, и каждая — не «ещё раз то же самое»:

  1. ДВЕ миграции схемы ни разу не шли на живом прогоне — только в тестах, и база прогона A стоит на schema_version 16. v17wave_selection (backend/internal/store/migrate.go:484): что каждая волна ВИДЕЛА в банке, ось, которой у retrieval_state нет. v18reasoning_in_completion (migrate.go:519), и это НЕ reasoning_tokens: тот лежит в базовой схеме как INTEGER NOT NULL DEFAULT 0 (migrate.go:94) и на DeepSeek равен нулю ПО ПОСТРОЕНИЮ — адаптер намеренно оставляет его нулём и уводит присланное провайдером число в новую колонку (provider_openai.go, ветка ReasoningSubset). Новая колонка НУЛЛАБЕЛЬНА и трёхзначна: NULL — вопрос не задан · 0 — измеренный ноль · >0 — думанье, и DEFAULT 0 не поставлен намеренно, иначе дефект вернулся бы первой же строкой. Приёмка спрашивает ТРЁХЗНАЧНОСТЬ, а не «не ноль».
  2. Прибор консистентности впервые даст числа С ЖИВОГО ПРОГОНА. Сегодня все I1/I2 получены ПОВТОРНЫМ чтением одной и той же сохранённой базы прогона A. Пере-скан не то же, что прогон: он не проходит через запись.
  3. Платформенный пак (идемпотентный резюм, терминальное состояние) проверяется СКВОЗЬ, а не юнитами.
  4. Вторая точка по денежной дыре — но ЧЕСТНО о том, что она даёт. Весь довод «четверть денег купила пустоту» стоит на ОДНОМ прогоне. ⚠ И не обманывайся ссылкой на квирки §3д: там сказано, что парный дизайн ловит эффект ×2.5 за 13 пар, ×2.0 за 22, ×1.4 за 93 — n = 2 этой нормы не выполняет и выполнить не может. ⇒ B покупает не величину, а пре-регистрированный знаменатель и проверку ЗНАКА. Написать в отчёте «25.4 % подтверждено» по двум розыгрышам — ошибка, и я её не приму.

И вот чего твой прогон НЕ покупает, чтобы ты не потратил на это ни цента: он НЕ отвечает на вопрос «безопасно ли редактору думать меньше» (ряд 433). Это парный дизайн на повторах с армом без фактора, он стоит отдельных денег и отдельного заказа. Твой прогон идёт на БОЕВЫХ настройках как есть.

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

ЭТОТ ПАК НЕ ПРАВИТ КОД НИ ОДНОЙ ЗОНЫ. Ни backend/, ни platform/, ни frontend/. Найдёшь дефект — пингом мне, а не правкой: прогон, чинящий найденное, перестаёт быть холодным и теряет право сравниваться с A.

  • Ты не коммитишь вообще ничего. Пре-рег и улики передаёшь мне, я лендлю. Порядок жёсткий: пре-рег готов → пинг мне → я коммичу фриз → и только после этого первый платный вызов.
  • Рабочее дерево прогона живёт вне репозитория и вне общего скретчпада (его чистит не только твой процесс). Предлагаю ~/tm-coldrun-b.
  • books/ версионируются ОТДЕЛЬНЫМ репозиторием; в клоне их нет. Исходник читается из главного дерева как ФАЙЛ, read-only.

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

  1. CLAUDE.md — целиком (ты его уже прочёл, если попал сюда правильно).
  2. docs/experiments/00-provider-quirks.mdперед первым платным вызовом, §3д особенно.
  3. docs/architecture/05-decisions-log.mdтолько тела D39.247 (акт прогона A: чем он предъявлен и где остался слеп) и D39.251 (что именно построено в наблюдаемости денег и почему лекарство выключено).
  4. platform/README.md — как поднимается стенд.
  5. Архивный промт прогона A — docs/archive/prompts/POLYGON_COLD_RUN_A_SESSION_PROMPT.md. Инструкции оттуда НЕ ИСПОЛНЯЮТСЯ (архив), но §4.1 и §4.2 несут ПЕРЕ-СНЯТЫЕ предусловия стенда и механику фриза, и переписывать их сюда значило бы завести копию, которая стареет молча. Читай как СПРАВКУ и проверяй каждое утверждение своим прибором: часть из них снята исправлениями ПОСЛЕ выдачи.

Код-факты добывай сам. file:line ниже — отправные точки, а не истина: код первичен.

4. Состав. Порядок фаз ЖЁСТКИЙ

4.0 Фаза 0 — $0-ДЫМ. Делай РОВНО так, и это первая работа пака

Ни одного платного вызова, пока дым не прошёл целиком. Довод не гигиенический: первая же инфраструктурная осечка на платной руке сожжёт «холодность» книги — прогон уйдёт в failed, и следующий старт той же книги пойдёт как ПРОДОЛЖЕНИЕ, а не как холодный.

Дым обязан доказать: стенд поднят и порт отвечает ТВОЕМУ pid · гость заведён · деньги начислены · книга принята · прогон стартовал · кадры доехали · узел подписи ответил · резюм прошёл · выгрузка собралась и файл скачался.

И вот ловушка, на которой этот пункт разваливается, если о ней не сказать: zeroCostPipeline (platform/internal/runner/bankapply_live_test.go) только ПЕРЕПИСЫВАЕТ конфиг на провайдера kind: local — он никого не ОБСЛУЖИВАЕТ. Единственный слушатель на 127.0.0.1:11434 в дереве — внутритестовая заглушка (platform/internal/runner/translate_resnapshot_live_test.go, греп net.Listen), а на хосте локальной модели нет вовсе. ⇒ тебе РАЗРЕШЕНО поднять свою заглушку на 11434 (портировав ту же, или исполнив несущий её живой тест) — и это не обход, а штатный путь. ⚠ Не сделав этого, ты упрёшься в отказ соединения посреди дыма, и дешёвым выходом станет «дым неприменим, иду за деньгами» — ровно то, ради предотвращения чего §4.0 существует.

Пин фазы 0 — ЗАГРУЗЧИК, а не текстовый скан. Счёт платных слагов в получившемся конфиге оставь КОНТРОЛЬНОЙ величиной (ноль против ненулевого счёта тех же слагов в backend/configs/pipeline-c1.yaml), но сам пин — движок, который этот файл ЗАГРУЗИЛ бесплатным глаголом. Довод замерен и стоил платформенной зоне круга приёмки: её рецепт был «проверен гардом» — сканом имён — и производил файл, который движок отказывается грузить (escalate_to must differ from the primary model, EXIT=10). Имя в конфиге и загружаемый конфиг — разные предметы.

4.1 Предусловия — проверь КАЖДОЕ своим прибором, список от прогона A мог устареть

Известное на 11.09 (справка, не истина): локальной модели на машине НЕТ (ни ollama, ни слушателя на 11434) ⇒ настоящие узлы проходятся только платно · кластер Postgres поднят на -h /tmp -p 55433 -U postgres, ОС-роль ubuntu-26 в нём НЕ заведена · четыре переменные окружения решают, существует ли путь вообще (TM_PLATFORM_EXPORT_FORMATS пуст по умолчанию ⇒ ручки выгрузки не монтируются, и последней трети пути для тебя нет) · epubcheck/java на хосте нет и поставить их нельзя.

АРТЕФАКТ КОНТРАСТА МАЙНИНГА — и здесь я в первой редакции ПЕРЕВЕРНУЛ факт, поймал опровергатель. CheckMiningContrast делает ТОЛЬКО os.Stat (backend/internal/config/pipeline.go:558=func (p *Pipeline) CheckMiningContrast) — никакой sha он не сверяет и удовлетворится фальшивым кандидатом, который лежит рядом на диске (~/tm-p9-work/cfg/contrast-zh.txt, 992 байта). ⇒ sha256 сверяешь ТЫ, руками: рецепт и эталон — docs/experiments/16-bank-mining.md:183 (jieba 0.42.1 dict.txt, 7197c3211ddd98962b036cdf40324d1ea2bfaa12bd028e68faa70111a88e12a8). ⚠ И ловушка имени: в конфигах файл зовётся mining-contrast.zh.txt и резолвится ОТ КАТАЛОГА pipeline.yaml, а источник — jieba_dict_general_zh.txt. Неверный артефакт молча меняет контур банка, то есть портит ровно те числа консистентности, ради которых B и покупается.

ПИН ДО ФРИЗА, дешёвый и обязательный: GET /v0/capabilities показывает НЕПУСТОЙ export_formats. Выгрузка гейтится ТРЕМЯ условиями сразу (platform/internal/config/config.go, греп ExportsEnabled), а не одной переменной, и проба возможностей — единственный дешёвый способ узнать, что выполнены все три, ДО того как двинутся деньги.

Ключи провайдера. Значение TM_PLATFORM_ENGINE_KEYS_PATH даю я по твоему пингу. Нет значения ⇒ СТОП ДО фриза. .env читать запрещено гардрейлом.

4.2 Фриз — делай РОВНО так

Фриз = sha коммита ПЛЮС бинари, собранные из ЛОКАЛЬНОГО КЛОНА (git clone <репо> <путь>). Довод — главное дерево движут параллельные сессии.

Не git worktree. Бинарь из ЛИНКОВАННОГО воркри не несёт VCS-штампа ВООБЩЕ (замер: 24 строки go version -m, из них vcs.* — 0), потому что .git воркри — ФАЙЛ и поиск корня VCS в Go его пропускает. ⇒ правило «отказывать при vcs.modified=true» на таком бинаре выполняется ВСЕГДА и не проверяет ничего. У клона .git — настоящий каталог, и штамп живой. Третье условие отказа обязательно: отсутствие строк vcs.*. Перед сборкой — test ! -e /tmp/.git; GOFLAGS=-buildvcs=false в фриз-сборке ЗАПРЕЩЁН.

⚠ Штамп снимается на КАЖДУЮ попытку, а не один раз: резюм может сменить бинарь под тем же прогоном — сверяй по run_attempts, а не по тому, что лежит на PATH в конце.

ПОРЯДОК ЖЁСТКИЙ, и он важен потому, что пре-рег обязан НАЗЫВАТЬ тот самый sha, который поедет: клон → записал sha и собрал бинари → написал пре-рег, НАЗЫВАЮЩИЙ этот sha → отдал мне → я коммичу → ты сверил, что заландженный пре-рег называет твой sha → и только теперь первый платный вызов.

Что делать, если я молчу. Канал может отсутствовать — это нормальный случай, а не авария. Ждёшь меня до конца своего хода, потом ОСТАНАВЛИВАЕШЬСЯ и пишешь отчёт с готовым пре-регом и пометкой «жду лендинга фриза и значения TM_PLATFORM_ENGINE_KEYS_PATH». Без обоих платная фаза не начинается ни при каких обстоятельствах — и это не формальность: пре-рег, не заландженный ДО денег, перестаёт быть пре-регом.

Что фриз НЕ запрещает: потолки правятся БЕЗ пере-фриза — фриз-гейт смотрит на ПОКУПАЮЩИЙ файл, а не на кассу. Меняется ЧТО покупается или чем судится — новый фриз; меняется СКОЛЬКО тратить — объявление в отчёте. Правка собственного драйвера после фриза — тоже новый фриз.

4.3 Пре-регистрация — главный рубеж пака, и он дороже самого прогона

ЗНАМЕНАТЕЛЬ ПРЕ-РЕГИСТРИРУЕТСЯ ДО ДЕНЕГ, иначе B ответит числом на другой вопрос. B — ЕЩЁ ОДИН одиночный прогон, и две точки распределением не станут. Настоящая ценность B не «вторая точка к 25.4 %», а request_log ВСЕХ единиц прогона ⇒ доля выброшенных первых попыток ПО ЕДИНИЦАМ, а не по вызовам.

Мера задана мной, делай РОВНО так (я снял её на прогоне A своим прибором, числа ниже — твой базис сравнения):

  • единица = (chapter, chunk_idx, stage, role). ⚠ Единица ОХВАТЫВАЕТ попытки и охватывает их намеренно — номера попытки в ключе нет. И знай асимметрию: у стадии terminology все строки прогона A несут chapter = 0, то есть chunk_idx там — индекс майнинг-батча, а не чанк главы. Одно слово «единица» покрывает два разных предмета; называй, какой именно, в каждом числе.
  • знаменатель = единицы, за которые заплачено хоть раз (sum(cost_usd) > 0). ⚠ На прогоне A этот фильтр не отсеял НИЧЕГО (17 единиц всего и 17 платных) — значит его поведение ни разу не проверялось, и на B единица из одних чекпойнтов может появиться впервые. Печатай ОБА счёта.
  • ЧИСЛИТЕЛЬ ПЕРВЫЙ — выброшенная покупка: единицы, где есть хоть одна оплаченная и НЕ принятая попытка (ok = 0 AND cost_usd > 0). Прогон A: 4 из 17 = 23.5 %, тогда как по ВЫЗОВАМ то же событие даёт 4 из 27 = 14.8 %. Две меры расходятся в полтора раза — вот почему мера объявляется заранее.
  • ЧИСЛИТЕЛЬ ВТОРОЙ, и первая редакция этого промта его СЛЕПО ПРОПУСКАЛА (нашёл опровергатель, я пере-снял сам): единицы, за ПРИНЯТЫЙ результат которых заплачено больше одного раза (ok = 1, ячейка куплена дважды). На прогоне A это вся стадия терминологии, пере-купленная на резюме: $0.028742 = 6.9 % цены книги, и мера «выброшенная первая попытка» этого НЕ ВИДИТ вовсе — строки ok = 1. ⚠ Черновик на том же резюме приехал бесплатно (6 строк tm_hit = 1), терминология — нет. Обе доли печатаются отдельно; складывать их в одно «потеряли N %» НЕЛЬЗЯ — это разные беды.

ДВА ПУТИ К ДЕНЕЖНОМУ ЧИСЛУ — и честно о том, чего их совпадение стоит. Путь 1 — по колонке degraded; путь 2 — по ok = 0 AND cost_usd > 0, колонки degraded не касаясь. У меня на A оба дали ровно $0.106472 = 25.4 % цены книги. Но на A они совпадают ПО ПОСТРОЕНИЮ, а не независимо: degraded там принимает ненулевое значение ровно на тех же четырёх строках. ⇒ совпадение на B — слабая улика, а вот РАСХОЖДЕНИЕ — сильная находка: оно означает, что классификатор и признак приёмки разъехались. ⚠ И не путай числа: 25.4 % — доля ДЕНЕГ, 23.5 % — доля ЕДИНИЦ. Это разные величины, и подменять одну другой в отчёте нельзя.

В пре-рег идут также: ожидаемый исход КАЖДОГО шага, написанный ДО прогона · sha256 исходника · sha256 ФАКТИЧЕСКОГО pipeline-YAML (платформа берёт файл ЦЕЛИКОМ, пер-полевого оверрайда нет ⇒ «прогон на c1» без sha — утверждение без носителя) · список глав с units_total · грант, TTL выгрузки.

ПРЕТРЕЙН — И ЭТО ТЕПЕРЬ НЕ ЗАПРЕТ, А ПРОЦЕДУРА (слово владельца 11.09 отменило прежнюю редакцию). 蛊真人 узнаётся моделями 4 из 5. Прежняя редакция этого промта на этом основании запрещала клеймы о качестве вовсе — владелец отменил запрет: он хочет увидеть качество на боевой книге. Но опасность никуда не делась и становится СИЛЬНЕЕ, когда читатель — большая модель: она способна «увидеть» в переводе то, что помнит из претрейна, и не заметить того, чего в переводе нет. ⇒ процедура вместо запрета: каждая находка о качестве обязана нести ДВЕ цитаты рядом — фрагмент ОРИГИНАЛА и фрагмент ПЕРЕВОДА. Находка, которая не может показать место в исходнике, — не находка, а воспоминание.

4.4 Платная фаза

Реши сам и аргументируй: какую книгу и сколько глав брать. Глав немного — слово владельца.

Мой приор, опровергается замером: те же главы 13 той же книги, что и в A. И вот ловушка, которая стоила бы тебе ТРОЙНОГО бюджета, — первая редакция промта в неё попадала. Файл books/gu-zhenren/coldrun-v16/guzhenren-ch1-10.gb18030.txt — это 10 глав, 57838 байт. Прогон A ел не его, а СРЕЗ в 17564 байта, sha256 ed870ba6065ce3eb…, сохранённый как /home/ubuntu-26/tm-coldrun-a/material/guzhenren-ch1-3.gb18030.txt (срез байт-в-байт равен первым 17564 байтам целого файла — проверено мною обеими sha). Интейк главами резать НЕ умеет: загрузишь целый файл — купишь ×3.3 текста против объявленных ≈$0.42. ⇒ режешь файл сам и кладёшь его sha в пре-рег.

ДВА ПОТОЛКА, а не один, и первая редакция называла только платформенный. Холд платформы ≈$2.5 — и движковые потолки в book.yaml: у прогона A стояло book_usd: 1.25, day_usd: 2.50. Прогон остановится на ДВИЖКОВОМ потолке раньше, чем на платформенном, и «упёрся в потолок» будет про число, которого ты не ждал. Назови в пре-реге ОБА и скажи, какой ставишь ты.

A↔B СРАВНИМЫ НЕ ПО КНИГЕ — И ЭТО НАДО ЗАПИСАТЬ ОГРАНИЧЕНИЕМ, А НЕ ЗАМОЛЧАТЬ. Между фризом прогона A (b0f5d89) и сегодняшней головой — 107 коммитов и 52 файла движка (+7678/85), включая stagerun.go, disposition.go, quality.go, httpllm.go, provider_openai.go, requestlog.go и models.yaml, то есть ровно денежный путь. B меряет ДРУГОЙ движок. Одинаковая книга делает сравнимыми ТЕКСТЫ, но не числа денег. ⇒ в пре-рег: sha движка B, число коммитов между ним и A, и прямая строка «двойная оплата могла измениться из-за наших правок, а не из-за провайдера».

Приёмка каждого узла — по ТРЁМ независимым следам (Postgres · диск и systemd · HTTP), не по самоотчёту движка.

Живость длинного прогона проверяется АКТИВНО: не жди финального уведомления — раз в пару часов сверяй рост числа вызовов и трат по леджеру ДВУМЯ чтениями. Зависшая задача от идущей по сигналу завершения неотличима, и у зависания нет цвета.

СЛЕДИ ЗА ЛОГАМИ И ЛОГИКОЙ ЖИВЬЁМ, а не только по итогу (слово владельца 11.09). Прогон — это не «запустил и жди файл»: смотри, что движок пишет, пока он это пишет. Каждое предупреждение, каждый флаг, каждая регенерация, каждый незнакомый finish_reason — читаются ТОГДА, а не в разборе. Вопрос к каждому: согласуется ли поведение с тем, что, по твоему чтению кода, должно было произойти? Расхождение логики и лога — находка, даже если прогон кончился успешно. Веди это списком по ходу: «время · что увидел · чего ожидал · что это значит».

Деньги: ждём ≈$0.42, кап ≈$2.5 холда. Упёрся в потолок — СТОП и пинг мне, не режь молча и не проси подъёма «по проекции»: прогнозный запрос оставляет ложный след «владелец согласился на пере-оплату», которой не было.

4.5 ВЫЧИТКА ВСЕГО ПЕРЕВОДА — отдельным опус-агентом с МИЛЛИОННЫМ контекстом

Это заказ владельца дословно, и это главная качественная работа пака.

Делай РОВНО так в части формы:

  1. Подними отдельного агента на opus (модель задавай ЯВНО) и загрузи ему в контекст ЦЕЛИКОМ: (а) весь получившийся перевод и (б) весь исходный китайский текст тех же глав. Контекст НЕ ЭКОНОМИТЬ — слово владельца: «пусть не экономит контекст, ему должно на всё хватить». Никаких выжимок, никаких «первых N абзацев», никакого пересказа вместо текста. Режешь текст — режешь находки, и молча.
  2. Его мандат — искать МАЖОРЫ, которые жёстко критуют по тексту и его качеству, в ПОРЯДКЕ ПРИОРИТЕТА владельца (он назвал его сам, и порядок несущий):
    1. КОНСИСТЕНТНОСТЬ банка памяти и терминов — один и тот же термин/имя/титул, приехавший в разных местах по-разному; термин, разошедшийся с банком; забытая форма.
    2. ОТСУТСТВИЕ ВЫДУМОК — текст, которого в оригинале НЕТ: дописанные предложения, пояснения от себя, «додуманные» связки, исчезнувшие куски (пропуск — та же выдумка, только с другим знаком).
    3. ХУДОЖЕСТВЕННОСТЬ И ЧИТАЕМОСТЬ получившегося русского текста.
    4. ОТСУТСТВИЕ TRANSLATIONESE — кальки, порядок слов оригинала, «китайский синтаксис русскими словами».
  3. Форма КАЖДОЙ находки — две цитаты рядом: фрагмент ОРИГИНАЛА и фрагмент ПЕРЕВОДА, плюс глава/юнит, плюс какой из четырёх приоритетов нарушен, плюс severity. Находка без цитаты из исходника не принимается — см. абзац о претрейне выше: модель знает эту книгу и способна «вспомнить» то, чего в нашем переводе нет.
  4. Решаешь сам и аргументируешь: сколько таких читателей поднять и как разделить между ними работу (один на всё · по приоритетам · по главам с перекрытием). Мой приор, опровергается доводом: один агент на ВЕСЬ текст сразу — консистентность банка по построению не видна тому, кто читает главу отдельно. Если делишь — объясни, чем компенсируешь потерю сквозного взгляда.

И назови ОТРИЦАТЕЛЬНЫЙ результат тоже: «выдумок не нашёл» — это результат, но только рядом с контрольной величиной («прочитано столько-то знаков перевода против стольких-то знаков оригинала»).

4.6 СВЕРКА ПРИБОРОВ С ВЫЧИТКОЙ — ради этого прогон и стоит своих денег

У движка есть СВОИ приборы качества: детерминированные $0-гейты, отчёт качества, счёт расхождения форм (I1/I2), флаги и колонка degraded, банк памяти и пост-проверка. Все они утверждают что-то о тексте. Твоя работа — спросить, совпадает ли их мнение с тем, что увидел читатель.

Построй таблицу 2×2 и заполни её именами находок:

читатель нашёл читатель не нашёл
прибор сказал подтверждение ложная тревога прибора
прибор смолчал СЛЕПАЯ ПОВЕРХНОСТЬ согласие

Интересны ДВЕ клетки, и левая нижняя — самая дорогая: это дефект, который сегодня уезжает читателю молча. Каждую такую назови отдельно: что именно прошло мимо, какой прибор обязан был это поймать, и почему не поймал — нет механизма, есть но выключен, есть но смотрит не туда.

4.7 КОД, КОТОРЫЙ ОТРАБОТАЛ — читать с оглядкой на получившийся текст

Не ревью движка вообще, а ревью ТОГО ПУТИ, который реально исполнился на этой книге. Порядок обратный обычному: сначала находка в тексте, потом код, который её пропустил.

Назови: какие стадии и гейты реально бежали · какие не бежали и почему · где в коде живёт механизм, отвечающий за каждый найденный мажор. ⚠ Пример связи, которую ждут: читатель нашёл разъехавшийся термин ⇒ читается путь инъекции банка и пост-проверка ⇒ ответ «механизма нет» / «механизм есть, но решает по единице, которой в продукте нет» / «механизм есть и промолчал вот здесь».

Кода НЕ ПРАВИТЬ (§2). Находка = пинг мне со строками.

4.8 ДЁРГАТЬ API ПЛАТФОРМЫ ПО-РАЗНОМУ — не один счастливый путь

Слово владельца: «пусть подёргает по-разному апишку через платформу». Один проход по счастливому пути доказывает, что дверь открывается, и ничего не говорит о том, что за ней.

Решаешь сам, что дёргать; мой приор — не менее шести РАЗНЫХ форм: заказ в главах против заказа в ЗНАКАХ (это разные ветки контракта и разные счётчики) · повтор того же запроса (идемпотентность) · резюм посреди прогона · старт второго прогона при идущем первом · выгрузка во ВСЕХ смонтированных форматах · узел подписи банка · отказные пути (несуществующая книга · нехватка баланса · курсор с мусором).

Ожидаемый исход КАЖДОГО дёрганья пишется ДО него. Иначе это не проверка, а экскурсия: любой ответ двери задним числом выглядит правильным.

4.9 Фаза 3 — $0 после прогона. Состав задан РОВНО так; чем именно предъявлять — решаешь сам

Прибор консистентности по ОТГРУЖЕННОМУ тексту существует и строить его НЕ НАДО — он живёт в backend/internal/pipeline/bookconsistency.go и достаётся как QualityReport().Consistency; печатает его backend/cmd/tmctl/render.go. Снимай I1/I2 с печатаемыми знаменателями (число без знаменателя в этом паке не принимается).

Дальше: выгрузка · структурное чтение EPUB (zip + container.xml + nav; epubcheck на хосте нет, и это законно) · обе новые миграции предъявлены ДАННЫМИ: wave_selection несёт строки ОБЕИХ волн (они выбирают над РАЗНЫМИ банками — черновик над базовым с исключёнными намайненными, редактор над обогащённым), а reasoning_in_completion предъявляется ТРЁХЗНАЧНО: сколько строк NULL, сколько 0, сколько >0. Не гонись за «не нулём»: 0 здесь — законный измеренный ответ, и отличать его от NULL — весь смысл миграции.

4.10 НАХОДКИ ВНЕ ЗАКАЗА — и это отдельный заказ владельца, а не приятный побочный эффект

Слово владельца 11.09: «важно, чтоб она находила проблемы даже там, где мы не ждём». Поэтому здесь стоит вопрос, у которого НЕТ заранее известного ответа, и он задаётся в КАЖДОЙ фазе, а не один раз в конце:

Что в этом прогоне стоит дороже, работает хуже или ведёт себя страннее, чем должно бы, — и о чём НИКТО не спрашивал?

Ради чего вопрос заведён — реальный случай, и он стоил четверти цены книги. Удорожание из-за падающих запросов НА НАШИХ СОБСТВЕННЫХ настройках никто не заказывал искать: просто кто-то посмотрел в леджер без гипотезы и увидел, что 25.4 % денег ушло в выброшенные первые попытки. Ни один тест не был красным, ни один гейт не сработал, в отчёте стояла зелень. Находка такого рода ценнее исполнения заказа, потому что заказанное найдут и без тебя.

Что докладывать (слово владельца, дословно по составу): криты · мажоры · регрессии · баги · жёсткие точки улучшения. Каждое — АРГУМЕНТИРОВАННО: что видел · чем предъявлено (file:line, строка лога, запрос и ответ, число из леджера) · почему это именно крит/мажор, а не вкусовщина · чего это стоит в деньгах, тексте или доверии читателя.

И следи за КОДОМ, а не только за выдачей. Ты читаешь логи и результаты движка — значит у тебя в руках единственная в проекте позиция, с которой видно и поведение, и его причину сразу. Увидел странность в выдаче — иди в код, который её произвёл, и назови место. Увидел в коде путь, который на этой книге НЕ исполнился, хотя должен был, — это тоже находка. Кода не править (§2): находка = пинг мне со строками.

5. Где этот пак мягкий — четыре места, назвал я, веер выбираешь ты

Мандат самопроверки — исполнением, субагенты разрешены явно. Направление:

  1. Сборщик, который молчит, и сборщик, который прочитал ноль, — неотличимы. Засей в стендовую БД заведомо ненулевой банк и заведомо удержанный юнит и потребуй, чтобы сборщики стали КРАСНЫМИ. Не покрасневший на подсадке сборщик в платную фазу НЕ ДОПУСКАЕТСЯ.
  2. Дым меняет ТРИ фактора разом (провайдер + книга + база) ⇒ при провале платной руки он не разделяет причину. Где дёшево — меняй по одному.
  3. Отрицательный замер обязан доказать, что спросил существующее. Рядом с каждым нулём ПЕЧАТАЙ контрольную величину. И помни две ловушки среды: grep здесь — обёртка над ugrep, чтит .gitignore и не видит books/; sqlite3 как CLI на машине НЕТ — только python3 + mode=ro.
  4. Число, выведенное из соседнего поля, не краснеет нигде. Если в строке есть поле, прямо отвечающее на вопрос (номер попытки живёт в trace_id), любой ВЫВОД ответа — по времени, по порядку, по соседству — уже дефект метода, даже когда сходится.

Адверсариальная стойка — то, чем оркестратор судит чужую работу; суди ею свою

Владелец просил передать это прямо. Ниже не правила пака, а СПОСОБ СМОТРЕТЬ, и он ловит то, чего не ловят ни тесты, ни второй круг:

  • Автор и ревьюер — разные роли, даже когда это один ты. Перечтение собственной работы рубежом НЕ считается. Поднимай отдельного читателя, которому НАЗВАНО, где мягко, и не показывай ему свои выводы раньше, чем он прочтёт предмет.
  • Спрашивай у аномалии, о ЧЁМ она — о предмете или о твоём приборе. Вмешательство в замер производит ложные улики, похожие на находки: у прошлой смены запись «непонятный исход» оказалась здоровой, а сломан был цикл того, кто мерил.
  • Верный результат при неверном методе не краснеет нигде. «Сошлось» — не доказательство: сходятся и по счастливому порядку строк. Спрашивай «чем это НАЗВАНО в самой строке?» прежде, чем вычислять.
  • «Не воспроизвелось» — не «недостижимо». Верный прогон при неверной гипотезе неотличим от «дефекта нет». Назови ЦЕПЬ звеньев от входа к следствию и проверь каждое, прежде чем писать «не воспроизводится».
  • Утверждение о молчании вакуумно. «Ошибки не было», «лишнего не купили», «предупреждений нет» — проверяемо только рядом с фикстурой или контролем, где это ОБЯЗАНО было прозвучать.
  • Заимствованное число проверяется не на существование, а на ТУ ЛИ КЛЕТКУ. Та же роль, та же модель, та же стадия, тот же режим? Прошлый пак чуть не включил денежный механизм по замеру из чужой роли.
  • Зелёная батарея плюс полный каталог мутаций сходимостью НЕ являются. Три смены подряд направленный второй читатель находил 6, 7 и 9 настоящих дефектов при полной зелени.
  • И главный вопрос отчёта — не «что не получилось», а «что ты знаешь и не сказала». На прямой вопрос сессия однажды назвала ДВЕНАДЦАТЬ слепых поверхностей своего прибора вместо одной, и две из двенадцати не прозвучали бы без вопроса: одну она видела в собственном выводе и прошла мимо, вторую знала из своего же комментария в коде.

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

Выбери 13 и назови какие: деньги под гонкой · граница «холодности» (что в прогоне перестало быть первым разом) · провенанс каждого числа (чем снято, каким прибором, на какой клетке).

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

Перед первой командой — записка: фазы, что чем предъявляется, где ждёшь осечки. Комплектность против заказа сверяй механически, а не памятью.

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

Каждое число и каждая категорика отчёта идут с командой, которой получены. Приёмка пере-снимает.

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

Первым действием — ≤10 строк СВОИМИ словами: что понял · что считаешь опасным · что считаешь неверным. Дословный пересказ подтверждает канал, но не понимание, и ошибку промта повторяет вместе с ним.

Адрес бери из /tmp/textmachine-channel — блок с role=оркестратор, — а не из этого промта: имя сессии не переживает рестарт окружения, и вписанное сюда имя однажды окажется мёртвым. Перед отправкой сверься с ListAgents: файл переживает смерть сессии, а ListAgents — нет.

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

И вторая её половина, без которой она вырождена: «где прибор слеп и я это знаю» — что невидимо · почему не чинил · чем закрывается. Формулировка прошлой смены, идущая нормой: «в коде названо, в отчёте нет — значит для следующей смены НЕ названо».

И ОТДЕЛЬНОЙ секцией — находки вне заказа (§4.10): криты · мажоры · регрессии · баги · жёсткие точки улучшения, каждая аргументированно и с носителем. ⚠ Эта секция обязана быть непустой ИЛИ нести строку «искал вот так, не нашёл» с перечислением того, где искал: «находок нет» и «не смотрел» в отчёте выглядят одинаково.

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

Конфликт промта с кодом или доками — пинг мне, не интерпретация. И у тебя есть право сказать «этого делать не надо» с аргументом: прошлые три сессии возражали, и в двух случаях правы были они.

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

Механизм — CLAUDE.md §«Связь между сессиями». Впиши свой блок в /tmp/textmachine-channel ПЕРВЫМ действием. Нужной роли нет ⇒ канала нет, и это нормально: НЕ опрашивай сессии подряд.

13. Критерий завершённости

У каждого пункта заказа — исход (сделано · не делаю с доводом · пинг) · круги СОШЛИСЬ (последний не дал НОВЫХ находок) · числа сняты ПОСЛЕ последней правки · всё живое в ДЕРЕВЕ или у меня, а не в письме · явное «работа завершена, править не планирую». Без последнего пак считается идущим.