textmachine/docs/BACKEND_BOUGHT_MEANS_DELIVERED_SESSION_PROMPT.md

20 KiB
Raw Blame History

Бэкенд-пак: КУПЛЕНО — ЗНАЧИТ ДОСТАВЛЕНО. Юнит, который не доделается НИКОГДА

Выдан оркестратором №23 (сессия textmachine-11) 11.09. Пак $0 — платных вызовов в нём нет. Предмет решён владельцем 05.09 (D39.204); ты строишь решённое, а не выбираешь между вариантами.

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

Читатель заплатил за главу. Движок купил первую попытку, получил флагуемый результат, пошёл за второй — и вторую ему не продали: потолок книги или дня не вмещает удвоенный бюджет регенерации (maxTokensForAttempt удваивает на каждой, значит попытка 1 резервирует вдвое больше попытки 0).

Дальше происходит вот что, и это проверяется одной строкой: backend/internal/pipeline/stagerun.go:204=infra failure; the cancelled-position mark — ЛЮБАЯ ошибка попытки уходит наверх из цикла, РАНЬШЕ UpsertChunkStatus.

Следствия два, и оба стоят денег читателя:

  1. Юнит не доделается НИКОГДА. Чекпойнт попытки 0 есть (реплей за $0), строки chunk_status НЕТ ⇒ читающие модели видят юнит как pending, экспорт не отдаёт ничего. Каждый резюм реплеит попытку 0 за $0 и умирает на попытке 1. Прогон уходит exit 4 при ПОЛНОСТЬЮ доставленных купленных юнитах.
  2. Волну нельзя продолжить без ДЫРЫ в непрерывном префиксе — то есть за это платят и соседние юниты, которые в бюджет влезали (разброс резервов внутри волны замерен ×2.976).

Решение владельца (D39.204, и оно НЕ обсуждается): отказ резервации на РЕТРАЕ деградирует во ФЛАГ, причина которого ОТЛИЧНА от исчерпания регенераций; текст попытки 0 оплачен и отгружается; волна идёт дальше. Вариант «минимальная покупка ≥ step_max_usd» СНЯТ владельцем — он стоил бы покупателю входного порога в пять глав. Не реализуй его и не предлагай.

И канон здесь сильнее, чем кажется: D2 п.2 уже ТРЕБУЕТ тегировать flag_reason. Значит новая причина — не добавка к контракту, а его ИСПОЛНЕНИЕ. (Ссылка «смена D2.3», гулявшая по бэклогу, неверна дважды: D2 и так кончается флагом, а D2.3 — про детектор вырождения перед удвоением.)

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

  • Зона — backend/, и только она. platform/ не трогать: её половина едет ОТДЕЛЬНЫМ промтом, но ОДНИМ АКТОМ с твоим (см. §4.3).
  • Ты не коммитишь. Готовое дерево передаёшь мне, я лендлю. git add -A запрещён каноном.
  • Свою секцию итогов пиши в docs/PROGRESS.md — это единственное исключение из «docs/ — зона оркестратора». Чужие незакоммиченные файлы в дереве не трогай.

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

  1. CLAUDE.md — целиком.
  2. Тело D39.204 в docs/architecture/05-decisions-log.md (решение владельца) и D2 п.2 — он в закрытой эре, тело в docs/archive/architecture/05-decisions-D1-D38.md, греп ^## D2\.. ⚠ Подномер собственного тела не имеет: D2.3 — это ПУНКТ 3 тела D2.
  3. Ряд 291 в docs/BACKLOG.md — там весь разбор, включая опровергнутую посылку прошлого оркестратора: «ретрай оставляет ФЛАГОВАННЫЙ юнит» — ЛОЖЬ, зона опровергла по строкам. Не наступи второй раз.
  4. backend/internal/pipeline/stagerun.go (цикл попыток и runAttempt), escalation.go (errReserveCeiling и кто на нём УЖЕ деградирует), disposition.go (словарь FlagReason).
  5. docs/architecture/12-go-style-notes.md — нормативы стиля, только больные места.

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

4. Состав

4.1 Деградация — делай РОВНО так в ЧАСТИ РЕШЕНИЯ, сам решай КАК

Ровно так (решено владельцем, отступление = пинг):

  • отказ резервации на попытке ≥1 при существующем оплаченном результате попытки 0 ⇒ флаг, а не ошибка наверх;
  • у флага СВОЯ причина, отличная от исчерпания регенераций: читатель и оператор обязаны отличать «мы перепробовали всё» от «денег не хватило на вторую попытку»;
  • текст попытки 0 отгружается;
  • волна идёт дальше.

Решаешь сам и аргументируешь: имя причины · где именно ставится деградация (в цикле runStage или внутри runAttemptу обоих есть довод, назови свой) · как при этом НЕ тронуть попытку 0: её отказ по-прежнему ОСТАНАВЛИВАЕТ книгу, это ратифицировано и менять нельзя (stagerun.go, греп mandatory).

Гипотеза, которую надо ПРОВЕРИТЬ, а не принять: деградация сама по себе закрывает и следствие (2) — у юнита появляется статус, значит дыры в непрерывном префиксе нет. Похоже на правду; предъяви замером.

4.2 Пин, ради которого пак существует

«Купленное доставлено ⇒ не exit 4». Прогон, где каждый купленный юнит доставлен, а один из них доставлен ФЛАГОВАННЫМ из-за нехватки денег на ретрай, обязан кончиться успехом, а не кодом 4.

