8.8 KiB
8.8 KiB
ТЗ / черновик ADR — ORCH-46: «Испорченный телефон» при заворотах агентам
Статус: ЧЕРНОВИК на согласование Славе. Перед запуском конвейером Слава выбирает вариант дизайна (см. §3) и подтверждает scope. ORCH-46 лезет в ядро (
stage_engine.py), поэтому ADR обязателен.
1. Проблема (факты из кода, проверено 06.06)
Когда задачу возвращают на доработку, орк формирует деву task_desc (→ .task-dev.md), и в
нём — только ссылка на файл, без сути замечаний. Дословно из src/stage_engine.py:
- Reviewer REQUEST_CHANGES (стр. ~419):
"...Note: REQUEST_CHANGES from reviewer (attempt N/3). Fix findings in docs/work-items/<WI>/12-review.md" - Tester FAIL (стр. ~455):
"...Note: Tests FAILED. Fix failures described in docs/work-items/<WI>/13-test-report.md"
Три корневые беды (ровно они убивали автономность ORCH-17):
- Испорченный телефон. Деву дают ссылку «иди читай файл», а не текст претензий. Ключевую мысль (напр. governance: «не трогай shared-гейт») легко проскочить.
- Противоречивые сигналы. Tester шлёт «Tests FAILED, чини тесты» (толкает лезть в тест-код → в т.ч. в shared-гейт), reviewer шлёт «не трогай gate». Два противоположных приказа в разных кругах, дев видит только последний.
- Нет памяти между кругами. Каждый developer-запуск — чистый агент (
agent_runsлишь считает количество). Дев не знает, на чём уже погорел в прошлых кругах → повторяет ошибку.
2. Что есть для решения (разведано)
12-review.mdсодержит структурированный блок## Findingsс уровнями### P0 — Blocker / P1 — Must fix / P2 — Should fix / P3 — Nice-to-have+ frontmatterverdict:. → findings машиночитаемы, можно извлечь P0/P1/P2.13-test-report.mdсодержит frontmatterresult:/verdict:/status:+ тело с описанием падений. → можно извлечь причину FAIL.agent_runs(БД) — поtask_id+agentсчитаются круги; туда же можно писать краткий «след» каждого заворота (что требовалось, к какому агенту относилось).- Передача в агента:
enqueue_job(agent, repo, task_desc, task_id)→ launcher пишетtask_descв.task-dev.md. Менять форматtask_descдостаточно, чтобы донести больше.
3. ВАРИАНТЫ ДИЗАЙНА (выбрать один — решение Славы)
Вариант A — «Вклеить findings» (минимальный, низкий риск) ⭐ рекомендую как старт
- В
task_descпри заворотах встраивать ТЕКСТ замечаний, а не только ссылку.- Reviewer: распарсить
## Findingsиз12-review.md, вынуть P0/P1 (must-fix) дословно вtask_desc. Ссылку на файл оставить как «полный контекст». - Tester: вынуть причину FAIL (reason + ключевые строки тела
13-test-report.md).
- Reviewer: распарсить
- Плюсы: бьёт прямо в беду №1 (испорченный телефон), правка локальная (формирование строки + парсер-хелпер), легко тестируется. Минусы: не решает №2/№3 полностью.
Вариант B — A + «память кругов» (средний)
- Всё из A, плюс: в
agent_runs(или отдельную мини-таблицуdev_round_notes) писать краткий след каждого заворота: круг N, агент-источник (reviewer/tester), суть требования. При новом запуске дева вклеивать вtask_descблок «История прошлых кругов: на чём уже погорел / чего НЕ делать». Бьёт по беде №3. - Плюсы: дев перестаёт повторять ошибки. Минусы: миграция БД/новая таблица, чуть сложнее.
Вариант C — A + B + «склейка противоречий» (полный, выше риск)
- Всё из A+B, плюс: если в истории есть конфликт сигналов (reviewer «не трогай X» vs tester «почини тесты, связанные с X»), орк склеивает их в одно непротиворечивое ТЗ с явным приоритетом (governance reviewer > tester по умолчанию; правило вынести в конфиг/ADR).
- Плюсы: убивает все три беды. Минусы: эвристика склейки сложна, риск ложной логики, больше тестов, заметнее правка ядра.
Моя рекомендация: делать A сейчас (быстрая большая отдача, низкий риск ядра), B и C — отдельными инкрементами после обкатки A на реальных заворотах. Но финальное слово — за Славой.
4. Scope (для выбранного варианта — заполнить после решения)
- Файлы:
src/stage_engine.py(формирование task_desc в 2-3 ветках), новый хелпер-парсер (напр.src/review_parse.py:extract_review_findings(path) -> str,extract_test_failures(path) -> str), тесты, ADR, CHANGELOG. - (Вариант B/C доп.: миграция БД /
src/db.py.) - НЕ трогать: сами гейты
check_*(ORCH-45/47 уже в проде), QG-реестр, сигнатуры публичных функций, webhook-пути (заворот идёт launcher-путём, finished_agent задан).
5. Acceptance Criteria (вариант A)
- AC-1: при reviewer REQUEST_CHANGES
.task-dev.mdсодержит ДОСЛОВНЫЙ текст P0/P1 findings из12-review.md(не только ссылку). - AC-2: при tester FAIL
.task-dev.mdсодержит причину падения (reason + релевантный фрагмент13-test-report.md). - AC-3: ссылка на полный файл сохранена как доп. контекст.
- AC-4: парсер устойчив к отсутствию/битому файлу (graceful: fallback на старую ссылку-строку,
никогда не падает — по образцу
_parse_tests_verdict, который «never raise»). - AC-5: существующие тесты
stage_engine/test_qgзелёные; добавлены юнит-тесты парсера (findings есть / пусто / битый YAML / только P3). - AC-6: retry-счётчик и rollback-логика НЕ изменены по поведению.
6. Команды проверки
- В контейнере:
python -m pytest tests/test_qg.py tests/test_stage_engine*.py -q. - Ручной снапшот task_desc: смоделировать заворот и проверить содержимое
.task-dev.md.
7. Грабли (из опыта 05.06 — обязательно учесть)
- Запуск через конвейер: заголовок задачи ≤80 символов (QG-0), иначе Blocked.
- Деплой после мержа:
/appзапечён в образ → нуженdocker compose build orchestrator+ рестарт + проверка claude-auth (HOME=/home/slin claude.exe --print, timeout 90с). - Gitea API: заголовок
Authorization: token <ORCH_GITEA_TOKEN>; heredoc через ssh+docker глотает вывод → скрипт+base64+docker cp. - Это правка ЯДРА (stage_engine) — на staging обязателен честный прогон; помнить про B6/ORCH-48 (staging-реестр пока видит прод-проекты — не блокер, но при E2E учитывать).