Files
orchestrator/docs/history/LESSONS_2026-06-05.md
2026-06-05 21:41:52 +00:00

9.5 KiB
Raw Blame History

Lessons Learned — 2026-06-05 (вечер): ORCH-17/45/47 + деплой прода

Итог дня

Закрыты три задачи (ORCH-17, ORCH-45, ORCH-47), два прод-гейта стали умнее, заведено 4 системных задачи в бэклог (ORCH-44/46/48 + B6). Главный сквозной урок: конвейер не мог провести эти задачи автономно из-за дыр в самом конвейере — потребовались ручные merge и ребилды прода. Корни задокументированы, чинятся отдельными задачами.


Подробный разбор: docs/history/LESSONS_ORCH-017.md. Кратко: косметика (2 ссылки) застряла 5 раз, объективный дедлок shared-гейта, ручной merge PR #37 (26c6f267).


2. ORCH-45 — CI-гонка в check_ci_green (исправлена, в проде)

Проблема

check_ci_green делал один запрос статуса CI сразу после developer. Если CI ещё pending 1-3 секунды (реальный кейс: опрос 17:58:54 → pending, CI позеленел 17:58:55) — гейт возвращал False один раз и задача застревала насмерть с зелёным CI.

Решение (PR #39, merge 982698c4)

Поллинг с ретраем: success/failure — терминальны (сразу), pending → ждать CI_POLL_INTERVAL_S(10с) до CI_POLL_MAX_ATTEMPTS(12) раз, истёк лимит → явный False с причиной "CI still pending after Ns" (не виснет молча). Параметры в config.py как env ORCH_CI_POLL_*. ADR-0004. +5 тестов (мок httpx + time.sleep).


3. ORCH-47 — тестер-гейт игнорил result: (исправлен, в проде)

Проблема (уловка-22)

check_tests_passed/_parse_tests_verdict читал только verdict:/status: из frontmatter 13-test-report.md, но промпт tester-агента велит писать result: PASS|FAIL. Честный тестер (result: PASS, без verdict:) → гейт «No machine-readable verdict» → ложный FAIL → петля dev↔review↔tester → Blocked. И сама ORCH-47 (которая это чинит) попала в тот же капкан: в проде крутился старый гейт → не понимал её собственный result: PASS → 3 круга петли. Змея кусает хвост: чтобы пройти гейт автономно, фикс уже должен быть в проде.

Решение (PR #40, merge 5d04de9e)

result: добавлен как равноправное поле наряду с verdict:/status:. Любое одно непустое поле достаточно. Negative-токен (BLOCKED/FAILED) в ЛЮБОМ поле авторитетен (ET-013 кейс сохранён). Token sets заморожены для обратной совместимости. ADR-001. +6 тестов (68 passed). После деплоя ручной advance_stage пнул застрявшую task → гейт принял result: PASS → прошёл testing. Петля исчезла навсегда.

Остаточная находка → B6 / ORCH-48

На staging деплоер дал 9/10 PASS, завалил B6 Registry isolation: staging-реестр видит боевые ET+ORCH вместо одного sandbox (нарушает «staging — только sandbox»). Деплоер честно поставил FAILED и НЕ стал натягивать зелёнку (вне мандата) → откат by design. К фиксу гейта отношения не имеет (E2E против sandbox прошёл). Заведена ORCH-48.


4. ДЕПЛОЙ ПРОДА — как правильно (важная операционная памятка)

/app запечён в образ, НЕ volume

docker-compose.yml: build: . + COPY src/ ./src/. Поэтому git pull + рестарт с --no-build НЕ довозит код — нужен docker compose build orchestrator. Деплой-хук (scripts/orchestrator-deploy-hook.sh) по дефолту целит в staging (by design) — для прода нужны env TARGET_SERVICE=orchestrator TARGET_PORT=8500 COMPOSE_PROFILE=''.

Порты/профили

  • prod orchestrator = порт 8500 (/health{"status":"ok"}), network_mode: host, профиль prod = пустой (стартует обычным docker compose up -d orchestrator).
  • staging = порт 8501, профиль staging (стартует только --profile staging).

Рабочая последовательность деплоя (проверена дважды 05.06)

  1. sudo chown -R slin:slin /home/slin/repos/orchestrator (см. грабля ниже).
  2. git checkout main && git reset --hard origin/main && git clean -fd -e '*.bak*' -e '.deploy-prev-image-prod'.
  3. docker compose build orchestrator.
  4. docker compose up -d orchestrator + health-loop на :8500.
  5. Проверка claude-auth (ребилд её ломает — см. ниже).
  6. Проверка что новый код активен в /app (grep маркера правки).

⚠️ ГРАБЛЯ: хост-репо рассинхронизирован с git (агенты пишут под root)

Хост-репо /home/slin/repos/orchestrator оказывался на feature-ветке (не main), а рабочая копия засеяна untracked+modified файлами, созданными агентами под uid=0 (root-owned) прямо в репо. → git pull --ff-only падал Permission denied / would be overwritten, обычный rm под slin не мог снести root-файлы. Лечение: sudo chown -R slin:slin <repo> → проверить что modified=совпадает-с-main и untracked=уже-в-main (дубликаты, не теряем) → git reset --hard origin/main + git clean. Хук это НЕ разруливает — сверять состояние хост-репо перед каждым деплоем.

⚠️ ГРАБЛЯ: ребилд ломает claude-auth (проверять ВСЕГДА)

Пересоздание контейнера может root-овнить /home/slin/.claude/.credentials.json и сделать /root/.claude пустышкой → агенты падают Not logged in. Защита — монтирование creds в compose (/home/slin/.claude + .claude.json), launcher форсит HOME=/home/slin. После каждого ребилда боевая проверка: docker exec orchestrator bash -c 'cd /tmp && HOME=/home/slin /opt/claude-code/bin/claude.exe --print "ОК"' (timeout 90с). 05.06 auth пережил оба ребилда — защита держит.


5. ЗАПУСК конвейера и Gitea API

Старт конвейера = Plane Backlog → In Progress

Конвейер стартует штатно переводом задачи в Plane из Backlog в In Progress (код: webhooks/plane.py handle_status_start — «pipeline is started when Slava moves the issue into In Progress»). Webhook создаёт task-row, заводит ветку, запускает analyst. Никаких ручных вставок в БД.

QG-0: лимит заголовка 80 символов

При старте задача с заголовком >80 символов заворачивается на QG-0 («Title слишком длинный») и уходит в Blocked. Чинить — укоротить name (суть в заголовок, детали в description), вернуть в Backlog, снова In Progress.

Gitea API грабли

  • merge/create PR требуют заголовок Authorization: token <ORCH_GITEA_TOKEN> (форма с префиксом token ), иначе 401 "token is required".
  • heredoc через ssh+docker exec глотает вывод python-скрипта. Надёжный путь: написать .py локально → base64 -w0ssh "echo <b64> | base64 -d > /tmp/x.py"docker cpdocker exec python3 /tmp/x.py. Это же обходит экранирование кириллицы/скобок.

Состояние прод-гейтов после 05.06

  • check_ci_green — поллинг с ретраем (ORCH-45)
  • check_tests_passed — читает result:/verdict:/status: (ORCH-47)

Бэклог (high) после дня

  • ORCH-44 — надёжность запуска агента (preflight слеп к auth; --effort гасит вывод; пустой run-лог → должен быть failed).
  • ORCH-46 — «испорченный телефон»: орк не передаёт деву ТЕКСТ замечаний reviewer/tester (только ссылку на файл), противоречивые сигналы tester↔reviewer, нет памяти между кругами.
  • ORCH-48 / B6 — staging registry isolation (staging видит прод-проекты вместо sandbox).