Files

141 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
work_item: ORCH-057
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-10
model_used: 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` базового образа; в образе создан
реальный 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.