docs(skills): предполёт в рецептах Кодекса, урок отдал форму сбора

- Зачем:
  - среда сама отвечает за пять секунд, теряет она унаследованный файловый
    дескриптор или нет, поэтому документ несёт проверку, а не ответ; форма
    сбора вывода за вечер менялась дважды и не должна жить в двух местах.
- Что:
  - в «Сквозные правила» 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>
This commit is contained in:
Dmitry DementievandClaude Opus 5 committed 2026-08-06 19:04:27 +03:00
1 parent 5665b96641
commit 1b73419c1d
2 files changed
+29 -27

No files matched your search

@@ -362,30 +362,16 @@ codex-cli 0.146.0 и была неверна. Развели две провер
- **Не всякий харнесс — этот харнесс.** В Claude Code CLI 2.1.223 на той же
машине и той же 0.146.1 всё штатно: файл на выходе — 18 байт, лог — семь
строк, `- < prompt.md` читается. Ярлыку «я в агенте» не верь, спроси среду
сама, это пять секунд:
```bash
codex --version > f; wc -c f # 0 — среда теряет унаследованный файловый
# дескриптор, собирай вывод каналом
# 18 — рецепты codex-exec.md как написаны
```
- **Правило, годное в обеих средах**: и промпт, и вывод гнать каналами,
потоки при этом не сливать —
```bash
cat "$D/task-prompt.md" | codex exec --json … -o "$D/task-result.md" - \
2> >(cat > "$D/task-stderr.txt") | cat > "$D/task-stdout.jsonl"
```
`2>&1 | cat` был бы короче и подложил бы ошибку разбора: строка stderr
в JSONL ломает `jq` и может встать первой вместо `thread.started`. В
разъехавшемся виде живут все три механизма рецептов — thread_id из первой
строки, сторож по росту лога, проверка отписки через `command_execution`.
Оговорка: подстановка процесса дописывает stderr асинхронно, перед чтением
этого файла в том же вызове нужен `wait`. Псевдотерминал из первой редакции
не нужен: `script` давал тот же JSONL ценой `\r` и непереносимости. Сами
рецепты `codex-exec.md` не правились — форма выше их не отменяет, а
дописывает сбор вывода.
сама — самотест стоит пять секунд и живёт предполётом в
[codex-exec.md](codex-exec.md).
- **Лечение живёт в рецептах, не здесь.** Форма сбора — каждый поток своим
каналом в свой файл — стоит там же, в предполёте, и включается по
результату самотеста; сами рецепты не правились. Три вещи, которые стоили
отдельной проверки. `2>&1 | cat` короче и подкладывает ошибку разбора:
строка stderr в JSONL ломает `jq` и может встать первой вместо
`thread.started`. Канал глотает код возврата (`false | cat` даёт ноль) —
отсюда `set -o pipefail` в форме. Псевдотерминал из первой редакции не
нужен: `script` давал тот же JSONL ценой `\r` и непереносимости.
- **Механизм не вскрыт.** Известно поведение, не причина: файл на входе и
выходе дочернего процесса пуст, канал цел, песочница ни при чём. Пишу это
свойством среды и не выдаю за объяснение.