23 KiB
23 KiB
2026-06-08 — Дневник
🎯 ORCH-66 (статусная модель) доехала до прода САМА — историческое
- ORCH-66 = новая статусная модель (Plane-статусы: To Analyse / Analysis / Code-Review / Awaiting Deploy / Deploy / Done + In Review для approve-pending).
- Прошла весь конвейер автономно: analyst→architect→dev→reviewer→tester→staging→Phase A. CI зелёный, merge-gate пройден, staging пересобран (
bc2347ab). - Стояла на
In Review= approval-pending прода, ждала Confirm Deploy Славы. Символично: статусная модель первой пошла в прод сама.
🟢 ORCH-67 заведена — Telegram tracker багфикс+enhancement (seq=67, id=34a8440d-4024-41fa-bf6e-398937e23dee)
ТЗ загружено в Plane как HTML (5458 симв.). Зависит от ORCH-66 (статусные имена) → запускать ПОСЛЕ прода ORCH-66. 4 требования:
- Bump заработал — причина бага найдена и НЕ в коде: bump-логика (
delete + send + repoint) корректна, но в продеtracker_mode = "edit"(дефолтconfig.py:345). EnvORCH_TRACKER_MODE=bumpне выставлен → режим edit (карточка остаётся вверху). Фикс: включить bump + сделать дефолтом. - Формат карточки со статусами как в Plane — показывать Plane-статус этапа.
- Номер задачи (ORCH-NN) — гиперссылка на страницу задачи в Plane, внутри карточки.
- Во ВСЕХ уведомлениях орка номер задачи тоже кликабельный → ведёт в Plane.
- Уточнение Славы (учтено в ТЗ): ожидание согласования BRD = Plane-статус
In Review(⏸️ approve-pending между Analysis и Architecture). Отразить как полноценный статус, не только строкой «⏸️ Подтверждение BRD ⏳».
🔧 Технические факты по notifications.py / tracker (для будущих задач)
update_task_tracker(task_id)— два режима черезSettings.tracker_mode(envORCH_TRACKER_MODE), case-insensitive; всё кроме"bump"→"edit". Оба держат инвариант «одна карточка на задачу».- edit (DEFAULT): первый вызов sendMessage (silent) + store message_id; далее editMessageText.
- bump (ORCH-042): delete старого → send нового внизу → repoint message_id.
parse_mode: HTMLуже включён в send/edit → гиперссылки<a href>делаются без изменения транспорта.render_task_tracker(task_id)— stateless рендер из БД: строка✅ <Stage> <dur> · <in>↓/<out>↑ · <cost> · <model>на этап + строка✅/⏸️ Подтверждение BRD <dur> · твоё время[ ⏳]между Analysis/Architecture.send_telegram(text, disable_notification)→ возвращает message_id;delete_telegram(message_id); есть список Telegram-ошибок «target уже отсутствует» (message_id_invalid и т.п.).
🔗 URL/env факты (env орка)
ORCH_GITEA_PUBLIC_URL=https://git.mva154.duckdns.org- НЕТ публичного Plane-URL в env орка — для гиперссылок нужен базовый URL
https://plane.mva154.duckdns.org. Заложено в ТЗ ORCH-67 как новый конфиг. - project_id: ORCH =
8da6aa25-a60e-44d6-a1e2-d8ae59aa7d6a, Sandbox =8c5a3025-4f9d-4190-b79f-fa06276bb27e. ORCH_PLANE_WEBHOOK_SECRET=e7d95e…8b16.
🐛 ORCH-68 root-cause: livelock reconciler = РЕГРЕССИЯ от ORCH-66 (Слава угадал)
- Слава: «это началось после внедрения 66ой» — подтверждено логами минута-в-минуту:
22:17:04.019рестарт после прод-деплоя ORCH-66 →Reconciler started (interval=120s)22:17:04.207(через 0.2с) первыйET-002 done разблокирована— ДО 22:17 этого лога не было ever.22:18:33Task 52: deploy->done (self)(ORCH-66 задеплоил себя). Спам каждые 120с, 191+ сообщений.
- Механизм: ORCH-66 ввела новую статусную модель (имена Done/Monitoring after Deploy). Reconciler сверяет локальную стадию↔Plane-статус; новые имена сломали сравнение терминальных → ET-002 (done/Done = синхронизирована) каждый тик считается «потерян webhook» →
_note_unblockвхолостую (no-op, токены НЕ тратятся, но спам + нарушает инвариант «fires only on actual state change»). - Чинить в
src/reconciler.py: маппинг терминальных/пост-деплойных статусов привести к новой модели; done+Done не должен триггерить unblock. - Root-cause-блок дописан в Plane ORCH-68 (seq=68, id=70fd4d24-4241-4dd5-9245-11e629a3fc60), HTML 3603→5419.
- ⚠️ Грабли: чуть не дописала root-cause в ЧУЖУЮ задачу seq=60 «Reconciler не должен трогать escalated» (тоже про reconciler) — поймала, откатила (вернула 549 симв.). Plane seq≠work_item_id; искать issue по полному списку и сверять название, не по ключевому слову.
- ⚠️ Plane API: ручной urllib через двойной SSH+docker молчит/не отдаёт JSON. Рабочий путь — использовать модули орка
src/plane_sync.py(PLANE_BASE,WORKSPACE,PLANE_HEADERS, httpx) внутри контейнера через файл-скрипт +docker cp. PATCHdescription_htmlработает (200).
🚀 ORCH-68 ЗАПУЩЕНА в работу (04:45 UTC) + архитектурный ответ
- Слава: «68 срочно запускай. Правильно ли ориентироваться на статус Plane?»
- Ответ: ДА, ориентир на Plane корректен по дизайну. Таблица
tasksне имеет status-колонки (reconciler.py:201 «live Plane state is the source of truth»). F-2 обязан опрашивать Plane и реплеить пропущенные вебхуки — это сердце автономности. - Баг — в МАППИНГЕ, не в идее:
_reconcile_plane_projectтянетlist_issues_by_state(pid, [to_analyse, approved, rejected]). ET-002 в Plane=Done— её не должно быть в выборке. На enduroget_project_statesсхлопывает статусы (reconciler.py:209-211) →Doneалиасится подapprovedUUID → ветка «Approved but stage never advanced → replay verdict» →_note_unblockкаждый тик. - Ключевая находка: у проекта orchestrator
Done=group=completed,Approved=group=started(разные UUID, НЕ склеены). На enduro — склеены. ⚠️ Правильный фикс: использоватьstate.group == "completed"для терминала, а не голый UUID-маппинг. Заложено в ТЗ. - Старт: Plane-статус ORCH-68 →
To Analyse(UUID8acc6109-934e-4cd5-954b-7495672f520c) = триггер конвейера. - QG-0 завернул первый раз: заголовок >80 симв. → задача ушла в
Blocked. Укоротила до 60 симв («BUG: reconciler livelock — спам unblock done-задачи (ET-002)») → Backlog → To Analyse → пошла. Урок: заголовок Plane-задачи для орка — <=80 символов (QG-0 hard check). - Сейчас: task 53, ORCH-068, stage=analysis; job 378 analyst running (pid 3332), ветка
feature/ORCH-068-bug-reconciler-livelock-unbloc. Аналитик получил полное ТЗ + root-cause + архитектурное уточнение. - ТЗ ORCH-68 в Plane: 5428→7007 симв (добавлен архитектурный блок).
✅ ORCH-68 BRD Approved (04:52 UTC) → analysis→architecture (архитектор run_id=347)
- Аналитик выдал 4 артефакта (BRD/ТЗ/AC/test-plan) в
docs/work-items/ORCH-068/. Проверила все — эталонная работа. - Аналитик углубил мой root-cause: разделил баг на 2 независимых дефекта: D1 (терминалы не исключены из actionable-выборки) + D2 (
_note_unblockзовётся безусловно после no-op dispatch, нарушает свой docstring). D2 — мина, которую я пропустила. - Захватил связанный баг кэша:
_STATES_CACHEживёт весь lifetime,reload_project_states()есть но не вызывается — именно из-за этого Слава рестартил орк после созданияConfirm Deploy. Поймали заодно (G5/AC-12, secondary). - Plane-статусы переходов: To Analyse → Analysis (
cb834d55) → In Review (c52e99b9, approve-pending BRD) → Approved (63f2c8fe) → Architecture (795cc32f). UUID approved для ORCH =63f2c8fe-dcda-4ace-952f-dd88bd0118ff. - Решение «state.group vs allowlist» правильно оставлено архитектору в ADR.
🟢 ORCH-69 заведена и запущена (05:09 UTC) — QG-0 title-лимит в параметр
- Решение Славы: «заведи задачу, сделаем как параметр, 200 по умолчанию».
- Предыстория: выяснили что 80 в QG-0 — НЕ техническое ограничение. Проверила все места ниже по течению: slug ветки
re.sub(...)[:30](webhooks/plane.py:488) режется независимо + выкидывает кириллицу ([^a-z0-9]→дефис); БДtitle TEXTбез лимита; Telegram-карточкаhtml.escape(title)без обрезки; worktree-путь по branch (=work_item_id+slug[:30]), не по title. Расширять безопасно. - ORCH-69 (seq=69, id=35338a57-d905-4958-b70c-fa1afd66110f): новый
ORCH_QG0_TITLE_MAX(дефолт 200) в config.py,_qg0_errorsчитает из settings, текст ошибки динамичный. Нижние лимиты (title<5, desc<20) НЕ трогать. Аддитивно/обратносовместимо (200>80). - Запущена: stage=analysis, ветка
feature/ORCH-069-qg-0-title-orch-qg0-title-max-. ⚠️ Обе (68 и 69) трогаютwebhooks/plane.py— следить за merge-конфликтом (merge-gate должен поймать, но держать в голове).
🎉 ORCH-68 В ПРОДЕ — орк сам себя починил (05:32 UTC, self-deploy)
- ORCH-68 прошла весь конвейер автономно и задеплоилась в прод. Статус → Done (
3738cd3c), post-deploy monitor HEALTHY. - ✅ Спам ET-002 = 0 после деплоя (было 191+). Фикс боевой.
- ✅ Код в проде:
_is_terminal_state,get_project_state_groups,skipped_terminal_total— D1 черезstate.group(ровно как хотели).
🔴 БАГ ORCH-70: Confirm Deploy НЕ триггерит Phase B (мёртвый триггер, регрессия ORCH-66)
- Инцидент: Слава нажал статус
Confirm Deployдля прод-деплоя ORCH-68 → оркno pipeline action. Деплой пошёл только после ручного перевода вApproved. - Root cause: диспетчер
handle_issue_status(webhooks/plane.py ~158-166) слушает ТОЛЬКОto_analyse/approved/rejected. Phase B (stage_engine.py ~215-224) триггерится поApproved.Confirm Deploy(008597eb) не в тройке → молчит. ORCH-66 добавила статус как метку (запись), но не подключила обратный путь (чтение/триггер). - Почему не поймали: (1) не в scope ORCH-68 (она чинит reconciler, явно N1-N3 «Phase B не трогать»); (2) дыра ORCH-66 — тесты проверяли ЗАПИСЬ статуса, не ОБРАТНЫЙ триггер; (3) staging не покрывает прод-путь — ручной
Confirm Deployживёт только на проде (Phase A staging автоматический). - Урок: тестировать ОБРАТНЫЙ путь статусов (нажатие → действие), не только запись. Новый статус = подключить в обе стороны. Прод-only пути нуждаются в явном тесте.
- Записано в репу орка:
docs/history/LESSONS_2026-06-08_confirm-deploy-deadtrigger.md(коммит main, sha 101bd1c5, через Gitea Contents API). - ORCH-70 заведена (seq=70, id=bfbc924f-b808-4f7b-87d4-88ac5e976240), Backlog. Цель:
Confirm Deployтриггерит Phase B + регресс-тест обратного пути. Не запущена — ждёт решения Славы по очереди. - Gitea для коммитов в репу орка:
ORCH_GITEA_URL=http://localhost:3000, owner=admin, repo=orchestrator, tokenORCH_GITEA_TOKEN(env контейнера). Contents API: GET→sha→PUT/POST base64.
🚨 КРИТ: ФАНТОМНЫЙ MERGE — прод расходится с main, 4 PR не слиты (08.06)
- Симптом: ORCH-67 в To Analyse не подхватился. Причина — прод слушает
in_progress(старый диспетчер), а неto_analyse(ORCH-66). - Диагноз (подтверждён md5 + git + PR-статус): PR#67(022)/68(059)/69(066)/70(068) — ВСЕ open, merged=False. Последний реально слитый — PR#66 (ORCH-065, bb03350).
- md5-сверка: прод reconciler.py/plane_sync.py == ветка ORCH-068 (≠ main). Прод = снимок ветки ORCH-068, НЕ main.
- Механизм (Слава угадал — «деплоилась старая версия»): ветка ORCH-068 срезана от
bb03350(ORCH-065), А НЕ от кода ORCH-066. В истории ветки-068 по ORCH-066 толькоdocs staging, не код (to_analyse=0 в ветке-068). Т.е. деплой 068 взял worktree от устаревшего main (065) + фикс reconciler → откатил статусную модель 66 из прода. - Таймлайн ET-002: 22:17 деплой ветки-066 (сломанный reconciler) → спам начался. 05:32 деплой ветки-068 (фикс livelock, но база 065 без 66) → спам=0 после 05:33. Подтверждает: код 66 БЫЛ в проде 22:17-05:32, потом стёрт деплоем 068.
- КОРЕНЬ: self-deploy Phase B собирает образ из ВЕТКИ (срезанной от main) + рапортует finalize SUCCESS, НО git-merge в main не отрабатывает (фантом). → следующая задача срезается от устаревшего main → теряет код незалитых предшественников. Накопительная потеря 022→059→066→068.
- Подозрение: регресс фикса ORCH-065 (idempotent merge / merge-lease) ЛИБО merge-step после него молчит. ORCH-065 — последний честный merge.
- Ребейз origin/feature/ORCH-066-plane на origin/main — ЧИСТЫЙ (конфликтов нет, git разрулил reconciler.py/plane_sync.py — разные места). НО простое слияние 66 затрёт фикс 68 → нужна цепочка 022→059→066→068.
- РЕШЕНИЕ Славы: «запускай сама, документируй, запиши урок» — выполняю.
🔧 ВОССТАНОВЛЕНИЕ main (08.06, автономно)
- Находка по ходу: ORCH-059 =
feat(deploy): Confirm Deploy status triggers prod deploy— уже реализует то, что я заводила как ORCH-70!handle_confirm_deployнаписан в 059, просто не слит (фантом). → ORCH-70 после долива 059 пересмотреть (останется только display-слой Monitoring after Deploy). - Матрица src-пересечений: 022(config/qg/security_gate/stage_engine), 059(plane_sync/stage_engine/webhooks), 066(plane_sync/reconciler/stage_engine/webhooks), 068(config/plane_sync/reconciler). Порядок цепочки 022→059→066→068 (= хронология PR 67<68<69<70).
- Интеграционная ветка
integ/restore-main-2026-06-08(worktree/tmp/integ_chainв контейнере): 022+059+066 слиты чисто (docs union). На 068 — код-конфликт reconciler.py (066 to_analyse vs 068 in_progress+D1/D2). Разрешение: каркас 068 + триггер to_analyse 066. - Урок в репу:
docs/history/LESSONS_2026-06-08_phantom-merge.md(sha 772ccab, CRITICAL постмортем + runbook диагностики). - Критбаг ORCH-71 (seq=71, id=017daf29) — root-fix фантома: верификация merge после деплоя + done-гейт по PR.merged + merge до рестарта контейнера. Backlog.
- Диагностический runbook (4 проверки фантома): (a) Gitea PR merged-флаги, (b) md5 prod vs
git show origin/main:<file>, (c) merge-base ветки vs main, (d) таймлайн деплой-логов. - ⚠️ БЛОКЕР: Dev-агент (vibecode/claude-sonnet-4.6) упал на billing error (кредиты исчерпаны, 0 токенов). Конфликт reconciler.py НЕ разрешён. ТЗ готово:
/tmp/DEV_TASK_merge_066_068.md. Нужен перезапуск Dev на другой модели.
🔍 АУДИТ статусной модели ORCH-66 (08.06) — 7 статусов-призраков
- В Plane заведен 21 статус, код (
_PLANE_NAME_TO_KEY, plane_sync.py ~119) знает только 14. Не подключены: Analysis, Code-Review, Awaiting Deploy, Confirm Deploy, Deploying, Monitoring after Deploy (+ To Analyse через отдельный alias). - Мёртвый код:
set_issue_awaiting_deploy/deploying/monitoringОПРЕДЕЛЕНЫ (plane_sync.py ~652-679) но НИГДЕ не вызываются (grep пуст). _STAGE_TO_STATE_KEYставит СТАРЫЕ статусы: analysis→in_progress (не Analysis), review→review (не Code-Review), deploy→in_progress (не Awaiting Deploy).Monitoring after Deploy(97b4a6cf) создан, но post-deploy окно идёт ПОВЕРХ Done (stage_engine.py:356 «arm monitor PAST done») → задача показывает Done, хотя ~15мин под наблюдением (это и есть «почему Done» Славы).- Вывод: ORCH-66 ввела красивую модель на доске, но деплойная под-модель (Awaiting Deploy→Confirm Deploy→Deploying→Monitoring) — декоративная, код её не использует.
- ORCH-70 расширена (3725→7027): с одного Confirm Deploy до всей деплойной под-модели (G4-G7): подключить статусы, заполнить name→key, привести stage→state, убрать/задействовать мёртвый код. Порядок actionable vs display-only — архитектору в ADR.
⚠️ QG-0 — правила заголовка/описания Plane-задач для орка (важно!)
- QG-0 = первый quality gate конвейера, функция
_qg0_errors(name, description)вsrc/webhooks/plane.py:366. Проверяет заголовок (name) и описание до старта аналитика. - Три проверки: Title ≥ 5, Title ≤ 80 (хардкод, без конфига), Description ≥ 20 символов (
.strip()).len()по Unicode-символам (кириллица = 1 символ, не байт). - soft vs hard: при
work_item.created— soft (только warning, стр.362). При старте конвейера (Status->In Progress) — hard (стр.435-457): блокирует и кидает вBlocked. Вот почему создаётся ок, а при запуске заворачивает. - 🔑 ПРАВИЛО: заголовок Plane-задачи для орка — короткий тайтл ≤ 80 символов, вся детализация — в description. Не впихивать описание в заголовок (моя привычка — забываю). Дважды наступила 08.06 (ORCH-67/68).
- ⚡ Возможный QoL-фикс (предложила Славе, ждёт решения): авто-обрезка заголовка до 80 («…») вместо блокировки, или вынести лимит 80 в конфиг.
📝 Грабли инструмента edit (зафиксировать)
editтребует строго:path+edits(массив), каждый элемент только{oldText, newText}— никаких лишних полей.oldTextдолжен совпадать дословно (включая пробелы/переводы строк). Несколько фейлов за сессию из-за неверной формы аргументов и неточного oldText.image(vibecode/claude-sonnet-4.6) падает с 403 Insufficient credits — генерация картинок недоступна.
Файлы, тронутые в сессии
tasks/orchestrator/STATUS_MODEL_DEEP_ANALYSIS.md,STATUS_MODEL_PROPOSAL.md,status_workflow.html/tmp/wi_tracker_desc.md(ТЗ ORCH-67),/tmp/wi1_desc.mdtemp/DEV_TASK_ORCH-022_test_fix.md