126 lines
11 KiB
Markdown
126 lines
11 KiB
Markdown
# Acceptance Criteria: Единообразные коммент-артефакты в Plane
|
||
|
||
Work Item ID: **ORCH-016**
|
||
Ревизия: 2 (по фидбэку стейкхолдера — все AC по агентам обновлены под строку длительности; добавлены AC-13 / AC-14)
|
||
|
||
Каждый AC сформулирован как чёткое условие PASS/FAIL. Проверяется автоматически (unit/integration) либо ручной верификацией в staging Plane (порт 8501).
|
||
|
||
---
|
||
|
||
## AC-1. Архитектор пишет единообразный коммент
|
||
- **Given** task завершила стадию `architecture` успешно, `06-adr/` содержит как минимум один ADR.
|
||
- **When** `_post_usage_comments(agent="architect", ...)` вызывается.
|
||
- **Then** в Plane появляется **ровно один** коммент со структурой:
|
||
- первая строка: `📐 Architect — Завершил архитектурную проработку. См. ADR ниже.`,
|
||
- строка `Длительность: <human>` (формат — см. AC-13), значение соответствует фактическому времени работы архитектора (±1с),
|
||
- блок «Документы:» с кликабельной ссылкой на `…/src/branch/<branch>/docs/work-items/<wid>/06-adr/`,
|
||
- **нет** строки `Verdict / Status`.
|
||
- **And** автор коммента — `architect` (`PLANE_BOT_TOKENS["architect"]`, fallback на shared token).
|
||
- **PASS** при выполнении всех пунктов; **FAIL** при отсутствии любого.
|
||
|
||
## AC-2. Разработчик пишет единообразный коммент
|
||
- **Given** task завершила стадию `development`, есть open PR.
|
||
- **When** `_post_usage_comments(agent="developer", ...)` вызывается.
|
||
- **Then** коммент в Plane:
|
||
- `💻 Developer — Завершил разработку. См. PR / branch ниже.`,
|
||
- строка `Длительность: <human>`,
|
||
- ссылки: `Branch <branch>` → `…/src/branch/<branch>`, `PR #<num>` → `…/pulls/<num>`,
|
||
- **нет** строки `Verdict`.
|
||
|
||
## AC-3. Ревьюер пишет коммент с вердиктом
|
||
- **Given** `12-review.md` содержит frontmatter `verdict: APPROVE` (или `REQUEST_CHANGES`).
|
||
- **When** `_post_usage_comments(agent="reviewer", ...)` вызывается.
|
||
- **Then** коммент:
|
||
- `🔎 Reviewer — Завершил ревью изменений.`,
|
||
- строка `Verdict: APPROVE` (или `REQUEST_CHANGES`) — содержимое соответствует frontmatter,
|
||
- строка `Длительность: <human>`,
|
||
- ссылка `Review` → `…/12-review.md`.
|
||
- **And** если frontmatter не содержит `verdict:` или файл недоступен — строка `Verdict:` опускается, остальное (в т.ч. длительность) публикуется.
|
||
|
||
## AC-4. Тестер пишет коммент с вердиктом
|
||
- **Given** `13-test-report.md` содержит frontmatter `verdict: PASS` (или `FAIL`).
|
||
- **When** `_post_usage_comments(agent="tester", ...)` вызывается.
|
||
- **Then** коммент:
|
||
- `🧪 Tester — Завершил прогон тестов.`,
|
||
- строка `Verdict: PASS` (либо `FAIL`),
|
||
- строка `Длительность: <human>`,
|
||
- ссылка `Test report` → `…/13-test-report.md`.
|
||
|
||
## AC-5. Деплоер пишет коммент со статусом
|
||
- **Given** task прошла стадию `deploy` (или `deploy-staging`), артефакт-лог существует с frontmatter `deploy_status: SUCCESS` (или `staging_status: SUCCESS`).
|
||
- **When** `_post_usage_comments(agent="deployer", ...)` вызывается.
|
||
- **Then** коммент:
|
||
- `🚀 Deployer — Завершил деплой.`,
|
||
- строка `Status: SUCCESS` (или `FAILED`),
|
||
- строка `Длительность: <human>`,
|
||
- ссылка `Deploy log` → `…/14-deploy-log.md` (и/или `Staging log` → `…/15-staging-log.md` для staging-стадии).
|
||
|
||
## AC-6. Аналитик не регрессирует
|
||
- **Given** существующий поток PR #12/#13 (status-only verdict).
|
||
- **When** аналитик завершает стадию `analysis` с готовыми `01..04`.
|
||
- **Then** в Plane:
|
||
- issue переведён в `In Review` (не меняется),
|
||
- коммент содержит **то же** человеческое описание (Approved/Rejected инструкции) и список ссылок `BRD / ТЗ / AC / Test Plan` — формат либо идентичен текущему, либо построен через тот же общий хелпер, что и остальные агенты, без потери смысла,
|
||
- дополнительно к существующему содержимому в комменте присутствует строка `Длительность: <human>` — значение поднимается из `agent_runs` (последний завершённый run агента `analyst` для этой задачи).
|
||
|
||
## AC-7. Один коммент на агента за стадию
|
||
- **Given** агент успешно отработал стадию.
|
||
- **When** наблюдаем ленту Plane.
|
||
- **Then** для **каждого** агента (`architect`, `developer`, `reviewer`, `tester`, `deployer`) на стадию приходится **ровно один** status-коммент с артефактами. Дополнительные сервисные комменты (`notify_stage_change`, `notify_qg_failure`, `notify_done`) сохраняются — они не считаются status-комментом.
|
||
|
||
## AC-8. Graceful fallback при отсутствии артефакта
|
||
- **Given** артефакт (например, `12-review.md`) ОТСУТСТВУЕТ в worktree на момент коммента (нестандартный сценарий).
|
||
- **When** `_post_usage_comments(agent="reviewer", ...)` вызывается.
|
||
- **Then** коммент всё равно публикуется: заголовок + описание, без ссылки на отсутствующий артефакт и без строки `Verdict:`. Исключения не пробрасываются.
|
||
|
||
## AC-9. Кликабельность через gitea_public_url
|
||
- **Given** в `.env` задан `GITEA_PUBLIC_URL=https://git.mva154.duckdns.org`, отличный от `GITEA_URL`.
|
||
- **When** любой агент пишет status-коммент.
|
||
- **Then** href всех артефакт-ссылок начинается с `https://git.mva154.duckdns.org/` (а не с внутреннего `gitea_url`).
|
||
- **And** при отсутствии `gitea_public_url` (пустая строка) — fallback на `gitea_url` (обратная совместимость).
|
||
|
||
## AC-10. Существующие тесты зелёные
|
||
- **Given** новый код влит в feature-ветку.
|
||
- **When** запускается `pytest tests/ -q`.
|
||
- **Then** все ранее существовавшие тесты проходят (нет регрессий status-only verdict, дедупа, `set_issue_done`).
|
||
|
||
## AC-11. Quality Gates не меняются
|
||
- **Given** изменения формата комментов.
|
||
- **When** инспектируется `src/qg/checks.py` и `src/stages.py`.
|
||
- **Then** реестр `QG_CHECKS` и `STAGE_TRANSITIONS` остаются идентичными версии до PR (diff в этих файлах = ∅).
|
||
|
||
## AC-12. Документация обновлена
|
||
- **Given** реализация добавлена в feature-ветку.
|
||
- **When** reviewer проверяет PR.
|
||
- **Then** в diff присутствуют обновления:
|
||
- `CHANGELOG.md` (раздел Unreleased, описание изменения — включая «строку длительности агента в комментах»),
|
||
- `docs/architecture/README.md` или `docs/architecture/internals.md` (упоминание единого формата status-комментов и строки длительности).
|
||
- **And** при отсутствии обновлений документации reviewer ставит `verdict: REQUEST_CHANGES` (правило проекта).
|
||
|
||
## AC-13. Формат строки длительности
|
||
- **Given** утилитка `fmt_duration(seconds: int) -> str` в `src/usage.py`.
|
||
- **When** ей передаются граничные значения.
|
||
- **Then** возвращаемая строка соответствует таблице:
|
||
- `0` → `"0s"`
|
||
- `12` → `"12s"`
|
||
- `59` → `"59s"`
|
||
- `60` → `"1m 00s"`
|
||
- `252` → `"4m 12s"`
|
||
- `3599` → `"59m 59s"`
|
||
- `3600` → `"1h 00m"`
|
||
- `3780` → `"1h 03m"`
|
||
- `10020` → `"2h 47m"`
|
||
- **And** ввод `None` или отрицательное значение → функция возвращает пустую строку (или `None`), а вызывающая сторона строку `Длительность:` не печатает.
|
||
- **PASS** при полном совпадении со всеми примерами таблицы.
|
||
|
||
## AC-14. Длительность — graceful fallback
|
||
- **Given** агент завершился, но `_duration_s` не пробрасывается явным параметром в коммент-хелпер (например, для аналитика).
|
||
- **When** строится status-коммент.
|
||
- **Then** хелпер запрашивает БД: последний `agent_runs` для `(task_id, agent)` с непустым `finished_at`, считает `int((julianday(finished_at) - julianday(started_at)) * 86400)` и подставляет в `fmt_duration`.
|
||
- **And** при отсутствии подходящей строки `agent_runs` (или `finished_at IS NULL`, или результат < 0) — строка `Длительность:` опускается; остальные части коммента (заголовок, описание, вердикт, ссылки) публикуются без изменений.
|
||
- **And** ошибка чтения БД не пробрасывает исключение наружу — логируется в `logger.debug` и трактуется как «значение неизвестно».
|
||
|
||
---
|
||
|
||
**Финальный PASS задачи:** все AC-1…AC-14 = PASS.
|