textmachine/docs/archive/prompts/BACKEND_ENGINE_KNOWS_SESSION_PROMPT.md

41 KiB
Raw Blame History

ОТРАБОТАН И ПРИНЯТ С ДВУМЯ ДОФИКСАМИ 08.09 — акт D39.228, лендинг 2b6f1f4 (21 путь). Инструкции ниже НЕ исполняются: пак закрыт. Исход: закрыты 355 · 357 · 358, а у 253 и 312 — только ДВИЖКОВАЯ половина (испр. 08.09: акт объявил их закрытыми целиком, платформенные половины живы); приёмкой заказана ТРЕТЬЯ смена поведения (лог и экран перестали спорить о полноте банка); ратифицировано, что аддитивное поле манифеста ключ не двигает, но обязано быть отличимо от своего нуля. Не взятое получило носители — строки 362 (ремонт против ремонта) и 363 (текстовый сайдкар молчит о неполноте); строка 360 объявлена исключением поимённо и ждёт слова владельца.

Пак бэкенда: «ДВИЖОК УЖЕ ЗНАЕТ — ДОВЕЗИ ДО ЧИТАТЕЛЯ»

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

Движок вычисляет правду и пишет её себе в лог, а тот, кто по этой правде принимает решение — владелец на экране подписи банка и оператор, читающий траты, — смотрит в другое место. Это один класс, а не три случая, и он сегодня стоит дороже всего остального в очереди.

  • Полнота банка. internal/pipeline/terminologist.go:99-103=ClassifyBatchesDropped int считает Consolidated · Declined · Unanswered · BatchesDropped · ClassifyBatchesDropped; :582 предупреждает — «this bank is PARTIALLY consolidated — a budget cut a pass». В Log. А носитель, который читает платформа и с которого строится экран подписи, — internal/pipeline/bankexport.go (BankExport: bank_version, book_id, total, signed, as_of, run_id, terms, proposed) — полей полноты не несёт вовсе. Наблюдение платформы за живым потоком 04.09 (H10/H11, строка 199): консолидировано 38, не спрошено ни разу 47, срезано бюджетом 5. Владелец подписал бы такой банк как полный.
  • Деньги. internal/pipeline/waverun.go:218=res.TotalUSD += r.lastTerminology.CostUSD складывает в итог волны только CostUSD рендер-паса; ClassifyCostUSD (terminologist.go:145) в TOTAL (this run) не попадает. А разложение «за что заплачено» относит классификатор в superseded, потому что обе банк-роли адресуются ОДНИМ именем стадии и делят позицию {глава, чанк, стадия}. Замер прогона 08.09 по строкам леджера: терминологическая фаза стоила $0.013608 — классификатор $0.009013 плюс два рендер-батча $0.002775 и $0.001820; в итог волны входит только рендерная половина, а разложение печатает $0.004595 (2) — ровно два последних. Оператор читает о своих деньгах два числа, не сходящиеся с сырым леджером — ровно тогда, когда решает, продолжать ли платить.

Что покупает твой результат. (1) Владелец видит на подписи, что банк неполон, ДО того как подписал. (2) Числа отчёта сходятся с леджером. (3) Ни один байт снапшота, хеша запроса, ключа манифеста и версии встроенных данных не двигается — пак $0 и ничего не перекупает.

2. Зона и git

