textmachine/docs/BACKEND_MONEY_HONESTY_SESSION_PROMPT.md

33 KiB
Raw Blame History

Промт: бэкенд-пак «ДЕНЬГИ И ЧЕСТНОСТЬ ВЫДАЧИ» — по следам первого платного прогона

Выдан оркестратором №21. Заказ владельца после холодного прогона v16. Пак $0: платных вызовов НЕ содержит. Всё, что здесь есть, чинится и проверяется без покупки. ⚠ Состав собран не из бэклога подряд, а из того, что ПЕРВЫЙ ПЛАТНЫЙ ПРОГОН предъявил живьём.

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

31.08 движок впервые за месяц перевёл книгу за настоящие деньги. Прогон ответил «да» на главный вопрос — переводит и отдаёт файл, предохранители работают. И он же показал, что денежные и отчётные поверхности местами ЛГУТ или СЛЕПЫ, причём каждый раз молча.

Пять вещей, увиденных на живых данных, а не в тестах:

  • самая крупная денежная статья — оплаченный ХВОСТ НЕУДАЧ: $0.123161 = 28.2% захода (11 строк ok=0 AND cost_usd>0), больше эскалации;
  • четверть денег захода ($0.103305 = 23.7%) ушла в эскалацию, у которой есть документированная альтернатива в 7.6× дешевле, выключенная по умолчанию;
  • фаза классификатора напечатала свою смету рядом со своим бюджетом, увидела, что не влезает, и всё равно стартовала — оборвалась, 3 батча из 4 не куплены, работа оплачена;
  • build при сбое уборки вернул бы exit 1, когда файлы УЖЕ на диске, и не напечатал бы отчёт (⚠ выведено из кода; живьём эта ветка НЕ сработала и не проверена);
  • снапшот-гард назвал причиной правку конфига, которой не было;
  • остановка по объёму не отличима от «что-то тихо сломалось» по коду выхода.

Твой результат — конвейер, который про деньги и про сделанную работу говорит правду: не молчит, не называет ложных причин и не платит за то, что по построению не может закончиться.

Пак НЕ про качество перевода и НЕ про калибровку ставки. Числа прогона — проекция на n=3, ими ничего не калибруют (D39.165 ⛔г).

1. Состав — два яруса, и смешивать их НЕЛЬЗЯ

Механическая причина деления. Снапшот стадии фолдит Model · PromptVersion · PromptSHA256 · Temperature · Reasoning (backend/internal/pipeline/snapshot.go:290=Reasoning string). Правка любого из них ⇒ --resnapshotпере-оплата уже купленной работы. Денежные бюджеты гейтов туда НЕ входят (они проходят как wiring). Строка бэклога 182 велит копить снапшот-движущие правки и вносить ОДНИМ касанием.

Этот пак — ТОЛЬКО ярус A. Ничего снапшот-движущего он не трогает.

Ярус A — твой. Порядок ранжирован по цене рычага, а не по дешевизне.

A0. Оплаченный ХВОСТ НЕУДАЧ не виден ни на одной $0-поверхности — а он крупнейшая статья. Замер прогона: 11 строк ok=0 AND cost_usd>0 = $0.123161 = 28.2% захода, больше эскалации. Крупнейшая единичная потеря — один edit-юнит, оплаченный ДВАЖДЫ: первая попытка упёрлась в finish=length, 16000 выходных токенов оплачено и выброшено. Ни status, ни report этой оси не показывают: деньги видны итогом, а НЕ разложением «за что заплачено впустую». Делай: дать хвост на $0-поверхности тремя срезами (ретраи attempt>0 · эскалационные хопы escalation=1оба в checkpoints, у которой НЕТ book_id, связь через JOIN jobs j ON c.job_id = j.id; и ok=0 AND cost_usd>0 · estimated=1оба в request_log). ⚠ Форма — твоё решение с аргументом: поле status --json, секция report, или оба. ⚠ Лечение самой причины (потолок вывода, finish=length) — СНАПШОТ-ДВИЖУЩЕЕ ⇒ ярус B. Здесь — только ВИДИМОСТЬ.

