work_item: ORCH-016 title: "Единообразные коммент-артефакты в Plane от всех агентов" revision: 2 # +TC-21..TC-25 по длительности (фидбэк стейкхолдера) tests: - id: TC-01 type: unit description: "build_status_comment(architect, duration_s=312, ...) формирует HTML c заголовком '📐 Architect — …', описанием стадии, строкой 'Длительность: 5m 12s' и ссылкой на 06-adr/. Строки Verdict нет." module: tests/test_status_comment_format.py expected: PASS - id: TC-02 type: unit description: "build_status_comment(developer, branch=..., pr_number=42, duration_s=...) включает ссылки на branch и на PR #42 через gitea_public_url + строку 'Длительность: ...'. Строки Verdict нет." module: tests/test_status_comment_format.py expected: PASS - id: TC-03 type: unit description: "build_status_comment(reviewer, duration_s=..., ...) при verdict=APPROVE в 12-review.md frontmatter выводит строку 'Verdict: APPROVE', строку 'Длительность: ...' и ссылку на 12-review.md." module: tests/test_status_comment_format.py expected: PASS - id: TC-04 type: unit description: "build_status_comment(reviewer, ...) при verdict=REQUEST_CHANGES выводит 'Verdict: REQUEST_CHANGES'. Строка длительности сохраняется." module: tests/test_status_comment_format.py expected: PASS - id: TC-05 type: unit description: "build_status_comment(reviewer, ...) при отсутствии файла 12-review.md публикует коммент без строки Verdict и без ссылки Review (graceful), при этом строка 'Длительность: ...' печатается, если duration_s передан." module: tests/test_status_comment_format.py expected: PASS - id: TC-06 type: unit description: "build_status_comment(tester, ...) при verdict=PASS в 13-test-report.md выводит 'Verdict: PASS', строку 'Длительность: ...' и ссылку на 13-test-report.md." module: tests/test_status_comment_format.py expected: PASS - id: TC-07 type: unit description: "build_status_comment(tester, ...) при verdict=FAIL выводит 'Verdict: FAIL'. Строка длительности сохраняется." module: tests/test_status_comment_format.py expected: PASS - id: TC-08 type: unit description: "build_status_comment(deployer, ...) при deploy_status=SUCCESS в 14-deploy-log.md выводит 'Status: SUCCESS', строку 'Длительность: ...' и ссылку на 14-deploy-log.md." module: tests/test_status_comment_format.py expected: PASS - id: TC-09 type: unit description: "build_status_comment(deployer, stage='deploy-staging') читает staging_status: из 15-staging-log.md и выводит соответствующую строку Status + строку длительности." module: tests/test_status_comment_format.py expected: PASS - id: TC-10 type: unit description: "URL ссылок строится через settings.gitea_public_url когда он задан; иначе — через settings.gitea_url (fallback)." module: tests/test_status_comment_format.py expected: PASS - id: TC-11 type: unit description: "Аналитик: _build_analyst_ready_comment (или его замена общим хелпером) сохраняет существующий контракт — текст про Approved/Rejected статус + список существующих BRD/ТЗ/AC/Test Plan ссылок. Дополнительно: при наличии завершённой строки agent_runs(analyst) для задачи коммент содержит строку 'Длительность: ...'." module: tests/test_analyst_comment_regression.py expected: PASS - id: TC-12 type: unit description: "Парсер frontmatter (verdict / deploy_status / staging_status) возвращает None при отсутствии файла, пустом файле или некорректном YAML — без проброса исключения." module: tests/test_status_comment_format.py expected: PASS - id: TC-13 type: integration description: "_post_usage_comments(agent='reviewer', ...) вызывает plane_sync.add_comment ровно один раз; передаваемый текст содержит '🔎 Reviewer', 'Verdict:', 'Длительность:' и href на 12-review.md." module: tests/test_post_usage_comments_integration.py expected: PASS - id: TC-14 type: integration description: "_post_usage_comments(agent='tester', ...) вызывает add_comment ровно один раз с автором 'tester' и корректным текстом, включая строку 'Длительность: ...'." module: tests/test_post_usage_comments_integration.py expected: PASS - id: TC-15 type: integration description: "_post_usage_comments(agent='deployer', ...) для стадии deploy постит коммент со ссылкой на 14-deploy-log.md, строкой 'Длительность: ...' И task_summary_comment (если оно сохраняется) — поведение не регрессирует." module: tests/test_post_usage_comments_integration.py expected: PASS - id: TC-16 type: integration description: "Регрессия status-only verdict model: при завершении analyst issue переводится в In Review, постится один коммент аналитика с инструкцией про статус Approved/Rejected, никакой автомат-advance не происходит." module: tests/test_analyst_status_only_regression.py expected: PASS - id: TC-17 type: integration description: "Регрессия дедупликации: повторный вебхук Plane с тем же event_id не приводит ко второму status-комменту от агента." module: tests/test_status_comment_dedup_regression.py expected: PASS - id: TC-18 type: integration description: "Регрессия set_issue_done / notify_done: финальный путь deploy→done по-прежнему переводит issue в Done и постит '✅ Task completed!' (отдельным комментом от status-коммента деплоера)." module: tests/test_notify_done_regression.py expected: PASS - id: TC-19 type: integration description: "Per-agent bot-авторство: status-комменты архитектора/разработчика/ревьюера/тестера/деплоера POST-ятся под соответствующим X-API-Key (PLANE_BOT_TOKENS[role]); fallback на PLANE_HEADERS при отсутствии бот-токена." module: tests/test_status_comment_authorship.py expected: PASS - id: TC-20 type: unit description: "Quality Gates не изменены: реестр QG_CHECKS и STAGE_TRANSITIONS идентичны контрольному снапшоту (smoke-тест против случайных правок)." module: tests/test_qg_registry_snapshot.py expected: PASS - id: TC-21 type: unit description: "fmt_duration(seconds) — табличная проверка форматирования: 0→'0s', 12→'12s', 59→'59s', 60→'1m 00s', 252→'4m 12s', 3599→'59m 59s', 3600→'1h 00m', 3780→'1h 03m', 10020→'2h 47m'." module: tests/test_fmt_duration.py expected: PASS - id: TC-22 type: unit description: "fmt_duration(None) и fmt_duration(-1) возвращают пустую строку (или None); вызывающая сторона при этом строку 'Длительность:' НЕ печатает." module: tests/test_fmt_duration.py expected: PASS - id: TC-23 type: unit description: "build_status_comment(architect, duration_s=None) и build_status_comment(architect) — коммент НЕ содержит строки 'Длительность:'; остальные строки (заголовок/описание/ссылки) на месте." module: tests/test_status_comment_format.py expected: PASS - id: TC-24 type: integration description: "Fallback по БД: при отсутствии явного duration_s билдер коммента читает agent_runs.started_at/finished_at для последней завершённой строки (task_id, agent) и подставляет fmt_duration результата. Проверка через тестовую SQLite с заранее проставленными timestamp'ами." module: tests/test_status_comment_duration_db_fallback.py expected: PASS - id: TC-25 type: integration description: "Регрессия: исключение при чтении agent_runs (например, БД залочена) → строка 'Длительность:' опускается, остальное публикуется; logger.debug содержит запись о неудачном чтении длительности." module: tests/test_status_comment_duration_db_fallback.py expected: PASS