Зона записи — backend/ плюс свой подзаголовок в секции «Бэкенд» docs/PROGRESS.md. Чужие зоны (platform/, frontend/, eval/, books/) не трогаешь ни строкой; docs/ кроме своей секции — тоже. Ты НЕ коммитишь: дерево готовишь и передаёшь оркестратору (канон — CLAUDE.md §«Git-координация мультисессий»). Никаких git add -A, reset --hard, переписывания истории. ⚠ Заведи подзаголовок #### Пак «движок уже знает» внутри секции «Бэкенд» и пиши только под ним: файл коммичу я, и чужой текст уедет под моим сообщением. .env не читать никогда.

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

  1. docs/BACKLOG.md — строки 253 (обе половины) · 357 · 358 · 355 · 312. Греп ^| 253 |. Строка — носитель заказа; расхождение строки с этим промтом — пинг, не интерпретация.
  2. docs/architecture/18-bank-ontology.mdнормативная страница банковых проекций: три правила дисциплины проекции и два класса дефектов. Ты добавляешь поля в проекцию банка ⇒ читаешь ДО работы. ⚠ Там же эррата 07.09 про класс A, заведённый сознательно.
  3. docs/architecture/15-money-path.md — денежный путь: что чем считается и где леджер есть нижняя граница.
  4. docs/architecture/12-go-style-notes.md — норматив формы («least mechanism», размер не критерий сплита, интерфейс объявляет потребитель, код английский).
  5. backend/cmd/tmmutate/main.goшапка целиком (контракт мутационного инструмента) плюс backend/Makefile, цели battery и mutations.

Ратифицированное, нужное по существу, вложено сюда и похода в журнал решений НЕ требует:

  • D39.226 — акт предыдущего пака этой зоны: что уже построено (узкий фильтр банка, пометка NOT ASKED в текстовом сайдкаре, каталог мутаций 259/48).
  • D39.225 п.10 правило остановки, применённое к секции предложений сайдкара: четвёртый круг по ней НЕ открывается (строка 353 — гейт «появится читатель»).
  • D39.104 п.1 — банк на проводе есть ЗАКОН для всех ролей независимо от статуса строки. Отсюда цена неполного банка: владелец подписывает то, что станет законом для всей книги.
  • D39.183 — запрет править тесты «чтобы прошло» про МОТИВ; правка от ЗАКАЗАННОЙ смены поведения — обслуживание, но объявляется в отчёте.
  • D39.208 п.5 — фикстура, где две различные величины совпали, делает весь их класс невидимым.
  • D39.216 — где нынешняя форма не выдерживает заказ, её РАЗВЯЗЫВАЮТ или переписывают, а не обкладывают заплатой; «дешевле подпереть» само по себе доводом НЕ является. Отступление законно, но объявляется с ценой: почему заплата дешевле развязки и что именно она откладывает. ⚠ Второй носитель одного знания не заводится: если правка требует держать две копии в согласии — развязка назрела. Это прямо про §4.1, где форму полей выбираешь ты.
  • Правило, купленное дважды подряд: пин на УСЛОВНОЕ сообщение обязан иметь фикстуру, где оно ОБЯЗАНО прозвучать. Тест, утверждающий только молчание, вакуумен ровно там, где сообщение ложно.

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

4.1 Полнота банка доезжает до того, кто подписывает — состав РОВНО так, форма полей — реши сам

Три поверхности подписи, и правда есть только в логе:

  • машинный сайдкар BankExport (internal/pipeline/bankexport.go) — полей полноты нет; его читает платформа, и с него строится экран;
  • текстовый сайдкар стоп-таблицы (internal/pipeline/mining.go) — несёт пометку NOT ASKED(…) (1 хит), и это единственное место, где она есть;
  • экран стопа на stdout (cmd/tmctl/render.go, renderSignatureStop) — про пропущенного кандидата не знает: хитов NOT ASKED там 0, при том что тот же рендерер УМЕЕТ печатать пер-строчные пометки (контроль — invented).

