- Зачем:
- среда сама отвечает за пять секунд, теряет она унаследованный файловый
дескриптор или нет, поэтому документ несёт проверку, а не ответ; форма
сбора вывода за вечер менялась дважды и не должна жить в двух местах.
- Что:
- в «Сквозные правила» codex-exec.md добавлен предполёт: самотест
`codex --version > f; wc -c f`, ветка «ноль байт» с раздельными каналами
и `set -o pipefail`, оговорка про `wait`.
- предполётная проверка песочницы переехала туда же из пункта про AppArmor,
три рецепта не тронуты — их POSIX-форма и код возврата остались честными.
- урок 2026-08-06 отдал самотест и форму предполёту, оставил находки:
дефект `2>&1 | cat`, съеденный каналом код возврата, ненужный `script`.
- Проверка:
- `false | cat > f; echo $?` — 0, с `set -o pipefail` — 1.
- `bash -c 'echo "{}"; echo err >&2' 2> >(cat > e) | cat > o` — потоки
в разных файлах, `jq` по логу проходит.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
392 lines
41 KiB
Markdown
392 lines
41 KiB
Markdown
# Эмпирика прогонов
|
||
|
||
Датированные факты: что поймал каждый этап конвейера, казусы, цифры.
|
||
Дописывай после каждого прогона в конец файла — это и есть «выжимка
|
||
опыта», ради которой скилл существует. Правку старых записей согласуй с
|
||
пользователем: это долговечная эмпирика.
|
||
|
||
Журнал накопительный, поэтому у него есть архив: записи с 2026-07-06 по
|
||
структурный рефакторинг 2026-07-31 включительно лежат в
|
||
[lessons-archive.md](lessons-archive.md) — они описывают заметно другую
|
||
редакцию скилла. Живые хвосты тех записей перед переездом сведены в
|
||
очередь на механизм (запись 2026-08-03). Когда файл разрастётся снова —
|
||
подвинь границу и перенеси старое туда же: архив вне пути чтения
|
||
прогона, поэтому его длина ничего не стоит, а дистилляция стоила бы
|
||
потерянных историй.
|
||
|
||
## 2026-07-31: одёргивания за день прогонов (Opus 5-координатор, старая редакция)
|
||
|
||
Фидбек пользователя после дня работы со скиллом; ценно тем, что это
|
||
перечень мест, где координатора приходилось останавливать руками.
|
||
|
||
1. **Повторное ревью отревьюенной постановки.** Координатор ревьюит
|
||
готовый тикет, уже прошедший ревью на этапе постановки. Правило
|
||
«одно ревью на версию артефакта» в этапе 2 ЕСТЬ (записано
|
||
2026-07-21) — и не держит. Класс отказа тот же, что с вкусовой
|
||
линзой (запись 2026-07-31, в архиве): правило в прозе не исполняется, нужен
|
||
механизм — например, перед этапом 2 координатор обязан назвать,
|
||
какая версия тикета когда ревьюилась, и пропустить этап, если
|
||
версия не менялась.
|
||
2. **Переоценка сложности.** Полный цикл ревью там, где хватило бы
|
||
саморевью. Шкала риска этапа 4 есть — и тоже не держит: дефолт
|
||
скилла «полный состав минус пропуски» (opt-out), координатор
|
||
склонен к максимальной церемонии. Кандидат на следующий заход:
|
||
перевернуть дефолт — минимальный хребет (постановка → исполнитель →
|
||
саморевью → приёмка) + явные триггеры эскалации (opt-in); добавить
|
||
слой дешевле, чем отменить запущенный.
|
||
3. **Код Кодекса нельзя показывать ученикам.** Формально задачу решает
|
||
хорошо, но «не хочу их учить так писать» — это не дефект кода, это
|
||
дефект назначения исполнителя. Боевое подтверждение оси вкуса,
|
||
принятой этим же днём: в учебном репозитории почти всё читает
|
||
человек → почти вся реализация уходит `craftsman`'у, Codex — на
|
||
обвязку и инфраструктуру. Проверить следующим прогоном, снимает ли
|
||
новый разрез эту боль.
|
||
4. **Скилл зовут ради механики субагентов, не ради конвейера.**
|
||
Регулярный сценарий: дать агенту знание «субагенты существуют, вот
|
||
как их звать» для специальной задачи — а вызов тянет весь конвейер.
|
||
Это отдельная ветка использования: дисциплина делегирования (Роли,
|
||
определения, файлы-вместо-пересказов) полезна вне цикла разработки.
|
||
Кандидат: выделить её в лёгкий скилл или отдельную точку входа,
|
||
чтобы «субагентная грамотность» не стоила 300 строк процесса.
|
||
|
||
Пункты 1–2 и 4 — открытый вопрос следующего структурного захода (сегодняшний
|
||
рефакторинг закрыт коммитом 3e0498e, не расширять задним числом).
|
||
|
||
## 2026-08-01: триаж судит находку, но не лечение (clickstream v2, тикет #36)
|
||
|
||
Конфигурация редкая: оркестратор и есть исполнитель — плейбук позвали
|
||
поверх готовой работы `/implement`, третьей линией (Кодекс, high) к двум
|
||
уже прошедшим Клод-линиям. Пересылать индекс некому, триаж вёлся в голове;
|
||
статусы по ID появились файлом только ради перепроверки, задним числом.
|
||
|
||
- **Все три находки верны, одно лечение — перебор.** REV-1 «имена не с чем
|
||
сверить» я закрыл записью 47 имён второй копией — то есть прибил гвоздями
|
||
решение чужого слоя (имена атрибутов складывает модель DDS, спека задала
|
||
только вид имени). Поймал владелец вопросом «ты прибил гвоздями?», не
|
||
процесс. Триаж в скилле судит находку (FIXED / REJECTED / …), а лечение
|
||
проезжает без суда — тем более что колонка «как проверить» у Кодекса
|
||
фактически лечение и предписывает.
|
||
- **`NEEDS_DECISION` был доступен и не сработал.** Починка замораживала
|
||
решение будущего тикета — ровно его случай. Не опознал, потому что правка
|
||
выглядела дешёвой: 47 механических строк. Урок-обобщение: дешевизна
|
||
починки ничего не говорит о том, чьё это решение.
|
||
- **Перепроверка тем же ревьюером перебор не ловит структурно**: вернула
|
||
`ALL_CLOSED`, подтверждая реализацию собственного предписания.
|
||
- **Промах в промпте ревью**: перечислены источники истины, но не «какие
|
||
решения ещё открыты и кем владеются» — ревьюер физически не мог знать,
|
||
что имена DDS не наши. Кандидат: обязательный блок открытых решений.
|
||
- Цифры: ревью 124 команды, 3 находки (2 MAJOR, 1 MINOR); перепроверка на
|
||
medium — 46 команд. Одна находка фактическая (комментарий рекламировал
|
||
торговые события, от которых спека отказалась) — её обе Клод-линии
|
||
пропустили: подтверждение ценности другой родословной.
|
||
|
||
## 2026-08-02: перепроверка толкает лечение в обе стороны (clickstream v2, тикет #38)
|
||
|
||
Конфигурация та же, что 08-01: оркестратор он же исполнитель, Кодекс (high)
|
||
третьей линией к двум прошедшим Клод-линиям. Снова три находки, все верны;
|
||
снова другая родословная дала класс, мимо которого прошли обе Клод-линии —
|
||
честность тестов: сторож сравнивал день −N с днём N, а сталкиваются −N и N−1.
|
||
|
||
- **Перепроверка тем же ревьюером не судит соразмерность лечения ни в одну
|
||
сторону.** 08-01 она вернула `ALL_CLOSED`, подтвердив исполнение
|
||
собственного предписания; здесь на ту же починку — `NOT_CLOSED` с
|
||
требованием недостижимого (полная неприкосновенность запомненной когорты:
|
||
в numpy владелец памяти размораживается всегда, а вид всегда показывает
|
||
`.base`). Одна дыра, две стороны. Приём: на `NOT_CLOSED` проверять не
|
||
только факт, но и существует ли закрывающее состояние, и мерить цену
|
||
альтернативы — здесь 16 МиБ копий на день вместо 2 мс, то есть размен
|
||
реального свойства на защиту от умысла.
|
||
- **Долг 08-01 не закрыт: статус вешается на находку, не на лечение.** Здесь
|
||
лечение судилось только потому, что владелец потребовал этого в
|
||
постановке («Кодекс коварен, польза бывает очевидна на первый взгляд»).
|
||
Механизма по-прежнему нет.
|
||
- **Новый класс: сломан не код, а измерительный прибор.** Цикл мутаций
|
||
«правка → прогон → откат» внутри секунды оставлял устаревший `.pyc`
|
||
(свежесть — по времени правки и размеру), тесты шли по байт-коду мутанта
|
||
и падали на восстановленном дереве. Чуть не «починил» работающее. Линии
|
||
ревью смотрят на код и такого не ловят; конвейер молча допускает, что
|
||
проверялка оркестратора исправна. Приём: мутации гонять с
|
||
`PYTHONDONTWRITEBYTECODE=1`, первым и последним прогоном — чистое дерево.
|
||
- **Польза линии пришла как «изменил, что я проверяю»**: находка развернула
|
||
батарею мутантов на дерево зёрен, которое я считал очевидным, — там
|
||
нашлись ещё два слепых сторожа. Слить ветвь дней с ветвью состава можно
|
||
было, не уронив ни одного из 297 тестов.
|
||
- Цифры: ревью 68 команд, 3 находки (1 MAJOR завышен — сценарий требует
|
||
сознательно снять флаг у массива, 2 MINOR); перепроверка на medium — 12
|
||
команд; батарея 17 мутантов, выживших нет.
|
||
|
||
## 2026-08-02: долг «суда над лечением» закрыт шапками (clickstream v2, тикет #39)
|
||
|
||
Штатная конфигурация: реализация — Опус-мастеровой, линия кода — Кодекс (high)
|
||
свежим тредом, линия задачи и вкуса — свежий Опус. Долг двух прошлых прогонов
|
||
закрыт руками: в шапку триажа и в шапку перепроверки дописаны абзацы про
|
||
соразмерность лечения (заготовки прогона; перенесены в шапки 2026-08-03).
|
||
|
||
- **Ручка сработала трижды за один прогон.** Перепроверка вкусовой линии
|
||
сама оценила правку спеки на перебор (вышла за границу промпта — принята
|
||
с доводом: четыре фразы без поведения, чинят противоречие, внесённое этим
|
||
же изменением), приняла закрытие маршрутом, отличным от подсказанного
|
||
(«запрет был не той половиной, которую надо чинить»), и обосновала
|
||
соразмерность нового модуля. Без ручки всё три проехали бы молча, как в #36.
|
||
- **10 FIXED, 0 REJECTED — повод посмотреть на лечения, а не приговор.**
|
||
Перебора не нашлось, но узнал я это проверкой, а не по отсутствию отказов.
|
||
- **Пересечение линий — ноль из десяти, и каждая принесла свою дыру в
|
||
честности тестов.** CODE-1: слепок детерминизма не включал ни порядок
|
||
колонок, ни публичные швы для соседнего тикета — перестановка колонок через
|
||
вызов проходила все три сторожа. TASK-4: сторож правил нарезки ловил склейку
|
||
двух визитов, но не разрез одного. Разные тесты, разные механизмы.
|
||
- **Тонкий лог перепроверки — повод проверить MAJOR самому.** 8 команд против
|
||
58 в самом ревью; закрытие единственного MAJOR перепроверил своим зондом
|
||
(перестановка колонок, правка каждого шва, стабильность того же дня) — закрыт
|
||
честно. Цена приёма — один скрипт оркестратора.
|
||
- **Два отказа вызова Кодекса, оба от чтения правил без разбора.**
|
||
`< /dev/null` по правилу «фоновому запуску закрывай stdin» убивает промпт,
|
||
который сам идёт через stdin (`No prompt provided via stdin`), — правило не
|
||
про этот случай. И `codex exec resume` (0.145.0) не принимает `-s`/`-C`:
|
||
среда треда задана при создании и на продолжении не переуказывается;
|
||
остальные ключи (`-m`, `-c`, `-o`, `--json`) те же, что у `exec`. Уточнено
|
||
2026-08-03: хвост «песочница только через `-c sandbox_mode=…`» был неверен —
|
||
ключ разбирается, но среду продолжения не меняет. Оба отказа закрыты по
|
||
месту: `codex-exec.md` (рецепт resume и правило stdin), `SKILL.md` этап 6
|
||
(правило `< /dev/null` сужено условием «нечего читать со входа»).
|
||
- Цифры: два ревью — 58 и 36 команд/инструментов, 10 находок (1 MAJOR,
|
||
8 MINOR, 1 NIT); триаж — 10 FIXED; перепроверки на medium — 8 и 12; тесты
|
||
297 → 353.
|
||
|
||
## 2026-08-02: шапки соразмерности сработали в третий раз (clickstream v2, тикет #40)
|
||
|
||
Конфигурация редкая по исполнителю: тикет залезал на территорию трёх соседних
|
||
(план состава #38, воронка и каталог #39), и вкусовую реализацию вёл не
|
||
`craftsman`, а `deep-reasoner` — решение пользователя, обоснование: не письмо
|
||
по готовой форме, а калибровка «померил — подкрутил — померил» под вилки мира.
|
||
Оправдалось: 41 минута, 26 новых тестов, числа мира легли в вилки с первого
|
||
захода. Линия кода — Кодекс (high) свежим тредом, линия задачи и вкуса —
|
||
свежий Опус.
|
||
|
||
- **Пересечение линий — одна находка из девяти, и обе линии описали её
|
||
по-разному.** Полуночная потеря покупки при выжившей странице подтверждения:
|
||
Кодекс сконструировал сценарий и дал MAJOR, Опус померил 14 канонических дней,
|
||
нашёл ноль случаев и записал в необязательные соображения. Не спор, а два
|
||
свидетельства об одном латентном дефекте (окно ~7 с на заказ). Приём:
|
||
сводя вердикты, ищи не совпадение формулировок, а совпадение явления —
|
||
разная оценка достижимости у линий нормальна и полезна.
|
||
- **Шапка соразмерности лечения окупилась на MAJOR'е.** Исполнитель отклонил
|
||
маршрут ревьюера («проверь симптом там, где он виден») и починил слоем выше —
|
||
граница суток даёт подтверждению место под торговый хвост. Довод сильный:
|
||
починка внутри `commerce` двигала бы просмотры страниц при правке торгового
|
||
подпотока, то есть ломала бы ровно то свойство, о котором вторая находка
|
||
того же ревью. Без шапки предписание проехало бы молча, как в #36.
|
||
- **9 FIXED / 0 REJECTED — и одно ослабление порога всё же было.** TASK-3:
|
||
группа стала строже (пары исключены), измеренный лифт упал ×4,7 → ×3,0,
|
||
и порог теста опущен `> 3` → `> 2`. Обосновано, но это ровно тот ход, от
|
||
которого предостерегает шапка, — судить его отдал перепроверке той линии,
|
||
что находку и подняла. Вернулась CLOSED с воспроизведёнными числами.
|
||
- **Тонкий лог перепроверки Кодекса (10 команд) — снова повод проверить MAJOR
|
||
самому.** Свой зонд оркестратора: 14 дней × два режима, включая стресс с
|
||
часовым торговым хвостом (окно, в котором дефект жил) — ноль подтверждений
|
||
без покупки и ноль покупок без подтверждения. Приём из #39 подтверждён.
|
||
- **Приёмка глазами нашла то, чего не даёт ни один вердикт: урок виден в
|
||
данных.** Распечатал один визит целиком и померил разрыв: у 157 покупок из
|
||
272 сумма по разобранным массивам не равна `purchaseRevenue` (2680 против
|
||
2679,8). Ради этого копейки в каталог и заводились — без своего прогона
|
||
осталось бы верить отчёту.
|
||
- Цифры: реализация 41 мин / 328k токенов, саморевью 8/8; ревью — Клод 33
|
||
инструмента, Кодекс 120 команд; 9 находок (2 MAJOR, 5 MINOR, 2 NIT),
|
||
пересечение 1; триаж 9 FIXED за 13 мин; перепроверки 13 и 10 команд, обе
|
||
ALL_CLOSED + 1 новый NIT (повтор фразы в спеке, внесённый починкой TASK-2) —
|
||
поправил сам по месту. Тесты 353 → 383.
|
||
- **Долг скилла остаётся тот же**: абзацы про соразмерность лечения третий
|
||
прогон подряд пишутся руками. Закрыт 2026-08-03.
|
||
|
||
## 2026-08-02: сломанный прибор доезжает до коммита (clickstream v2, тикет #50)
|
||
|
||
Продолжение #40 после грилинга: реализация — `deep-reasoner` (калибровка
|
||
чисел мира), линия кода — Кодекс (high) свежим тредом, линия задачи и вкуса —
|
||
свежий Опус. Ревью постановки — одна линия (Кодекс), вторая пропущена: решения
|
||
уже прогриллены и лежат в спеке.
|
||
|
||
- **Ошибка измерения всплыла трижды на трёх уровнях, и ни разу её не поймал
|
||
тот, кто мерил.** (1) Оркестратор мерил на зерне 0, а весь мир и все тесты
|
||
живут на `CANONICAL_SEED` — поймало ревью постановки; (2) в знаменателе
|
||
«просмотры карточек» сидели строки событий корзины, потому что событие
|
||
садится на ту же страницу, — поймал исполнитель; (3) маска «строка с
|
||
массивом товаров» захватывала и строку покупки — поймал сам оркестратор,
|
||
сверив арифметику отчёта. Два из трёх уже уехали в коммит спеки. Класс
|
||
дефекта не новый (#38 — устаревший `.pyc`), но новое здесь то, что прибор
|
||
ломается на **чтении** данных, а не на прогоне, и потому переживает и
|
||
тесты, и ревью кода. Приём: числа, попадающие в постановку и спеку, сверять
|
||
арифметикой независимо от источника — сумма частей, тождества между
|
||
колонками; и называть зерно явно везде, где написано «канонический день».
|
||
- **Наблюдение владельца по итогам дня: Кодекс дрейфует к букве.** Прогон
|
||
его уточняет, а не подтверждает целиком. На **постановке** Кодекс работал
|
||
ровно по смыслу — половина из девяти находок это охота на формальность
|
||
(«критерий закрывается одним визитом», «требование живёт в прозе, а не в
|
||
чекбоксе»). На **коде** он вернул 1 MINOR за 120 команд и прошёл мимо
|
||
главного дефекта прогона — дефекта цели, видного только тому, кто держит в
|
||
голове, зачем тикет заведён. Часть промаха назначена линзой оркестратора
|
||
(«не дублируй вкусовую линию»), но остаётся устойчивый осадок из #36/#38/
|
||
#40: **лечения** Кодекса буквальны даже внутри его линзы. Кандидат в
|
||
механизм (не решение): требовать от линии Кодекса перед индексом один
|
||
абзац — «что сделает эту правку провальной, даже если все критерии
|
||
зелёные».
|
||
- **Шапка соразмерности сработала дважды за прогон.** Исполнитель отверг
|
||
предложенный ревьюером ряд вероятностей, перемерив его (давал 1,84 при
|
||
требуемых 2), и закрыл находку другим маршрутом; перепроверка поймала
|
||
необязательный сдвиг порога (0,05 → 0,03 при измеренных 7,25% — старый пол
|
||
проходил). Второе — новый факт: **порог, сдвинутый и честно объявленный,
|
||
всё равно бывает лишним**; объявление снимает скрытность, но не заменяет
|
||
проверку необходимости.
|
||
- **Ревьюер признал своё предложение неверным на перепроверке** — раньше
|
||
такого не встречалось. Перепроверка, которой явно поручено судить лечение,
|
||
судит и собственное предписание.
|
||
- **Приёмка глазами снова дала то, чего не даёт ни один вердикт**: один
|
||
распечатанный визит показал новый сюжет целиком (шесть карточек, две в
|
||
корзину, корзина не открыта) и заодно, что кладут не только магниты, —
|
||
то есть главная правка видна на одном случайном примере.
|
||
- Казус: `make` в промпте звался из `generator/`, а Makefile лежит в корне —
|
||
три «красных» прогона на пустом месте, и ревью постановки этого не поймало
|
||
(команды проверки оно не запускало).
|
||
- Цифры: ревью постановки 32 команды / 9 находок, все приняты; реализация
|
||
~31 мин, саморевью 3/3; слепые ревью — Опус 28 инструментов / 7 находок,
|
||
Кодекс 120 команд / 1, пересечение **ноль**; триаж 8 FIXED + второй круг
|
||
на 1 новую находку, 0 отклонённых; перепроверки 15 и 18; тесты 383 → 394.
|
||
- **Долг четвёртый прогон подряд тот же**: шапки соразмерности так и не
|
||
перенесены. Закрыт 2026-08-03.
|
||
|
||
## 2026-08-03: долг соразмерности закрыт, и найдена его настоящая причина
|
||
|
||
Сессия без прогона: разбор `lessons.md` по `/writing-great-skills` и правка
|
||
шапок. Долг, висевший с #39, закрыт — правки лежат в
|
||
`prompts/triage-header.md` и `prompts/recheck-header.md`, содержание там,
|
||
здесь не дублирую.
|
||
|
||
- **Причина не в размере починки, а в весе слова** (диагноз пользователя).
|
||
Пока код писал Кодекс, а ревьюил Опус, послушный исполнитель был прав:
|
||
ревьюер сильнее как архитектор. После разворота ролей — вкусовая
|
||
реализация Опусом, ревью Кодексом — послушание стало вредным: Кодекс
|
||
очень сильный исполнитель, но слабее как мыслитель-архитектор, настойчив,
|
||
склонен к формализации без учёта высокоуровневой цели и продавливает
|
||
Опуса на свои решения. Перекос усиливает разница ступеней: Опус на medium
|
||
против Сола на high уступает ещё и по «званию».
|
||
- **Цифра под диагнозом**: #39, #40, #50 — около 28 находок, ноль
|
||
отклонений.
|
||
- **Два кандидата сняты сверкой с эмпирикой, а не по вкусу.** Требование
|
||
объявлять ослабление порога отдельной строкой — против него сам урок #50
|
||
(«объявление не заменяет проверку необходимости»), а оба случая (#40,
|
||
#50) поймала перепроверка. Пункт «оценивай довод исполнителя, а не факт
|
||
несогласия» — дубль строки, уже стоявшей в шапке.
|
||
- **Правило об арбитре в споре не писалось намеренно**: спора ни разу не
|
||
было (ноль отклонений), правило под несуществующую ситуацию есть
|
||
перерегулирование. Ждём первого отклонения — новые шапки как раз должны
|
||
его породить.
|
||
- **Разбор самого файла**: 783 строки, 22 записи; собственное правило
|
||
«поглощён урок — сожми до строки-факта» сработало один раз (07-12) и с
|
||
тех пор нет — записи после него по 30–80 строк, часть держит вторую копию
|
||
действующих правил SKILL.md. Дистилляция архива вынесена отдельным
|
||
заходом.
|
||
|
||
**Очередь на механизм** (сведена сюда, чтобы не искать по всему файлу):
|
||
блок открытых решений в промпте ревью — «какие решения ещё открыты и кем
|
||
владеются» (#36); абзац от линии Кодекса «что сделает эту правку
|
||
провальной, даже если все критерии зелёные» (#50); приёмы против сломанного
|
||
прибора оркестратора (#38 — `PYTHONDONTWRITEBYTECODE=1` и чистое дерево
|
||
крайними прогонами; #50 — арифметика чисел, попадающих в спеку, и явное
|
||
зерно; #39/#40 — тонкий лог перепроверки как повод проверить MAJOR своим
|
||
зондом; #40/#50 — один пример целиком на приёмке); мелочи по месту —
|
||
сведение вердиктов по совпадению явления, а не формулировки (этап 5), ревью
|
||
постановки не запускает команды тикета (этап 2), оговорка про `< /dev/null`
|
||
рядом с приёмом в `codex-exec.md`; старьё — ранжирование правил задачи
|
||
(07-07), эхо файла задачи (07-13), A/B на gpt-5.6-terra (07-13), пп. 1–2 и 4
|
||
одёргиваний (07-31).
|
||
|
||
## 2026-08-04: находки холодного ревью долечены; запрет против значения
|
||
|
||
Сессия без прогона, продолжение 08-03: триаж находок холодного ревью самого
|
||
скилла. Что именно поправлено — в коммитах от `c18472e`, здесь не дублирую.
|
||
|
||
- **Правило, нарушаемое рассуждением, лечится значением, а не ещё одним
|
||
запретом.** «Не режь ревьюеру read-only» стояло в двух местах — и было
|
||
нарушено при сборке команды для этого же холодного ревью: не по
|
||
незнанию, а доводом «ревью документа рук не требует». Промпт при этом
|
||
сам обещал ревьюеру опыты во временных файлах, которые песочница
|
||
запрещала, — тред пришлось убить и перезапустить. Вылечено тем, что
|
||
песочница названа значением с причиной при нём, а ветке ревьюера дан
|
||
целый рецепт: не осталось повода собирать команду руками.
|
||
- **Случай третий той же формы** (два прежних в архиве: 07-22 канал
|
||
обёртки, 07-30 `danger-full-access` «на всякий случай» из-за оговорки
|
||
«боем не обкатано»). Отказ скилла — не отсутствующее правило, а правило,
|
||
оставляющее рассуждению право на исключение; оговорка в рецепте читается
|
||
как приглашение к самодеятельности.
|
||
- **Скретчпад поднимается из транскрипта сессии.** Ребут стёр каталог;
|
||
шесть документов восстановлены fast-worker'ом из JSONL сессии
|
||
(`~/.claude/projects/<проект>/<id>.jsonl`): вызовы Write отдают тело
|
||
дословно, файлы чужих процессов — из эха Read с обрезкой номеров строк.
|
||
Не поднимаются промпты, ушедшие в `cat ... |` на stdin: их тело в
|
||
транскрипт не попадало. Цена — 48k токенов субагента, три минуты.
|
||
- **Вывод под этим**: пережить сессию должно то, что лежит вне скретчпада.
|
||
Индексы находок целиком не переносим — в handoff идут открытые, с
|
||
номером и доводом линии; закрытые читаются по коммитам.
|
||
- **Диагноз пользователя: краткость исполнителя ломает решение.** Метку
|
||
NEEDS_DECISION ставит тот, кто единственный держит код в голове, а
|
||
наверх уходит голый вопрос — координатор кода не читал по устройству
|
||
ролей, владелец тем более. Дословно: «Опус пишет так, как будто я очень
|
||
хорошо разбираюсь в коде и проблеме, а так бывает далеко не всегда».
|
||
Отсюда требование вариантов, их цены и рекомендации — и к исполнителю, и
|
||
к координатору, когда он несёт развилку владельцу.
|
||
|
||
## 2026-08-06: вывод Кодекса теряет харнесс, а не версия
|
||
|
||
Запись переписана в тот же вечер: первая редакция валила отказ на версию
|
||
codex-cli 0.146.0 и была неверна. Развели две проверки — холодная A/B
|
||
(изолированная установка 0.146.0 рядом с глобальной 0.146.1, обе штатны) и
|
||
контрольные прогоны изнутри харнесса, где отказ живёт и на 0.146.1.
|
||
|
||
- **Версия ни при чём.** Чистые 0.146.0 и 0.146.1 на этой же машине пишут в
|
||
перенаправленный файл штатно: `codex --version > f` — 18 байт, `--json` —
|
||
семь строк JSONL с `thread.started` и `command_execution`. Списать отказ
|
||
на версию — первый соблазн: он объясняет всё и не требует ничего. Цена
|
||
проверки — десять минут на установку в отдельный префикс, и она стоит
|
||
того, чтобы гипотеза не уехала в журнал утверждением.
|
||
- **Ось — файл против канала.** Изнутри харнесса T3 Code (SDK-хост) на
|
||
0.146.1: `codex --version > f` — ноль байт и код 0, `codex --version |
|
||
cat > g` — 18 байт. То же на полном вызове: `exec --json … > log` — пусто,
|
||
он же через `2>&1 | cat > log` — семь строк, thread_id в первой,
|
||
`command_execution` дважды. Отчёт `-o` пишется в обоих случаях: файлы,
|
||
которые Кодекс открывает сам, целы — пропадает унаследованный дескриптор,
|
||
когда за ним файл. Stderr так же: `Error loading config.toml…` виден
|
||
только через канал. Отключение песочницы Bash ничего не меняет.
|
||
- **Тот же разрез объясняет и вход.** `exec - < prompt.md` изнутри даёт
|
||
`No prompt provided via stdin` и код 1, `cat prompt.md |` работает; вне
|
||
харнесса работают оба. Одна причина на обе находки первой редакции — и обе
|
||
снимаются каналом.
|
||
- **Не всякий харнесс — этот харнесс.** В Claude Code CLI 2.1.223 на той же
|
||
машине и той же 0.146.1 всё штатно: файл на выходе — 18 байт, лог — семь
|
||
строк, `- < prompt.md` читается. Ярлыку «я в агенте» не верь, спроси среду
|
||
сама — самотест стоит пять секунд и живёт предполётом в
|
||
[codex-exec.md](codex-exec.md).
|
||
- **Лечение живёт в рецептах, не здесь.** Форма сбора — каждый поток своим
|
||
каналом в свой файл — стоит там же, в предполёте, и включается по
|
||
результату самотеста; сами рецепты не правились. Три вещи, которые стоили
|
||
отдельной проверки. `2>&1 | cat` короче и подкладывает ошибку разбора:
|
||
строка stderr в JSONL ломает `jq` и может встать первой вместо
|
||
`thread.started`. Канал глотает код возврата (`false | cat` даёт ноль) —
|
||
отсюда `set -o pipefail` в форме. Псевдотерминал из первой редакции не
|
||
нужен: `script` давал тот же JSONL ценой `\r` и непереносимости.
|
||
- **Механизм не вскрыт.** Известно поведение, не причина: файл на входе и
|
||
выходе дочернего процесса пуст, канал цел, песочница ни при чём. Пишу это
|
||
свойством среды и не выдаю за объяснение.
|
||
- **Цена неверной атрибуции — коммит в репозиторий скилла.** Правило «пока
|
||
причина не снята запуском с одним изменением, она гипотеза» у меня было —
|
||
и не спасло: внутри серии я честно менял по одному параметру, но вся серия
|
||
целиком стояла в одной среде, и согласованность её прогонов читалась
|
||
подтверждением. Отсюда добавка к правилу: среда — тоже параметр, и первый
|
||
кандидат на подозрение, когда наблюдение расходится с документацией
|
||
инструмента. Сняла ошибку чужая проверка, не моя.
|
||
- **Уцелевшая ловушка**: запуск из недоверенного каталога (пробовал из
|
||
`/tmp`) даёт `Not inside a trusted directory and --skip-git-repo-check was
|
||
not specified.` Снаружи это видно в stderr и коде 1; изнутри харнесса
|
||
сливается со всеми прочими отказами в пустоту и код 1.
|
||
- Цифры: два захода контрольных прогонов, промпт односложный («выполни
|
||
`pwd`»), `model_reasoning_effort="low"`; отчёт `-o` — 46 байт в каждом,
|
||
лог через канал — семь строк.
|