Files
PaperClipAI/server
DottaandPaperclip fec0b57659 fix(workspaces): reconcile superseded offline finalization attempts (#19179)
## Thinking Path

> - Paperclip manages AI agents and preserves their work.
> - Workspace migration must keep saved files and their recovery
records.
> - A crashed finalization attempt can remain running after a later
attempt succeeds.
> - The old row then blocks migration even when the saved result and
export have exact receipts.
> - Offline maintenance can reconcile the obsolete attempt after Cloud
stops all old writers.
> - This pull request fails only that attempt and records the receipt
that supersedes it.
> - Missing proof still blocks migration.

## Linked Issues or Issue Description

Related storage migration work: #18841 and #18943.

**What happened?**

An old running workspace finalization row can block offline enrollment
after a later finalization has saved the same run and workspace.

**Expected behavior**

Maintenance should reconcile the old attempt when exact saved receipts
prove it is obsolete. It must preserve the accepted result, successful
receipt, execution ownership, local files and recovery records.

**Steps to reproduce**

1. Retain a running finalization attempt for a native run.
2. Commit an accepted run result, a finalized workspace reference and a
later successful finalization receipt for the same company, task, run
and workspace.
3. Stop all application and worker deployments. Run offline enrollment.
4. The old attempt blocks enrollment. This change records it as failed
with receipt provenance before workspace import.

## What Changed

- Add a bounded offline reconciliation service for local workspace
sources that still need migration.
- Require the stopped-writer acknowledgement, maintenance switch and
existing active-execution gate.
- Lock the finalizer ownership, run, coordinator, workspace, accepted
result and operation receipts. Hold busy or incomplete records.
- Fail only the obsolete attempt. Preserve its metadata and add the
superseding receipt, result and workspace digests. Persist the activity
audit in the same transaction.
- Run reconciliation before workspace import. Keep unrelated, uncertain
and saved-work obligations held.
- Add real PostgreSQL tests for receipt proof, company scope, ownership
races, queued work, audit rollback and repeated maintenance.

## Verification

- `cd server && node ../node_modules/vitest/vitest.mjs run
src/services/offline-workspace-operation-reconciliation.test.ts
src/services/remote-workspace-migration.test.ts
src/services/remote-workspace-migration-concurrency.test.ts
src/maintenance/ephemeral-migration-service.test.ts`: 135 tests passed
across four suites before the final integration test. The final focused
suite passed all 33 cases, including a real
local-files-to-object-storage workspace import after reconciliation.
- The local server TypeScript check found one unrelated stale Runner
declaration: `codexUsageBaselineForNextRun` is absent from the reused
build output. It found no error in the changed files. CI must verify
fresh build outputs.
- Fresh GitHub Actions CI passed on
`d302fbddd430d42346611302ad7307cf809c3449`, including typecheck, build,
Runner, server and browser gates. Greptile gave 5/5 on the same head
with no findings.
- The external Paperclip Review check remains queued while it waits for
its assigned reviewer agent. Do not merge until that check passes.
- This PR does not claim live-data or deployed migration acceptance. A
legacy preparation attempt without a superseding receipt remains held.

## Risks

- The Cloud caller must establish the stop-all-deployments fence. An
environment switch cannot prove that old writers stopped.
- Only a succeeded native run with an unowned committed finalizer, an
accepted result, a finalized matching workspace and a later completed
successful receipt can pass.
- Future controller leases, retained workspace owners, busy rows,
uncertain work and independent save-work obligations stay held.
- Expired legacy controller lease fields remain unchanged. The service
changes no run, task, lease, recovery or source authority.

## Model Used

OpenAI Codex, exact model ID `gpt-6.1-sol`. Context window size is not
exposed. Used code reasoning, repository tools and local 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
- [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
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-04 22:25:08 -06:00
..