Заказ: довези до ОБОИХ читателей то, что движок уже посчитал. Что именно нести — Consolidated, Declined, Unanswered, BatchesDropped, ClassifyBatchesDropped — и в какой форме (плоские поля, вложенный объект, одно суммарное «полон/неполон» плюс детали) решаешь ты; аргументируй в отчёте. Что не обсуждается: (а) поля берутся из УЖЕ вычисленного — ПРОИЗВОДНАЯ от посчитанного (например бит «полон») законна и приветствуется, запрещён ПЕРЕСЧЁТ полноты вторым механизмом; (б) версию формата сайдкара (tm-bank-v1) НЕ бампать — платформа разбирает аллоулистом и новое поле игнорирует, это ПИНГ ей, а не поломка; (в) на stdout-экране оператор узнаёт о пропущенных кандидатах. Но НЕ обязательно пер-строчной пометкой, и вот почему — это ловушка вырожденной фикстуры. cmd/tmctl/render.go: bankStopStdoutCap = 20, строки сортируются reviewRank, а у не-спрошенной строки Dst пуст ⇒ ранг 1000 ⇒ она уходит ПОСЛЕДНЕЙ и при ≥20 строках проваливается под кап. Фикстура на ≤20 строк будет зелёной, а на боевом банке оператор не увидит ничего. ⇒ задано СВОЙСТВО (оператор со стдаута узнаёт, сколько кандидатов не спрашивали и почему), форму выбираешь ты — сводная строка над таблицей или пер-строчная пометка плюс работа с капом; и фикстура обязана быть ШИРЕ капа; (г) секцию предложений сайдкара не трогать — по ней применено правило остановки (D39.225 п.10, строка 353). «ОБА ЧИТАТЕЛЯ» = машинный сайдкар и stdout-экран. Текстовый сайдкар стоп-таблицы уже несёт NOT ASKED и счётчиков полноты от тебя НЕ требует — трогать его в этом пункте не надо.

ПОСЧИТАННОЕ ДВИЖКОМ САМО НЕТОЧНО — не довози его буквально, иначе построишь ложную тревогу. Три факта, которые смешивать нельзя:

  • BatchesDropped (рендер-пас срезан) — вот это и есть неполный БАНК: термины не консолидированы.
  • ClassifyBatchesDropped (классификатор срезан) — банк ПОЛОН, не уточнены ТИПЫ. Другой факт.
  • Unanswered — по собственному тексту предупреждения «counts them together with terms the role saw and did not answer», то есть СЛИВАЕТ «не предложено бюджетом» и «предложено, роль не ответила». И предупреждение terminologist.go кричит «PARTIALLY consolidated» при BatchesDropped > 0 **||** ClassifyBatchesDropped > 0. На прогоне 08.09 было batches_dropped=0, classify_batches_dropped=1, consolidated=29, unanswered=0 — то есть рендер-пас ЦЕЛ, а движок всё равно говорит «неполон». ⇒ вывод «полон/неполон» из dropped > 0 даёт ЛОЖНУЮ ТРЕВОГУ ровно на этом прогоне — то, что пункт запрещает абзацем ниже. Полнота БАНКА выводится из рендер-паса; срез классификатора несётся ОТДЕЛЬНО.

ГЛАВНАЯ ЛОВУШКА ЭТОГО ПУНКТА, и наивная проекция в неё падает. exportBank зовётся из ПЯТИ мест (bookrun.go:180 run-start/seeded · bookrun.go:258 run-finished · mining.go:249 auto-continue · mining.go:269 signature-stop · status.go:1125 redrive/re-seeded), а r.lastTerminology заполняется РОВНО в одном (mining.go:170). Плюс mining.go:66: майнинг не сконфигурирован ⇒ терминология не запускается вовсе. ⇒ на четырёх границах из пяти счётчики нулевые, и «consolidated=0 unanswered=0» прочтётся как «неполноты нет» там, где её просто НЕ МЕРИЛИ. Это класс D39.202 — прибор, отвечающий на свой вопрос, — и ровно он куплен строкой 312 из §4.3 («toc_unresolved = 0, потому что целей НОЛЬ»). Заказ: «не мерено» и «полно» обязаны быть РАЗЛИЧИМЫ на выходе; форма различения твоя. ⚠ Самый простой путь — граница: поля осмысленны там, где пас ШЁЛ (signature-stop, run-finished), и на run-start/seeded их быть не должно вовсе (omitempty), иначе «неполон» повиснет на проекции следующего прогона.

Предъявление — не «поле добавлено», а «читатель видит»: нужны ТРИ фикстуры, и третья — та, которую легче всего забыть: (1) банк неполон ⇒ артефакт и экран это НЕСУТ; (2) банк полон ⇒ молчат, ложной тревоги нет; (3) терминология не работала вовсе (граница run-start или майнинг не сконфигурирован) ⇒ выход говорит «не мерено», а НЕ «полно».

