textmachine/docs/BACKEND_BOUGHT_MEANS_DELIVERED_SESSION_PROMPT.md

345 lines
38 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Бэкенд-пак: КУПЛЕНО — ЗНАЧИТ ДОСТАВЛЕНО. Юнит, который не доделается НИКОГДА
> Выдан оркестратором №23 (сессия `textmachine-11`) 11.09. Пак **$0** — платных вызовов в нём нет.
> Предмет решён владельцем 05.09 (`D39.204`); ты строишь решённое, а не выбираешь между вариантами.
## 1. Какая проблема и что решит твой результат
Читатель заплатил за главу. Движок купил первую попытку, получил флагуемый результат, пошёл за второй — и
**вторую ему не продали**: потолок книги или дня не вмещает резерв регенерации. ⚠ **И тут точность несущая,
первая редакция промта её теряла:** `maxTokensForAttempt` удваивает **только ВЫХОДНОЙ** бюджет, а резерв
считается оценкой по цене, промпту, потолку и буферу размышления (`backend/internal/pipeline/stagerun.go`,
греп `EstimateUSD`) — промпт и аддитивный буфер НЕ удваиваются. Значит «попытка 1 стоит ×2» — неправда, и
окно, в котором отказ неизбежен на ≥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 ⛔ КОНСТРУКЦИЯ ПЕРЕ-РЕШЕНА ВЛАДЕЛЬЦЕМ 11.09 — читай это ПЕРЕД кодом
**Слово владельца дословно:** «Надо о таком просто сообщать в виде метаданты, которая сейчас и пишется
предупреждением, и иметь возможность поднять просто потолок и возобновить прогон, так как **это ситуация
всё же СТАНДАРТНАЯ СО СТОПОМ, просто он произошёл по какой-то другой причине**».
**Это отменяет обе половины прежнего заказа — и моего, и `D39.204` п.4.** Ни «деградировать во флаг», ни
«волна идёт дальше» больше НЕ строится. Прежний план заводил новый исход; новый — **возвращает ситуацию в
УЖЕ ПОСТРОЕННЫЙ штатный путь остановки**, из которого она сегодня выпадает.
**Что это значит механически (моё чтение; спорь, если код скажет иначе):**
1. **Прогон ОСТАНАВЛИВАЕТСЯ, как при любом отказе по потолку.** Не продолжается с флагом. ⭐ И это заодно
снимает то, чем ряд 291 пугал: «продолжить волну нельзя без ДЫРЫ в непрерывном префиксе» — при остановке
дыры не возникает вовсе.
2. **Отказ ретраю публикует ту же метадату, что и любая остановка по потолку** — кадр
`Ceiling{Halted, Scope, ShortfallMicroUSD}` (`backend/internal/runevents/runevents.go`, греп
`ShortfallMicroUSD`). ⭐ **Он уже несёт ровно то, что владелец просит:** «пополни хотя бы на столько, и
тот же вызов будет допущен» — и это **ратифицировано им же, `D39.203`**. Строить новый носитель не надо.
**И твоя находка №2 этим РАЗРЕШАЕТСЯ, а не отменяется:** ты была права, что `ceilingReached`
идемпотентен по прогонному флагу и съел бы событие настоящей остановки — но теперь съедать НЕЧЕГО: эта
остановка И ЕСТЬ настоящая. Публикуй через штатный путь.
3.**НАСТОЯЩИЙ ДЕФЕКТ — УЖЕ, чем я написал, и он назван в самом дереве.** Механизм «отметить
остановленную позицию» построен ИМЕННО против невидимых дыр:
`backend/internal/pipeline/stagerun.go:142`=`THE MARK FOR A STOPPED POSITION IS ATTACHED TO EVERY EXIT`,
и его комментарий приводит замер прежнего инцидента — «прогон, остановленный на эскалационном хопе,
рассчитал деньги и не оставил строки вовсе: `committed=0.001176`, `chunk_status_rows=0`». **Но метка —
no-op для всего, что не «доставленный вызов, который остановил человек»** (`recordCancelledStage`).
Отказ по потолку под это не подпадает ⇒ юнит остаётся без строки. **Вот дыра, и вот что ты закрываешь.**
4. **Поднял потолок → резюм ДОДЕЛЫВАЕТ юнит.** Значит строка, которую ты пишешь, обязана быть
НЕ-ТЕРМИНАЛЬНОЙ для резюма — по образцу `FlagCancelled`, единственной причины, у которой
`resolvedForResume` ложен (`backend/internal/pipeline/cutcall.go:293`=`FlagReason(cs.FlagReason) != FlagCancelled`),
и ложен именно потому, что это «оплачено, но не сделано». Твой случай той же природы.
**Делай РОВНО так:** остановка штатная · метадата через уже построенный кадр с недостачей · **юнит получает
строку, а не пустоту** · строка НЕ терминальна для резюма · после пополнения резюм доделывает.
**Решаешь сам и аргументируешь:** как назвать причину в строке юнита (или взять существующую) · где ставится
метка · как отличить «остановлено на ретрае» от «остановлено на попытке 0» в носителе, и надо ли отличать.
**Попытку 0 не трогать:** её отказ и сегодня останавливает книгу штатно — ратифицировано.
**КТО ПЛАТИТ — НЕ ПРЕДМЕТ ЭТОГО ПАКА.** Слово владельца 11.09: «пока платит за всё ЮЗЕР, потом будем
решать эту проблему». Механизм «платит продукт» не строить; существующее биллинговое поведение не трогать
ни в какую сторону, даже где оно выглядит непоследовательным. ⚠ И отдельной строкой отчёта НАЗОВИ (не чини):
объёмный леджер сегодня считает флагованный юнит НЕ доставленным, то есть грант за него не съеден — это
расходится со словом владельца и существует ДО твоего пака. Он объявил вопрос отложенным.
**Отгрузка обрезанного текста не строится**`D2` запрещает отгружать загрязнённое, и это не зависит от
того, кто платит.
### 4.2 Пин, ради которого пак существует
**«ОСТАНОВКА, КОТОРАЯ ЛЕЧИТСЯ ПОПОЛНЕНИЕМ».** Три утверждения, и они про разное:
1. **Юнит, на ретрае которого отказал потолок, ПОЛУЧАЕТ СТРОКУ.** Сегодня её нет — это и есть невидимая
дыра. Пин обязан печатать величину, доказывающую, что деньги были потрачены, а строка появилась: пустой
`chunk_status` рядом с ненулевым `committed` — ровно тот замер, которым дерево описывает прошлый
инцидент.
2. **Остановка несёт НЕДОСТАЧУ.** `ShortfallMicroUSD` ненулевой и таков, что пополнение на него допускает
тот же вызов. ⚠ Пин на «событие вообще есть» вырожден — утверждай ЧИСЛО.
3. **Пополнил потолок → резюм ДОДЕЛАЛ юнит.** ⛔ **И это ГАРД, а не доказательство лечения — поправка
исполняющей сессии, принята.** Моё «сегодня второй прогон умирает вечно» НЕВЕРНО: строки у юнита нет ⇒
гейт резюма не срабатывает ⇒ позиция ре-атакуется, попытка 0 реплеится из чекпойнта за $0, ретрай
покупается, и при поднятом потолке юнит доделывается **уже сегодня, без пака**. Вечно умирает только
резюм БЕЗ пополнения. ⇒ этот пин стережёт ратифицированное `D4`, чтобы пак его не сломал, и **на дефекте
он ЗЕЛЁН**. Так и напиши.
**И отсюда норма приёмки этого пака, которой у нас ещё не было ни в одном:** сними ЦВЕТ КАЖДОГО из трёх
пинов на дереве **ДО** фикса, числом, и положи замер в отчёт. На дефекте краснеет только первый. «Пин
зелен» и «пин стережёт» — разные утверждения, и без этого замера они сливаются.
**Про коды выхода.** Прежняя редакция промта требовала `exit 2` вместо `exit 4`. **Снято:** при штатной
остановке код остаётся тем, каким он и был для остановки по потолку. Предмет пака — не смена кода выхода, а
то, что за ним стоит: **строка вместо пустоты и лечимость пополнением.**
**Два гейта поймают тебя сами — назову, чтобы не терять круг:** `TestEveryFlagReasonIsRanked` потребует
завести новую причину в `flagSeverity` (`backend/internal/pipeline/status.go`), если ты её заводишь, а
`TestEveryOperatorMessageIsCatalogued` — внести новое сообщение в
`backend/internal/pipeline/testdata/operator-messages.txt` (сегодня в каталоге 134 строки, из них о потолке
уже говорят четыре — посмотри их прежде, чем писать пятую).
### 4.3 ⛔ ДЕФЕКТ, КОТОРЫЙ ТВОЙ ПАК НАКОРМИТ — и он НЕ латентный. Чинить ЗДЕСЬ
Нашла исполняющая сессия, посылку я пере-проверил и **она у неё неверна в СТОРОНУ МЯГКОСТИ**.
`backend/internal/pipeline/quality.go` (греп `draftEchoRecovered`) считает эхо ВОССТАНОВЛЕННЫМ по одному
признаку — `FirstFlagReason == cjk_artifact`, — **не спрашивая, флагована ли строка сейчас и чем**. Денежный
отказ эхо-рероллу даст ровно эту картину: первый флаг — эхо, итоговый — денежный, реролла не было, а отчёт
скажет «восстановлено».
**Сессия назвала это латентным «потому что ключ 0». Ключ НЕ ноль:** `regenerate_echo_before_escalate: 1`
стоит **во всех ЧЕТЫРЁХ боевых конфигах** (`backend/configs/pipeline-c1.yaml`, `-c2`, `-arm-glm`,
`-arm-mistral` — сверено мною по каждому). ⇒ дефект оживает **в день лендинга твоего пака**, а не когда-то
потом. **Чини его в этом паке и пинь** — «диспозиция в отчёте» здесь недостаточна.
### 4.4 Платформенная половина — **твоё дело назвать, не построить**
Карта заметок платформы **РУКОПИСНАЯ** (`platform/internal/ingest/notes.go`) и уезжает независимо от
словаря движка. Цена несделанного **замерена**: `PD-246` — минор 0.10.0 сутки жил ЛОЖНЫМ на проводе, причина
доезжала читателю как `unspecified`, и поймала это зона своей пере-проверкой ПОСЛЕ слов оркестратора
«приёмка закончена».
**отдельным пунктом отчёта** назови мне: точное значение новой причины на проводе · что платформа обязана
записать прогону, который кончился флагом вместо `exit 4` · какой её пин это стережёт. Я передам это
платформенной сессии, и **акт будет один на две половины**.
**И следствие, которое стоит назвать сразу, потому что оно про деньги читателя:** объёмный леджер считает
флагованный юнит НЕ доставленным (`backend/internal/pipeline/volume_test.go`, греп
`TestAFlaggedUnitIsNotReportedAsDelivered`). Значит грант за него не съеден, а книга честно короче — это
хорошая новость, но она обязана быть СКАЗАНА в отчёте, иначе следующая смена откроет её заново.
### 4.5 Приложение — ДВА пина, краснеющих по УДАЧЕ (ряд 379, ОБЕ половины)
Отдельная от §4.1 работа; делай её ПОСЛЕ основной. ⛔ **И мой диагноз здесь был НЕВЕРЕН — опровергнут
замером, а не мнением. Читай, чем именно, иначе повторишь мою ошибку.**
**Половина (б).** Запись каталога `CUTCALL-a-refusal-pays-when-the-reply-outruns-the-write` стережёт самую
дорогую половину денежного бита `delivered()`
(`backend/internal/llm/attemptcut.go:189`=`answered && t.firstByte.Load()`): провайдер ОТКАЗЫВАЕТ и рвёт
коннект, пока наше тело ещё пишется — байт ответа есть, статуса в руках нет, и чтение «байт = доставка»
оплачивает сметой каждый отказ (замер прежнего пака: 22 отказа из 25, один на $0.80).
**Два независимых замера на посадке (снятие `answered &&`), и они расходятся:** мой — **7 красных из 8**
(снят на нагруженной машине, рядом шла батарея); опровергателя на спокойной — **8 из 8**, а на сорока
процессах **39 FAIL / 1 PASS**. ⇒ пин краснеет по УДАЧЕ, это подтверждено обоими; частота зависит от
нагрузки, и поэтому «восемь красных подряд» **не является критерием приёмки**: сегодня, без единой правки,
восьмёрка выпадает примерно в 82 случаях из 100.
**А вот ПРИЧИНА не та, что я написал.** Я заказывал «сделать приход байта ответа НЕИЗБЕЖНЫМ до обрыва».
Зонд опровергателя (40 итераций, печать того, что реально получил клиент) дал **39 × обрыв с отказом
записи и 1 × ПОЛНЫЙ `401`**, и ни разу — «ни куска, ни статуса». То есть байт приходит практически всегда,
а мутант выживает в ДРУГОМ случае: клиент успевает вычитать `401` ЦЕЛИКОМ, `Do` возвращает не ошибку
записи, а ОТВЕТ, и `delivered()` не спрашивают вовсе — ошибка уходит статусной веткой. **Моё лекарство
било по половине, которая и так держится, и увеличивало вероятность ровно того исхода, в котором мутант
выживает.** (И «~6 МБ тела» тоже неверно: 11.0 МБ — Go не эскейпит кириллицу в JSON.)
**Задача — делай РОВНО так в части ЧТО, способ твой:**
1. **Тест утверждает СВОЮ ПОСЫЛКУ и печатает её:** что `Do` вернул ошибку ЗАПИСИ и что трасса видела
первый байт. **Сценарий не состоялся ⇒ тест КРАСНЫЙ**, а не зелёный «мимо предмета». Сегодня он зелен и
на полном `401`, то есть на другом предмете.
2. **Прямой табличный пин на сам `delivered()`** — он убивает посадку `answered &&` детерминированно, без
гонки вообще.
3.У фикстуры `MaxAttempts: 3` — до трёх бросков кости на один `Complete`; **границу утверждай ПО
ПОПЫТКЕ**, а не по итогу вызова.
**Половина (а) — её первая редакция промта не заказывала вовсе.** Тот же ряд 379 несёт вторую половину:
две строки таблицы девяти в `backend/internal/pipeline/cutcall_test.go:402`=`time.Sleep(50 * time.Millisecond)`
разводятся ОКНОМ СТЕННЫХ ЧАСОВ, и по какую сторону границы заголовков сел `cancel()`, не утверждается
ничем — замер приёмки дал **2 красных из 8**. **Ряд закрывается ТОЛЬКО вместе с этой половиной.**
**Критерий приёмки берётся из самого ряда 379, он сильнее моего:** «каждый из двух пинов **ПЕЧАТАЕТ
величину, доказывающую пройденную границу, и ПАДАЕТ, когда сценарий не состоялся»**.
## 5. Где этот пак мягкий — четыре места, назвал я, веер и глубину выбираешь ты
Мандат самопроверки — **исполнением**; субагенты разрешены явно. Адверсариальный проход по СВОЕЙ ГОТОВОЙ
работе обязателен.
1.**Пин, утверждающий только молчание, вакуумен ровно там, где сообщение ложно.** «Ошибка не вышла
наверх» — утверждение о молчании. Фикстура обязана быть такой, где новая причина ОБЯЗАНА прозвучать, и
тест утверждает её ИМЯ.
2.**Фикстура обязана сделать отказ резервации НЕИЗБЕЖНЫМ на попытке ≥1 и НЕВОЗМОЖНЫМ на попытке 0**
и окно считается по РЕАЛЬНОЙ оценке резерва, а не по «×2» (см. §1).
Денежный пин, флейковый на мутанте, измеряет пустой сценарий: у нас уже был пин, дававший 2 красных из
8, потому что деньги были ВЕРОЯТНЫ, а не неизбежны. Гоняй свой не один раз.
3.**Посадка обязана бить в тот же слой, что стережёт пин.** За прошлый пак мутация трижды оказалась не
про то: недостижимое условие в фикстуре · не собирающаяся посадка (НЕизмеренная — хуже выжившей) · код
против гейта над данными.
4.**Новая причина — факт ПРОВОДА, а не словаря.** Тест, проверяющий только, что константа добавлена в
`FlagReason`, не доказывает, что читатель её увидит. Скажи, чем предъявлена дорога от флага до
отчёта/экспорта.
⚠ И общее, стоившее трёх смен подряд: **зелёная батарея плюс полный мутационный каталог сходимостью НЕ
являются.** В последних трёх паках направленный второй читатель находил 6, 7 и 9 дефектов при полной зелени.
### ⭐ Адверсариальная стойка — способ смотреть, не правило пака
-**Автор и ревьюер — разные роли, даже когда это один ты.** Перечтение своей работы рубежом не
считается: поднимай читателя, которому НАЗВАНО, где мягко.
-**Спрашивай у аномалии, о ЧЁМ она — о предмете или о твоём приборе.**
-**Верный результат при неверном методе не краснеет нигде.** «Сошлось» — не доказательство.
-**Утверждение о молчании вакуумно** без фикстуры, где оно ОБЯЗАНО прозвучать.
-**Заимствованное число проверяется не на существование, а на ТУ ЛИ КЛЕТКУ:** та же роль, та же модель,
та же стадия, тот же режим?
-**Главный вопрос отчёта — не «что не получилось», а «что ты знаешь и не сказала».**
### ⭐ Находки ВНЕ заказа — отдельный заказ владельца
Слово владельца 11.09: **находить проблемы даже там, где мы не ждём.** Задавай себе в каждой фазе вопрос, у
которого нет заранее известного ответа: **что здесь стоит дороже, работает хуже или ведёт себя страннее,
чем должно бы, — и о чём никто не спрашивал?** Ради чего он заведён: удорожание из-за падающих запросов на
НАШИХ настройках никто не искал — просто кто-то посмотрел в леджер без гипотезы и увидел 25.4 % цены книги
в выброшенных попытках, при зелёных тестах и молчащих гейтах.
**Докладывай отдельной секцией: криты · мажоры · регрессии · баги · жёсткие точки улучшения** — каждое
аргументированно, с носителем (`file:line`, число, команда) и с ценой в деньгах, тексте или доверии
читателя. ⚠ Секция обязана быть непустой ИЛИ нести строку «искал вот так, не нашёл» с перечислением мест:
«находок нет» и «не смотрел» в отчёте выглядят одинаково.
## 6. Предметные оси ревью
Выбери 13 и назови какие. Мой приор: **деньги под гонкой** · **терминальное состояние прогона** (что
видит платформа и что видит человек) · **обратная совместимость словаря причин**.
## 7. Записка-план ДО работы
Перед первой правкой — записка: что меняешь, чем предъявишь, где ждёшь сопротивления. Комплектность против
заказа сверяй механически.
## 8. Заявление = команда
Каждое число и каждая категорика отчёта — **с командой, которой получены**. Дифф `^func Test` — **исполнением,
не памятью**. Приёмка пере-снимает.
**И три нормы кодового пака, каждая ловит свой класс:**
- **перед отчётом сверь КАЖДЫЙ клейм с результатом инструмента ЭТОЙ сессии** — не с памятью о прогоне;
- **последний абзац отчёта оказался планом или обещанием? Сделай его СЕЙЧАС** — обещание в отчёте не
переживает смены;
- **в длинной сессии — интервальная самоверификация субагентом против ЯВНЫХ критериев** (`D39.121`), а не
в конце: проверка, отложенная до сдачи, проверяет уставшую работу уставшим взглядом.
## 9. Эхо-протокол старта
**Порядок двух первых действий:** сперва впиши свой блок в `/tmp/textmachine-channel` (§12), потом отправь
эхо — эхо без блока некуда адресовать.
**Эхо** — ≤10 строк СВОИМИ словами: что понял · что считаешь опасным · что считаешь неверным.
Не пересказ: дословный пересказ подтверждает канал, но не понимание, и ошибку промта повторяет вместе с
ним.
**Адрес бери из `/tmp/textmachine-channel`** — блок с `role=оркестратор`, — а не из этого промта: имя сессии
не переживает рестарт окружения. Перед отправкой сверься с `ListAgents`: файл переживает смерть сессии, а
`ListAgents` — нет.
## 10. Что НЕ удалось — обязательная секция отчёта
И вторая её половина: **«где прибор слеп и я это знаю»** — что невидимо · почему не чинил · чем
закрывается. ⭐ Норма прошлой смены: **«в коде названо, в отчёте нет — значит для следующей смены НЕ
названо».**
## 11. Канал вопросов и право отказаться
Конфликт промта с кодом или доками — **пинг мне, не интерпретация**. Право сказать «этого делать не надо» с
аргументом у тебя есть и им пользовались: в двух случаях из трёх правы были сессии, а не я.
**Тесты и гейты под зелень не подгонять.** Правка, вызванная ЗАКАЗАННОЙ сменой поведения, — обслуживание,
и протухший тест держать не нужно; но она **ОБЪЯВЛЯЕТСЯ** в отчёте: что изменилось, какой тест это
описывал, куда уехала гарантия.
### ⭐ Старший коллега — Fable 5. **Разрешён ОДИН на сессию (слово владельца 11.09)**
У тебя есть право поднять **одного** агента на модели **`fable`** и держать его как СОВЕТЧИКА при сомнениях —
тем же способом, каким это делает оркестратор. Владелец разрешил ровно одного на сессию.
**Как с ним работать, и форма здесь важнее числа:**
- **Поднимаешь ОДНОГО и держишь его весь пак.** Ценность этого агента — в НАКОПЛЕННОМ контексте смены:
он помнит, что ты уже решил и почему. ⛔ **Второго не поднимай** — вопросы ДОСЫЛАЮТСЯ первому (`SendMessage`
по его id), а не адресуются свежему. Свежий агент вместо накопленного — потеря именно того, ради чего он
заведён.
- **Модель задавай ЯВНО** (`model: "fable"`), иначе она унаследуется и ты не будешь знать, что у тебя
работает.
- **О чём его спрашивать:** сомнение в решении · развилка, где оба пути выглядят законными · «не заказываю
ли я уже построенное» · «не противоречит ли это ратифицированному» · спорная формулировка в отчёте.
**Спрашивай С КОНТЕКСТОМ и со СВОЕЙ рекомендацией** — вопрос без твоего варианта ответа даёт совет ни
о чём.
-**Он советчик, а не источник истины: его ответ проверяется деревом.** У оркестратора он за смену
ошибся дважды на фактах (называл платный прогон бесплатным, объявлял ряд новым предметом) — и оба раза
его ВЫВОД оставался верным. Проверяй посылки, принимай выводы по существу.
- **Что он дал оркестратору за эту смену** — для калибровки, чего от него ждать: поймал, что я собирался
завести новый ряд бэклога под предмет, у которого ряд уже был; развернул порядок паков доводом, который
я не назвал; и назвал условие, без которого два прогона стали бы несравнимы.
## 12. Прямой канал
Механизм — `CLAUDE.md` §«Связь между сессиями». Впиши свой блок в `/tmp/textmachine-channel` ПЕРВЫМ
действием. Нужной роли нет ⇒ канала нет, и это нормальный случай: НЕ опрашивай сессии подряд.
## 13. Критерий завершённости
У каждого пункта заказа — исход (сделано · не делаю с доводом · пинг) · круги СОШЛИСЬ (последний не дал
НОВЫХ находок; прежние закрыты таблицей «находка → что сделано → ЧЕМ ПРЕДЪЯВЛЕНО») · **таблица мутаций
полная, выжившие названы, и КАЖДАЯ новая запись помечена `battery`** (прошлый пак этого не сделал, и его
«21/21 RED» оказался разовым прогоном смены, а не гейтом проекта) · числа сняты ПОСЛЕ последней правки ·
всё живое в ДЕРЕВЕ, а не в письме · явное **«работа завершена, править не планирую»**. Без последнего пак
считается идущим.