A1. Эхо идёт СРАЗУ в эскалацию, потому что дешёвая ручка выключена по умолчанию. RegenerateEchoBeforeEscalate (backend/internal/config/pipeline.go:170=regenerate_echo_before_escalate, читается backend/internal/pipeline/stagerun.go:139) — opt-in, дефолт 0 = «escalate straight away», и не задан НИ в одном шиппинг-конфиге. Замер прогона: 5 эхо → 5 хопов на deepseek-v4-pro = $0.103305 = 23.7% захода. Комментарий рядом с самой ручкой говорит, почему это дорого зря: эхо у flash 0731 стохастично на вызов (побайтно одинаковые запросы дают эхо/не-эхо, D39.61), и ре-ген восстанавливает ≈7.6× дешевле хопа. Делай: реши, какой дефолт правильный, и обоснуй замером/квирками, а не вкусом. ⚠ Снапшот правка НЕ двигает — проверено оркестратором, гейта здесь нет: Retries в backend/internal/pipeline/snapshot.go не встречается ни разу (grep -c Retries = 0). ⚠ Настоящий вопрос обратный и он твой: ре-ген не фолдится осознанно, значит два прогона с разным числом ре-генов дают ОДИН снапшот и внешне неразличимы. Скажи, честно ли это; предложишь носитель числа ре-генов в отчёте — хорошо, но саму свёртку не трогай: она снапшот-движущая ⇒ ярус B.

A2. Фаза стартует, зная, что не влезает в собственный бюджет. backend/internal/pipeline/terminologist.go:702=estimate before any call печатает estimate_usd и budget_usd РЯДОМ; следующий оператор — проверка ошибки ЧТЕНИЯ бюджета, а сравнения нет. Улика — ОДИН трейс, ce5990b3…: estimate_usd=0.048924 budget_usd=0.02 → фаза стартовала → оборвалась строкой budget would be exceeded by the next batch … spent_usd=0.009188 … batches_left=3. ⚠ Числа снимай САМА из books/gu-zhenren/coldrun-v16/logs/ (только чтение). spent_usd=0.009188 процитировано дословно; накопленное это или трата ЭТОГО прохода — пере-выведи, я не проверял.

И ГЛАВНОЕ, из-за чего наивный предикат недопустим: в том же прогоне есть КОНТРПРИМЕР. Трейс f6bb59d4… дал estimate_usd=0.024239 budget_usd=0.02 — тоже «смета больше бюджета» — и завершился. Смета сознательно консервативна (верхняя граница). ⇒ Предикат «смета > бюджета ⇒ отказать» отказал бы работе, которая влезает. Это опровержение моей первой формулировки, и я её снимаю.

Делай: фаза не смеет обрываться на середине, оставив оплаченную частичную работу. Форма — твоё решение с аргументом, и вот границы:

  • усечение плана до влезающего — приор оркестратора, ложных отказов не даёт;
  • пропуск фазы с явной строкой — допустимо;
  • отказ классом Refusal ЗАПРЕЩЁН. Фаза идёт ВНУТРИ bank-mining-стопа, то есть ПОСЛЕ оплаченной черновой волны, а платформа читает полосу 1019 дословно как «nothing reached a provider, nothing was spent» (platform/internal/ingest/exit.go, греп nothing was spent). Отказ этим классом сделает движок лжецом о деньгах.

Стопгапа по числам НЕТ, и это проверено: classify_budget_usd и gates.terminology.* не существуют НИ В ОДНОМ файле backend/, а escalation.budget_usd в шиппинг-конфигах стоит 0 НАМЕРЕННО — это выключатель, а не протухшее число. Реальные носители лежат в КНИЖНЫХ конфигах вне твоей зоны. ⇒ в этом паке — только механизм; числа — пинг.