КЛАСС A ЗАВОДИТСЯ СОЗНАТЕЛЬНО, и это надо ОБЪЯВИТЬ. 18-bank-ontology.md требует у проекции НАЗВАННОГО читателя. У новых полей его сегодня нет: Consolidated/Unanswered/BatchesDropped дают 0 хитов в platform/internal/ при 183 go-файлах (контроль: слово bank знают 65 из них). Читатель появится на платформенной стороне и заказан ПИНГОМ. ⇒ назови класс A в отчёте прямо, как это сделал предыдущий пак зоны (D39.225 п.4), а не оставляй читателя подразумеваемым.

4.2 Два числа о деньгах, не сходящиеся с леджером — делай РОВНО так

  • (а) Итог волны занижен. internal/pipeline/waverun.go:218=res.TotalUSD += r.lastTerminology.CostUSDа CostUSD по собственному докстрингу — «what THIS run's RENDER phase paid»; классификаторская стоимость лежит отдельным полем ClassifyCostUSD (terminologist.go:145, заполняется на :406) и в TOTAL (this run) не попадает вовсе. Замер прогона 08.09 по строкам леджера: терминологическая фаза стоила $0.013608 = классификатор $0.009013 + рендер-батчи $0.002775 и $0.001820; в итог входит только рендерная сумма $0.004595, то есть две трети денег фазы до итога не доезжают. ⇒ ВКЛЮЧИТЬ. ⚠ Я рассматривала второй вариант («объявить в строке, что классификатор считается отдельно») и снимаю его: он оставляет TOTAL МЕНЬШЕ леджера, а этого пак запрещает ниже и требует §13. Вариант один. ⚠ Числа выше — из отчёта зоны о том прогоне (docs/PROGRESS.md, секция «Бэкенд»), СЫРОГО леджера того прогона в дереве НЕТ (замер: .db новее 07.09 — 0 при 163 в дереве) ⇒ предъявляй на СВОЕЙ фикстуре, а эти числа бери как описание симптома, не как мишень для воспроизведения.
  • (б) Разложение относит классификатор в «купил ничего». Обе банк-роли адресуются одним синтетическим именем стадии (terminologist.go:65 terminologyStageName, проставляется обоим), а разложение ключуется pos{Chapter, ChunkIdx, Stage} без роли (internal/pipeline/paidtail.go), и более ранний из двух батчей с одинаковой позицией уезжает в SupersededUSD. Улика живого прогона — три строки леджера (0 0 terminology classifier · 0 0 terminology terminologist · 0 1 terminology terminologist) при печатном «the book's TERMINOLOGY … (2)», где два — последние. ⇒ развести позиции банк-ролей в ключе разложения. Роли различимы уже сегодня (roleTerminologist / roleClassifier), и колонка role в БД ЕСТЬ (store/migrate.go) — миграция не нужна. ПРАВИТСЯ ЧИТАТЕЛЬ, НЕ ПИСАТЕЛЬ, и это денежная граница, а не вкус. Соблазн дать классификатору СВОЁ имя стадии есть, и он покупает перепокупку: чекпойнты адресуются EnsureJob(bookID, 0, terminologyStageName, snapID), новое имя стадии = новый джоб = старые чекпойнты не матчатся = на резюме классификатор оплачивается заново. ⇒ имя стадии НЕ переименовывать; роль доезжает до разложения отдельным полем. Но на ВХОДЕ разложения роли нет: store.CheckpointUsage поля Role не несёт, и запрос её не выбирает (internal/store/ledger.go, тип и его SELECT). ⇒ правка internal/store/ledger.go РАЗРЕШЕНА и входит в заказ — это не выход за скоуп. И она делает ЛОЖНЫМ комментарий, стоящий в самом предмете: paidtail.go про идентификацию класса по стадии — «equivalent to reading checkpoints.role and needing no store change». Правя механизм, снимай и это утверждение: держать два носителя одного знания в согласии — ровно то, что запрещает D39.216 п.3(б). ТЕСТ, КОТОРЫЙ ОБЯЗАН ОСТАТЬСЯ ЗЕЛЁНЫМ И НЕ ПОДЛЕЖИТ ПРАВКЕ: TestAReboughtGlossaryBatchIsStillALoss (paidtail_test.go) держит ДВА вызова в ОДНОЙ позиции и требует, чтобы ранний уехал в superseded. Это ДРУГОЙ случай — перепокупка ОДНОЙ роли при росте черновикового множества (строка 233), и она остаётся потерей. Твоя правка разводит РАЗНЫЕ роли, а не амнистирует перепокупку одной. Покраснел он — ты сломала класс, а не починила свой. ⚠ И существующие фикстуры paidtail_test.go — ровно вырожденный класс D39.208 п.5: коллизионного случая (две РАЗНЫЕ роли в одной позиции) в них нет ни одного, поэтому батарея на этом дефекте зелёная. Фикстуру, где роли РАЗЛИЧНЫ, заводишь ты. Обе половины предъявляются СВЕРКОЙ С ЛЕДЖЕРОМ, а не чтением кода: тест берёт числа отчёта и числа леджера на одной фикстуре и утверждает их отношение. ⚠ Отношение назови точно, это два разных утверждения: для (а) — РАВЕНСТВО (итог обязан сойтись с суммой строк), для (б) — что классификаторская строка попала в свой класс, а не в superseded. «Леджер есть нижняя граница» — про мир, а не про этот тест: там, где движок не записал вызов, равенства нет и быть не может, и это отдельный класс (PD-441, строка 331), в пак НЕ входящий.

