8.6 KiB
Lessons Learned — ORCH-017 (Telegram approve-ping links)
Дата: 2026-06-05
Задача: ORCH-017 — Прямые ссылки на BRD и Plane-таску в Telegram-уведомлении об апруве BRD
Итог: смержено вручную (PR #37, merge 26c6f267) после ~5 застреваний конвейера
TL;DR
Косметическая задача (две HTML-ссылки в уведомлении) 5 раз застряла в конвейере и каждый раз требовала ручного пинка. Корень — не баг задачи, а дыры автономности конвейера. Код был готов и зелёный (434 теста), но пайплайн не мог довести его до merge сам. В итоге — ручной merge Owner-ом; четыре системные дыры заведены в бэклог (ORCH-44/45/46/47).
Хронология застреваний
- Auth claude после rebuild — агенты падали
Not logged in(root-owned creds +/root/.claudeпустышка). См. отдельный разбор в memory/INCIDENT по auth. → починено + защищено монтированием. check_ci_greenrace — гейт опросил CI один раз в17:58:54→pending; CI дозеленел в17:58:55(промах на 1 секунду). Повторного опроса нет → задача висит насмерть с зелёным CI.- Петля dev↔review↔testing →
max retries reached(MAX_DEVELOPER_RETRIES=3). - Откат неполный — убрали код shared-гейта, но оставили 2 doc-строки про него → рассинхрон код↔доки → reviewer снова REQUEST_CHANGES.
- Объективный дедлок (см. ниже) → ручной merge.
Корневые проблемы (→ бэклог)
P1. check_ci_green промахивается на гонке CI (→ ORCH-45)
Гейт читает статус CI ровно один раз сразу после developer. Если CI ещё pending — задача
застревает молча, без повторного опроса. Нужен polling с ретраем: pending → ждать N×15с,
success → advance, failure → rollback, вечный pending → уведомить (не застревать молча).
P2. Developer не понимает замечаний reviewer/tester — "испорченный телефон" (→ ORCH-46)
Это прямой удар по автономности. Три причины, почему dev повторял одну и ту же ошибку:
- Испорченный телефон. При REQUEST_CHANGES
stage_engine.py:~421шлёт developer-у только"Fix findings in docs/work-items/<WI>/12-review.md"— без текста претензий, лишь ссылку на файл. Ключевую governance-мысль легко проскочить. → Вклеивать ТЕКСТ findings прямо в task_desc. - Противоречивые сигналы. После tester прилетает
"Tests FAILED. Fix failures"(толкает чинить связанное с тестами → dev лез в test-gate). После reviewer —"не трогай gate". Два противоположных приказа. → Склеивать замечания tester+reviewer в одно непротиворечивое ТЗ. - Нет памяти между кругами. Каждый запуск developer — новый чистый агент, не помнит прошлых заворотов. Видит "тесты падают" → снова лезет в gate. → Передавать историю прошлых REQUEST_CHANGES/ FAIL ("на чём уже погорел, чего НЕ делать"). Можно: ранняя эскалация к Owner при повторе.
P3. check_tests_passed игнорирует поле result: (→ ORCH-47)
_parse_tests_verdict (src/qg/checks.py) читал только verdict:/status: из frontmatter
13-test-report.md. НО промпт tester-агента (.openclaw/agents/tester*) предписывает писать
result: PASS | FAIL. Честный тестер (отчёт ORCH-017: result: PASS, без verdict:/status:)
проваливал гейт ложным «Tests FAILED» → откат на development. ORCH-016 проходил лишь потому, что
дублировал verdict: И result:. → Гейт должен читать result: как первоклассное машинное поле.
ВАЖНО: это shared-гейт (влияет на ВСЕ проекты общего прода) → требует отдельного ADR
(CLAUDE.md правило 2), потому вынесено в свой work item, не в ORCH-017.
P4. Preflight слеп к auth и битым флагам (→ ORCH-44)
claude --version отвечает даже без логина → preflight=ok, а реальный запуск падает Not logged in.
Плюс --effort с CLI 2.1.142 + --print/--output-format json гасит вывод. Нужны: дешёвая
проверка auth без токенов (права+дата истечения OAuth в .credentials.json), фикс effort,
«пустой лог + job running + процесс мёртв → failed».
Главный урок: объективный дедлок shared-инфры
ORCH-017 попала в неразрешимый автономно дедлок из-за того, что тест-отчёт уже написан под
новый контракт (result: PASS):
- С фиксом гейта в ветке → reviewer заворачивает (governance: shared-инфра без ADR). ❌
- Без фикса гейта →
check_tests_passedне видитresult:→ ложный FAIL → откат. ❌
Вывод: изменение shared quality-gate нельзя протаскивать внутри прикладной задачи. Оно создаёт циклическую зависимость (артефакты задачи зависят от изменённого гейта, а гейт нельзя менять без отдельного ADR). Менять shared-гейты — только отдельным work item со своим ADR. Если артефакты уже написаны под новый контракт — задача физически не пройдёт, пока не приедет фикс гейта.
Урок про роль ассистента/оператора
Когда оператор раз за разом пинает гейты и чистит за dev вручную — это сигнал «конвейер не тянет автономно». Честнее предложить Owner-у ручной merge/эскалацию, чем гонять карусель кругов и доказывать конвейеру то, что уже готово (код зелёный, reviewer: «технически корректно», претензии процедурные).
Урок про откат
При откате кода обязательно откатывать и доки/CHANGELOG, иначе возникает обратный рассинхрон код↔доки (доки описывают фичу, которой в коде уже нет) → reviewer заворачивает. Откат — это код + доки + changelog + (при необходимости) тест-отчёт одним согласованным движением.
Что сработало хорошо
- Reviewer ловит governance-нарушения — корректно завернул протаскивание shared-гейта в прикладную задачу. Процедурно прав, даже когда код технически верный.
- Безопасный ручной пинок гейта через
stage_engine.advance_stage(...)— без ребилда/мержа, перевызывает QG внутри процесса орка. - Ручной merge как осознанный выход из дедлока (с явным ОК Owner), а не бесконечные круги.