feat(orchestrator): ephemeral session pods — restart policy, volumes, init containers

An MCP server container is long-lived and restarts forever; an agent session pod
is the opposite — it does a unit of work and dies. ContainerSpec could not
express that: restartPolicy was hardcoded 'Always' in generatePodSpec, and there
were no volume, workdir, or init-container fields at all.

Adds four optional fields to ContainerSpec (restartPolicy, workdir, volumes,
initContainers) and implements them in both backends. All optional, so every
existing caller is byte-identical — generatePodSpec still emits 'Always' unless
asked otherwise, and omits volumes/initContainers keys entirely when unused.

Kubernetes gets this nearly free: initContainers run to completion in
declaration order before any app container starts, so "clone the repos, then
work them" needs no sequencing logic from us. generateDeploymentSpec
deliberately ignores spec.restartPolicy — k8s rejects anything but 'Always' on a
Deployment pod template — and says so in a comment.

Docker has no init containers, so they are emulated as sequential runs sharing
the same volumes. The important property is the failure path: a non-zero init
exit aborts BEFORE the main container is created, and the error carries the init
container's last 50 log lines. Otherwise a failed git clone would leave an empty
workspace that looks exactly like a successful one, and the agent would start
work against nothing. Named Docker volumes are namespaced by container name to
stand in for emptyDir.

Tests: 10 k8s manifest tests (defaults unchanged, each restart policy, volume
and mount emission, init ordering, name sanitization, security context still
hardened) and 9 Docker tests including the abort-before-main case and log
propagation.

Local: build clean, workspace 2310 passed (+19), lint unchanged at the repo's
pre-existing 869.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4wNHWf7xSwnZCWpJcyv9p
This commit is contained in:
Michal
2026-08-08 10:36:21 +01:00
parent fceb3cfb95
commit ffcd0f985b
6 changed files with 452 additions and 9 deletions

View File

@@ -2917,9 +2917,9 @@
"testStrategy": "Type tests: verify ContainerSpec accepts all new optional fields, verify existing code still compiles without providing new fields.",
"priority": "high",
"dependencies": [],
"status": "pending",
"status": "done",
"subtasks": [],
"updatedAt": "2026-08-08T08:55:58.627Z"
"updatedAt": "2026-08-08T09:36:21.123Z"
},
{
"id": "141",
@@ -2931,9 +2931,9 @@
"dependencies": [
"140"
],
"status": "pending",
"status": "done",
"subtasks": [],
"updatedAt": "2026-08-08T08:55:58.627Z"
"updatedAt": "2026-08-08T09:36:21.132Z"
},
{
"id": "142",
@@ -2945,9 +2945,9 @@
"dependencies": [
"140"
],
"status": "pending",
"status": "done",
"subtasks": [],
"updatedAt": "2026-08-08T08:55:58.627Z"
"updatedAt": "2026-08-08T09:36:21.139Z"
},
{
"id": "143",
@@ -3251,9 +3251,9 @@
],
"metadata": {
"version": "1.0.0",
"lastModified": "2026-08-08T09:29:43.398Z",
"lastModified": "2026-08-08T09:36:21.139Z",
"taskCount": 162,
"completedCount": 104,
"completedCount": 107,
"tags": [
"master"
]