ГРАНИЦА ЭТОГО ПУНКТА, и она снята чтением ОБЕИХ сторон шва — не выводи её заново и не расширяй. Это правка ОТЧЁТА, а не денег: платформа биллит НЕ TotalUSD, а committed_usd — сумму по таблице spend (platform/internal/runs/reconcile.go докстринг attemptSpend), а классификатор ходит тем же учтённым путём, что и все стадии (runBankAttemptrunAttempt, terminologist.go:783-796), и его деньги в spend УЖЕ лежат. ⇒ ни один счёт пользователя не двигается, согласия владельца пункт не требует. Если тебе кажется, что нужно тронуть ЛЕДЖЕР, — это стоп и пинг: там будет двойной счёт, а не починка.

СОСЕДНЯЯ МИНА — не в этом пункте, но в шаге от него, и я называю её ГРАНИЦЕЙ, а не заказом. Твоя правка waverun.go порога согласия НЕ касается: база порога — projectBookUSD в internal/pipeline/rebill.go, другая сумма. Но если работа поведёт тебя в ПРОЕКЦИЮ (ProjectedBookUSD, status, добавка контура к bookUSD) — там порог СОГЛАСИЯ на пере-оплату считается БЕЗ банкового контура НАМЕРЕННО («THE CONSENT THRESHOLD IS COMPUTED WITHOUT THE CONTOUR, and the two numbers part company HERE»), и первая версия той правки сложила контур ДО взятия порога и тихо ОСЛАБИЛА денежный гейт; поймала приёмка. ⇒ пошла в проекцию — это стоп и пинг, а не «заодно».

4.3 Третий член того же класса — реши сам, бери если по пути

Строка 312, остаток Д-3: движок предупреждает о нечитаемом оглавлении в свой Log.Warn, а платформа читает events.jsonl — то есть та же форма «знает один, смотрит другой». Проверь сам, тот ли это класс; если да и если дёшево — закрой тем же движением. Если дорого или предмет другой — скажи в отчёте, оставлю строкой.

