feat(code-editing): Step 4 — save→redeploy orchestration (flag-gated, inert) - #67
Merged
Merged
Conversation
… inert) The integration step: create version → validate (PARAMS + requirements vs allowlist) → build image (injectable build_fn = Step-1 egress-locked pipeline in prod) → forward-only atomic activate. Fail-closed; flag-gated (AGENT_VERSIONED_DISPATCH_ENABLED, default OFF). - services/agent_redeploy.py: the orchestrator. Validation is fail-closed BEFORE a build is spent; build failure marks the version 'failed' and NEVER reaches activate (prior active version keeps serving). Activation is FORWARD-ONLY (advances version_no only) — a refinement over the signed-off advisory-lock: same last-submitted-wins WITHOUT holding a txn/lock across the multi-second E2B build. - migration 070: agent_runs.version_id — the in-flight isolation anchor. Dispatch resolves the active version ONCE and stamps version_id, so a concurrent edit can't change a running run's binding. Mirrored in check_db (idempotent), additive/reversible. - cloud.py: flag helper + _resolve_dispatch (resolve-once, NULL-image fallback) + version_id binding + prod build_fn (mirror config-driven, empty until Step 4b). Save path redeploys when the flag is on; the .code write stays in sync as the fallback. - sandbox.py: provider accepts files + image_ref (per-version image boot + multi-file), backward-compatible (None → current single-file .code path). PROVEN: - Real-Postgres proof (scripts/agent_redeploy_proof.py, 8/8): (A) build failure → active pointer UNMOVED + failed version recorded; (B) in-flight isolation — run dispatched before the edit stays bound to v1, run after gets v2 (version_id binding); (C) forward-only activate — older build can't clobber a newer active version. - 9 unit tests (fail-closed validation, build-never-activates, flag-off dispatch identical). - Migration 070 ephemeral-pg proof: additive, idempotent, reversible. - Full suite 616 passed; flag OFF → dispatch byte-identical (ininert). Mirror = option (B): build_fn injectable (fake in tests). Real mirror is a FLIP-ON gate, not a merge gate — Step 4b proves the real end-to-end build before the flag flips. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The integration step, per the signed-off design. Wires building + versioning + activation onto the dispatch path — flag-gated and inert (
AGENT_VERSIONED_DISPATCH_ENABLED, default OFF). No merge — for review.The flow
create version → validate (PARAMS extraction + requirements vs allowlist) → build image (injectable build_fn) → forward-only atomic activate. Fail-closed: any failure before activation leaves the prior active version serving.The two tests you said you'd review hardest — proven against real Postgres
scripts/agent_redeploy_proof.pyruns the real orchestrator + dispatch resolver against a live DB with an injected fake build_fn (no E2B/mirror needed):redeployraisesRedeployError(build), the new version is markedfailed, andactive_version_idis still v1 — a bad edit can't take an agent down.agent_runs.version_id) to v1; a run dispatched after gets v2. The binding is set once at dispatch and never re-read, so the activate can't touch a running run.One refinement over the signed-off design (flagging it)
The design said
UNIQUE + advisory lockfor the double-save race. I implementedUNIQUE + forward-only activateinstead — activation only advancesversion_no, so a slow older build can't clobber a newer already-active version (proof C). This gives the same last-submitted-wins without holding a DB transaction/lock across the multi-second E2B build (which the advisory-lock approach would have required). Same guarantee, no long-held connection.Flag-gating + backward-compat
.codepaths, byte-identical. Proven by the unchanged suite + explicit_resolve_dispatchflag-off unit test.image_ref IS NULL(backfilled v1) falls back to the.codepath but still bindsversion_idfor audit — gradual cutover, agents move to the image path only as rebuilt.Migration 070 (
agent_runs.version_id)Additive/nullable; idempotent
check_dbmirror; ephemeral-pg proof: additive, idempotent, reversible (existing runs intact withversion_id NULL, down-migration clean).Mirror — option (B), as agreed
build_fnis injectable (realbuild_agent_imagein prod, fake in tests — same pattern as Step 1'ssandbox_factory). The prod build_fn readsAGENT_MIRROR_URL(empty until the mirror stands up). The mirror is a flip-on gate, not a merge gate — Step 4b proves the real end-to-end build before the flag ever flips.Tests
9 new unit tests (fail-closed validation, build-never-activates, flag-off dispatch identical, NULL-image fallback, versioned path). Full suite 616 passed.
Not in this PR (next)
🤖 Generated with Claude Code