5.2 KiB
ORCH-2 / S-4 — git worktree per task (изоляция shared /repos)
Дата: 2026-06-02
Ветка: feature/ORCH-2-worktree
Источник: AUDIT_2026-06-02.md (SERIOUS S-4), DEV_TASK_ORCH2_WORKTREE.md
Исполнитель: Dev (Opus 4.8 Tokenator)
Проблема (S-4)
Все git-операции (launcher.launch cmd, _monitor_agent commit/push, check_tests_local)
делали git checkout <branch> в одном общем /repos/<repo>. При двух активных задачах
checkout одной перетирал рабочую копию другой → гонки (на ET-009 это дало «два коллектора»
и путаницу веток).
Решение
git worktree per branch. Каждая задача (ветка) работает в изолированной рабочей копии:
/repos/<repo> ← основной clone (fetch / worktree mgmt / read-only)
/repos/_wt/<repo>/<safe-branch> ← worktree задачи (рабочая копия агента)
Изменения
| Файл | Что |
|---|---|
src/config.py |
+ worktrees_dir: str = "/repos/_wt" |
src/git_worktree.py (новый) |
_safe, get_worktree_path, ensure_worktree, remove_worktree |
src/agents/launcher.py |
launch(): ветка резолвится заранее → ensure_worktree; cmd = cd <worktree> без git checkout; _write_task_file(repo, branch, ...) пишет в worktree; _monitor_agent commit/push в worktree (checkout убран); чтение 01-questions.md/10-conflict.md из worktree; QG-диспетчер прокидывает branch |
src/qg/checks.py |
_repo_path(repo, branch) helper (worktree если есть, иначе shared); артефакт-чеки получили опциональный branch; check_tests_local → ensure_worktree + make test в worktree (TODO про S-4 удалён) |
src/webhooks/plane.py |
QG-диспетчер прокидывает branch; review-файл fallback читается из worktree |
src/webhooks/gitea.py |
git branch -r --contains <sha> — подтверждено read-only, оставлено в main clone (+ комментарий) |
tests/test_git_worktree.py (новый) |
покрытие _safe/get_worktree_path/ensure_worktree/remove_worktree + изоляция двух веток (реальные локальные git-репо в tmp, без сети) |
tests/test_launcher.py |
TestWriteTaskFile обновлён под новую сигнатуру (запись в worktree) |
docs/ARCHITECTURE.md |
раздел «Изоляция через git worktree»; убран пункт про shared-checkout гонки |
Совместимость с прежними фиксами
- B-1 (запись task-файла без docker, прямой
open()): сохранена — теперь путь = worktree. - B-2 (Popen stdout → файл, monitor
proc.wait()без зомби): не тронут. - S-5 (
check_reviewer_verdict— только YAML-frontmatter): не тронут, добавлен лишь worktree-путь. - S-1 (
check_tests_local— свойmake testвместо Gitea CI): сохранён, тесты теперь в worktree.
Обратная совместимость QG-диспетчеризации: артефакт-чеки принимают branch опционально
(default None → shared /repos/<repo>), поэтому существующие 2-арг вызовы/тесты не сломаны.
Проверка
# Тесты (в контейнере через образ — хостовый .venv сломан):
IMG=$(docker inspect orchestrator --format '{{.Config.Image}}')
docker run --rm -v /home/slin/repos/orchestrator:/code -w /code --entrypoint python3 $IMG -m pytest tests/ -q
# → 37 passed, 9 failed (pre-existing test_webhooks 401/signature — НЕ относятся к ORCH-2,
# идентичны baseline на main).
# test_git_worktree.py изолированно → 9 passed.
Тест изоляции (в работающем контейнере)
docker exec orchestrator python3 -c "
import sys; sys.path.insert(0,'/app')
from src.git_worktree import ensure_worktree
import subprocess
p1 = ensure_worktree('enduro-trails','feature/wt-test-A')
p2 = ensure_worktree('enduro-trails','feature/wt-test-B')
b1 = subprocess.run(['git','-C',p1,'branch','--show-current'],capture_output=True,text=True).stdout.strip()
b2 = subprocess.run(['git','-C',p2,'branch','--show-current'],capture_output=True,text=True).stdout.strip()
assert p1!=p2 and b1!=b2, 'NOT ISOLATED'
print('ISOLATION OK', p1, p2, b1, b2)
"
(Результат прогона на сервере — см. ниже / в отчёте Стрим.)
Ограничения / заметки
- Очередь задач (ORCH-1 / F-2b) не входит в эту задачу.
remove_worktreeсуществует, но автоматический вызов приdoneне подключён (опционально, отдельным шагом).