42 KiB
Пак бэкенда: «ВЫЗОВ, КОТОРЫЙ ОБОРВАЛИ МЫ»
1. Какая проблема и что решит твой результат
Движок отправляет запрос провайдеру, тот принимает его и генерирует — а мы по своему же дедлайну
перестаём ждать и рвём соединение. Провайдер об этом не знает и работу не отменяет. Дальше движок
выбрасывает единственную улику: internal/llm/httpllm.go:409 — data, _ := io.ReadAll(...), ошибка
чтения уходит в _, а обрыв распознаётся по РАЗМЕРУ. Тело, оборванное нашим дедлайном, маленькое ⇒ не
отличимо от целого ⇒ не разбирается как JSON ⇒ объявляется «оплаченным 2xx с нечитаемым телом» и
ретраится (:433 терминален только для >16 МиБ; :365 даёт один повтор).
Цена — один замер и одно наблюдение, и разница между ними важна. docs/experiments/23-editor-tier.md §5: латентности ровно 2×attempt_s,
$0.475893 = 23.8 % цены руки — это САМИ четыре строки; юниты целиком, вместе с их попытками 0, —
$0.689215 = 34.5 %. ⛔ Источник пишет дословно «две законные цифры, и путать их нельзя» и регистрирует
эту путаницу СВОИМ дефектом №11; не повторяй её, называя одно число двумя долями. Живой прогон 08.09: два редакторских вызова,
unexpected end of JSON input, $0.407606 из $1.259217 = 32 % бюджета. ⚠ Что это ИМЕННО таймауты —
не измерено, а выведено по совпадению подписи с замером выше: сырого леджера того прогона в дереве нет
(.db новее 07.09 — 0 при 163). Не опирайся на второе число как на улику класса.
Корень — НЕ транспорт, а дедлайн против оси регенерации. DeepSeek держит 75–76 tok/s (n=139). Грант
редактора 16 000 ≈ 213 с; реген удваивает его до 32 000 ≈ 427 с и НЕ трогает время, а attempt_s
равен 240. Потолок по времени 17–21 тыс. токенов; максимум, когда-либо доставленный регеном, — 19 354 =
60 % гранта, и 13 доставок из 17 уложились бы в исходные 16 000. ⇒ ось эскалации сегодня фиктивна:
резервация бронирует недостижимое и съедает headroom под книжным потолком (строка 369).
Что покупает твой результат. (1) Мы перестаём покупать одну генерацию дважды. (2) Оператор и читатель видят, какие деньги — оценка, а не факт. (3) Эскалация становится настоящей: правильный дедлайн делает выданный бюджет достижимым.
2. Зона и git
Зона записи — backend/ плюс своя секция в docs/PROGRESS.md (это ЕДИНСТВЕННОЕ исключение из
«docs/ — зона оркестратора»). Чужие зоны (platform/, frontend/, eval/, books/) не трогаешь ни
строкой; расхождения — пингом. Ты НЕ коммитишь: дерево готовишь и передаёшь на лендинг. Никаких
git add -A, reset --hard, переписывания истории. .env не читать никогда.
3. Карта чтения — ЗАКОН, дальше только по её ссылкам
docs/BACKLOG.md— строки (⚠ «строка N» здесь — ID в первой колонке, а не номер строки файла:sed -n '360p'даст пустоту, греп^| 360 |— нужный ряд) 360 (несёт СОШЕДШУЮСЯ конструкцию лечения целиком), 369 (ось эскалации), 78 (движковая половинаPD-441: публикация оценочных строк). Греп^| 360 |.docs/experiments/00-provider-quirks.md— канон велит читать ПЕРЕД правкой адаптеров и вызовов. ⚠ Класса, который ты чинишь, там НЕТ (замер:early-200/«empty lines»/«10 minutes» — 0 хитов) — это пробел, и он пингом полигону, не твоя правка.docs/research/21-llm-transport-survey.md— §Q6 и ЭРРАТА ОРКЕСТРАТОРА 08.09 в шапке: обзор неверен дважды, и обе половины вместе полтора месяца держали неверный дедлайн. Читай эррату ПЕРЕД §Q6.docs/architecture/15-money-path.md— денежный путь; леджер есть НИЖНЯЯ граница.backend/cmd/tmmutate/main.go— шапка целиком (контракт мутационного инструмента) +backend/Makefile, целиbatteryиmutations.
Ратифицированное, нужное по существу, вложено сюда и похода в журнал решений НЕ требует:
- ⛔
D39.230п.1 — СЛОВО ВЛАДЕЛЬЦА, и у него есть УСЛОВИЕ. Оценка за оборванный нами вызов списывается с читателя. Но пометка — часть решения, а не украшение: строка обязана нести свой класс и флагestimated=1, а счёт и сумма оценочных строк — публиковаться машинно-читаемо рядом сcommitted_usd. Списать с человека непроверенную оценку без видимой пометки — НЕ то, на что дано слово. D39.230п.2 — платная проба вендорского баланса ОТКЛОНЕНА владельцем. ⇒ вопрос «биллит ли вендор оборванное» осознанно ОТКРЫТ; оценка есть верхняя граница под гипотезой «вендор досчитывает». Проб не проектировать и не предлагать.D39.230п.3 — ожидание провайдера до ~20 минут РАЗРЕШЕНО. Сверху не убьёт ничто:RuntimeMaxSec/WatchdogSec— 0 хитов при 16 файлах с systemd-свойствами, у движка дедлайна нет.D39.216— где форма не тянет, её развязывают или переписывают; «дешевле подпереть» доводом НЕ является; второй носитель одного знания не заводится (п.3б).D39.183— запрет править тесты «чтобы прошло» про МОТИВ; правка от ЗАКАЗАННОЙ смены поведения — обслуживание, но объявляется отдельным пунктом отчёта.D39.202— прибор, честно отвечающий на СВОЙ вопрос, читается как ответ на другой. Ноль и «не смотрели» неразличимы без контрольной величины.
4. Состав и разметка свободы
4.1 Признак: граница денег — ДОСТАВКА запроса, а не статус-строка — делай РОВНО так
⛔ Доктрина «2xx ⇒ провайдер уже списал» (httpllm.go:428, stagerun.go:610) ЛОЖНА для нашего боевого
провайдера. DeepSeek документирует ранний 200 с пустыми строками, пока запрос ждёт планирования, и
закрытие соединения, если инференс не начался за 10 минут; в наших логах пустое тело при 200 видно буквально
(response="\n", 8 строк из 617 «llm exchange» под books/gu-zhenren/ — счёт мой). ⚠ Но НЕ бери эту строку как
улику self-cut: она пришла на 91-й секунде при дедлайне 240 — ушли не мы. Настоящие self-cut в том же
файле лежат ровно на 240.0 с — четыре трейса в probe-4axes/logs/p7-off.log ⚠ (счёт опровергателя
приёмки, оркестратором НЕ пере-снят; пере-сними сама, если будешь на них опираться). Разница и есть предмет
пака: одна подпись, два разных класса, и различает их только признак §4.1. ⇒ 200 значит «принят», не «сгенерирован», и ветвь No 2xx ever arrived
на DeepSeek недостижима по построению — все наши обрывы прятались под decode_error.
Единственный факт, общий для всех этих случаев: запрос ДОСТАВЛЕН, и ушли МЫ. Он фиксируется без байта
на проводе — httptrace.ClientTrace{WroteRequest, GotFirstResponseByte} в attempt(). Различение
проверено исполнением на клиенте той же сборки:
| случай | WroteRequest |
GotFirstResponseByte |
|---|---|---|
| доставлен, заголовки держат, наш дедлайн | true |
false |
| TLS-рукопожатие висит — НЕ доставлен | false |
false |
ранний 200 + "\n", наш дедлайн |
true |
true |
Заказ: (а) ошибка ReadAll больше не выбрасывается; (б) заводится типизированная
AttemptTimeoutError{Delivered, AfterHeaders, BytesRead, WhitespaceOnly, Elapsed}; (в) исходы —
перечислены ниже поимённо, свой набор не собирай. ⛔ Обёртывание обязано СОХРАНИТЬ
errors.Is(err, context.Canceled) для кодов выхода — иначе стоп прогона получит чужой exit-код.
ПОСЛЕ 2xx — пять исходов:
| исход | признак | вызовов | деньги | чанк |
|---|---|---|---|---|
| целое, JSON ок | readErr == nil |
1 | usage | как есть |
| целое, JSON битый | readErr == nil, разбор упал |
2 (кап 1, как сегодня) | оценка | флаг |
| self-cut | readErr != nil, дедлайн attemptCtx, родитель ЖИВ |
1 | settleUSDForCutCall |
флаг; резюм — 0 вызовов |
| отмена РОДИТЕЛЕМ (стоп, Ctrl-C) | readErr != nil, ctx.Err() != nil |
1 | settleUSDForCutCall |
⛔ своя причина cancelled, НЕ общий флаг «нужен человек»; резюм — 1 вызов на ТОМ ЖЕ бюджете |
| разрыв соединения | readErr != nil иначе (ErrUnexpectedEOF, h2 stream) |
2 | settleUSDForCutCall |
на исчерпании — инфра-пауза, НЕ флаг |
ДО заголовков — четыре: self-cut доставленный (1 вызов, флаг, резюм 0) · отмена родителем
доставленного (1, деньги те же, резюм 1 на том же бюджете) · разрыв после доставки (2, деньги те же,
инфра-пауза, резюм 1) · НЕ доставлен (до max_attempts, $0, освобождение резерва, резюм 1 — это
первая покупка, а не перекупка).
⚠ TestBilledDecodeErrorReBillCap не меняется — у него readErr == nil, это второй исход таблицы.
4.2 Диспозиция: не ретраить то, что оборвали мы — делай РОВНО так
- Доставлен + наш дедлайн (с заголовками и без) — класс
attempt_timeout, чекпойнт + флаг, БЕЗ ретрая, сумма — черезsettleUSDForCutCall. - НЕ доставлен (дедлайн до
WroteRequest) — единственный случай, где «ничего не куплено» верно по построению: остаётся как сегодня (retryable, на исчерпании освобождение резерва, инфра-пауза). - ⛔ ОТМЕНА РОДИТЕЛЕМ доставленного вызова (стоп прогона, Ctrl-C) — это тот самый случай, с которого
начался заказ (строка 331), и диспозиция у него ДРУГАЯ. Деньги — та же
settleUSDForCutCall(ровно то, что проситPD-441— по-русски: «сеттлить оценку и при отмене вызова, который успел уйти, различая по ФАКТУ ухода»), но чанк получает СВОЮ причинуcancelled, а не общий флаг «нужен человек»: вызов был здоров, остановил его ЧЕЛОВЕК. ⛔ Это НЕ «флага нет». Дыры без пометки не должно быть ни в один момент: пока прогон не резюмирован, диспозиция чанка неok, и экспорт показываетflagged(cancelled)— читается как «остановлено, резюм пере-сделает», а не как «нужен человек». Флаг, врущий о ПРИЧИНЕ, запрещён отдельно (D39.93п.2); невидимая дыра запрещена тем более. ⛔ И резюм обязан пере-делать его на ТОМ ЖЕmax_tokens—maxTokensForAttemptудваивает бюджет по оси попыток (disposition.go:393-401,base << uint(attempt); петля берёт его из НОМЕРА попытки,stagerun.go:147), и здесь это ловушка: удвоение купит вдвое больший вызов за здоровье, которого никто не терял. ⛔⛔ КАК это построить — задано, потому что наивный путь НЕВОЗМОЖЕН, и это проверено. В сторе ровно три функции (Reserve,Release,SettleWithCheckpoint), деньги нельзя записать БЕЗ чекпойнта, а чекпойнт — ключ резюма (ON CONFLICT (request_hash) DO NOTHING⇒ «Duplicate settle: book no new spend»). ⇒ «заплатить и пере-сделать на том же ключе» несовместимо по построению. Развязка — в ПЕТЛЕ, а не в сторе: индекс попытки и счётчик УДВОЕНИЙ разводятся.maxTokens = base << escalations, гдеescalationsрастёт только наlength/empty; кап регенерации считает УДВОЕНИЯ, а не индекс. Тогда попытка N+1 берёт тот же бюджет, но НОВЫЙ хеш (Attempt— самостоятельное измерение) ⇒ свежиеreserve → call → settle,ON CONFLICTнедостижим, инвариантcommitted == sum(checkpoints)цел, стор не тронут. ⛔ Стор и его инварианты не трогать — упрёшься, это пинг. ⚠ И проверь побочное:priceprojection.goсчитает проекцию черезmaxTokensForAttempt(«RETRIES ARE IN IT, AND THAT IS THE POINT») — смена оси двигает СМЕТУ. Двинулась — назови в отчёте числом. ⚠ Видимое следствие, назови его в отчёте: стоп прогона теперь ПЛАТИТ оценку за каждый летящий вызов (в редакторской волне это до восьми × ~$0.13). Слово владельца это покрывает («оборванный НАМИ» — мы рвём по его команде), но молча вводить это нельзя. - Разрыв соединения ПОСЛЕ доставки — один ретрай (кап ключуется на «доставлен», а не на «2xx»), на
исчерпании инфра-пауза, не флаг: серия таких — мёртвый провайдер, и довод нулевой ветви про
флаг-шторм здесь верен. ⛔ Но деньги назвать обязательно, иначе граница течёт через эту дверь:
сегодняшний инфра-путь зовёт
releaseReservationи даёт $0, а запрос был ДОСТАВЛЕН ⇒ идётsettleUSDForCutCall+ классconnection_lost, и ТОЛЬКО потом пауза; резюм пере-делает на том же бюджете. Для post-header разрыва это сегодняшнее число, для pre-header — новое, и объявляется заказанной сменой поведения. ⚠ Довод против «оставить ретрай, он же 3 раза из 7 спасал»: правильный дедлайн даёт то же самое без монетки по цене полного счёта. Клапан на будущее — ДАННЫЕ (tok_s_floor), не код.
4.3 ⛔ ТРЕТЬЯ УТЕЧКА, которой нет даже в строке 331 — делай РОВНО так
Сегодняшняя нулевая ветвь (stagerun.go:634) зовёт releaseReservation и чекпойнта НЕ пишет, ставя
стадию failed ⇒ резюм ПОКУПАЕТ ВЫЗОВ ЗАНОВО. Убрать ретрай и оставить это значит закрыть класс
наполовину: тот же платный вызов уходит другой дверью.
Заказ: доставленный self-cut получает чекпойнт, и резюм его находит. Предъявление именно этим: тест
утверждает, что после self-cut резюм на том же снапшоте не делает НИ ОДНОГО HTTP-вызова. Мутация:
убрать запись чекпойнта — тест обязан покраснеть текстом про свежий вызов, а не про деньги.
4.4 Дедлайн считается от бюджета — делай РОВНО так по форме, числа реши сам и обоснуй
timeouts получает tok_s_floor, queue_slack_s, attempt_max_s; дедлайн вызова =
clamp(queue_slack_s + max_tokens/tok_s_floor, attempt_s, attempt_max_s), считается в attempt() из
maxTokens запроса. attempt_s становится ПОЛОМ ⇒ ни один существующий конфиг не теряет времени.
Дефолт пола — 35.5 tok/s (128 000/час, единственное опубликованное вендором число).
⭐ Почему этот дефолт правильный, и это же твой тест: он ПРОИЗВОДНЫЙ, и на черновике (8 496 токенов)
даёт 238.95 с — сегодняшние 240 с точностью до секунды. То есть нынешнее значение верно ровно для
черновика и было перенесено на редактора слепо. ⛔ Тест-тождество обязан пинить ФОРМУЛУ, а не число, и вот операционная форма — иначе его исполнят
формально. assert derive(8496) == 238.95 негоден: это литерал, произведённый формулой, и через полгода
его «починят» под круглые 240. Требуется: ожидание вычисляется в тесте из двух вендорских констант
(час, 128 000) и гранта; литералов 238/239/240/900 в тест-файле НЕТ — предъяви грепом с
контрольной величиной; не меньше ДВУХ грантов (8 496 и 32 000); отношение удвоения
derive(2N) − slack == 2·(derive(N) − slack); края clamp; пустое и нулевое поле дают ДЕФОЛТ, а не
деление на ноль и не нулевой дедлайн.
Твоё — ЧИСЛА. Моё — ПРАВИЛО их вывода, и оно РОВНО так:
tok_s_floor— НИЖЕ p10 наблюдаемой скорости модели по ≥100 строкамrequest_log, округление вниз объявлено (DeepSeek: p10 ≈ 67 ⇒ 50);queue_slack_s— документированное ВЕНДОРОМ максимальное ожидание до инференса (DeepSeek — 600). ⛔ Меньше — только с доводом и ПИНГОМ: владелец сказал «готов ждать» именно про ~20 минут, и меньший слак меняет принятый им размен молча, в другую сторону;attempt_max_s— слак + максимальный грант С УДВОЕНИЕМ / пол, округлённый вверх (DeepSeek: 600 + 32000/50 = 1240). ⛔ И два механизма, без которых «новый провайдер без правки Go» не работает: WARN на старте для провайдера БЕЗtok_s_floor, чей стадийный грант с учётом удвоения выше ~8.5k («дефолт 35.5, дедлайн для 32 000 = 900 с, задай после первого прогона»), и валидационный тестmodels.yaml, ТРЕБУЮЩИЙ поле для таких провайдеров. ⚠ Снапшот не двигается, и проверено это ПРЯМО, а не соседством:buildSnapshotID(internal/pipeline/snapshot.go) перечисляет входы поимённо, и таймаутов среди них нет — читай сам список, а не грепай близость слов. ⛔ Прежняя редакция этого пака писала «AttemptS— 0 хитов из 120 файлов соsnapshot»: замер был неверен в ЧИСЛИТЕЛЕ (хит 1 —config/models.go) и в ЗНАМЕНАТЕЛЕ (файлов 145), а вывод верен — правый вердикт по неправой причине,D39.202. Если твоя правка список входов меняет — СТОП и пинг: перекупка книг словом владельца не покрыта.
4.5 Пометка — УСЛОВИЕ решения владельца — делай РОВНО так
Класс attempt_timeout и estimated=1 едут в чекпойнт и request_log; classify() узнаёт класс на
резюме; paidtail включает его в LostUSD. И сверх того — то, ради чего дано слово: счёт и сумма
оценочных строк публикуются машинно-читаемо рядом с committed_usd (D39.230 п.1; это же движковая
половина PD-441, строка 78). ⚠ Поверхность назови точно: это тот JSON, который ЧИТАЕТ платформа
(tmctl status --json), а не новый файл. Формат — пингом платформе, не решением за неё. ⚠ Сегодня флаг estimated виден только человеку в tmctl render.go;
платформа его не читает — ей нужно число, а не строка экрана.
4.6 Оператор не должен принимать ожидание за висяк — реши сам, бери если по пути
С разрешённым ожиданием до ~20 минут INFO-лог говорит «calling model» и потом молчит. Дешёвая строка «жду
провайдера: прошло X из Y» раз в N минут снимает это. ⚠ И назови в отчёте, что waitForSettle теперь ждёт
до самого длинного летящего вызова — это принятая цена решения владельца, но она должна быть названной.
4.6-бис Мандат чистоты — делай РОВНО так
Пак ПРОЕКТИРУЕТ: новый тип ошибки, три новых поля конфига, новая денежная семантика. ⇒ D39.216 действует
буквой: где нынешняя форма не выдерживает заказ, её развязывают или переписывают, а не обкладывают
заплатой; «дешевле подпереть» доводом НЕ является; второй носитель одного знания не заводится (п.3б).
Отступление законно, но объявляется С ЦЕНОЙ: почему заплата дешевле развязки и что именно она откладывает.
⚠ Нота требует этой строки в КАЖДОМ паке с проектированием и называет её отсутствие дефектом промта — она
здесь не для полноты.
4.7 Чего в паке НЕТ — не делай, и это ОБЪЯВЛЕННЫЕ сужения
- Стриминг — не спас бы ни одно из 19 замеренных событий; цена:
stream:trueв теле ⇒RequestHash⇒ перекупка книги, непроверенная байт-идентичность склейки, новый парсер, потеря usage-fidelity. Trip-wire обзора переписан: доля self-cut в спенде редактора ПОСЛЕ починки дедлайна. - Платная проба вендорского баланса — ОТКЛОНЕНА владельцем (
D39.230п.2). Не проектировать. - Адаптивный пол из леджера на лету — прячет число от оператора, тащит состояние прогона в дедлайн.
max_attemptsи бэкофф — другая ось, не трогать.- Порог по латентности («≈2×attempt_s») — совпадение; протухнет молча при смене
attempt_s. - Idle-timeout в non-streaming — схлопывается в общий бюджет (§Q6 прав).
- Разбор обрывков тела.
- Оценка по времени
elapsed × rate— догадка на догадке; оправдана только исходом пробы, которой не будет. - Денежная сумма как YAML-ручка — политику нельзя переключать молча конфигом; она за одной функцией.
- Строка 368 (
est_tokensзанижена в 5 раз) — отдельный носитель, другой предмет. Наткнёшься — наблюдением в отчёт, не чини: два денежных класса в одном лендинге мы сегодня уже разводили. - Anthropic-адаптер (
provider_anthropic.go) — ВНЕ пака целиком: поверхность deprecated (из стека убрана 04.07), боевой цены ноль, а тесты и мутации она бы добавила. Уходит строкой бэклога.
5. Мандат самопроверки ИСПОЛНЕНИЕМ — «перечитал сам» не считается
- Каждая гарантия предъявляется ИСПОЛНЕНИЕМ на фейк-сервере, а не чтением. Пять исходов после 2xx и
четыре до заголовков — ДЕВЯТЬ фикстур, и у каждой утверждается ЧИСЛО HTTP-вызовов, а не только исход.
⛔ Счёт вызовов берётся у ФЕЙК-СЕРВЕРА (сколько запросов он принял), а не счётчиком клиента: клиент
считает свои намерения, сервер — факты.
⛔⛔ И к КАЖДОЙ доставленной-и-потерянной фикстуре — ПАРНОЕ утверждение о РЕЗЮМЕ, иначе конструкция
вырождается в противоположную сторону: сессия может «пере-закрыть» — не пере-делывать НИЧЕГО
доставленного — и остаться зелёной. Ожидания: self-cut → резюм 0 вызовов; отмена родителем и
исчерпанный разрыв → ровно 1 вызов на ТОМ ЖЕ
max_tokens; не доставлен → 1. ⛔ Поля утверждаются ДВУСТОРОННЕ, иначе они декоративны:WhitespaceOnly—trueна теле"\n"иfalseна обрывке JSON;Delivered— обе стороны. И денежное утверждение на каждой строке:estimated=1,cost_usd == estimate, класс на месте; у «не доставлен» —reserved_usdвернулся в 0. - Мутации — на копии, рецепт УЖЕ в цели
mutations(backend/Makefile); своего однострочника не пиши. Краснота читается ПО ТЕКСТУ падения: говорит ли он про сломанное тобой. - Мутируй и СВОИ новые фикстуры. ⛔ Особая осторожность: у тебя условные сообщения (пометка
estimated, WARN про пол провайдера) — на каждое нужна фикстура, где оно ОБЯЗАНО прозвучать, И вторая, где обязано молчать. Тест, утверждающий только молчание, вакуумен. - Субагенты РАЗРЕШЕНЫ ЯВНО — и на охват, и на адверсариальный проход по ГОТОВОЙ работе.
⛔ Направление — что уязвимо ИМЕННО в этом паке (норма куплена замером 08.09: направленный проход
нашёл шесть дефектов пака на ЗЕЛЁНОЙ батарее): (1) фикстуры, где «доставлен» и «не доставлен»
случайно совпали — весь пак стоит на этом различении; (2) путь резюма: чекпойнт написан, но
classify()его не узнаёт ⇒ перекупка возвращается тихо; (3)errors.Is(context.Canceled)после твоего обёртывания — коды выхода ломаются молча, И одновременноerrors.Asобязан НАХОДИТЬ твой тип: два утверждения в одной фикстуре, не в разных; (4) исход «отмена родителем» — его легко потерять, потому что он единственный, где деньги списываются, а флага НЕТ. - Проверяемый артефакт — таблица «находка → что сделано → ЧЕМ ПРЕДЪЯВЛЕНО» плюс столбец «закрыт в N носителях из M», где M посчитан командой.
- BASELINE НА ВХОДЕ сними САМ и сверь с моим:
make battery→ 19ok· 0 FAIL · 4 «no test files» · 4 скипа;make mutations→ 65 записей · 0 выживших · свип0 of 276;python3 docs/scripts/counts.py --check→ «Литералы сходятся». ⛔ Печатай счёт СКИПОВ рядом с числомok— норма куплена 08.09: «20 пакетов ok» и «20 ok при 431 скипе» неразличимы, и приёмка так приняла механизм, ни разу его не коснувшись. Красное на входе — находка и пинг, а не твоя работа.
6. Оси ревью — характер «Код», плюс деньги и шов (ось вправе заменить с аргументом)
Тест утверждает не то, что думает (D39.171): часы как способ синхронизации там, где предмет НЕ время, и
ассерт по подстроке в общем буфере. Обе формы дают и ложное красное, и тихо-зелёное — оно дороже.
Деньги: любое число из СЫРОГО леджера, а не из агрегата; леджер — нижняя граница.
Шов: платформа биллит пользователю committed_usd и просила у движка публикацию оценочных строк
(PD-441). Инвентарь её каналов — чтением ЧУЖОГО кода, не по памяти; правок в platform/ НЕ делать.
Индустриальный первоисточник прежде велосипеда: httptrace — stdlib; если решишь иначе, отвергни с доводом.
7. Записка-план ДО работы
До первой правки — короткая записка в свою секцию журнала: что берёшь, в каком порядке, что считаешь рискованным. После работы — сверка комплектности против §4 МЕХАНИЧЕСКИ (таблицей), не перечитыванием.
8. Заявление = команда
⛔ Эрудиция НЕ улика: утверждение о коде, провайдере или чужой зоне грунтуется file:line, цитатой или
замером — либо несёт пометку «мнение». Каждое число и категорика — с командой, которой получены. Отрицательный замер печатается ВМЕСТЕ с
контрольной величиной. Сверх этого: перед отчётом сверь каждый клейм с результатом инструмента ЭТОЙ
сессии, а не с памятью и не с этим промтом — адреса §4 сняты 08.09 и могли уехать. Последний абзац
отчёта оказался планом или обещанием? сделай это СЕЙЧАС. ⛔ Править тест/гейт, чтобы он прошёл, —
НЕДОПУСТИМО; исключение — правка от ЗАКАЗАННОЙ смены поведения, и она объявляется отдельным пунктом.
Сессия длинная — поставь себе интервальную самоверификацию субагентом против ЯВНЫХ критериев §13.
9. Эхо-протокол старта
ДО работы — ≤10 строк СВОИМИ словами: скоуп · инварианты · что НЕ делаешь. Дословный пересказ промта подтверждает канал, но не понимание, и ошибку промта повторяет вместе с ним. Эхо — оркестратору по адресу из прямого канала (§12); канала нет — эхо первой секцией отчёта, работа продолжается.
10. Что НЕ удалось — обязательная секция отчёта
Что не вышло, что не проверено, где сомневаешься. «Не проверено» и «опровергнуто» — РАЗНЫЕ исходы.
11. Канал вопросов и право сказать «этого делать не надо»
Конфликт промта с кодом или доками — пинг, а не интерпретация: конструкция этого пака сошлась в консилиуме двух моделей, но её проверяли чтением, а не твоим прогоном. Считаешь пункт неверным — скажи с доводом, довод сильнее моей подписи. Решение владельца требуется, если работа упрётся в перекупку книг, в скоуп или в продукт.
12. Прямой канал
Механизм — CLAUDE.md §«Связь между сессиями». Впиши СВОЙ блок в /tmp/textmachine-channel первым делом,
чужие блоки не трогай. ⚠ Адрес из файла не доказывает, что сессия жива: сверься с ListAgents. Нужной роли
нет или имя не отвечает ⇒ канала нет, и это НОРМАЛЬНЫЙ случай: НЕ опрашивай сессии подряд — вопрос
секцией в отчёт, работа продолжается.
13. Критерий завершённости — по нему тебя примут
Работу доводишь до конца САМ; приёмка идёт последней и вторым кругом твоей самопроверки не служит. Готово — это когда:
- у КАЖДОГО пункта §4 есть исход: сделано · не делаю с доводом · пинг;
- круги СОШЛИСЬ: последний проход не дал НОВЫХ находок, прежние закрыты таблицей;
- каждый класс закрыт со ЗНАМЕНАТЕЛЕМ «N из M», и M посчитан командой;
- ДЕВЯТЬ фикстур §5.1 существуют, утверждают ЧИСЛО вызовов у СЕРВЕРА и несут ПАРНОЕ утверждение о резюме; пин резюма (§4.3) предъявлен мутацией; поля утверждены двусторонне;
- тест-тождество §4.4 пинит формулу, а не константу;
- числа сняты ПОСЛЕ последней правки, со счётом скипов рядом с числом
ok; - таблица мутаций ПОЛНАЯ, и выжившие названы поимённо (выжившая мутация — находка, а не шум);
- дифф
^func Testснят ИСПОЛНЕНИЕМ, а не памятью, и назван прибор, которым считан; - всё живое — в ДЕРЕВЕ, а не в письме;
- сказано явно: «работа завершена, править не планирую». Без этой фразы пак считается идущим.
Деньги
Пак $0. Платных вызовов провайдерам НОЛЬ: все девять исходов предъявляются на httptest-сервере,
формула дедлайна — арифметикой, резюм — фикстурой. ⛔ Платная проба вендорского баланса ОТКЛОНЕНА
владельцем (D39.230 п.2) — не проектировать и не предлагать. Кажется, что нужен платный прогон, — это
стоп и пинг, а не вызов.
Отчёт
Своя секция в docs/PROGRESS.md: исход по каждому пункту §4 · таблица «находка → что сделано → чем
предъявлено» · столбец «закрыт в N из M» · числа со счётом скипов · заказанные смены поведения отдельными
пунктами · пинги (квирк-реестр — полигону; публикация оценочных строк — платформе) · §10 «что не удалось» ·
вопросы оркестратору.