12 KiB
Технические риски — ORCH-016
Work Item: ORCH-016 Стадия: architecture Автор: architect Дата: 2026-06-05
Риски ранжированы по приоритету (P0 = блокер, P1 = серьёзный, P2 = умеренный, P3 = информационный). Каждый риск содержит митигацию и/или способ детекции на тестах.
R-1 (P1) — Self-hosting: сломанный коммент => слепая зона по ORCH-задаче
Описание. Изменение касается генерации комментов; орк дорабатывает сам себя. Если новый build_status_comment падает / отдаёт пустую строку / отдаёт битый HTML, стейкхолдер (Слава) потеряет видимость прогресса именно по той задаче, которая сломала комменты — и не сможет диагностировать без docker logs.
Митигация.
- Внешний
try/except Exceptionвокруг сборки HTML: при любом исключении возвращаем простой fallback-текст видаf"{icon} {role} готов"+logger.exception(...). Лучше «уродливый» коммент, чем тишина. - Юнит-тесты
tests/test_status_comment_format.py(TC-01..TC-12, TC-23) фиксируют золотой HTML — регрессия ловится на CI до прод-деплоя. - Обязательный staging-гейт (
check_staging_statusдля orchestrator) — финальный предохранитель: задача с ORCH-меткой не дойдёт до прод-контейнера, пока staging-инстанс (8501) не подтвердит, что комменты собираются.
R-2 (P1) — Plane HTML sanitization: <sub> / <br> / <ul> могут не рендериться
Описание. Plane (self-hosted) санитизирует входящий HTML. Эталон аналитика подтверждает рендер <ul> / <li> / <a> / <b>; рендер <sub> и <br> НЕ подтверждён на текущей версии Plane.
Митигация.
- На staging (8501) опубликовать тестовый коммент
build_status_comment(...)руками (черезpython -mскрипт или curl на dev-задачу) и визуально проверить рендер тех-хвоста и переводов строк ПЕРЕД мержем PR. - Если
<sub>не рендерится — fallback: оставить usage-метрику обычной строкой с·разделителем (без<sub>). - Если
<br>не рендерится — переходим на\n(Plane сам интерпретирует) либо упаковываем строки в<p>...</p>. - Развилка фиксируется в
12-review.mdreviewer'ом по факту проверки.
Детекция. Ручной чек-лист в staging-логе (15-staging-log.md) с приложенным скриншотом коммента.
R-3 (P2) — SQLite contention при DB-фоллбэке длительности
Описание. get_agent_duration(task_id, agent) делает SELECT по agent_runs в момент сборки коммента. SQLite-БД одновременно используется очередью (jobs), воркером, вебхуками и Telegram-трекером; пиковая нагрузка → коротко блокирующиеся читатели.
Митигация.
- Запрос идёт по индексу
(task_id, agent)(если его нет — добавление индекса не входит в scope ORCH-016, но запрос всё равно быстрый: типичныйagent_runs≤ 50 строк на задачу). try/except Exceptionоборачивает SELECT →logger.debug(...)→None. При залоченной БД строка «Длительность:» просто опускается (AC-14).- Запрос делаем ТОЛЬКО когда
duration_sне передан явно (т.е. только для аналитика).
Детекция. TC-25 — integration-тест на исключение в чтении agent_runs.
R-4 (P3) — Расхождение значений длительности (param vs DB)
Описание. _duration_s в src/agents/launcher.py:391 считается как int(time.time() - _start_ts). DB-фоллбэк считает (julianday(finished_at) - julianday(started_at)) * 86400. Возможно расхождение в 1 секунду (округление) или больше (если finished_at пишется не сразу).
Митигация. AC-13 допускает погрешность ±1с. Для аналитика, где используем только DB-фоллбэк, отклонений между двумя источниками не наблюдается (источник один).
Не митигируется специально — последствия нулевые (декоративная строка).
R-5 (P2) — Скрытые callers usage_comment / artifact_links
Описание. ADR-001 предписывает удалить usage_comment и переписать artifact_links на HTML. В рамках только grep по src/ я нашёл единственного клиента — _post_usage_comments в src/agents/launcher.py. Однако функция могла использоваться скриптами (scripts/), тестами (tests/), миграционными утилитами или внешними интеграциями.
Митигация. Developer на стадии development обязан выполнить полный grep:
grep -rn "usage_comment\|artifact_links" . --include="*.py"
И переписать все вызовы. Если найдётся внешний потребитель — оставить usage_comment как deprecated-обёртку и зафиксировать в 12-review.md.
Детекция. TC-10 (полный pytest зелёный), TC-17 (дедуп-регрессия), reviewer-чек.
R-6 (P2) — Регрессия status-only verdict model аналитика (PR #12/#13)
Описание. Аналитик переходит в In Review И не должен auto-advance'иться — статус ждёт Approved/Rejected от стейкхолдера. Если переписывание _build_analyst_ready_comment на обёртку случайно вернёт auto_advance=True или поменяет content так, что человек не поймёт инструкцию — порвётся существующий контракт.
Митигация.
- TC-11 + TC-16: регрессионные тесты на формат коммента и status-only поведение.
- ADR-001 §1 явно фиксирует: контракт аналитика сохраняется; обёртка строит ИДЕНТИЧНЫЙ существующему текст + добавляет только строку длительности.
R-7 (P3) — Локализация и кодировка emoji в HTML
Описание. В src/usage.py emoji-ы записаны \Uxxxxxxxx-escape'ами. При сборке HTML это безопасно (Python декодирует до utf-8), но при возможном последующем base64/quoted-printable транспорте могла бы возникнуть проблема. Plane API принимает utf-8 → риск минимален.
Митигация. Не требуется. Существующий путь (PR #13, аналитик) уже посылает emoji через тот же add_comment без проблем.
R-8 (P3) — Дублирование YAML-парсинга frontmatter
Описание. ADR-001 §5 принимает дублирование (~10 строк) в src/frontmatter.py и оставляет src/qg/checks.py со своим парсером. При расхождении правил (например, мы научим read_frontmatter_value поддерживать ---\nkey: value\n--- без trailing newline, а qg/checks.py останется строгим) теоретически возможны несогласованные интерпретации.
Митигация. Принято в scope discipline; следующая задача-рефактор объединит. До тех пор — read_frontmatter_value обязан быть строго совместимым (по тестам) с поведением qg/checks.py на канонических случаях (BR-frontmatter с trailing newline после ---).
R-9 (P0) — НЕ перезапускать прод-контейнер orchestrator
Описание. Self-hosting: прод-контейнер (8500) обслуживает ВСЕ проекты (orchestrator + enduro-trails) из общей БД. Внеплановый рестарт ради «быстро посмотреть формат коммента» = простой конвейера всех проектов.
Митигация.
- Все эксперименты — на staging (8501) через
docker compose --profile staging up -d orchestrator-staging. - Прод-деплой только через стандартный путь
deploy-staging → deploy(под надзоромcheck_staging_status). - ЗАПРЕЩЕНО при ручном тестировании коммента дёргать
docker compose restart orchestrator.
Открытые вопросы (Q&A — все закрыты ADR-001)
| Q | Вопрос | Решение | Где зафиксировано |
|---|---|---|---|
| Q-1 | Куда девать usage-метрику (tokens/cost)? | Сохранить как <sub>…</sub> хвостом в том же комменте. |
ADR-001 §3 |
| Q-2 | «Длительность:» или «Duration:»? | «Длительность:» (русский, соответствует остальным меткам). | ADR-001 §4 |
| Q-3 | Один общий хелпер или раздельные для analyst/прочих? | Один: build_status_comment(...); analyst — ветка внутри. |
ADR-001 §1 |
| Q-4 | Парсер frontmatter — переиспользовать qg/checks.py или новый? |
Новый src/frontmatter.py; qg/checks.py НЕ трогаем в этом PR. |
ADR-001 §5 |
| Q-5 | Контракт DB-фоллбэка длительности. | `get_agent_duration(task_id, agent) -> int | None`, см. SQL в ADR-001 §6. |
| Q-6 | HTML vs Markdown. | HTML (как у эталона); artifact_links переписывается на <a>. |
ADR-001 §7 |
| Q-7 | Судьба старого usage_comment(...). |
Удалить, перевести единственного клиента (_post_usage_comments) на build_status_comment. |
ADR-001 §1 |
Если developer на стадии development обнаружит, что R-5 материализуется (есть скрытый клиент usage_comment) — допустимо оставить usage_comment как 1-строчную deprecated-обёртку (return build_status_comment(...)) и зафиксировать факт в 12-review.md без возврата в architecture.
Risk register для ORCH-016. Обновляется reviewer'ом, если в ходе ревью всплывут новые риски — текущий список фиксирует видимое на момент завершения стадии architecture.