Skip to content

refactor(deploy): extract the workspace durability contract from the route - #133

Merged
pparage merged 1 commit into
devfrom
refactor/workspace-side-effects
Aug 6, 2026
Merged

refactor(deploy): extract the workspace durability contract from the route#133
pparage merged 1 commit into
devfrom
refactor/workspace-side-effects

Conversation

@pparage

@pparage pparage commented Aug 6, 2026

Copy link
Copy Markdown
Member

Follow-through on the note at the end of #132. Behaviour-preserving.

Why

Four review rounds found four ways to get one ordering wrong:

# failure
#130 a duplicate clobbered a live deployment's password
#131 a committed row whose workspace had no password, and whose retry hit the 409
#132 a foreign-key violation reported as "already exists"
#132 a secret left behind for a deployment that never existed

Each fix added another branch to create_deployment, which by then owned workspace creation, name reservation, secret seeding, transaction management and best-effort token provisioning. A fifth patch was the wrong move.

What

app/core/workspace_secrets owns the rule all four fixes were circling:

the vault password is durable if and only if the deployment row is

vault_seed is a context manager, so the caller cannot apply the seed and forget the revert:

with vault_seed(ws.path, payload.secrets):
    await session.commit()

The file goes back to its previous state — removed if there was none, restored if an operator had seeded one — exactly when the commit does not happen. Reverting is best-effort and logs rather than raising, so it can never mask the failure that triggered it.

provision_host_token moves out as well, and stays deliberately outside that contract: it talks to Proxmox rather than to the workspace's durability, and preflight remains the source of truth for whether the credential works.

The handler drops from 175 to 136 lines and now reads as: validate → reserve → seed+commit → provision.

Verification

  • the ten route tests written across those four rounds pass unchanged — that is the safety net for "behaviour-preserving"
  • eleven new unit tests own the contract directly, including two cases the route tests could not reach: revert on BaseException (a cancelled request must not leave the secret) and a revert that itself fails not masking the original error
  • all four original reproductions re-run against this branch: first=201 duplicate=409 vault=ORIGINAL, deployments persisted: 1, and both bad references reporting 404 NOT_FOUND

488 passed, ruff clean.

…route

Four review rounds found four ways to get one ordering wrong: a
duplicate clobbering a live workspace, a committed row with no password,
a foreign-key error reported as a name clash, and a secret outliving the
row it belonged to. Each fix added another branch to create_deployment,
which by then owned workspace creation, name reservation, secret
seeding, transaction management and token provisioning.

app/core/workspace_secrets now owns the rule those fixes were all
circling: the vault password is durable if and only if the deployment
row is. vault_seed is a context manager, so the caller cannot apply the
seed and forget the revert —

    with vault_seed(ws.path, payload.secrets):
        await session.commit()

reverts the file exactly when the commit does not happen. Proxmox token
provisioning moves out too, staying deliberately outside that contract:
it talks to Proxmox, not to the workspace's durability.

Behaviour-preserving. The ten route tests written across those four
rounds pass unchanged, and the new unit tests own the contract directly,
including revert-on-BaseException (a cancelled request) and a revert
that itself fails not masking the original error.
@pparage
pparage merged commit 7ca3938 into dev Aug 6, 2026
2 checks passed
@pparage
pparage deleted the refactor/workspace-side-effects branch August 6, 2026 10:56
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.

1 participant