fix(host-service): don't reuse a tombstoned workspace on same-branch create
What & why
Since #6296 turned workspace deletes into tombstones (archivedAt + archiveReason, row kept for the board's Merged/Deleted history), the create flow's branch-idempotency lookup findExistingWorkspaceByBranch still matched on (projectId, branch) with no archived filter — the one consumer #6296's "consumers updated" pass missed. Recreating a deleted workspace's name therefore "reused" the tombstone: exit 0, alreadyExists: true, no worktree created, and the desktop redirected to the dead row's id, which workspace.list filters out — landing users on the "Workspace not found" screen. CLI/SDK/MCP callers got a success response for a workspace that doesn't exist (the automation-fleet failure described in #6383).
This PR adds the isNull(workspaces.archivedAt) guard to the lookup, matching the convention every sibling lookup already follows (adopt-existing-worktree.ts, workspace.list, session folder dedupe). #6296 explicitly planned for re-creating a workspace on a tombstoned branch ("Tombstones aren't phantoms — same-branch history must survive re-creating a workspace on that branch"); this makes that path reachable.
Note: #6384 proposes the same guard — happy to defer to it if it lands first; this PR adds an independent regression test and desktop-flow verification.
How I tested it
- New integration test (
workspace-create-delete.integration.test.ts): create → delete (assert tombstone) → create on the same branch → asserts a fresh live row with a real worktree on disk,alreadyExists: false, and the tombstone's history untouched. Watched it fail onmain(alreadyExistscame backtrue) before the fix. - End-to-end in the dev desktop app (before/after): reproduced the bug twice on
main— each recreate left zero new rows, no worktree, no branch, and the renderer sat on the tombstone's id showing "Workspace not found" (screenshots below). With the fix, repeated create → delete → recreate cycles on the same name each produced a fresh live workspace coexisting with its tombstone, verified inhost.dband on disk. bun run lint(clean — no warnings),bun run typecheck, full@superset/host-servicesuite: 1112 pass / 0 fail.
Known limitation (deliberately out of scope): a create that lands while a destroy of the same branch is still mid-pipeline (archive-first, worktree removed last) can adopt the dying worktree; that window predates this change and is better handled by serializing create/destroy separately.
Checklist
- PR title follows conventional commits (
type(scope): subject) -
bun run lintandbun run typecheckpass (CI fails on lint warnings too) - "Allow edits from maintainers" is checked on fork PRs
Summary by cubic
Prevents workspace.create from reusing a tombstoned workspace on the same branch, fixing “Workspace not found” after recreate. Previously the idempotency lookup matched archived rows, returned alreadyExists: true, and created no worktree; now it ignores tombstones and inserts a fresh live workspace with a real worktree.
- Filters archived rows in findExistingWorkspaceByBranch by adding isNull(workspaces.archivedAt) in
@superset/host-service. - Adds an integration test for delete → same-branch recreate asserting a new id, alreadyExists: false, live worktree, and preserved tombstone history.
- No API or schema changes; adopt path already excludes archived rows. Known gap unchanged: a create racing a delete on the same branch can adopt the dying worktree.
Summary by CodeRabbit
-
Bug Fixes
- Creating a workspace after deleting a previous one now creates a new active workspace instead of reusing the archived workspace record.
-
Tests
- Added coverage confirming archived workspaces remain unchanged and newly created workspaces receive a distinct ID and worktree.