12 KiB
work_item, stage, author_agent, status, created_at, model_used
| work_item | stage | author_agent | status | created_at | model_used |
|---|---|---|---|---|---|
| ORCH-057 | analysis | analyst | ready-for-review | 2026-06-10 | claude-opus-4-8 |
01 — BRD (бизнес-требования): ORCH-057 — нормализация legacy root-owned файлов при миграции на uid 1000 (one-time + защита)
Work Item: ORCH-057 · Repo: orchestrator · Стадия: analysis
1. Бизнес-контекст и проблема
ORCH-040 перевёл оба контейнера (orchestrator 8500, orchestrator-staging 8501) с root
на user: "1000:1000" (slin). Изменён был только docker-compose.yml. Однако bind-mount
/home/slin/repos → /repos уже содержал файлы и каталоги, созданные прежним root-контейнером
(root:root). Смена user: владельца существующих файлов НЕ меняет.
Реальный инцидент (прод, 06.06, поймали на первом запуске ORCH-043). Первый job под uid 1000 упал на стадии launch (НЕ на коде задачи):
fatal: could not create leading directories of
'/repos/_wt/orchestrator/feature_ORCH-043-.../.git': Permission denied
Причина: /repos/_wt/ и старые worktree-папки = root:root → uid 1000 не может создать рядом
новый каталог worktree. Установлено фактически: ошибка возникает в src/git_worktree.py::ensure_worktree
(вызов git worktree add), куда конвейер приходит из src/agents/launcher.py::_spawn (стр. 500)
и _materialize_deferred_branch (ORCH-088). Агент даже не стартует — падает создание worktree.
Ручной workaround (применён Стрим, прод снова рабочий, ОДНОРАЗОВО):
sudo chown -R 1000:1000 /home/slin/repos/_wt
sudo chown -R 1000:1000 /home/slin/repos/orchestrator/.git /home/slin/repos/enduro-trails/.git
sudo chown -R 1000:1000 /home/slin/repos/orchestrator # +data/runs/*.log (37 root-логов)
ADR-001 ORCH-040 упоминал «массовый chown старых root-файлов» лишь абстрактно («вне объёма кода», «разовая операция Owner») и НЕ дал конкретной процедуры чистки legacy worktree — поэтому deployer её не выполнил, и баг проявился в проде. Прод сейчас рабочий (ручной фикс наложен), но проблема воспроизведётся на чистой среде, новом репо или после любого исторического запуска под root, если её не закрыть кодом + процедурой.
Это follow-up / закрытие недоделанного AC ORCH-040 (legacy-файлы), а не новая фича.
2. Объём (scope)
В объёме
- Защита launcher (код): при
Permission deniedна создании worktree выдавать внятную, диагностируемую ошибку «legacy root-файлы в/repos/_wt— требуется нормализация прав» с указанием команды, а НЕ сыройgit fatal. - Раннее обнаружение (код): детектирование наличия файлов с
uid != <target_uid>вORCH_REPOS_DIR(включая_wt,.git/objects,.git/worktrees,data/runs) при старте контейнера / перед претензией на job — чтобы конвейер падал внятно и заранее, а не сырым git-фаталом на launch. - Процедура нормализации (документация): в
docs/operations/INFRA.md(и собственный ADR ORCH-057) — обязательная одноразовая процедура нормализации legacy root-файлов при миграции uid, с точными командами и областью охвата (_wt,.git,data/runs). - Опционально (по решению архитектора): механизм one-time нормализации при буте/деплое — init-контейнер/хук под root, либо blocking-entrypoint-проверка.
Вне объёма
- Изменение логики конвейера,
STAGE_TRANSITIONS,QG_CHECKS,check_*, схемы БД. - Пересмотр самого решения ORCH-040 (uid 1000) — оно принято и остаётся.
- Перенос инстанса на другой хост / другой uid (отдельная задача при миграции хоста).
- Массовая ретроактивная переработка ADR-001 ORCH-040 (его история не переписывается; допускается forward-breadcrumb-ссылка на ORCH-057 — решает архитектор).
- Выбор конкретного варианта реализации one-time нормализации (a/b/в) — зона архитектора (06-adr).
3. Заинтересованные стороны
- Заказчик / Owner — Слава (homenet542), инициатор; принимает результат.
- Эксплуатация — Стрим (применял ручной workaround); потребитель процедуры в INFRA.md.
- Затронутые проекты —
orchestrator(self-hosting) иenduro-trails(общий инстанс, общая очередь, общий bind-mount/repos): нормализация прав/reposкасается обоих репо.
4. Бизнес-требования (BR)
- BR-1 — После миграции контейнера на новый uid конвейер запускается без ручного
chown: либо авто-нормализация прав, либо явная блокирующая ошибка с инструкцией (никогда не сыройgit fatalна launch). - BR-2 — На свежей среде / новом репо / после исторического запуска под root проблема не воспроизводится (детект + понятная диагностика срабатывают до падения агента).
- BR-3 —
INFRA.mdи ADR содержат конкретную процедуру нормализации legacy root-файлов (точные команды, область:_wt,.git/objects,.git/worktrees,data/runs), помеченную как обязательный шаг миграции uid. - BR-4 — Несоответствие владельца наблюдаемо: оператор узнаёт о проблеме из лога/уведомления/ read-only статуса, а не по падению задачи на launch.
- BR-5 — Защита
ensure_worktreeраспознаёт класс ошибки «нет прав на создание worktree» и сообщает причину + лечащую команду (опц. — авто-самолечение, если процесс имеет права).
5. Нефункциональные требования (NFR)
- NFR-1 (self-hosting безопасность) — Решение никогда не перезапускает/не роняет
прод-контейнер
orchestrator, не трогаетmain/force-push/прод-образ. Контейнер бежит под uid 1000 (без root) → код не может делатьchownбез root; код ограничивается детектом + внятной диагностикой/блокировкой, а фактическийchown— операторская/init-процедура. - NFR-2 (общий инстанс) — Нулевая регрессия для
enduro-trails: feature под kill-switch и scope-флагом (по образцуserial_gate/coverage_gate); выключено → поведение 1:1 как до ORCH-057. - NFR-3 (never-raise / fail-safe) — Детект-леаф никогда не бросает наружу неожиданное исключение и не блокирует старт сервиса по своей ошибке; деградирует в WARNING.
- NFR-4 (идемпотентность) — Повторный запуск детекта/нормализации на уже корректной среде — no-op без побочных эффектов.
- NFR-5 (обратимость) — Поведение откатывается выключением kill-switch без миграций/правки схемы.
- NFR-6 (наблюдаемость) — Вердикт (есть/нет mismatch, сколько файлов, какие корни) логируется
структурно; при проблеме — Telegram с кликабельным номером задачи (если применимо) + read-only
отражение в
GET /queue.
6. Допущения и ограничения
- Целевой uid:gid рантайма =
1000:1000(slin), подтверждён ORCH-040 (P-3); на хосте/repos,/app/dataштатно1000:1000. - Контейнер бежит под numeric uid 1000 без записи в
/etc/passwdбазового образа; в образе создан реальный userslin(uid 1000) дляgetpwuid()(ORCH-058, Dockerfile). Под uid 1000chownчужих (root) файлов невозможен без CAP_CHOWN/root. git config --system --add safe.directory '*'уже в образе — git доверяет bind-mount.- Корни проверки:
ORCH_REPOS_DIR(/repos), включая_wt,<repo>/.git/objects,<repo>/.git/worktrees, иdata/runs(37 root-логов в инциденте). start_pipeline(ORCH-088) отложил срез ветки на момент claim analyst-job → детект уместен и на старте сервиса, и перед claim'ом (точку выбирает архитектор).
7. Критерии успеха
После миграции uid (или на чистой среде) первый же job проходит launch без ручного chown, либо —
если права не нормализованы — конвейер выдаёт понятную блокирующую диагностику с командой
исправления вместо сырого git fatal. INFRA.md/ADR содержат воспроизводимую процедуру.
Для enduro-trails — нулевая регрессия. Детальные PASS/FAIL — в 03-acceptance-criteria.md.
8. Риски
- Контейнер без root не может
chown→ авто-самолечение возможно только частично/при наличии прав; основной гарант — детект+диагностика+процедура (детали —10-tech-risks.md, архитектор). - Рекурсивный обход больших
.git/objects/_wtможет быть дорог → нужен дешёвый/семплированный детект и кэш (как preflight TTL). - Ложно-блокирующая ошибка может застопорить и enduro-trails (общий
/repos) → строгий scope/fail-safe. - Правка
docker-compose.yml/entrypoint (init-контейнер) = деплой self → групповой риск (NFR-1), обязательная страховка staging.