4.4 Чего в паке НЕТне делай, и это ОБЪЯВЛЕННЫЕ сужения

  • Секция предложений сайдкара банка — по ней применено правило остановки (D39.225 п.10), гейт возврата назван строкой 353: появление первого ЧИТАТЕЛЯ секции. Четвёртый круг не открывается.
  • Платформенные половины строк 253 и 224 — чужая зона. Твоё действие — ПИНГ в отчёте, не правка.
  • Всё, что двигает снапшот, хеш запроса, ключ манифеста или версию встроенных данных. В этом паке заказанных смен поведения ДВЕ, и обе — в путях отчётности и артефактов: §4.1 и §4.2.
  • СТРОКА 360 — ТАЙМАУТ ЧТЕНИЯ, МАСКИРУЮЩИЙСЯ ПОД НЕЧИТАЕМОЕ ТЕЛО. НЕ БЕРЁШЬ, и я называю это прямо, потому что она ДОРОЖЕ всего, что в этом паке. Замер полигона: 23.834.5 % цены редакторской руки; ошибка чтения выбрасывается в _, обрезок биллится по оценке и РЕТРАИТСЯ. Почему не здесь: (1) это другой класс — не «движок знает, а читатель не видит», а «движок не знает, что оборвал сам»; (2) её денежная половина требует слова владельца (платит ли пользователь за вызов, который оборвали МЫ) и сцеплена со строкой 331, где тот же предмет закрыт ПРОТИВОПОЛОЖНО — нулём вместо оценки. Идёт отдельным паком. ⚠ Наткнёшься на неё по пути — не чини, отдай наблюдением в отчёт: молчаливая починка здесь смешает два денежных класса в одном лендинге.
  • Строки 261 · 262 · 331 — члены того же класса «вызов оборвали мы»; уезжают вместе с 360.
  • Переписывание Runner, дробление internal/pipeline — запрещены D39.224 §7. ⚠ «Новый детектор границ» там же — не запрет, а УСЛОВИЕ; к твоим задачам не относится, но силу пункта не путай.
  • Платные вызовы — ноль, см. §Деньги.

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

  1. Каждая новая гарантия предъявляется МУТАЦИЕЙ, и краснота читается ПО ТЕКСТУ падения: говорит ли он про сломанное тобой. Правый вердикт по неправой причине — дыра, а не поимка.
  2. Мутации — ТОЛЬКО на копии дерева, и рецепт копии УЖЕ СТОИТ в цели mutations (backend/Makefile) — своего однострочника не пиши, он станет вторым носителем и разойдётся. Гонишь батарейное подмножество — make mutations. Гонишь одиночную посадку -id, то есть копию делаешь руками, — повтори цель ДОСЛОВНО: распаковка в подкаталог $tmp/backend (а не в корень времянки), исключения --exclude='./.env*' и --exclude=./bin, и два трапа: EXIT убирает, а INT TERM убирает И ВЫХОДИТ (exit 130) — иначе прерванный прогон продолжает жить. Рабочее дерево не правится никогда, в том числе «на секунду».
  3. Мутируй и СВОИ новые фикстуры. И особая осторожность здесь: у тебя ДВА условных сообщения (неполный банк · пропущенный кандидат). Пин на каждое обязан иметь фикстуру, где оно ОБЯЗАНО прозвучать, и вторую, где оно обязано молчать. Предыдущий пак этой зоны выпустил ТРИ ложных операторских предупреждения подряд, и все три были зелёными именно потому, что утверждалось только молчание.
  4. Новые записи — в каталог cmd/tmmutate/mutations.json. Ключи СТРОЧНЫЕ: id, package, why, edits, плюс необязательный battery. ⚠ package — пакет ПИНА, а не пакет правки: инструмент гоняет один пакет. ⚠ battery ставится не всем: сегодня это 48 записей из 259 — гейтовое подмножество; какие из твоих туда входят, решаешь ты и говоришь почему.
  5. BASELINE НА ВХОДЕ (снят оркестратором 08.09): make battery → 19 ok · 0 FAIL · 4 «no test files» · 4 скипа поимённо; make mutations48 записей · 0 unexpected · anchors swept: 0 of 259. Красное на входе — находка и пинг, а не твоя работа.
  6. Субагенты РАЗРЕШЕНЫ ЯВНО — и на охват, и на адверсариальный проход по ГОТОВОЙ работе. Направление, что здесь уязвимее всего: (1) вторая половина утверждений про условные сообщения; (2) сверка отчёта с леджером — легко заявить и трудно доказать; (3) фикстуры, где «полон» и «неполон» случайно совпали.
  7. Проверяемый артефакт — таблица мутаций в отчёте: мутация → где посажена → красный тест → ТЕКСТ падения, и отдельной строкой выжившие, если такие есть.