A3. build лжёт кодом выхода, и book_files обещает файлы, которых нет. (а) После коммита файлов build удаляет копии незапрошенных форматов (backend/internal/pipeline/bookbuild.go:372=os.Remove(r.bookFilePath(f))); сбой возвращается голой ошибкой ⇒ exit 1 при новых файлах УЖЕ на диске и БЕЗ BuildReport. По контракту полосы читатель решит «инфра-сбой, файлов нет» и спишет прогон. (б) build --format epub молча удаляет соседний .book.txt (набор рядом с БД всегда от ОДНОЙ сборки) — предъявлено живьём, exit 0, — а status --json ПОСЛЕ этого продолжал печатать путь удалённого файла в book_files. ⚠ Формулировка «в ту же секунду» СНЯТА: одномоментного снимка не делалось, наблюдение — листингом (отчёт прогона §6 п.3). Делай: (а) — чинить: сбой уборки не смеет выглядеть как «ничего не записано». (б) — ⚠ это НЕ обязательно дефект движка: book_files документирован как карта МЕСТ. Реши сам и аргументируй: либо движок публикует только существующее, либо это строка КОНТРАКТА («потребитель не вправе выводить существование из наличия пути») и тогда — пинг оркестратору, а не правка. Платформа это читает.

A4. Снапшот-гард называет причину, которой не было. backend/internal/pipeline/stagerun.go:55=the config/prompts changed. Прогон: конфиг и промпты не тронуты ни байтом, снапшот двинул выросший авто-банк (движок сам предупреждал об этом WARN'ом раньше). Сообщение отправляет следующую сессию искать правку, которой не существует. Делай: назвать НАСТОЯЩУЮ причину сдвига или перестать называть её вовсе. Причина выводима: снапшот знает, какое поле разошлось.

A5. Остановка по объёму неотличима по коду выхода — и это факт ШВА. Прогон: --max-units 3 + один флагнутый чанк ⇒ exit 2, а не 0: ветка errors.As(err, &flagged) стоит раньше (backend/cmd/tmctl/main.go, греп refusalExit, тело exitCode). Объёмный стоп своего кода не имеет вовсе — он едет РЕЗУЛЬТАТОМ, не ошибкой. То есть «я купил столько и всё» и «что-то тихо сломалось» для потребителя кодов машинно неразличимы; различает только строка VOLUME CEILING:. ⚠ Платформа читает КОДЫ ВЫХОДА и поток events.jsonl; отчёт translate ей не виден вовсе. Новый код выхода — слово в ратифицированный словарь, пинг, а не решение сессии. ⇒ Этот пункт — ПИНГ С ДОМАШНЕЙ ЗАГОТОВКОЙ. Твоя работа: перечислить машинные носители признака, которые СУЩЕСТВУЮТ (кандидаты: словарь Finished.Outcomebackend/internal/runevents/, греп Outcome; полоса кодов; кадры потока), сказать про каждый, ратифицирован ли он и достаёт ли до платформы, и предложить ОДИН с доводом. Правку вносит следующий пак после ратификации.

A6. Строка 238 — деньги слепы к правке исходника НА МЕСТЕ. backend/internal/pipeline/rebill.go:123=func (r *Runner) projectRebill( сверяет content-hash строки только в bank-only ветке со сдвинутым снапшотом; при ТОМ ЖЕ снапшоте строка идёт как «$0 resume» без сверки ⇒ translate перекупает юниты без предупреждения в смете. Подтверждено обеими половинами. Единственный видимый след — INFO manifest: the stored manifest is stale. Делай: диспозиция строки — «адресный фикс + посадка-тест»; форма свободна с аргументом. ⚠ Репро строишь СВОЕЙ фикстурой: прогон эту пробу сознательно НЕ запускал (правка исходника закрывала его платную часть навсегда); ближайший носитель — «2 units re-bought» финального ревью пака D39.175 п.5.

A7. Строка 239 — checkWave статуса не видит исчезнувшую из конфига стадию. У экспорта правило есть (backend/internal/pipeline/export.go:367=func (r *Runner) exportConfigDrift(), у статуса — нет (backend/internal/pipeline/status.go:693=checkWave := func(snaps map[string]bool). Прогон воспроизвёл дословно: status говорит config_drift=false, export на ТОМ ЖЕ конфиге — true. Делай: перенести правило + посадка.

A8. prompt_version не отслеживает байты промпта. Деньги защищены — PromptSHA256 фолдится в снапшот; СРАВНИМОСТЬ прогонов по метке — нет. Прогон чуть не построил каузальный вывод на сравнении со стендом, у которого при неизменной метке v3-discourse-reflow промпт правился 01.08. Делай: реши форму и аргументируй. ⚠ Из трёх форм две снапшот-нейтральны — гейт при расхождении метки и хеша · явный носитель рядом с меткой; третья, метка производная от хеша, СНАПШОТ-ДВИЖУЩАЯ (PromptVersion — снапшотное поле) ⇒ она ярус B и в этом паке НЕ делается. Это про честность СРАВНЕНИЙ.

Про перелёт суб-бюджета эскалации, чтобы ты не завела его дефектом: прогон предъявил на живых деньгах бюджет $0.08 против факта $0.103305, перелёт +29.1%. Это НЕ дефект и НЕ твой пункт: пре-хоп-гейт делает read-then-act, и перелёт ≤1 хопа ратифицирован и задокументирован. Трогать механизм — пинг. Названо здесь только чтобы ты не потратила на него проход.

A9A11 — по остатку ресурса, в этом порядке: строка 233 (трата терминолога масштабируется КНИГОЙ, а не грантом: покупка одного юнита ≈1.5× стоимости юнита) · строка 194 (деньги банковых ролей вне контура согласия) · строка 232 (ось «свежий/пере-делка» из ПОЛНОТЫ СТРОК, а не из факта отгрузки: добавление стадии превращает дочитанную книгу в «N units NEVER delivered» и приглашает купить её снова — backend/internal/pipeline/volume.go:121=LeftFresh is undelivered units). ⚠ Строка 232 ТРЕБУЕТ от промта назвать развилку, и я называю: ключ анонса несёт ВОЛНУ, значит «юнит отгружен» — факт per-wave, и отгружающей считается волна, владеющая ПОСЛЕДНЕЙ стадией; при другом выборе черновой-только конвейер получил бы остаток не там. Решение твоё, с аргументом.

Строка бэклога 197 (фикс-лист ФЧ-1…ФЧ-8, вес «скоро — следующее касание денежного пути») в пак НЕ взята сознательно: она про НЕПРИБИТЫЕ гарантии уже построенного, а этот пак — про поверхности, которые лгут. Возьмёшь хвостом ресурса — не возражаю, но после A9A11.

Ярус B — НЕ ТВОЙ, назван, чтобы ты не взяла его попутно

Рычаг эффорта редактора (stages[edit].reasoning: "off""low") двигает снапшот и ждёт контролируемой пробы. Не трогай. Вендор-факт для контекста: DeepSeek 13.08.2026 дал pro три уровня low/high/max (Change Log + таблица guides/thinking_mode, сверено оркестратором 31.08); наш носитель протух на 18 суток. Прогон ехал вендор-дефолтом high, потому что конфиг слал "off", а ReasoningNone шлёт low|medium|high и молчит только на off (backend/internal/llm/capability.go:52=ReasoningNone is the OpenAI-compat baseline).

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

Пишешь: backend/ + свою секцию «Бэкенд» в docs/PROGRESS.md — краткий итог сессии туда ОБЯЗАТЕЛЕН, это единственное исключение канона (CLAUDE.md §«Роли сессий и зоны»), и туда же идут пинги A3(б) и A5. Не пишешь: platform/, frontend/, eval/, books/, остальное в docs/.

  • Ты НЕ коммитишь. Лендит оркестратор.
  • НИКОГДА: git add -A · git add . · git commit -a · reset --hard · checkout поверх грязного дерева · перезапись истории · git stash (стек общий с другими сессиями).
  • В дереве могут лежать чужие незакоммиченные правки — не трогать.
  • Каталог books/ — СИМЛИНК в соседний чекаут с ОТДЕЛЬНЫМ git-репозиторием. find без -L даёт ложный ноль; sqlite3 без ?mode=ro открывает базу НА ЗАПИСЬ и удаляет отслеживаемые -wal/-shm. Любое чтение чужой базы — только sqlite3 'file:<путь>?mode=ro'.
  • ⚠ Улика прогона: books/gu-zhenren/coldrun-v16/ — читать можно и нужно, менять нельзя.

3. Карта чтения — ЗАКОН, пять позиций

  1. docs/experiments/00-provider-quirks.md — эхо-мина, стохастичность эха, цены и ручки. Несущее для A1. ⚠ Факт о провайдере правится ТОЛЬКО пробой или вендор-докой, с датой и способом в самой формулировке.
  2. docs/architecture/15-money-path.md §2 «Деньги ДВИЖКА» — леджер, оба потолка, суб-бюджеты. Якоря пере-проверены 31.08, им можно верить.
  3. docs/architecture/17-seam-inbound-law.md — п.7 (мутирующий глагол сначала даёт проекцию, потом мутирует) несёт A2; коды выхода читает платформа — это A5.
  4. backend/README.md — волны, стадии, чанкование, артефакты.
  5. Отчёт прогонаbooks/gu-zhenren/coldrun-v16/REPORT.md. Твоя фактура: живые логи, числа с отметками момента, дословные строки движка. ⚠ Читай его ВМЕСТЕ с шапкой pipeline.yaml того же каталога: шапка несёт вендор-факт, ставший ложным 13.08, и НЕ правится намеренно — это конфиг, которым куплен прогон, правка задним числом фальсифицировала бы улику.

Остальное — код первичен, достаёшь сама грепом.

4. Разметка свободы

Делай РОВНО так (отступление = пинг, не интерпретация):

  • A1 гейтится твоим же вердиктом о снапшоте. Двигает — пункт уезжает в ярус B, в паке НЕ делается;
  • новый код выхода не заводится — полоса ратифицирована, это пинг оркестратору (A5);
  • правка/удаление теста, голдена или гейта ради зелени — НЕДОПУСТИМА. Несогласие с тестом — пинг, не правка;
  • make battery в backend/ — гейт зоны; скипы называть ВСЛУХ, не молча;
  • каждая правка получает посадку (мутация, которую она ловит), а не только зелёный тест;
  • ничего снапшот-движущего. Пятёрка Model · PromptVersion · PromptSHA256 · Temperature · Reasoning — самые частые оси, а НЕ определение: снапшот фолдит порядка тридцати, включая версии правил (ClassifierVersion, StyleCheckVersion…), и комментарии там прямо велят бампать версию при правке правила. Определение одно: снапшот-движущее = всё, что попадает в payload buildSnapshotID (backend/internal/pipeline/snapshot.go, греп func.*buildSnapshotID). ⇒ Гейт машинный, а не память: сними snapshot ID на фикстуре ДО и ПОСЛЕ своего диффа и предъяви равенство. Это дешевле любого списка и не протухает.

Решаешь сама и аргументируешь: форма отказа в A2 · форма признака в A5 · движок против контракта в A3(б) · форма гейта метки в A8 · порядок и глубина A9A11 по остатку ресурса · что из A9A11 не влезло (скажи прямо, не растягивай).

5. Оси предъявления

Каждый пункт получает вердикт предъявлено / не предъявлено / опровергнуто. Три исхода, не два.

Для A1A5 предъявление означает: посадка, которая КРАСНЕЕТ адресно (падает целевой тест, а не батарея вообще) — и она сажается на состояние ДО твоей правки, иначе она проверяет саму себя. Для A6/A7 — воспроизведение дефекта из отчёта прогона до правки и его молчание после. ⚠ У A2 отдельная ось: никакая частичная работа не должна быть оплачена при отказе — покажи это на фикстуре, а не рассуждением. ⚠ D39.171, и пак попадает в неё лбом: A2, A4 и A5 все трогают ТЕКСТ сообщений, а ассерт по подстроке в общем лог-буфере даёт ТИХО-ЗЕЛЁНОЕ. Посадка на сообщение обязана предъявить, что она краснеет при подмене ИМЕННО этой строки. ⚠ Оси выше — приор оркестратора, не потолок: считаешь, что уязвимо другое, — замени с доводом и скажи об этом в отчёте.

6. Мандат самопроверки ИСПОЛНЕНИЕМ

Самоотчёт «проверено» без исполнения регулярно оказывается ложным.

Тебе ЯВНО разрешены субагенты. Модель задавай ИМЕНЕМ и знай, сколько их работает. По умолчанию для трудного суждения — Fable 5; веер под предмет выбираешь ты.

  1. Записка-план ДО первой правки — что берёшь, в каком порядке, чем докажешь каждое. Вердикт по снапшоту для A1 — первым пунктом.
  2. Дифф ^func Test — ИСПОЛНЕНИЕМ, не памятью.
  3. make battery целиком перед сдачей; скипы вслух.
  4. Собственные адверсариальные посадки ВНЕ списка этого промта — не меньше трёх. Промт написан оркестратором, который сегодня трижды ошибся в фактуре; считай его приором, а не истиной.
  5. Адверсариальный проход по СВОЕЙ ГОТОВОЙ работе ПЕРЕД сдачей. Субагент получает твой отчёт, твои команды и мандат «найди, где она выдаёт непроверенное за проверенное». Артефакт — секция отчёта: какой моделью, сколько агентов, что дано на вход, КАЖДАЯ находка дословно + твоя диспозиция. Ноль находок — тоже запись, но тогда назови, что проверялось и чем. ⚠ Уязвимо здесь прежде всего: клеймы «посадка красная адресно» · утверждения о снапшоте · утверждение, что частичная работа не оплачена · любое число, взятое из отчёта прогона, а не пере-снятое тобой.
  6. Перед отчётом сверь КАЖДЫЙ клейм с результатом инструмента ЭТОЙ сессии.
  7. Последний абзац отчёта — план или обещание? Сделай сейчас.
  8. Интервальная сверка с заказом на каждой естественной границе: «что предъявлено / что ещё нет», и хотя бы одну отдай субагенту с явными критериями §5.

7. Записка-план и комплектность

Записка-план до первой правки (§6.1). Перед сдачей — механическая сверка отчёта против §1 по пунктам: каждый A получает вердикт §5. Пункт, который ты решила не брать, — решение с доводом, а не молчание. ⚠ Где всё живёт: записка-план и отчёт — ФАЙЛОМ в репозитории (при лендинге оркестратор уносит их в docs/archive/reports/); краткий итог сессии — секцией «Бэкенд» в docs/PROGRESS.md. /tmp умирает с окружением: что должно пережить рестарт, туда не кладётся.

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

Каждое число и каждая категорика — С КОМАНДОЙ, которой получены. Приёмка пере-ранит выборочно. Клейм о рантайме без живого прогона = PLAUSIBLE, и так помечается. ⚠ Числа прогона (23.7% · $0.103305 · 16 термов) — чужие: либо пере-сними их сама из coldrun-v16 read-only, либо помечай «со слов прогона».

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

ДО первой правки — ≤10 строк: скоуп / инварианты / чего не делаешь. Первым действием по каналу §12.

10. Obstacle reporting

Обязательная секция: что НЕ удалось и что НЕ проверено. Пустая секция при непустой работе — дефект отчёта. Ты вправе сказать «этого делать не надо» с аргументом — это поощряется.

11. Канал вопросов

Конфликт промта с кодом ⇒ пинг, НЕ интерпретация. Код первичен: промт мог устареть, и его автор сегодня уже трижды ошибался в фактуре. Mid-flight правки доезжают ТОЛЬКО релеем — владелец пере-передаёт, ты эхо-подтверждаешь, и это отдельный пункт отчёта.

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

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