Skip to content

api::workspace_delete is the delete without the unsaved-work guard #395

Description

@blooop

Finding

api::workspace_delete — the frozen wf surface — is the delete without the unsaved-work guard.

Removal is three exported functions that the caller must sequence correctly:

function site params
unsaved_work_in flows/lifecycle.rs:868 6
guard_removal flows/lifecycle.rs:806 3
workspace_delete flows/lifecycle.rs:972 8, #[allow(clippy::too_many_arguments)]

17 parameters of interface. The sequence — probe for unsaved work, refuse unless --force, then delete — lives in the binary, at dl/src/commands.rs:664-740. dl gets it right. Nothing makes a second caller get it right, and devlaunch-core/src/lib.rs freezes only workspace_delete into api, so a wf that links the promised surface deletes a clone holding uncommitted work without ever asking.

The comment at dl/src/commands.rs:688 calls the guard "the one thing dl refuses on its own account". That is the problem stated as a feature: it is the one thing a caller refuses, and the frozen API has no caller.

Shape

One deep module. remove(context, target, insistence, notices) -> Result<Removal, NotRun>, absorbing target resolution, opening the records once, the unsaved-work probe, the guard, the volume sweep and the delete. Removal::Refused(RemovalRefused) is an arm, so a caller that ignores the guard does not compile.

Two ordering constraints move from prose into the module while this is open:

  • lifecycle.rs:980-988 — volumes must be named before devpod delete, because delete destroys the record holding their names. Currently a comment.
  • The guard must run before the delete, currently a comment plus the binary's control flow.

Cost, deliberately

This changes public-api.api.txt, which CI diffs — a deliberate PR, not a refactor. That is the right weight for a change that decides whether wf can delete unsaved work, and #251 §7 already says an addition to api is a deliberate PR and a removal a breaking change.

Proving it

Red-first, and the red is reachable from the promised surface alone: call api::workspace_delete against a clone with an uncommitted change and watch it go. There is no such test today because the guard is not on that path.

Found by an architecture review.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions