Files
PaperClipAI/server
DottaandClaude Opus 5.5 ad0543ae90 test(recovery): re-arm a capture-policy save whose finished coordinator names a lapsed owner (#20672)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Workspace recovery re-arms a save that an older capture policy
exhausted (#20569), so the files are saved without a person
> - On staging, one save of this kind was not re-armed after the deploy.
Its export hold also carries a workspace finalization block, and it has
a resolved no-replay sibling for the same run
> - #20661 found that discovery skipped a hold when the run's finished
coordinator still named a lease owner whose lease had lapsed. The same
discovery clause gates the capture-policy re-arm
> - This pull request adds a regression test for that exact
capture-policy shape. It shows that #20661 alone makes the worker re-arm
and save it
> - The benefit is that the capture-policy path keeps this guarantee in
later changes

## Linked Issues or Issue Description

Refs #20661
Refs #20569

**What happened?**
An exhausted capture-policy save (`export_interrupted`, cause
`provider_error`, 6 of 6 attempts, phase `preserve_files`) was not
re-armed on the worker's first pass after #20569 was deployed.

**What did you expect to happen?**
The worker re-arms the save once under the current capture policy, saves
the files, and returns the hold to the system.

**Steps to reproduce**
1. Exhaust a save under capture policy 1 with `export_interrupted`. Add
a workspace finalization block and a resolved no-replay sibling for the
same run.
2. Leave a lapsed `native-finalizer:` lease owner on the run's
`terminal_failure` coordinator.
3. Run the workspace recovery worker. Before #20661,
`nextWorkspaceRecoveryAt` returns null and the hold is never selected.

## What Changed

- `workspace-recovery-capture-policy.test.ts`: add "re-arms a save whose
finished coordinator still names a lapsed finalizer owner". The test
uses the staging record: export hold with `historicalWorkspaceSource`
and `workspaceFinalizationBlock`, a resolved no-replay sibling, waiting
user input, and a lapsed finalizer owner. It drives the worker's own
discovery loop until the worker is idle.
- No production code changes.

## Verification

- Red: with the source files from before #20661 (`git checkout
686893636d^ -- <the four source files>`), the new test fails.
`nextWorkspaceRecoveryAt` returns null, so the worker is never woken.
- Green: on current master, `pnpm --filter @paperclipai/server exec
vitest run src/services/workspace-recovery-capture-policy.test.ts`
passes (5 tests). The file passed 4 runs in a row.
- The test asserts that the save completes under policy 2, the hold
returns to the system, `releasedLapsedOwner` is recorded, and the lapsed
owner is released.

## Risks

- Low risk. This change adds a test only.
- Previous-release story: the test uses rows in the shape an older
release saved, with no capture-policy marker. No migration is needed.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, with tool use (shell,
code editing, browser GET reads) in Claude Code.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 18:47:29 -06:00
..