И пин на саму незаклиниваемость: после такого прогона резюм не делает НИ ОДНОГО свежего платного вызова по этому юниту и не умирает. Сегодня он умирает вечно.

4.3 Платформенная половина — твоё дело назвать, не построить

Карта заметок платформы РУКОПИСНАЯ (platform/internal/ingest/notes.go) и уезжает независимо от словаря движка. Цена несделанного замерена: PD-246 — минор 0.10.0 сутки жил ЛОЖНЫМ на проводе, причина доезжала читателю как unspecified, и поймала это зона своей пере-проверкой ПОСЛЕ слов оркестратора «приёмка закончена».

отдельным пунктом отчёта назови мне: точное значение новой причины на проводе · что платформа обязана записать прогону, который кончился флагом вместо exit 4 · какой её пин это стережёт. Я передам это платформенной сессии, и акт будет один на две половины.

4.4 Приложение — фикстура, краснеющая по УДАЧЕ (ряд 379(б))

Отдельная, маленькая и не связанная с §4.1 работа; делай её ПОСЛЕ основной.

Запись каталога CUTCALL-a-refusal-pays-when-the-reply-outruns-the-write стережёт самую дорогую половину денежного бита delivered() (backend/internal/llm/attemptcut.go:189=answered && t.firstByte.Load()). Замер оркестратора 11.09: на чистом дереве пин TestARefusalIsNotAPurchaseEvenWhenTheReplyOutrunsTheWrite даёт 8 зелёных из 8, на своей посадке — 7 КРАСНЫХ ИЗ 8, один ЗЕЛЁНЫЙ. Текст падения верный и про предмет; дыра в ФИКСТУРЕ: она шлёт ~6 МБ тела, сервер читает строку запроса, отвечает 401 и рвёт связь SetLinger(0) — и успеет ли транспорт записать GotFirstResponseByte раньше, чем Do вернёт ошибку записи, решает гонка, а не построение. ⇒ прежние RED этой записи были удачей.

Задача: перестроить фикстуру так, чтобы приход байта ответа был НЕИЗБЕЖЕН до обрыва, и предъявить 8 из 8 красных на посадке при 8 из 8 зелёных на дереве. Способ выбираешь сам.

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

Мандат самопроверки — исполнением; субагенты разрешены явно. Адверсариальный проход по СВОЕЙ ГОТОВОЙ работе обязателен.

  1. Пин, утверждающий только молчание, вакуумен ровно там, где сообщение ложно. «Ошибка не вышла наверх» — утверждение о молчании. Фикстура обязана быть такой, где новая причина ОБЯЗАНА прозвучать, и тест утверждает её ИМЯ.
  2. Фикстура обязана сделать отказ резервации НЕИЗБЕЖНЫМ на попытке ≥1 и НЕВОЗМОЖНЫМ на попытке 0. Денежный пин, флейковый на мутанте, измеряет пустой сценарий: у нас уже был пин, дававший 2 красных из 8, потому что деньги были ВЕРОЯТНЫ, а не неизбежны. Гоняй свой не один раз.
  3. Посадка обязана бить в тот же слой, что стережёт пин. За прошлый пак мутация трижды оказалась не про то: недостижимое условие в фикстуре · не собирающаяся посадка (НЕизмеренная — хуже выжившей) · код против гейта над данными.
  4. Новая причина — факт ПРОВОДА, а не словаря. Тест, проверяющий только, что константа добавлена в FlagReason, не доказывает, что читатель её увидит. Скажи, чем предъявлена дорога от флага до отчёта/экспорта.

⚠ И общее, стоившее трёх смен подряд: зелёная батарея плюс полный мутационный каталог сходимостью НЕ являются. В последних трёх паках направленный второй читатель находил 6, 7 и 9 дефектов при полной зелени.

Адверсариальная стойка — способ смотреть, не правило пака

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

Находки ВНЕ заказа — отдельный заказ владельца

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

Докладывай отдельной секцией: криты · мажоры · регрессии · баги · жёсткие точки улучшения — каждое аргументированно, с носителем (file:line, число, команда) и с ценой в деньгах, тексте или доверии читателя. ⚠ Секция обязана быть непустой ИЛИ нести строку «искал вот так, не нашёл» с перечислением мест: «находок нет» и «не смотрел» в отчёте выглядят одинаково.

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

Выбери 13 и назови какие. Мой приор: деньги под гонкой · терминальное состояние прогона (что видит платформа и что видит человек) · обратная совместимость словаря причин.

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

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

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

Каждое число и каждая категорика отчёта — с командой, которой получены. Дифф ^func Testисполнением, не памятью. Приёмка пере-снимает.

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

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

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

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

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

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

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

Тесты и гейты под зелень не подгонять. Правка, вызванная ЗАКАЗАННОЙ сменой поведения, — обслуживание, и протухший тест держать не нужно; но она ОБЪЯВЛЯЕТСЯ в отчёте: что изменилось, какой тест это описывал, куда уехала гарантия.

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

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

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

У каждого пункта заказа — исход (сделано · не делаю с доводом · пинг) · круги СОШЛИСЬ (последний не дал НОВЫХ находок; прежние закрыты таблицей «находка → что сделано → ЧЕМ ПРЕДЪЯВЛЕНО») · таблица мутаций полная, выжившие названы, и КАЖДАЯ новая запись помечена battery (прошлый пак этого не сделал, и его «21/21 RED» оказался разовым прогоном смены, а не гейтом проекта) · числа сняты ПОСЛЕ последней правки · всё живое в ДЕРЕВЕ, а не в письме · явное «работа завершена, править не планирую». Без последнего пак считается идущим.