From 78ee8bfa4850f19715c82cfe1d561d68f6547c0c Mon Sep 17 00:00:00 2001 From: Dmitry Dementiev Date: Tue, 4 Aug 2026 00:14:23 +0300 Subject: [PATCH] =?UTF-8?q?fix(skills):=20=D1=81=D1=82=D0=BE=D1=80=D0=BE?= =?UTF-8?q?=D0=B6=20=D0=B7=D0=B0=D0=B2=D0=B8=D1=81=D1=88=D0=B5=D0=B3=D0=BE?= =?UTF-8?q?=20=D1=82=D1=80=D0=B5=D0=B4=D0=B0=20=D1=80=D0=B0=D0=B7=D0=B2?= =?UTF-8?q?=D1=8F=D0=B7=D0=B0=D0=BD=20=D1=81=20=D0=B2=D0=B5=D1=82=D0=BA?= =?UTF-8?q?=D0=BE=D0=B9=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D0=BD=D0=B8=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Зачем: - сторож был зашит на task-result.md и task-stdout.jsonl, то есть на артефакты этапа 3. На ревью и на починке отчёт исполнителя уже лежит рядом, цикл не делал ни одного тика и выходил молча — страховка отсутствовала ровно там, где прогон длиннее всего. - отсутствующий лог был неотличим от неростущего: `|| echo 0` выдавал ноль два тика подряд, и неверный путь читался как застой. - Что: - пара файлов вынесена в переменные REPORT и LOG первой строкой, с указанием подставлять их от страхуемой ветки. - отсутствие лога стало отдельным сигналом NOLOG (редирект создаёт лог сразу, так что через тик его не быть не может). - дописано, что выход из цикла снимает страховку: после STALLED сторож перезапускают руками. - поправлено описание ловушки bfs: он ругается в stderr, а пустым отдаёт только stdout — «молча» было неверно. - Проверка: - симуляция четырёх исходов: штатное завершение, зависание, неверный путь к логу (NOLOG) и ветка ревью при лежащем рядом отчёте этапа 3 — последняя как раз и не работала до правки. Co-Authored-By: Claude Opus 5 --- .../references/codex-exec.md | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/agents/.agents/skills/claude-subagent-playbook/references/codex-exec.md b/agents/.agents/skills/claude-subagent-playbook/references/codex-exec.md index c55ea28..1edba21 100644 --- a/agents/.agents/skills/claude-subagent-playbook/references/codex-exec.md +++ b/agents/.agents/skills/claude-subagent-playbook/references/codex-exec.md @@ -52,33 +52,40 @@ WSL2 Ubuntu: exec/resume/`-o`/фоновый Bash — весь конвейер) его реальному выходу. - **О зависании фоновый запуск молчит**: он будит по выходу, а повисший тред не выходит — живой процесс и работающий процесс снаружи неразличимы. - Признак жизни — рост `stdout.jsonl`, а не статус (2026-07-07). Долгий - прогон страхуй сторожем — вторым фоновым Bash, который выходит либо когда + Признак жизни — рост JSONL-лога, а не статус (2026-07-07). Долгий прогон + страхуй сторожем — вторым фоновым Bash, который выходит либо когда появился `-o`-отчёт, либо когда лог перестал расти. Сторож ходит по артефактам, а не по pid: фоновый Bash отдаёт id задачи харнесса, а pid - процесса тебе неоткуда взять. + процесса тебе неоткуда взять. Пара файлов — **от той ветки, которую + страхуешь** (у ревью `review-impl-*`, у починки `fix-*`): подставь их в + первую строку, иначе сторож проверит чужой отчёт, найдёт его на месте и + выйдет, не сделав ни одного тика. ```bash + REPORT="$D/task-result.md"; LOG="$D/task-stdout.jsonl" # ветка исполнителя prev=-1 - while [ ! -s "$D/task-result.md" ]; do + while [ ! -s "$REPORT" ]; do sleep 300 - [ -s "$D/task-result.md" ] && break - cur=$(wc -c < "$D/task-stdout.jsonl" 2>/dev/null || echo 0) + [ -s "$REPORT" ] && break + [ -e "$LOG" ] || { echo NOLOG; break; } + cur=$(wc -c < "$LOG") [ "$cur" = "$prev" ] && { echo STALLED; break; } prev=$cur done ``` - Две ловушки, обе проверены на симуляции 2026-08-03. Выход проверяй **и - после `sleep`** — иначе сторож объявит застой ровно в тот тик, когда - Кодекс дописывал отчёт. И не переводи признак жизни на относительные - метки времени: `find -newermt '-10 minutes'` под `bfs` (подмена `find` в - части дистрибутивов) молча отдаёт пустой stdout — сторож закричит на - первом же тике. + Проверено симуляцией 2026-08-03: выход проверяй **и после `sleep`**, иначе + сторож объявит застой в тот самый тик, когда Кодекс дописывал отчёт. И не + переводи признак жизни на относительные метки времени: + `find -newermt '-10 minutes'` под `bfs` (подмена `find` в части + дистрибутивов) ругается в stderr, а в подстановку команды отдаёт пустой + stdout — ошибка проглотится, и сторож закричит на первом же тике. - `STALLED` — повод посмотреть, а не вердикт: длинная команда внутри - песочницы (сборка, тесты) событий не пишет. Разбудил — прочти последнюю - строку JSONL и решай сам. + `NOLOG` — путь неверен или запуск не состоялся: редирект создаёт лог сразу, + так что через тик его не быть не может. `STALLED` — повод посмотреть, а не + вердикт: длинная команда внутри песочницы (сборка, тесты) событий не пишет. + Разбудил — прочти последнюю строку JSONL и решай; решил, что жив, — + перезапусти сторож: выходом из цикла он страховку снял. - **thread_id — в первой строке stdout-JSONL** (`{"type":"thread.started",...}`). Забирай сразу после старта: это страховка — если процесс умер или его прибил хост, тред жив: `codex exec resume «дай финальный отчёт»`.