# План работ: master-service MVP sandbox ## Контекст - Источники требований: `docs/master.md`, `meetings/meeting_1_document.md`, `README.md`, `docs/*` - Базовый template уже готов: typed config, DI container, observability, FastAPI adapter и versioned API под `/api/v1` - Текущая цель: минимальное управление Docker sandbox без auth - MVP API: `POST /api/v1/create` - Sandbox policy: TTL `300` секунд, одна активная sandbox на `chat_id`, повторный `create` переиспользует активную сессию - Volume policy: chat volume `rw`, dependencies volume `ro`, lambda-tools volume `ro` - Host paths вычисляются из typed config, а HTTP request передает только `chat_id` - Cleanup выполняется периодическим in-process loop внутри master-service ## Вне текущего scope - auth и access control - p2p lease и WebSocket transport - workspace/chat CRUD API - chat files, artifacts, S3, quota и retention policy - центральная БД и multi-node orchestration ## Правила выполнения - Выполняем по одной задаче - Коммиты не делаем - Если по ходу нужна смена архитектуры, останавливаемся и согласуем решение - `domain/` и `usecase/` не импортируют Docker, FastAPI, OpenTelemetry, env или YAML - Inner layers работают только через минимальные domain сущности и usecase порты ## Очередь задач ### M01. ADR и минимальный sandbox scaffolding - Исполнитель: `primary-agent` - Статус: completed - Зависимости: нет - Commit required: no - Scope: зафиксировать MVP-решение в ADR и создать минимальные сущности, ошибки и usecase-контракты для sandbox orchestration - Файлы: `docs/006-mvp-docker-sandbox-orchestration.md`, `domain/sandbox.py`, `domain/error.py`, `usecase/interface.py`, `usecase/sandbox.py` - Критерии приемки: в `domain/` есть минимальная `SandboxSession` и sandbox-ошибки; в `usecase/` есть порты `SandboxSessionRepository`, `SandboxRuntime` и `Clock`; созданы скелеты `CreateSandbox` и `CleanupExpiredSandboxes`; ADR занимает 10-20 строк ### M02. Typed config для sandbox runtime - Субагент: `feature-developer` - Статус: completed - Зависимости: `M01` - Commit required: no - Scope: расширить typed-config слоем `sandbox` с настройками image, TTL, cleanup interval, host paths и container mount paths - Файлы: `adapter/config/model.py`, `adapter/config/loader.py`, `config/app.yaml` - Решение: chat host path строится как путь под общим `sandbox.chats_root/`; request не передает host path напрямую - Критерии приемки: конфиг собирается в typed dataclass-дерево; дефолтный TTL равен `300`; есть отдельные настройки для `chats_root`, `dependencies_host_path`, `lambda_tools_host_path`, `chat_mount_path`, `dependencies_mount_path`, `lambda_tools_mount_path`, `cleanup_interval_seconds`; inner layers не читают env ### M03. Docker runtime adapter для sandbox lifecycle - Субагент: `feature-developer` - Статус: completed - Зависимости: `M01`, `M02` - Commit required: no - Scope: реализовать outer adapter над Docker для создания и остановки sandbox контейнера с нужными labels и mount policy - Файлы: `adapter/docker/runtime.py`, `adapter/docker/__init__.py` - Ограничения: все Docker-детали остаются в `adapter/`; runtime не должен протекать во внутренние слои - Критерии приемки: runtime умеет создать sandbox container по входным параметрам usecase; chat volume монтируется как `rw`; dependency и lambda-tools volumes монтируются как `ro`; контейнер получает labels с `session_id`, `chat_id` и `expires_at`; runtime переводит ошибки Docker в понятные исключения адаптера ### M04. In-memory session repository и usecase `CreateSandbox` - Субагент: `feature-developer` - Статус: completed - Зависимости: `M01`, `M02`, `M03` - Commit required: no - Scope: реализовать in-memory registry активных sandbox-сессий и usecase создания sandbox с логикой reuse по `chat_id` - Файлы: `repository/sandbox_session.py`, `usecase/sandbox.py`, `adapter/di/container.py` - Решение: если по `chat_id` есть неистекшая сессия, usecase возвращает ее без нового container start; если сессия истекла, usecase инициирует stop старой sandbox и создает новую - Критерии приемки: одна активная sandbox на `chat_id`; TTL-логика использует порт `Clock`; usecase не импортирует Docker; container wiring остается singleton-based ### M05. Cleanup expired sandboxes и lifecycle wiring - Субагент: `feature-developer` - Статус: pending - Зависимости: `M04` - Commit required: no - Scope: реализовать usecase cleanup просроченных sandbox и подключить периодический cleanup loop в FastAPI lifecycle - Файлы: `usecase/sandbox.py`, `adapter/di/container.py`, `adapter/http/fastapi/app.py`, при необходимости `adapter/http/fastapi/dependencies.py` - Ограничения: не ломать ADR про раннее OTel instrumentation; lifecycle loop должен стартовать и останавливаться один раз - Критерии приемки: cleanup находит истекшие сессии, останавливает sandbox через runtime и удаляет их из registry; интервал cleanup берется из конфига; shutdown корректно завершает фоновую задачу ### M06. HTTP endpoint `POST /api/v1/create` - Субагент: `feature-developer` - Статус: pending - Зависимости: `M04` - Commit required: no - Scope: добавить минимальную HTTP ручку для создания или переиспользования sandbox без auth - Файлы: `adapter/http/fastapi/schemas.py`, `adapter/http/fastapi/dependencies.py`, `adapter/http/fastapi/routers/v1/router.py`, при необходимости `adapter/di/container.py` - Request: `{ "chat_id": "..." }` - Response: `session_id`, `chat_id`, `container_id`, `status`, `expires_at` - Критерии приемки: router остается тонким; handler только переводит HTTP input в команду usecase и маппит ошибки в HTTP; endpoint живет под `/api/v1/create`; auth не добавляется ### M07. Тесты для create, reuse, TTL и mount policy - Субагент: `test-engineer` - Статус: pending - Зависимости: `M03`, `M04`, `M05`, `M06` - Commit required: no - Scope: покрыть тестами ключевое поведение MVP без запуска реального production Docker stack - Файлы: `test/*` - Критерии приемки: есть unit-тесты для `CreateSandbox` и `CleanupExpiredSandboxes` с fake clock; есть HTTP smoke-тест для `POST /api/v1/create`; есть adapter-level тест с mock Docker client на mount policy `chat=rw`, `deps=ro`, `tools=ro`; тесты не тащат FastAPI или Docker в inner-layer тесты ### M08. Архитектурный и boundary review по MVP sandbox - Субагент: `code-reviewer` - Статус: pending - Зависимости: `M07` - Commit required: no - Scope: проверить соблюдение clean architecture, dependency direction и соответствие MVP-ограничениям - Файлы: весь измененный код - Критерии приемки: Docker остается только во внешнем adapter; FastAPI не протекает в `domain/` и `usecase/`; TTL и mount policy читаются как явные, тестируемые правила; замечания сформулированы как точечные правки или подтверждение готовности