Files

12 KiB
Raw Permalink Blame History

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-3INFRA.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 базового образа; в образе создан реальный user slin (uid 1000) для getpwuid() (ORCH-058, Dockerfile). Под uid 1000 chown чужих (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.