Files
PaperClipAI/server
DottaandClaude Fable 5.2 52cdf76bf3 fix(ephemeral): start a volume-free server over harness backups a volume-free server left unsaved (#20990)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - A hosted Paperclip server can run volume-free: its durable state is
in the database and object storage, and its local disk is replaced with
every deployment
> - At startup, a volume-free server runs a readiness gate that refuses
to start when it finds data that still needs migration off a volume
> - One of those findings is a harness backup that never reached durable
storage. A volume-free server that stops in the middle of a run always
leaves some
> - The gate then refuses every later start, the process exits, and the
host restarts it into the same refusal. The workspace stays down until a
person repairs it
> - This pull request lets a server start over such backups when its
filesystem carries the volume-free owner marker
> - The benefit is that a volume-free server recovers from an
interrupted run by itself

## Linked Issues or Issue Description

Refs #20952 (the same crash loop for Runner controller files; this is
the next check in the same gate).

**What happened?**

A hosted volume-free workspace stopped while runs were in progress.
Every later start logged `Paperclip server failed to start` with
`Volume-free server data is not eligible:
native_harness_backups_require_migration`, and exited. The host
restarted the container and the server exited again. The workspace did
not serve any request for more than two hours.

**Expected behavior**

A volume-free server starts after an interrupted run. Restart recovery
handles the runs whose local harness backup was lost with the old
container.

**Steps to reproduce**

1. Run a volume-free server (`PAPERCLIP_EPHEMERAL_SERVER=true`) with
native Runner tasks in progress.
2. Stop the server process before the harness backup of an active
session reaches durable storage.
3. Start the server again. It refuses to start with
`native_harness_backups_require_migration`.

**Paperclip version or commit**

`87fe4d979355232570428deba480b47e1812a26c` (contains #20952).

## What Changed

- `assertEphemeralServerData`: when the only reason is
`native_harness_backups_require_migration` and the filesystem carries
the volume-free owner marker (`volumeFreeControllerStateOwned`), the
gate removes that blocker, logs a warning, and lets the server start.
- A filesystem without the marker is refused as before. All other
blockers are unchanged.
- `readEphemeralServerDataEligibility` is unchanged, so the migration
and enrollment callers still see the blocker.
- Added `ephemeral-server-startup-run-state.test.ts`.

## Verification

- Red: with the change to `ephemeral-server-contract.ts` reverted,
`starts a volume-free server over harness backups a volume-free server
left unsaved` fails (1 failed, 2 passed).
- Green: `npx vitest run
src/__tests__/ephemeral-server-startup-run-state.test.ts
src/__tests__/ephemeral-server-data.test.ts` in `server/`: 2 files, 8
tests passed.
- Not run locally: the full suite. CI supplies that coverage.
- Not verified: a live volume-free start. The hosted workspace that
showed the failure will receive this change through the normal release.

## Risks

- A server on a marked volume-free filesystem now starts with unsaved
harness backups. Those backups were on a disk that no longer exists, so
the refusal protected nothing. The affected runs depend on restart
recovery.
- The marker is the only evidence that there is no volume. A filesystem
that still is a volume and does not carry the marker keeps the refusal.
- The gate does not repair or delete the stale lease stamps. The warning
repeats at each start until restart recovery settles those runs.

## Model Used

Claude Fable 5.2 (`claude-fable-5-2`), through Claude Code with tool use
and code execution.

## 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
- [ ] 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 Fable 5.2 <noreply@anthropic.com>
2026-11-11 20:02:27 -06:00
..