Files
orchestrator/docs/work-items/ORCH-016/03-acceptance-criteria.md

126 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.