Files
orchestrator/docs/work-items/ORCH-016/02-trz.md

16 KiB
Raw Blame History

ТЗ: Единообразные коммент-артефакты в 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} — финальную локализацию метки фиксирует архитектор; русский предпочтителен, остальные комменты уже на русском).

Источник значения (приоритет сверху вниз):

  1. Параметр функции_post_usage_comments() в src/agents/launcher.py:682 вызывается из контекста, где _duration_s уже посчитан на строке 391 (int(time.time() - _start_ts)). Простейший путь — пробросить duration_s явным аргументом в usage_comment(...) / новый build_status_comment(...).
  2. Fallback из БД — если параметр не передан (например, для аналитика, чей коммент строится в _build_analyst_ready_comment в src/stage_engine.py:298), читаем
    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
    
    Это последний завершённый run этой роли по задаче.
  3. Если оба источника пусты / 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 — заводим ADR ADR-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 при коммитах.