Skip to content

Delete Workroom: a reload already in flight can republish the workroom once its tombstone lifts #295

Closed

Description

@joelmoss

🤖 Left by Claude Code. This was found by the adversarial review of #294 (#287), where Delete Project had the same bug and #294 fixes it.

The bug

AppStore.startWorkroomTeardown removes the deletingWorkrooms tombstone as soon as the teardown returns:

// AppStore.swift, startWorkroomTeardown (success path)
try await cli.delete(name: workroom.name, project: project.path) { … }   // or RemoteWorkrooms.delete
deletingWorkrooms.remove(targetID)

Nothing begins a newer load first. A reload() that called cli.list before the CLI wrote config still holds a snapshot listing the workroom. It may be suspended in projectStore.prepareRepositories. When it resumes, load() checks only that no newer generation exists (latest.generation != load.generation). None does, so the read wins claimPublication. applyingDeletionTombstones no longer filters the workroom, so apply publishes it again, along with its repository routes.

The deleted workroom then reappears in every window until the next reload, such as the app-focus reloadIfStale 4s later. A remote workroom comes back pointing at a host that has already been destroyed.

The fix

Use the same fix as Delete Project in #294: on success, begin a fresh, quiet load before lifting the tombstone. The newer generation makes any older read lose claimPublication.

await load(warnings: "fast", surfaceErrors: false)
deletingWorkrooms.remove(targetID)

surfaceErrors: false keeps a failed list from reporting a successful delete as an error. Call load directly, not reloadIfStale(minInterval: 0): that wrapper still checks lastLoadAt, so a backward clock step can skip it.

The failure path is already correct, because it lifts the tombstone before reload().

Test

#294 adds testStaleReloadInFlightAcrossSuccessfulDeleteDoesNotResurrectProject to AppStoreDeleteRaceTests. It parks a stale read in a gated prepareRepositories, using PrepareGate on a shared ProjectStore, across a successful delete. A workroom variant should go red without the fix: it was mutation-checked for the project case.

Related: #116, #287, #294.

Activity

  1. added 2 commits that reference this issue on Oct 3, 2026
    7eba4aa
    165fec5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions