Skip to content

fix(sandbox): reconcile agent resources on resume - #1546

Open
0xAlcibiades wants to merge 2 commits into
paradigmxyz:mainfrom
0xAlcibiades:alcibiades/reconcile-sandbox-resources
Open

fix(sandbox): reconcile agent resources on resume#1546
0xAlcibiades wants to merge 2 commits into
paradigmxyz:mainfrom
0xAlcibiades:alcibiades/reconcile-sandbox-resources

Conversation

@0xAlcibiades

Copy link
Copy Markdown
Contributor

Closes #1545

Change

AgentSandboxConfig gains default_resources, populated from the same
SESSION_SANDBOX_RESOURCES the create path renders. resume reconciles the
stored pod template against it before setting replicas = 1.

resume only receives a sandbox id, not a spec, which is why the configured
value has to reach the backend through config rather than being re-resolved.

Four decisions worth reviewing

It runs while the sandbox is paused. replicas is still 0 and no pod
exists, so nothing is restarted — the reconciled template is simply what the
next pod is built from. That is what makes this safe to do unconditionally on
resume rather than gating it behind an explicit migration.

Only the agent container's resources is touched. The rest of the template
is session identity — harness args, env, principal annotations — and
re-rendering it from current config would rewrite a session's own setup
underneath it. That is the difference between reconciling fleet policy and
resetting the session.

A container whose name does not match is left alone, rather than patched by
index. Guessing would rewrite whichever container happened to sit there; a test
covers the agent container not being index 0.

The patch is positional JSON, not a merge. A merge patch on containers
replaces the whole array, which would mean round-tripping every container
through the generated types and risking anything they do not model. This is the
one thing here that touches Cargo.toml: it enables kube's jsonpatch feature.
If you would rather not take that dependency I can rewrite it as a read-modify-
write of the full array, but the positional patch is the smaller blast radius.

A failed reconcile warns rather than failing the resume. A stale limit is worse
than a current one, but both are better than a turn that cannot start.

Testing

Four new tests over the drift decision, extracted as a pure function so it needs
no cluster: drift reported with the correct index when the agent container is
not first, no drift when already current, no drift (and no patch) when no
container matches the configured name, and a container with no resources at all
being filled in.

cargo test -p centaur-sandbox-agent-k8s: 68 pass. cargo fmt --all --check and
cargo clippy --all-targets -- -D warnings clean on both touched crates.

The reconcile itself talks to the API server, so it is not exercised here — the
tested part is which container to patch and whether to patch at all.

A Sandbox CR stores the pod template rendered when the session was created,
and every pod recreation re-renders from that stored template. So a change to
the configured agent resources never reaches a session that already exists,
even when its pod is destroyed and recreated: the replacement comes back on
the old limits.

That inverts the usual remedy. Recycling the pod does not migrate the
session; only recreating the CR does, and that destroys the workspace the
session is holding. The sessions that outlive a resources change are the
long-running ones with the largest accumulated state, which are exactly the
ones a memory raise is meant to protect -- one was OOM-killed at three and a
half hours on a limit that had already been raised for everyone else.

resume now brings the stored template back in line with the configured
resources before setting replicas to 1. It runs while the sandbox is paused
and no pod exists, so nothing is restarted; the reconciled template is simply
what the next pod is built from.

Only the agent container's resources is touched. The rest of the template is
session identity -- harness args, env, principal annotations -- and
re-rendering it from current config would rewrite a session's own setup
underneath it. A container name that does not match is left alone rather than
patched by index.

The patch is positional JSON rather than a merge, because a merge on
containers replaces the whole array; that is what the new kube jsonpatch
feature is for. A failed reconcile warns instead of failing the resume: a
stale limit is better than a turn that cannot start.
replace errors when the container has no resources member (the case a
session created before this setting exists hits), so a resume would fail to
reconcile and warn instead of bringing the limits in line. add inserts the
member when absent and replaces it when present.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sandbox CR pins the resources rendered at create; a config change never reaches an existing session

1 participant