# 01 — BRD: Агенты пишут файлы под root в смонтированный хост-репо

Work Item: **ORCH-040**
Тип: инфра-фикс (runtime / docker-compose)
Исполнение: через Dev напрямую (по решению Owner)

## 1. Бизнес-контекст и проблема

Контейнер `orchestrator` (prod, 8500) работает под `uid=0 (root)`. Он монтирует
хостовый каталог `/home/slin/repos` → `/repos` (rw). Claude-CLI агенты запускаются
через `subprocess.Popen` **внутри контейнера**, то есть тоже под root. Они пишут:

- в git worktree задач — `/repos/_wt/<repo>/<branch>/...`;
- в прод-клон — `/repos/<repo>/docs/work-items/...` (через коммит/пуш из worktree).

В результате на **хосте** файлы создаются с владельцем `root:root`.

### Симптом
При ребилде/деплое прода `git pull` / `git reset` под пользователем `slin` падает:

```
error: insufficient permission for adding an object to repository database .git/objects
Permission denied  (на docs/work-items/ORCH-016, владелец root:root)
```

Каждый будущий деплой будет ломаться, пока вручную не выполнить `chown`.

### Диагноз (живая разведка 05–06.06)
- `docker exec orchestrator id` → `uid=0(root) gid=0(root) groups=0,999`.
- Хост `slin` = `uid=1000 gid=1000`, группы: `sudo`, `docker(999)`.
- `/home/slin/repos` → `/repos` (rw); на хосте `/repos` уже `1000:1000 rwxrwxr-x`.
- `docs/work-items/*` на хосте — `root:root` (наследие прошлых прогонов).

## 2. Цель

Агенты конвейера **не должны** создавать `root`-файлы в хостовом репозитории.
После любого прогона конвейера `git pull/status/reset` под `slin` на хосте
работает **без ручного chown**.

## 3. Объём (scope)

В объёме:
- Изменение runtime-режима контейнера так, чтобы артефакты создавались под
  `uid:gid` хоста (`1000:1000`).
- Сохранение работоспособности: claude-auth (preflight), git/ssh, docker.sock
  (деплой), запуск конвейера.
- Обновление документации (INFRA.md, CHANGELOG, ADR с обоснованием варианта).
- Проверка на staging (8501) ДО прода.

Вне объёма:
- Массовое исправление прав уже существующих `root:root` файлов в истории
  (разовый `chown` на хосте делает Owner; в задаче — только описать команду).
- Изменение логики конвейера, QG, схемы БД.
- Смена модели/effort агентов, прочие фичи.

## 4. Заинтересованные стороны
- Owner (Слава) — заказчик, владелец хоста mva154.
- Стрим — разведка/контекст.
- Проект enduro-trails — co-tenant того же прод-инстанса (групповой риск).

## 5. Ограничения и риски (off-limits)

Self-hosting: прод-инстанс `orchestrator` ОДИН на все прод-проекты, общая БД и
очередь. **Нельзя ломать**: запуск конвейера, доступ к Plane/Gitea/SSH из агентов,
docker.sock. Любой рестарт контейнера под новым uid — **только в окно тишины**
(нет активных задач). Тестировать на staging ПЕРЕД продом.

### Известные мины (подтверждены разведкой)
- **МИНА 1 — docker.sock**: `/var/run/docker.sock` = `srw-rw---- root:999`.
  Доступ идёт через gid 999, не через root. При переходе на непривилегированный
  uid обязателен supplementary group `999`. *В текущем `docker-compose.yml` уже
  есть `group_add: ["999"]` для обоих сервисов — учесть, не сломать.*
- **МИНА 2 — claude creds (БЛОКЕР)**: `/home/slin/.claude/.credentials.json` =
  `root:root 0600`. Сейчас читает контейнер-root. Под `uid=1000` без доступа →
  `claude-auth` ломается → весь конвейер умирает (preflight ORCH-044 заворачивает).
  Проверить ПЕРВЫМ.
- **МИНА 3 — claude бинарь**: реальный бинарь `/opt/claude-code/bin/claude.exe`
  (root:root, `+x` для всех — ok). `ORCH_CLAUDE_BIN=/usr/bin/claude` в env не
  существует; launcher использует hardcode `CLAUDE_BIN=/opt/claude-code/bin/claude.exe`.
  Под uid 1000 исполним, но проверить запуск.
- **SSH-маунт**: `/home/slin/.orchestrator-ssh` → `/root/.ssh:ro`. При смене uid
  HOME/домашний каталог меняется — путь к ключам нужно поправить (деплой по ssh).
- **HOME**: launcher форсит `HOME=/home/slin` (две точки: env Popen и git_env).
  Креды читаются из `/home/slin/.claude`. Учесть при смене uid.

## 6. Бизнес-ценность
Устранение постоянного ручного `chown` после каждого деплоя; деплой прода
перестаёт ломаться на правах; снимается источник простоя конвейера всех проектов.

## 7. Допущения
- Хост-каталоги `/app/data` и `/repos` уже `1000:1000` (запись под uid 1000 пройдёт).
- Dockerfile уже содержит `git config --system --add safe.directory '*'`.
- Окно тишины для рестарта контейнера согласуется с Owner.

## 8. Host-prerequisites (предусловия на стороне Owner)
Часть фикса невозможно закрыть только кодом — есть действия на хосте mva154,
которые выполняет Owner (в гит не коммитятся, фиксируются в ADR/INFRA). Это
обязательные предусловия Варианта 1; без них переход на uid 1000 ломает конвейер:
- **P-1 (блокер, МИНА 2):** обеспечить чтение `/home/slin/.claude/.credentials.json`
  под uid 1000 (рекомендация — `chown -R 1000:1000 /home/slin/.claude`). Способ
  выбирает ADR; анализ фиксирует факт предусловия.
- **P-2:** ssh-ключи (`/home/slin/.orchestrator-ssh`) читаемы uid 1000.
- **P-3:** подтверждение `slin = uid 1000 gid 1000` (подтверждено разведкой).
- **P-4:** рестарт прод-self только в окно тишины (`GET /status` без активных задач).

Детализация и команды — в `02-trz.md` §10.
