auto-sync: 2026-06-07 13:30:01

This commit is contained in:
Stream
2026-06-07 13:30:01 +03:00
parent 81bd820b32
commit a8cb57967c

View File

@@ -1,183 +1,54 @@
# 2026-06-07 (вс)
## 🏆 ORCH-36 self-deploy ЗАМКНУЛСЯ — прод задеплоил сам себя
Утренняя сессия (06:0007: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=<main HEAD>`.
- 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 → нормализ `<no value>` →
`[[ -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.