docs(skill): добавлен handoff по наблюдаемости

- Зачем:
  - нужно передать на другую машину договорённости по наблюдаемости coordinator-loop.
- Что:
  - добавлен handoff с форматом live-логов, summary и правилами gitignore.
  - зафиксированы отказ от state.md и run-id, а также best-effort heartbeat.
- Проверка:
  - просмотрен staged diff нового handoff-файла.
This commit is contained in:
ddadmin committed 2026-06-14 20:10:47 +03:00
1 parent 8f6d9de9d5
commit cf4056fe66
1 file changed
+229
@@ -0,0 +1,229 @@
# Handoff: наблюдаемость coordinator-loop
Дата: 2026-06-14 20:00 MSK
Статус: рабочая договорённость, ещё не внесена в `SKILL.md`
## Зачем этот handoff
Нужно передать на другую машину выводы обсуждения про минимальную наблюдаемость
работы субагентов в `coordinator-loop`. Это не runtime-инструкция: обычный агент
при запуске скилла читает `SKILL.md`, а не этот файл. Если решение надо проверить
на реальном цикле, короткий минимум придётся добавить в `SKILL.md`.
## Контекст
- Скилл: `/home/dementev/dotfiles/agents/.agents/skills/coordinator-loop/`.
- Основная инструкция: `SKILL.md`.
- Человеческое описание и границы: `README.md`.
- Обоснование процесса: `references/rationale.md`.
- В `dotfiles` уже были сделаны коммиты:
- `aa3e362 fix(skill): уточнена обработка чужих правок координатором`
- `8f6d9de docs(skill): уточнено назначение README coordinator-loop`
## Проблема
При долгой работе worker-а координатор и пользователь плохо видят, что происходит.
Чатовый контекст ненадёжен: координатор может уйти в compaction, потерять детали
старта команды или не понять, сколько длится ожидание. При этом нельзя превращать
координатора в секретаря, который постоянно ведёт подробный журнал.
Нужна минимальная наблюдаемость:
- понять, какой issue сейчас в работе;
- увидеть последнюю фазу и последнюю нетривиальную команду;
- восстановить примерную длительность фаз;
- не спамить координатора сообщениями;
- не смешивать процессный шум с рабочими коммитами.
## Принятый дизайн
Использовать feature-local файлы рядом с локальными issues:
```text
.scratch/<feature>/coordinator-runs/
live/ # временные live-логи, в .gitignore
<NN>-<issue-slug>.md
summary.md # короткий итог, можно коммитить
```
Причина: `.scratch/<feature>/` уже является местом локальных issues. Наблюдаемость
должна жить рядом с ними, а не в глобальной папке.
## Git-правило
Не игнорировать весь `.scratch/`: в этом репозитории `.scratch/` используется как
локальный issue tracker и коммитится. Игнорировать только живой шум:
```gitignore
# Временные live-логи coordinator-loop.
.scratch/*/coordinator-runs/live/
```
`summary.md` можно коммитить как итоговый артефакт прогона.
## Live-log
Один файл на issue. Этого достаточно: цикл по feature одноразовый, а если worker
упал и был запущен заново, новый worker продолжает дописывать тот же файл.
Координатор перед запуском worker-а:
1. создаёт `coordinator-runs/live/<NN>-<issue-slug>.md`;
2. передаёт путь worker-у в задании;
3. передаёт тот же путь reviewer-у, если reviewer нужен.
Worker и reviewer:
- только дописывают в конец файла;
- не обязаны читать предыдущие записи;
- ставят текущую временную метку в каждой записи;
- не пишут рассуждения и полный вывод тестов.
Координатор:
- знает путь к live-log;
- читает его только при необходимости: пользователь спросил статус, worker долго
молчит, произошёл фазовый переход, нужен контекст перед коммитом;
- не обязан вручную поддерживать live-log.
## Формат записи
Append-only Markdown-блоки. Они читаются глазами лучше, чем строки с `|`, и не
ломаются от команд с кавычками или длинными путями.
```md
### 2026-06-14 19:52 MSK — worker — tests
- event: started
- command: `uv run pytest tests/generator/test_state.py`
- note: checking state v2 restore cases
```
```md
### 2026-06-14 19:58 MSK — worker — tests
- event: passed
- result: 8 passed
- next: self-review
```
Минимальные поля:
- заголовок: время, роль, фаза;
- `event`: `started`, `progress`, `passed`, `failed`, `blocked`, `heartbeat`,
`restarted`, `final`;
- `command`: команда, если запись про запуск проверки;
- `result`: короткий итог, если есть;
- `next`: следующий шаг, если понятен;
- `note`: короткая поясняющая заметка, если нужна.
## Что логировать
Обязательные события:
- старт работы по issue;
- перезапуск worker-а после сбоя: `event: restarted`;
- смена фазы;
- начало нетривиальной команды;
- результат нетривиальной команды;
- блокер;
- финальный отчёт готов.
Нетривиальная команда: тесты, линтеры, сборка, Docker, миграции, симуляции,
обращение к внешнему сервису, обработка заметного объёма данных, либо любая
команда, длительность которой агент не уверен как оценить.
Не логировать:
- каждую мелкую правку;
- каждый прочитанный файл;
- `rg`, `sed`, `ls`, `git diff`, `git status` и похожие быстрые операции;
- внутренние рассуждения;
- полный вывод тестов.
## Heartbeat
Heartbeat нужен как best-effort, а не строгий таймер.
Если работа длится больше примерно 5 минут и агент находится между командами или
может безопасно прерваться на запись, он дописывает:
```md
### 2026-06-14 19:55 MSK — worker — tests
- event: heartbeat
- note: still working; waiting for simulation/test result
```
Не строить отдельный таймер или фоновый процесс ради heartbeat. Если запущена
блокирующая команда, достаточно записи `event: started` перед ней.
## Почему не state.md
Обсуждали отдельный `state.md`, который хранил бы текущий issue, фазу и ожидаемый
следующий шаг. Отказались: если `state.md` ведёт координатор, это добавляет
нагрузку и снова делает координатора секретарём. Если координатор ушёл в
compaction, восстановиться можно из `git status` и хвоста последнего live-log.
Первый заход: без `state.md`.
## Почему без run-id
Обсуждали `live/<run-id>/<issue>.md`. Отказались: работа над feature идёт как
один проход по issues. Старые прогоны не должны накапливаться. Если worker упал,
новый worker пишет `event: restarted` в тот же файл issue.
## Summary
После завершения issue координатор переносит короткий итог в `summary.md`. Live-log
остаётся временным и игнорируемым.
Формат раздела на issue:
```md
## <NN>-<issue-slug>
Commit: <hash> <subject>
Result:
- <что наблюдаемо работает>
Checks:
- `<command>` — passed/skipped
Review:
- self-review: <summary>
- independent review: <summary or not run>
Risks:
- <none / list>
```
## Что ещё не сделано
- Это решение пока не внесено в `SKILL.md`.
- `.gitignore` проекта пока не обновлён правилом для `live/`.
- Не было реального прогона coordinator-loop с такой наблюдаемостью.
- Нужно решить, делать ли наблюдаемость всегда или только по явной просьбе / для
длинных задач. Текущая рекомендация: включить как лёгкий стандарт для
coordinator-loop, потому что нагрузка на координатора мала.
## Рекомендуемые следующие шаги
1. Внести короткий раздел «Наблюдаемость» в `SKILL.md`, иначе агент при запуске
`/coordinator-loop` не обязан читать этот handoff или README.
2. Добавить в `.gitignore` правило `.scratch/*/coordinator-runs/live/`.
3. На ближайшем реальном прогоне проверить, не создаёт ли live-log лишний шум.
4. После прогона уточнить `SKILL.md`: оставить, упростить или сделать режим
опциональным.
## Suggested skills
- `write-a-skill` — при переносе правил в `SKILL.md`, чтобы не раздувать основной
файл и оставить runtime-инструкции короткими.
- `conventional-commits` — если изменения в скилле или `.gitignore` будут
коммититься.
- `grill-me` — если нужно ещё раз стресс-тестировать развилки: always-on vs opt-in,
формат summary, порог heartbeat.
- `coordinator-loop` — только при реальном прогоне issues после обновления
`SKILL.md`.