16 KiB
ТЗ: Единообразные коммент-артефакты в Plane от всех агентов
Work Item ID: ORCH-016 Стадия: analysis → architecture → development Автор: analyst Дата: 2026-06-05 Ревизия: 2 (по фидбэку стейкхолдера — добавлен §2.5 Duration; обновлены §1, §2.1, §6)
Контракт: что именно меняем в коде / какие модули задействованы / какие проверки появятся. Архитектурные решения принимает архитектор; здесь — границы изменения.
1. Задействованные модули
| Модуль | Роль в изменении |
|---|---|
src/usage.py |
Главная точка изменения. Здесь сейчас живут usage_comment(), artifact_links(), AGENT_ARTIFACT, AGENT_DISPLAY, AGENT_ICON — основа форматирования. Нужно расширить/добавить хелпер построения единого status-коммента + утилитку форматирования длительности (fmt_duration(seconds: int) -> str). |
src/stage_engine.py |
Эталонная функция аналитика _build_analyst_ready_comment(). По возможности — переиспользовать новый общий хелпер (или хотя бы выровнять формат: emoji + заголовок + описание + список ссылок). К аналитику также прикручиваем строку длительности (см. §2.5). |
src/agents/launcher.py |
_post_usage_comments() — точка, где постится коммент по завершении агента (architect/developer/reviewer/tester/deployer). Должен звать новый хелпер. _duration_s уже считается на строке 391 — пробросить его (или достать из agent_runs.started_at/finished_at) в хелпер. |
src/db.py |
Только для чтения в рантайме коммент-хелпера: agent_runs.started_at, agent_runs.finished_at (уже существуют). Никаких ALTER. |
src/plane_sync.py |
add_comment() — без изменений (используется как транспорт). |
src/qg/checks.py |
Только для чтения: модели парсинга frontmatter verdict: / deploy_status: / staging_status: — переиспользуем эту логику (вынести в отдельную утилитку, либо импортировать там, где она уже есть). |
src/config.py |
settings.gitea_public_url, settings.gitea_owner, settings.gitea_url — без изменений, переиспользуются. |
2. Контракт нового коммент-формата
2.1 Структура (одинакова для всех агентов)
{ICON} {RoleName} — {one-line human description of stage result}
[Verdict / Status: <VALUE>] # опционально, см. 2.3
Длительность: <human-format> # см. 2.5; опускается, только если значение неизвестно
<b>Документы:</b>
• <a href="…">{label}</a> # одна или несколько ссылок
Поля:
{ICON}— берётся изAGENT_ICON(уже есть вusage.py).{RoleName}— изAGENT_DISPLAY(уже есть).{description}— фиксированная строка на роль, см. 2.2.- Verdict / Status — см. 2.3, опускается если не извлекается.
- Длительность — см. 2.5, печатается всегда, когда значение есть; по умолчанию доступна (это нативная метрика
agent_runs). - Ссылки — см. 2.4.
2.2 Описания стадий (per-agent text)
| Агент | Описание (рус.) |
|---|---|
| analyst | «Подготовил BRD / ТЗ / Acceptance Criteria. Для продвижения переведите задачу в статус Approved.» (как сейчас в _build_analyst_ready_comment) |
| architect | «Завершил архитектурную проработку. См. ADR ниже.» |
| developer | «Завершил разработку. См. PR / branch ниже.» |
| reviewer | «Завершил ревью изменений.» |
| tester | «Завершил прогон тестов.» |
| deployer | «Завершил деплой.» |
Точные формулировки финализирует architect; аналитик фиксирует факт наличия 1-предложного описания на каждую роль.
2.3 Verdict / Status строка
Печатается отдельной строкой над списком документов. Источник — frontmatter артефакта; парсить идемпотентно (если файл недоступен — строку пропустить):
| Агент | Поле | Где парсим | Возможные значения | Формат строки |
|---|---|---|---|---|
| analyst | — | — | — | не печатается |
| architect | — | — | — | не печатается |
| developer | — | — | — | не печатается (CI-статус — отдельный гейт) |
| reviewer | verdict: |
docs/work-items/<wid>/12-review.md (YAML-frontmatter) |
APPROVE / REQUEST_CHANGES |
Verdict: APPROVE |
| tester | verdict: (или эквивалентный фронт-кей) |
docs/work-items/<wid>/13-test-report.md |
PASS / FAIL |
Verdict: PASS |
| deployer | staging_status: (для deploy-staging) / deploy_status: (для deploy) |
15-staging-log.md / 14-deploy-log.md |
SUCCESS / FAILED |
Status: SUCCESS |
Если значение в frontmatter отсутствует или не распознано → строка Verdict / Status НЕ выводится (вердикт-парсинг гейтов и сама логика гейтов не меняется).
2.4 Ссылки на артефакты
Базовый URL: (settings.gitea_public_url or settings.gitea_url).rstrip('/').
Префикс: /{owner}/{repo}/src/branch/{branch}/.
| Агент | Артефакты (label → путь) |
|---|---|
| analyst | BRD 01-brd.md, ТЗ 02-trz.md, AC 03-acceptance-criteria.md, Test Plan 04-test-plan.yaml (уже есть) |
| architect | ADR-папка docs/work-items/<wid>/06-adr/ (уже есть) |
| developer | Branch …/src/branch/<branch>, PR …/pulls/<num> (уже есть) |
| reviewer | Review docs/work-items/<wid>/12-review.md (уже есть) |
| tester | Test report docs/work-items/<wid>/13-test-report.md (уже есть) |
| deployer | Deploy log docs/work-items/<wid>/14-deploy-log.md; staging-лог 15-staging-log.md (если применимо к стадии) |
Несуществующий файл в worktree → ссылка опускается (как сейчас в _build_analyst_ready_comment).
2.5 Строка длительности работы агента
Что печатаем: одну строку вида Длительность: {human} (или Duration: {human} — финальную локализацию метки фиксирует архитектор; русский предпочтителен, остальные комменты уже на русском).
Источник значения (приоритет сверху вниз):
- Параметр функции —
_post_usage_comments()вsrc/agents/launcher.py:682вызывается из контекста, где_duration_sуже посчитан на строке391(int(time.time() - _start_ts)). Простейший путь — проброситьduration_sявным аргументом вusage_comment(...)/ новыйbuild_status_comment(...). - Fallback из БД — если параметр не передан (например, для аналитика, чей коммент строится в
_build_analyst_ready_commentвsrc/stage_engine.py:298), читаемЭто последний завершённый run этой роли по задаче.SELECT CAST((julianday(finished_at) - julianday(started_at)) * 86400 AS INTEGER) FROM agent_runs WHERE task_id = ? AND agent = ? ORDER BY id DESC LIMIT 1 - Если оба источника пусты /
None/ отрицательны — строкаДлительность:НЕ печатается (graceful, как и для вердикта).
Форматирование (fmt_duration(seconds: int) -> str в src/usage.py):
| Диапазон | Формат | Пример |
|---|---|---|
0 ≤ s < 60 |
{s}s |
12s, 45s |
60 ≤ s < 3600 |
{m}m {ss}s |
4m 12s, 1m 03s |
s ≥ 3600 |
{h}h {mm}m (секунды отбрасываем) |
1h 03m, 2h 47m |
Округление: целые секунды (input — int). При s == 0 всё равно печатаем 0s (видно, что метрика известна и стадия отработала почти мгновенно).
Покрытие ролей: строка длительности добавляется для всех агентов, включая аналитика. Для аналитика — строго через fallback из agent_runs (его коммент строится в stage_engine.py, не в launcher.py).
Что НЕ делаем:
- Не меняем схему
agent_runs(поляstarted_at/finished_atуже есть,_duration_sуже считается). - Не изобретаем новый отдельный коммент с длительностью — длительность встраивается в существующий status-коммент.
- Не считаем «время от первого вебхука до коммента» — берём чистое время процесса агента (тот же
_duration_s, что попадает вnotify_agent_finished), чтобы значение совпадало с тем, что уже видно в Telegram live tracker / логах.
2.6 Один коммент на агента за стадию
Текущий триггер — _post_usage_comments() вызывается один раз в успешном auto-advance пути после агента. Никаких новых триггеров не добавляем. Дубликаты исключены текущей логикой (одно завершение агента → один коммент).
2.7 Usage-метрики (токены / стоимость)
Текущий usage_comment() встраивает «8.5M in / 45.8k out · $7.29» в первый строкой. По требованиям Славы это «без раздувания», но не запрещено явно. Решение:
- Сохранить usage-метрику как последнюю строку коммента (мелким техническим хвостом, например
<sub>8.5M in / 45.8k out · $7.29 · Длительность: 4m 12s</sub>), либо - Перенести в
task_summary_comment(только для финального deployer-summary).
Финальный выбор — за архитектором (см. вопрос Q-1 в 10-tech-risks.md). Длительность из §2.5 — отдельная строка от usage-метрики и присутствует независимо от того, как решится вопрос про токены/стоимость.
2.8 Бот-авторство
plane_add_comment(..., author=<role>) — сохраняется. Все агенты комментируют под своим bot-токеном (PLANE_BOT_TOKENS). Изменения формата текста на это не влияют.
3. Изменения API
Нет. Внешние webhooks (/webhook/plane, /webhook/gitea), /health, /status, /queue — не меняются.
4. Изменения схемы БД
Нет. Используются существующие таблицы tasks, agent_runs, jobs.
5. Новые Quality Gate checks
Нет. Гейты не меняются. Парсинг verdict: / deploy_status: / staging_status: в коммент — отдельная утилитка, не QG.
6. Требования к коду
- Все новые функции — с docstring (зачем нужны, какие инварианты сохраняют).
- Парсинг frontmatter артефакта — graceful: исключение → строка вердикта опускается, лог в
logger.debug. - Чтение длительности — graceful: исключение или
None→ строка длительности опускается, лог вlogger.debug. Отрицательные / нулевые значения:0печатается как0s, отрицательные опускаются. fmt_duration(seconds: int) -> str— чистая, без БД-зависимостей, легко тестируется юнитом.- Никаких новых внешних зависимостей: использовать
pyyaml(уже в проекте) или существующий парсер frontmatter изsrc/qg/checks.py. - Поведение для проектов без артефактов (например, ENDURO-* до запуска агента) — graceful no-op: коммент с описанием и без ссылок (минимум — заголовок).
- HTML (как у аналитика) предпочтительнее markdown — Plane корректно рендерит
<ul><li><a>и<b>.
7. Артефакты по pipeline
06-adr/— не требуется (нет архитектурного сдвига; обсуждается локально архитектором, в случае спорного решения по 2.6 — заводим ADRADR-001-status-comment-format.md).07-infra-requirements.md— не требуется (нет новой инфраструктуры).08-data-requirements.md— не требуется (БД не меняется).12-review.md/13-test-report.md/14-deploy-log.md— формируются на соответствующих стадиях по канону.CHANGELOG.md— обновить в том же PR (разделUnreleased).
8. Документация
В том же PR обновить:
docs/architecture/README.md— короткое упоминание единого формата комментов (можно в раздел «Plane Sync»).docs/architecture/internals.md— если там есть раздел проusage.py/комменты — обновить.CLAUDE.md— без изменений (правила не меняются).
9. Чего НЕ делать
- Не менять реестр
QG_CHECKS. - Не менять
STAGE_TRANSITIONS. - Не менять
add_comment/_headers_for/PLANE_BOT_TOKENS. - Не «комментировать» комменты других стадий задним числом.
- Не использовать
--no-verifyпри коммитах.