Files
PaperClipAI/server
Priya RamanandPaperclip f382df24b7 fix(server): fence a terminal reap against an in-flight reopen
Close a lifecycle race between a reopen and the terminal-workspace reaper. A
reopen publishes the workspace as active before the route changes the source
issue out of the terminal state. In that window the reaper could observe a
still-terminal source issue, archive the freshly rebuilt worktree, and delete
it. The lifecycle-generation fence did not stop this, because the reaper made a
new archive decision at the reopened generation.

Add a reopen-pending flag in the workspace metadata. The reopen sets the flag in
the same write that publishes the row as active. Both destructive paths exclude
a flagged workspace, so neither one archives a worktree that a reopen rebuilt.

- The reaper takes the per-workspace lifecycle lock before the archive write.
  The archive statement re-checks the status, the terminal predicates, and the
  reopen-pending flag under the lock, so it never archives a reopened row.
- The reaper clears the flag on a later pass once the source issue leaves the
  terminal state, so a normal terminal cycle can reap the workspace again.
- The archive route archives under the same lock through a new service method
  and clears the flag, so an explicit close cannot race a concurrent reopen.

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-08-13 01:46:26 +00:00
..