docs: uroki ORCH-017 (deadlock shared-gate, isporchennyy telefon, otkat) #38
103
docs/history/LESSONS_ORCH-017.md
Normal file
103
docs/history/LESSONS_ORCH-017.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# 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).
|
||||
|
||||
---
|
||||
|
||||
## Хронология застреваний
|
||||
|
||||
1. **Auth claude после rebuild** — агенты падали `Not logged in` (root-owned creds + `/root/.claude`
|
||||
пустышка). См. отдельный разбор в memory/INCIDENT по auth. → починено + защищено монтированием.
|
||||
2. **`check_ci_green` race** — гейт опросил CI **один раз** в `17:58:54` → `pending`; CI дозеленел в
|
||||
`17:58:55` (промах на 1 секунду). Повторного опроса нет → задача висит насмерть с зелёным CI.
|
||||
3. **Петля dev↔review↔testing → `max retries reached`** (MAX_DEVELOPER_RETRIES=3).
|
||||
4. **Откат неполный** — убрали код shared-гейта, но оставили 2 doc-строки про него → рассинхрон
|
||||
код↔доки → reviewer снова REQUEST_CHANGES.
|
||||
5. **Объективный дедлок** (см. ниже) → ручной 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), а не бесконечные круги.
|
||||
Reference in New Issue
Block a user