Files
orchestrator/docs/work-items/ORCH-057/12-review.md

7.3 KiB
Raw Blame History

verdict, work_item, stage, author_agent, status, created_at, model_used, type, work_item_id, version
verdict work_item stage author_agent status created_at model_used type work_item_id version
APPROVED ORCH-057 review reviewer approved 2026-06-10 claude-opus-4-8 review ORCH-057 1

Review ORCH-057

Summary

Follow-up ORCH-040: закрыт недоделанный AC по legacy root:root файлам, ломавшим создание worktree под uid 1000. Реализованы три аддитивных, обратимых kill-switch'ем слоя ровно по ADR-001: D1 actionable-ошибка в ensure_worktree, D2 детект-леаф src/fs_normalize.py (never-raise, TTL-кэш, scope-aware), D3 best-effort startup-наблюдаемость в main.lifespan (WARNING + Telegram, claim не блокируется), плюс GET /queue блок fs_ownership и POST /fs-normalize/check. Документация (INFRA.md процедура, architecture/README.md, сквозной adr-0031, CHANGELOG, .env.example) обновлена в том же PR.

Проверено по 4 осям; все 7 AC выполнены, P0/P1 findings нет. Регресс pytest tests/ -q1507 passed; целевые модули (test_fs_normalize, test_fs_normalize_startup, test_git_worktree_perm, test_api_queue) — 25 passed, покрывают TC-01…TC-12.

Соответствие ТЗ (02-trz) и AC (03-acceptance-criteria)

  • FR-1 / AC-1, AC-2 ✓ — git_worktree._raise_if_permission + fs_normalize.is_permission_failure/ build_worktree_help: класс «нет прав» (Permission denied/could not create leading directories/ insufficient permission/PermissionError/EACCES/EPERM) → actionable RuntimeError с причиной, chown-командой и ссылкой на INFRA.md. Обе точки сбоя обёрнуты (os.makedirs + оба worktree add). Не-прав-ошибки сохраняют прежний raw-контракт (TC-02 PASS). Под kill-switch — no-op, контракт 1:1.
  • FR-2 / AC-3 ✓ — scan_ownership обходит /repos/_wt, <repo>/.git/{objects,worktrees}, data/runs; ранний выход на первом lstat.st_uid != target_uid; чистая среда → mismatch=False идемпотентно; never-raise → консервативный mismatch=False (TC-03/04/05).
  • FR-3 / AC-4 ✓ — startup-хук never-fatal: WARNING + Telegram при mismatch; claim не блокируется (D3, преднамеренно — внятный ранний отказ даёт D1, знающий repo). Read-only блок fs_ownership в GET /queue (TC-10/TC-12).
  • FR-4 ✓ — normalize() chown только при _is_privileged() (geteuid==0); под uid 1000 — no-op + честный лог, НЕ ошибка; gated fs_normalize_auto (дефолт False) (TC-08).
  • FR-5 / AC-7 ✓ — INFRA.md: блокер P-5 + подраздел «Миграция uid: обязательная нормализация» со всеми корнями; work-item ADR + сквозной adr-0031.
  • §7 совместимость / AC-5 ✓ — applies(repo) first (kill-switch + scope; пустой CSV → self-hosting only через is_self_hosting_repo); enduro-trails не сканируется при дефолте. TTL-кэш (fs_scan_cache_ttl_s). Регресс зелёный (1507 passed).

Соответствие ADR

  • Реализация совпадает с ADR-001 D1D6 (включая сознательный отказ от блокирующего claim-гейта и init-контейнера — обоснование в «Альтернативах»). Сквозная регистрация adr-0031 присутствует и отражена в architecture/README.md.
  • Трассировка (AC-6 / TRACEABILITY): инварианты конвейера не тронуты — commit 9852871 НЕ затрагивает src/stages.py, src/qg/checks.py, src/db.py, src/stage_engine.py. Маркеры ORCH-040/088 в git_worktree/main читаются, зафиксированные инварианты (never-fatal startup, отложенный срез ветки) не сломаны. STAGE_TRANSITIONS/QG_CHECKS/check_*/machine-verdict/схема БД — байт-в-байт прежние.

Качество кода

  • src/fs_normalize.py — чистый leaf (импортирует только config/logging/os/time, лениво qg.checks/notifications); строгий never-raise на каждой публичной функции; docstrings на всех публичных символах; os.lstat (не stat) для честной оценки симлинков. Зависимость односторонняя (git_worktreefs_normalize).
  • Узкий _PERM_MARKERS сознательно не реклассифицирует не-прав-ошибки (защита AC-2).
  • Тесты содержательны (214/136/139/68 строк), используют tmp_path/monkeypatch, без реального chown и записи в /repos; покрывают обе ветки классификатора, идемпотентность, scope, kill-switch, TTL-кэш, startup-never-fatal.
  • Утечек/секретов/security-дыр не выявлено; chown физически возможен только под root (_is_privileged).

Findings

P0 — Blocker

  • Нет.

P1 — Must fix

  • Нет.

P2 — Should fix

  • Нет.

P3 — Nice-to-have (не блокирует)

  • snapshot() в GET /queue на холодном кэше инициирует реальный обход .git/objects синхронно в обработчике запроса. На практике кэш прогрет startup-хуком и TTL=300s, обход только для self-hosting — латентность пренебрежима, паттерн зеркалит coverage_gate. Можно при желании отдавать в /queue только кэш без форс-скана. Информационно.

Документация

Обновлена в том же PR — golden source синхронен с кодом:

  • docs/operations/INFRA.md — P-5 (блокер миграции uid) + подраздел процедуры со всеми корнями ✓
  • docs/architecture/README.md — компонент «FS ownership detect» (D1D3, условность, наблюдаемость) ✓
  • docs/architecture/adr/adr-0031-legacy-ownership-normalization.md — сквозной ADR (tracked) ✓
  • docs/work-items/ORCH-057/06-adr/ADR-001-…md — work-item ADR ✓
  • CHANGELOG.md — запись ORCH-057 ✓
  • .env.example — 6 флагов ORCH_FS_*

README.md «Известные ограничения» (ORCH-079): пункт про legacy-ownership/uid-миграцию там отсутствует — закрывать/снимать нечего, обзорная витрина в обновлении не нуждается.

Вывод: изменение src/ сопровождено обновлением документации → требование правила 6 выполнено.