15 KiB
work_item, stage, author_agent, status, created_at, model_used, escalate
| work_item | stage | author_agent | status | created_at | model_used | escalate |
|---|---|---|---|---|---|---|
| ORCH-112 | analysis | analyst | ready-for-review | 2026-06-15 | claude-opus-4-8 | full-cycle |
01 — BRD / Bug-report: ORCH-112 — failed/cancelled task artifacts must be cleaned from shared checkout
Work Item: ORCH-112 · Repo: orchestrator · Стадия: analysis · Трек: Bug → эскалация в full-cycle
⚠️
escalate: full-cycle(ADR-001 D5 ORCH-019). Баг помеченBug, но по сути это архитектурный + safety-critical (self-hosting) дефект: правка лежит в самом опасном пути прод-деплоя (хост-хук, прямо перед рестартом прод-контейнера) и требует решения о политике жизненного цикла shared checkout (ADR). Поэтому выпускается полный analysis-пакет, а не облегчённый bug-пакет. Оператор снимает багфикс-трек:POST /bug-fast-track/escalate?work_item=ORCH-112→ задача пойдёт через стадиюarchitecture(architect выпустит ADR для политики cleanup/изоляции).
1. Бизнес-контекст и проблема
Симптом (наблюдаемое)
Self-deploy задачи ORCH-111 упал на шаге git pull origin main хост-хука деплоя с ошибкой:
error: Your local changes to the following files would be overwritten by merge:
src/config.py
Please commit your changes or stash them before you merge.
Деплой прерван, конвейер потребовал ручного вмешательства оператора (на self-hosting это групповой риск — встаёт деплой и всех других проектов).
Причина симптома (установленный факт)
В общем (shared) checkout /home/slin/repos/orchestrator оставались грязные файлы от
ранее неуспешной/отменённой/перезапущенной задачи ORCH-104 (тема Lite installer):
- модифицированный tracked-файл:
src/config.py; - модифицированный/untracked:
docs/deployment/LITE_SETUP.md; - untracked:
scripts/install_lite.py,tests/test_install_lite.py,docs/deployment/lite-install.example.yaml.
Через несколько дней эти остатки заблокировали git pull другой задачи (ORCH-111).
Локализация (анализ — куда смотреть архитектору/разработчику)
Установленный факт о топологии (CLAUDE.md / docs/architecture/README.md):
/home/slin/repos/orchestrator (хост) == /repos/orchestrator (контейнер, bind-mount) ==
main clone (settings.repos_dir/<repo> = settings.deploy_host_repo_path). Это deploy-база
и база управления worktree'ами, а НЕ рабочая копия агента.
-
Первичный дефект — нерезистентный
git pull.scripts/orchestrator-deploy-hook.sh:224-226делаетcd "$REPO"(= deploy-база) и голыйgit pull origin mainбез гигиены рабочего дерева. Любая локальная правка tracked-файла блокирует merge → деплой падает. Проверено: во всёмsrc/+scripts/нет ни одногоgit reset --hard/git clean/git stashдля приведения базы к чистому состоянию. Shared checkout трактуется как «всегда чистый», что не гарантировано. -
Невыполненный/неэнфорснутый инвариант + отсутствие «дворника». Нормальный конвейер не пишет в рабочее дерево main clone: агенты работают в изолированных worktree'ах
/repos/_wt/<repo>/<branch>(git_worktree.ensure_worktree);docker buildиспользует контекст worktree (image_freshness._host_worktree_path), не main clone; fallback'и гейтов на main clone — только чтение (git show origin/main:...,qg/checks.py:451,coverage_gate.py:297,stage_engine.py:145). Поэтому грязь ORCH-104 почти наверняка — ручной/брошенный WIP в shared checkout во время инцидента ORCH-104 (косвенное подтверждение: файлыinstall_lite.py/test_install_lite.py/lite-install.example.yamlникогда не существовали в git-истории — закоммиченный артефакт ORCH-104 этоscripts/setup_lite.py, commite2cf883). Вне зависимости от источника: нет механизма, который детектирует/чистит грязную базу и нет задокументированного/энфорснутого инварианта «main checkout — неизменяемая deploy-база, не workspace». -
cancel_taskчистит worktree + remote-ветку, но НЕ shared checkout.stage_engine.cancel_task(шаг 3d, строки ~2330-2343):remove_worktree(repo, branch)+gitea.delete_remote_branch(repo, branch). Это корректно (конвейер в main clone не пишет), но означает нулевое покрытие случая «грязная deploy-база» в каскадах failed/cancelled.
Вывод: даже если первопричина грязи — ручное действие, устойчивость должна быть на стороне
системы: deploy-база обязана самовосстанавливаться в чистый origin/main перед pull, а
политика жизненного цикла — гарантировать, что остатки failed/cancelled задач не клинят будущие
операции.
2. Объём (scope)
В объёме
- Сделать self-deploy
git pull origin main(shared deploy-база) устойчивым к грязному рабочему дереву — приведение базы к чистомуorigin/mainавтономно, без ручного вмешательства. - Гарантировать, что после failed / cancelled / брошенной задачи в shared checkout не остаётся
рабочих остатков, способных заблокировать будущий деплой/операцию (сходимость базы к чистому
origin/main). - Задокументировать (и где осуществимо — мягко энфорснуть/гардить) инвариант «shared main checkout — deploy/worktree-management база, НЕ редактируемый workspace».
- Наблюдаемость: лог + Telegram-алерт, когда deploy-база найдена грязной и автоочищена (или отказ).
Вне объёма
- ❌ Запрет/контроль ручных операций оператора в shared checkout (вне технической власти системы; закрываем устойчивостью, а не запретом).
- ❌ Изменение модели worktree per-task (
git_worktree, ORCH-2) — она корректна и не трогается. - ❌ Любое изменение
STAGE_TRANSITIONS/QG_CHECKS/check_*/ machine-verdict ключей / схемы БД. - ❌ Изменение поведения деплоя на чистой базе (happy-path должен остаться байт-в-байт).
- ❌ Выбор конкретного механизма (reset --hard vs janitor vs guard) — это зона архитектора (ADR).
3. Заинтересованные стороны
- Заказчик/оператор (Слава) — страдает от ручного разруливания залипших деплоев; принимает результат.
- Self-hosting конвейер orchestrator — прямой потребитель (надёжность прод-деплоя).
- Все проекты на общем инстансе (enduro-trails) — косвенно: залипший self-deploy орка останавливает обслуживание их задач.
4. Бизнес-требования (BR)
- BR-1 — Грязное рабочее дерево shared deploy-базы (модифицированные tracked-файлы и/или
untracked-файлы) НЕ должно блокировать self-deploy
git pull origin main: деплой обязан привести базу к чистому, актуальномуorigin/mainбез ручного вмешательства. - BR-2 — После failed / cancelled / брошенной задачи в shared checkout не должно оставаться
рабочих остатков этой задачи, способных заблокировать будущий деплой/git-операцию; база
сходится к чистому
origin/main. - BR-3 — Инвариант «shared main checkout (
<host_repos_dir>/<repo>) — deploy/worktree-management база, НЕ workspace» должен быть задокументирован (docs/operations/INFRA.md+docs/architecture/README.md) и, где осуществимо, энфорснут/гардирован; конвейер/агенты никогда не пишут рабочие изменения в main clone (верифицировать, что это так). - BR-4 — Наблюдаемость: обнаружение грязной базы и факт автоочистки (или отказ) должны логироваться и алертиться (Telegram, кликабельный номер) — оператор видит, что гигиена сработала.
- BR-5 — На чистой базе поведение деплоя — байт-в-байт прежнее (обычный fast-forward
git pull); никакого регресса happy-path.
5. Нефункциональные требования (NFR)
- NFR-1 (self-hosting safety) — гигиена никогда не трогает ветку
mainна remote, не делает force-push, не рестартит прод-контейнер вне штатного гейта, не удаляет worktree/ветки других активных задач. Оперирует только настроенным путём deploy-базы. - NFR-2 (сохранность deploy-состояния) — автоочистка не должна удалять артефакты, легитимно
живущие под
$REPO/рядом: rollback-снимки$REPO/.deploy-prev-image-*(deploy_prod_prev_image_file),deploy-hook.log, sibling-состояния<repos_dir>/.deploy-state-*/.merge-lease-*.json, и админ-записи worktree в.git/worktrees. (Наивныйgit clean -xfdв$REPOуничтожил бы.deploy-prev-image-*и сломал rollback — это жёсткое ограничение для архитектора/разработчика.) - NFR-3 (обратимость / kill-switch) — новое поведение под флагом; выключенный флаг → деплой
байт-в-байт как до ORCH-112 (голый
git pull origin main). - NFR-4 (надёжность) — never-raise / fail-safe (по образцу leaf'ов
serial_gate/cancel); идемпотентность; restart-safe; сбой гигиены не должен маскировать или ухудшать исход деплоя сверх текущего. - NFR-5 (нулевая регрессия конвейера) —
STAGE_TRANSITIONS/QG_CHECKS/check_*/ machine-verdict ключи / схема БД / exit-code-контракт хука (0/1/2, ORCH-036) — байт-в-байт. - NFR-6 (область) — изменение скоупится на self-hosting (
orchestrator); поведение для прочих репо/синхронного деплоя агентом — не ухудшается.
6. Допущения и ограничения
- Shared checkout и хост-хук физически разделяют один путь с контейнером через bind-mount
(
repos_dir↔host_repos_dir); хук исполняется на хосте по ssh (ORCH-036, detached). - Build-once путь (
SOURCE_IMAGEretag) не зависит от содержимого рабочего дерева main clone — прод получает ровно staging-валидированный образ; значит дискард рабочего дерева base перед pull безопасен для деплоимого артефакта. (--build-stagingсобирается из worktree, не из main — отдельный контур.) - Источник истины кода —
origin/main; локальные правки в deploy-базе по определению не должны существовать (это deploy-база, а не место работы). - Конкретный механизм (resilient pull через reset+clean со скоуп-исключениями / активный janitor /
guard инварианта / комбинация) — открытый вопрос для архитектуры, решается в
06-adr/.
7. Критерии успеха
Self-deploy успешно выполняет git pull на ранее грязной shared-базе без ручного вмешательства;
deploy-база сходится к чистому origin/main; rollback-состояние и sibling-артефакты сохранены;
happy-path и весь конвейер — без регресса; обязательный регресс-тест красный до фикса, зелёный
после. Детальные PASS/FAIL — 03-acceptance-criteria.md.
8. Риски
- Деструктивная гигиена (
reset --hard/clean) в прод-deploy-базе рядом с рестартом прода — ошибка скоупа может удалить rollback-state/логи (см. NFR-2) → ADR обязателен. - Маскировка реальной первопричины: если в будущем какой-то код начнёт писать в main clone, «тихая автоочистка» это скроет → нужна наблюдаемость (BR-4).
- Кросс-каттинг с ORCH-036 (self-deploy), ORCH-058 (image-freshness/provenance), ORCH-090 (cancel),
ORCH-2 (worktree-модель). Детали/митигации —
10-tech-risks.md(заполняет архитектор).