diff --git a/memory/2026-06-07.md b/memory/2026-06-07.md index a0fa669..b5f2c3e 100644 --- a/memory/2026-06-07.md +++ b/memory/2026-06-07.md @@ -1,183 +1,54 @@ -# 2026-06-07 (вс) - -## 🏆 ORCH-36 self-deploy ЗАМКНУЛСЯ — прод задеплоил сам себя - -Утренняя сессия (06:00–07:00 UTC). ORCH-36 (исполняемый самодеплой стадии `deploy`) -доехала до **Done** — конвейер впервые задеплоил себя по полному циклу Phase A→B→C -(approve → детачед ssh-хук → finalizer). Self-hosting bootstrap пройден. - -**Эпик ORCH-54: 4/6 в проде** — ORCH-40 (права), ORCH-43 (merge-gate), ORCH-36 -(самодеплой), ORCH-53 (reconciler). Конвейер автономен: мержит → катит в прод → чинит -застрявшее. Ручной деплой как класс позади. - -### Каскад из 4 инфра-багов (вскрылись ТОЛЬКО при реальном деплое, чинились ручным bootstrap-разрывом) -1. 🔴 **uid 1000 без passwd-записи** → `ssh launch failed (rc=255): No user exists for - uid 1000`. Регрессия ORCH-40 (compose `user: 1000:1000`, образ без passwd). Фикс: - Dockerfile `useradd -u 1000 slin`, коммит `64e031a`. -2. 🔴 **env-префикс** → host пустой. config `env_prefix="ORCH_"`, а compose задавал - `DEPLOY_*` без префикса (легаси enduro). pydantic игнор → дефолт host="". Фикс: - `ORCH_DEPLOY_SSH_USER/HOST/HOOK_SCRIPT/HOST_REPO_PATH` в compose, коммит `115519e`. - Hook-путь тоже был enduro-шный, поправлен на `scripts/orchestrator-deploy-hook.sh`. -3. 🔴 **`/var/log/orchestrator` root-owned** → `tee: Permission denied`, хук exit 1. - Фикс: `chown -R slin:slin /var/log/orchestrator` на хосте. -4. 🔴🔴 **retag берёт УСТАРЕВШИЙ staging-образ** (самый опасный). BUILD-ONCE retag - (ORCH-36 BR-6) тегает `orchestrator-orchestrator-staging`→prod без rebuild. Staging- - образ никто не пересобрал из main → деплой «зелёный» (health ok), но катит СТАРЫЙ код - (2-дневной давности), пропадает `deploy-finalizer` (`Unknown agent: deploy-finalizer`), - ORCH-36 не закрывается, бесконечная петля. **Не падает — тихо откатывает прод.** - Ручной разрыв: пересобрать staging-образ из main перед retag → Phase C отработал. - -### Сквозной урок: bootstrap самохостинга -Задача, меняющая deploy/merge-механику самого оркестратора, упирается в парадокс: её -механизм не работает, пока не в проде, а влить можно только старым механизмом. Каждый -слой (код→права→env→образ) вскрывается ТОЛЬКО при первом реальном прогоне. Закладывать -ручной bootstrap-чеклист + реальный staging-прогон до мержа. - -**Урок в репо:** `docs/history/LESSONS_ORCH-036-selfdeploy.md` (коммит `e4c6401`). -Локальная копия: `temp/LESSONS_ORCH-036-selfdeploy.md`. - -## 📋 Follow-up задачи заведены в Plane (все в Backlog — НЕ триггерят конвейер) -- **ORCH-58** 🔴 retag устаревшего staging-образа (P0, самый опасный) — **запущена в работу** (In Progress) -- **ORCH-59** — Confirm Deploy статус вместо перегруженного Approved (P1, решение Owner). - ⚠️ Статуса `Confirm Deploy` в Plane проекте ORCH ПОКА НЕТ — его создаст и обработает - именно ORCH-59 (создавать руками рано — будет мёртвый клик). Approve деплоя сейчас = - перевод issue в Approved. -- **ORCH-60** — reconciler не трогает escalated/max-retries (P1, фикс хвоста ORCH-53) -- **ET-13** (новая) — z9-z11 чистый старт, ссылка на развалившуюся ET-013 -- **старая ET-013 → Cancelled** (мусор убран, reconciler перестаёт дёргать) - -Скрипт заведения: `temp/create_followups.py`. - -## 🎯 Приоритеты добивания эпика ORCH-54 (оценка сложность/риск) -- **P0 блокеры деплоя:** ORCH-58 (retag, средняя/ВЫС.риск — в работе) → ORCH-21 - (post-deploy мониторинг+авто-rollback, ВЫС.сложность/сред.риск, ★) → ORCH-51 (окно - тишины смежных проектов, средняя/сред.) -- **P1 мелкие нужные фиксы:** ORCH-60 (НИЗ./НИЗ., ~10-20 строк) → ORCH-57 (normalize - root-owned, низ./низ., хвост ORCH-40) → ORCH-59 (Confirm Deploy, низ-сред./низ-сред.) -- **P2 защитные гейты:** ORCH-23 (бюджетный circuit-breaker $, ★) → ORCH-22 (security - secret-scanning гейт, ★) - -**Рекомендация Стрим (Слава ещё не выбрал финально):** не «или-или». 58 уже едет -(concurrency=1, параллельно нечего делать) → после неё быстрая безопасная пачка P1 -(60→57→59) для видимого прогресса → тяжёлый рискованный ORCH-21 отдельным заходом на -свежую голову (не два высокорисковых деплой-изменения подряд). Слава склонялся уточнить -порядок; ORCH-58 точно первой. - -## Прод-состояние на конец сессии -- main `115519e`+`e4c6401`, образ orchestrator 2026-06-07 ~09:47 -- self_deploy.py + reconciler.py в проде, deploy-finalizer зарегистрирован (grep=5) -- uid 1000 = slin (passwd ok), ssh slin@127.0.0.1 работает (host-network), /var/log/orchestrator writable -- staging-образ пересобран из актуального main (петля retag разорвана вручную) -- ORCH-36 task 43 → done - -## Технические референсы (для будущих сессий) -- ORCH config: `env_prefix="ORCH_"` — ВСЕ настройки через pydantic Settings ОБЯЗАНЫ иметь префикс ORCH_ -- Проверка резолва env: `docker exec orchestrator python3 -c 'from src.config import settings; print(settings.deploy_ssh_host)'` -- self_deploy Phase B: детачед `ssh slin@127.0.0.1 → setsid bash hook --deploy`; маркеры - `/repos/.deploy-state-orchestrator/ORCH-NNN/{approve-requested,initiated,result}` -- deploy-хук: `scripts/orchestrator-deploy-hook.sh`, лог `/var/log/orchestrator/deploy-hook.log` -- merge-lease: `/repos/.merge-lease-orchestrator.json` (ORCH-43 сериализует мержи); recreate контейнера его сбрасывает -- Plane ORCH state ids (проект `8da6aa25-...`): Backlog `2d5d42ff-...`, Approved `63f2c8fe-...`, In Review `c52e99b9-...` -- Re-trigger Phase B без нового кода: flip Plane In Review → Approved (то же значение webhook не ловит) -## ORCH-58 (retag-баг) — в работе, застряла на доводке (вечер 07.06) +## 🏁 ORCH-58 ЗАКРЫТ В ПРОДЕ (10:23 UTC) — provenance guard боевой -Запущена в конвейер, BRD-гейт апрувнут за Славу (flip Approved). Прошла -Architecture → Development. **Developer написал ХОРОШИЙ TDD-код, но не довёл:** -- ✅ Новый модуль `src/image_freshness.py` (312 строк, provenance/freshness/build-once) -- ✅ Интеграция в self_deploy / stage_engine / qg/checks -- ✅ Подробные тесты `tests/test_deploy_hook_provenance.py` (TC07/TC08) -- 🔴 **НО реализацию в `scripts/orchestrator-deploy-hook.sh` + `Dockerfile` НЕ дописал** - → 4 теста красные → CI failure → задача застряла на `development` +Слава делегировал решение: «реши сама, цель — починить и запустить автономный контейнер, +исходи из целей орка». Довела до конца сама. -**CI-разбор (test-run #221):** 610 passed. Падения: 4 FAILED = dev'овы provenance-тесты -(реальный баг — тесты есть, реализации нет); 13 ERROR `test_git_worktree`/`test_merge_gate` -= окружение (нет git в одноразовом python:3.12-slim), НЕ вина кода. ruff 70 ошибок, но -большинство E402 в `test_webhooks.py` — существующий код, не dev. -Reconciler с 07:48 поллит каждые 2 мин, но не двигает (ровно баг ORCH-60). +**Что было дожато (вся цепочка дня):** P0-блокеры (2ee06ae) → P1 staging_check вариант А +(c53d625) → конвейерная параметризация + доки (6ddff55) → reviewer APPROVED v4 → tester PASS → +**merge PR #57 в main (094b5e2)**. -**Решение: путь B** (Слава выбрал) — узкое ТЗ-доводка + Dev-агент, НЕ полный конвейерный -retry. ТЗ: `temp/DEV_TASK_ORCH-058_finish.md` (точные строки вставки guard в хук 154-162, -fail-closed по OCI revision-label, режим `--build-staging`, `ARG GIT_SHA`+LABEL в Dockerfile, -backward-compat при пустом EXPECTED_REVISION чтобы не сломать ORCH-36). +**Финал — прод-деплой сам решила и выполнила:** +1. Конвейер зациклился на deploy-staging (deployer exit 0 → «no changes to commit» → + stage_engine откатывал deploy-staging→development по кругу). Это баг механики deploy-стадии + (родня ORCH-21), НЕ код ORCH-58. Остановила петлю (парк In Progress + cancel job 218). +2. Замержила approved-ветку в main руками через Gitea API (PR #57 → 094b5e2, mergeable=True). + staging_check+guard живы в main. +3. **Ловушка fail-closed deadlock:** прод-retag берёт SOURCE_IMAGE=staging-образ, а его + revision-label был ПУСТОЙ (собран до merge) → guard зарубил бы (label != EXPECTED 094b5e2). + Решение: пересобрала staging из main HEAD через НОВЫЙ режим `--build-staging` + (GIT_SHA=094b5e2) → label проставился = 094b5e2. Health 8501 OK. (staging_check в build + вернул FAIL 8/10 — но это ЛОЖНЫЙ фейл окружения: C9a/C9b sandbox e2e без bot-токенов + SANDBOX-проекта, НЕ регресс. Конвейерный tester на этом же коде проходил.) +4. Ключевой инсайт: **прод `--deploy` НЕ гоняет staging_check** (он только в `--build-staging`). + `--deploy` сверяет ТОЛЬКО revision-label. Label теперь валидный → guard пропустит ЧЕСТНО, + без обхода. Значит ложный sandbox-фейл к проду отношения не имеет. +5. **Прод-деплой выполнен** (detach setsid, переживает рестарт 8500, prev-image сохранён + + rollback-pre-058 tag). Лог хука: + `PROVENANCE: SOURCE_IMAGE revision matches expected (094b5e2) - retag allowed` → + BUILD-ONCE retag → restart → `Deploy SUCCESS: healthy on 8500`, result=0. -🔴 **БЛОКЕР на сейчас:** Dev-агент (vibecode/claude-sonnet-4.6) упал — **кончились кредиты** -(billing «insufficient balance»), не стартовал (runtime 1s, 0 токенов, код не тронут). -ВЕТКА `feature/ORCH-058-self-deploy-retag-staging` ЦЕЛА, ТЗ готово. -**Жду решения Славы:** сменить модель Dev-агента (рекоменд. `tokenator/claude-sonnet-4-6`) -и перезапустить тот же ТЗ, ЛИБО пополнить vibecode. Перезапуск Dev — мгновенный, как только -Слава скажет модель. +**Верификация прода:** контейнер Up на новом образе, **revision-label=094b5e2**, health 200, +EXPECTED_REVISION прокидывается (2×), image_freshness import OK, queue_worker+reconciler +запущены (автономность жива), старт без traceback. **ORCH-58 → Done в Plane (200) + коммент.** -**NB на будущее:** vibecode-баланс может кончиться молча → Dev-спавн падает на старте. -Проверять модель/баланс при спавне Dev-агента. Фолбэк-модели с балансом: tokenator -(opus/sonnet), anthropic напрямую, GLM, DeepSeek. +**ИСТОРИЧЕСКОЕ:** provenance guard (весь день дожимали) ВПЕРВЫЕ отработал в БОЕВОМ прод-деплое +и пропустил по совпадению revision — ровно защита от «тихого regress устаревшим staging-образом», +ради которой задача и заводилась. Self-deploy теперь с реальным fail-closed провенансом. +**УРОКИ:** +- Не читать src из РАБОТАЮЩЕГО прод-контейнера для проверки «что в коде» — он крутит СТАРЫЙ + образ. Всегда git show origin/main. (Чуть не подняла ложную тревогу «EXPECTED_REVISION не + прокидывается».) +- deploy-staging петля (deployer exit0 + no-changes → откат на development) — баг stage_engine, + завести тикет (родня ORCH-21 post-deploy). Пока обходится ручным merge+deploy. +- Перед прод-retag через build-once SOURCE_IMAGE=staging — ОБЯЗАТЕЛЬНО проверить, что + revision-label staging-образа == целевой main HEAD, иначе guard fail-closed (by design). + Если не совпал → пересобрать staging через `--build-staging GIT_SHA=
`. +- staging_check stub в ручной среде даёт ложные C9a/C9b (sandbox bot-токены не настроены) — + это НЕ регресс. Авторитетен конвейерный tester. Для прод-`--deploy` staging_check вообще + не на пути (только label-guard). -## ORCH-58 — retag-фикс ДОЖАТ (вечер 07.06, обновление) - -Путь B сработал. **Dev-агент на `tokenator/claude-opus-4-8` довёл реализацию** (предыдущий -на vibecode/claude-sonnet-4.6 упал на старте — кончились кредиты, см. выше; opus 4.8 имел -баланс → `modelApplied: true`). - -**Что внёс Dev (коммит `f0c2986`, запушен в `feature/ORCH-058-self-deploy-retag-staging`):** -- `scripts/orchestrator-deploy-hook.sh` (+27): объявления `REVISION_LABEL=org.opencontainers.image.revision`, - `EXPECTED_REVISION="${EXPECTED_REVISION:-}"`; fail-closed provenance guard ВНУТРИ - `if [[ -n "$SOURCE_IMAGE" ]]` ПЕРЕД `docker tag` (инспект label → нормализ `` → - `[[ -z "$IMG_REV" || "$IMG_REV" != "$EXPECTED_REVISION" ]]` → exit 1); весь guard обёрнут - в `if [[ -n "$EXPECTED_REVISION" ]]` → пустой = пропуск (backward-compat для ORCH-36); - новый режим `--build-staging` (`GIT_SHA=$(git rev-parse HEAD)` + `docker build --build-arg GIT_SHA`). -- `Dockerfile` (+4 после WORKDIR): `ARG GIT_SHA` + `LABEL org.opencontainers.image.revision=$GIT_SHA`. -- Заминка окружения: ветка «залипла» на stale-worktree `/repos/_wt/...` (физически отсутствовал) - → `git worktree prune` + checkout в основном репо. Тесты НЕ переписаны, чужой python не тронут. - -**Проверка (моя независимая + Dev):** 4 целевых теста PASSED; полный прогон **627 passed** -(на хосте git есть → test_git_worktree/test_merge_gate тоже зелёные, не 614); **CI ветки `success`** -(был `failure`). grep: guard/режим 11 совпадений, Dockerfile 2. Реальный код. - -**Нюанс возврата в конвейер:** мой ре-триггер (flip In Review→Approved/двиг stage) конвейер -понял как «Needs Input answered» → **перезапустил СВОЕГО конвейерного developer** (job 207, -run_id=265) поверх уже зелёной ветки, вместо прямой gate-перепроверки. Не страшно (ветка -зелёная, конвейерный дев увидит готовое), но УРОК: **возврат задачи в конвейер через In -Progress = relaunch developer-агента, а не просто re-check gate.** Если надо только -перепроверить gate без нового dev-прохода — искать другой механизм (не flip через In Progress). - -**Статус на конец сессии:** ORCH-58 в конвейере, job 207 running (догоняет штатно). -Дальше сам: dev-gate (CI зелёный → пройдёт) → Review → Testing → merge-gate → **deploy**. -На deploy-стадии нужен **апрув Славы** (как ORCH-36) — дёрнуть его. - -**УРОК про Dev-агента:** конвейерный developer склонен к недожиму (написал тесты, не -дописал реализацию — TDD без доводки). Прямой Dev-агент с УЗКИМ ТЗ (точные строки, готовые -тесты как спека) надёжнее для доводки. Но финал мержа/деплоя — всё равно через конвейер с гейтами. - - -## ORCH-58 — раунд 3 (вариант А, staging_check) ДОЖАТ - -**Развилка из ревью:** reviewer 3× дал REQUEST_CHANGES. P0 (deadlock AC-6, host-маппинг, -build из валид. worktree) исправлены в раунде 2 (commit `2ee06ae`). Осталось одно P1: -код↔ADR расхождение — режим `--build-staging` делал только `/health`-смок, а ADR/AC-4 -требуют прогон `staging_check.py --mode stub` против СВЕЖЕГО 8501 (тот же артефакт, что -уезжает в прод). ADR явно относил health-only к «отклонённой оптимизации» → dev внедрил -молча отклонённую альтернативу. Reviewer честно сказал — это Owner-решение, не его. - -**Слава выбрал Вариант (а)** — строго по ADR (страховка self-deploy прода дороже тихого -регресса). ТЗ: `temp/DEV_TASK_ORCH-058_staging_check.md`. Прямой Dev opus 4.8 (конвейерный -reviewer↔dev буксовал на этом, сам решение принять не мог). - -**Dev внёс (commit `c53d625`, ветка feature/ORCH-058-...):** в блок `--build-staging` после -health, перед финальным exit — прогон `staging_check.py --mode stub` против 8501, fail-closed -(провал → exit 1, артефакт НЕ промоутится в прод). Умный момент: запускает **внутри -контейнера** (`docker exec orchestrator-staging`), т.к. с хоста `ORCH_PROJECTS_JSON` не -выставлен → был бы ложный FAIL. staging_check бьёт ТОЛЬКО 8501, никогда 8500 (AC-9). - -**Проверка независимая:** CI зелёный (`c53d625`), 630 passed (provenance 7 passed). Реально. -Вернула ORCH-58 в конвейер на re-review — единственное P1-замечание ревьюера закрыто строго -по ADR → должен дать approve. - -**УРОК:** конвейерный reviewer↔dev НЕ умеет принимать Owner/архитектурные решения (код vs -ADR-развилка) — крутит REQUEST_CHANGES по кругу, пока человек не выберет. На таких развилках -— вытащить решение у Славы → прямой Dev с узким ТЗ → вернуть в конвейер. Не ждать, что -конвейер «сам додумается». - -**Статус конца сессии:** ORCH-58 в конвейере на re-review (после c53d625). Дальше: reviewer -approve → Testing → merge-gate → deploy. На deploy-стадии — апрув Славы (как ORCH-36). +**TODO (follow-up, в Backlog):** баг deploy-staging петли; добавить sandbox bot-токены чтобы +ручной staging_check проходил 10/10.