ADR 0001: доменная модель и compute backend SPI¶
- Статус: принято и реализовано; оставшиеся OpenShell gaps отслеживаются в compatibility matrix
- Дата: 2026-10-16
- Ответственные за решение: сопровождающие Quarshell
- Область: compute backends и оркестрация Gateway
Контекст¶
В driver package определены собственный request и контракт Backend, типизированные
backend identity и capabilities, а также optional extension interfaces. Все
встроенные реализации напрямую регистрируют этот контракт; Gateway выбирает
только native Backends. Remote ComputeDriver plugins реализуют тот же Backend
contract через pinned OpenShell protocol. VM backend пока fail-closed при
Gateway runtime validation: его host-supervisor и isolation lifecycle ещё не
завершены. Бывший flat Spec/ComputeDriver compatibility API удалён.
Решение¶
- Продукт владеет доменным контрактом. Оркестрация использует
BackendCreateRequest,Backend,BackendInfoи типизированные доменные значения. Transport messages, внешние protobuf-типы и запросы container engine не входят в этот контракт. - Обязательный lifecycle остаётся небольшим.
Backendотвечает за identity, объявление capabilities, валидацию и выполнение create, start, stop, delete, list и inspect. Необязательное поведение описывают узкие extension interfaces, напримерInteractiveExec,FileTransfer,ServiceForward,LogAccessи runtime extensions. Backend реализует только реально поддерживаемые функции. - Capability должна совпадать с реализацией. Вызывающая сторона получает
extension через
driver.RequireExtension[T]. Helper проверяет и объявленную capability, и наличие соответствующего метода; при отсутствии любого из них возвращается типизированныйUnsupportedError. Нельзя молча отключать запрошенное поведение безопасности или lifecycle. - Сначала валидация, затем фиксация состояния. Gateway разрешает и валидирует create request до записи durable lifecycle state и расходования одноразового upload token. Secrets передаются только на короткую операцию и не копируются в durable create records.
- Использовать прямой модульный backend-контракт. Все встроенные реализации
напрямую регистрируют
Backendи владеют типизированной create-моделью. Gateway разрешает только native factory и возвращает её ошибку без fallback. Предыдущее предложение о migration adapter заменено решением о прямом переносе от 2026-10-21; очистка неиспользуемого flat API отслеживается в B0.6. - Сохранять закреплённый wire contract. Сгенерированные OpenShell schema и Gateway implementation сохраняют точные upstream service, field и package identifiers. Gateway methods напрямую сопоставляют эти requests с доменными операциями. Собственные имена domain и API не наследуют upstream wire identifiers. Неподдерживаемые операции возвращают типизированный unsupported-результат на границе протокола.
- Клиенты независимы. CLI и browser UI — отдельные API clients. CLI может включать terminal presentation code и вызывать SDK; browser UI использует typed browser client и Gateway API. Gateway не импортирует CLI или UI, а browser UI не запускает CLI.
Пример контракта¶
Ниже — фрагмент реализованного Go SPI. Тип настроек принадлежит конкретному
backend package; общему request не нужен сериализованный driver config:
type Backend interface {
ID() BackendID
Capabilities(context.Context) (BackendInfo, error)
ValidateCreate(context.Context, BackendCreateRequest) error
Create(context.Context, BackendCreateRequest) (Handle, error)
Start(context.Context, core.ID) error
Stop(context.Context, core.ID) error
Delete(context.Context, core.ID) error
List(context.Context) ([]Info, error)
Inspect(context.Context, string) (Info, error)
}
type BackendCreateRequest struct {
SandboxID core.ID
Name string
Workspace WorkspaceTarget
Workload WorkloadSpec
Resources ResourceLimits
Mounts []Mount
Network NetworkSpec
Runtime RuntimeAssets
Config any // типизирован настройками backend, это не wire-format map
}
transfer, err := driver.RequireExtension[driver.FileTransfer](
ctx, backend, driver.CapabilityFileTransfer, "copy into sandbox",
)
if err != nil {
return err // сохранить Unsupported; не утверждать, что операция выполнена
}
return transfer.CopyTo(ctx, sandboxID, source, destination)
Настоящий BackendCreateRequest также содержит sandbox name и флаг admission
небезопасного mount. Значения runtime и network временны. Реализация вызывает
ValidateCreate до создания backend resources и отклоняет входные данные,
которые не может безопасно обработать.
Структура модулей и адаптеров¶
Целевые границы ответственности:
core/ доменные значения, policy, validation и типизированные ошибки
proto/ схемы product API и сгенерированные product clients
driver/ Backend SPI и Docker, Podman, MicroVM adapters
runtime/ guest init, supervisor и guest protocol
proxy/ egress enforcement и credential mediation
providers/ provider profiles и credential refresh validation
gateway/ auth, оркестрация, durable state и API adapters
sdk/ Go и Python API clients
cli/ команды, вызовы SDK и terminal presentation
ui/ browser app и typed browser API client
Это границы владения кодом, а не требование немедленно разделить каждый repository. Текущие repository и Go module paths пока используют имена Cautem; этапы переименования описаны в плане переименования и релиза.
Gateway resolver в quarshell-gateway/internal/httpapi/compute.go выбирает
зарегистрированные native backends. Обработчик OpenShell protocol один раз
преобразует запрос в модульный create request. Backend владеет typed config и
реализует доменный SPI без импорта CLI packages и transport schemas.
Последствия¶
- Новый backend можно добавить за SPI без backend-specific условий в API clients и без включения его настроек в общую wire schema.
- У optional features есть явная capability negotiation; отсутствие функции обрабатывается fail-closed.
- Все Docker, Podman, Kubernetes и VM backends регистрируют модульный Backend;
прежняя flat
Spec/ComputeDrivercompatibility-поверхность удалена. - Docker, Podman и MicroVM переходят независимо и проходят собственные runtime acceptance gates. Текущий код и локальные тесты не доказывают полную совместимость функций или production readiness.
- На gRPC compatibility boundary неподдерживаемое поведение преобразуется в предусмотренный протоколом unsupported status. Существующие wire identifiers сохраняются, а собственные API используют своё пространство имён.
- Переименование modules, packages и binaries ждёт настройки целевых remotes, публикации replacement dependencies и успешной сборки consumer без локальных workspace overrides. Порядок cutover и rollback задан в release plan.
Проверка¶
Решение отражено в driver/backend.go, Gateway backend resolver,
compatibility RPC adapter, RPC inventory и contract tests. Тесты проверяют
adapter и явный unsupported path. Production acceptance backend-ов определяется
feature matrix и реестром открытых gaps; этот ADR не меняет их статусы.