6. Оси ревью — характер «Код», плюс деньги (ось вправе заменить с аргументом)

Тест утверждает не то, что думает (D39.171): часы как способ синхронизации там, где предмет не время, и ассерт по подстроке в буфере, куда пишет кто-то ещё. Обе формы дают и ложное красное, и тихо-зелёное — оно дороже: зелёное, не проверившее ничего, не перечитывает никто. Третья ось твоя: деньги — любое число выводится из СЫРОГО леджера, и леджер есть нижняя граница, а не оценка.

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

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

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

Каждое число и категорика отчёта — с командой, которой получены. Отрицательный замер печатается ВМЕСТЕ с контрольной величиной, доказывающей, что вопрос задан существующему предмету. Сверх этого, про код:

  • перед отчётом сверь каждый клейм с результатом инструмента ЭТОЙ сессии, а не с памятью и не с этим промтом: адреса §4 сняты 08.09 и могли уехать;
  • дифф ^func Test — исполнением, ИМЕНАМИ через comm, а не разностью счётчиков;
  • последний абзац отчёта оказался планом или обещанием? сделай это СЕЙЧАС;
  • править или удалять тест/голден/гейт, чтобы он прошёл, — НЕДОПУСТИМО; исключение — правка от заказанной смены поведения (§4.1, §4.2), и она объявляется отдельным пунктом;
  • сессия длинная — поставь себе интервальную самоверификацию субагентом против ЯВНЫХ критериев §13.

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

ДО работы — ≤10 строк СВОИМИ словами: скоуп · инварианты, которые не имеешь права сломать · что НЕ делаешь. Дословный пересказ промта подтверждает канал, но не понимание, и ошибку промта повторяет вместе с ним. Отправь эхо оркестратору по адресу из прямого канала (§12); канала нет — эхо идёт первой секцией отчёта, и работа продолжается.

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

Что не вышло, что не проверено, где сомневаешься. Пустая секция при непустой работе — сама по себе находка; «не проверено» и «опровергнуто» — РАЗНЫЕ исходы.

11. Канал вопросов и право сказать «этого делать не надо»

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

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

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

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

Работу доводишь до конца САМ; приёмка идёт последней и вторым кругом твоей самопроверки не служит. Готово — это когда:

  • у КАЖДОГО пункта §4 есть исход: сделано · не делаю с доводом · пинг;
  • круги СОШЛИСЬ: последний проход не дал НОВЫХ находок, прежние закрыты таблицей «находка → что сделано → ЧЕМ ПРЕДЪЯВЛЕНО»;
  • каждый класс закрыт с ЗНАМЕНАТЕЛЕМ: «закрыт в N носителях из M», и M посчитан командой, а не на глаз;
  • таблица мутаций полная, выжившие названы;
  • числа отчёта сверены с СЫРЫМ леджером, а не с логом;
  • числа сняты ПОСЛЕ последней правки, а не вспомнены;
  • всё живое — в ДЕРЕВЕ, а не в письме;
  • сказано явно: «работа завершена, править не планирую». Без этой фразы пак считается идущим.

Деньги

Пак $0. Платных вызовов ноль: всё, что нужно предъявить, предъявляется на ФЕЙК-провайдере и на собственных фикстурах. ⚠ Сырого леджера прогона 08.09 в дереве НЕТ (замер: файлов .db новее 07.09 — 0 при 163 в дереве, свежайший от 02.09) — числа этого прогона живут только описанием в отчёте зоны, и воспроизводить их не надо. Если тебе кажется, что задача требует платного прогона, — это стоп и пинг, а не вызов.

Отчёт

Секция «Бэкенд» в docs/PROGRESS.md, подзаголовок #### Пак «движок уже знает»: исход по каждому пункту §4 · таблица мутаций · таблица «находка → что сделано → чем предъявлено» · столбец «закрыт в N из M» · сверка отчёта с леджером числами · пинги в чужие зоны (платформенные половины 253 и 224) · §10 «что не удалось» · вопросы оркестратору.