Files
PaperClipAI/server
DottaandPaperclip 29a66d679e fix(workspaces): verify archived repository intents before publication (#20441)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Workspace migration moves local files into durable, authenticated
snapshots.
> - Archived Git workspaces can retain an unmaterialized repository
request after their local tree is removed.
> - Admission cannot prove filesystem absence from the removed tree.
> - This pull request checks strict request candidates against the
private restored Git tree and the authenticated snapshot readback.
> - Publication rechecks current repository rows without changing the
request or task history.

## Linked Issues or Issue Description

**What happened?**
An archived workspace with an authenticated restoration recipe and an
unresolved, unmaterialized repository request fails migration with
`repository_preparation_unresolved`. Its original directory no longer
exists.

**Expected behavior**
Migration can preserve the request when the actual private restored tree
proves its target absent and every parent safe. It must refuse partial
materialization, symlinks, or changed request state.

**Steps to reproduce**
1. Archive a Git workspace with a valid saved recipe and a pending
repository request.
2. Remove its original local workspace directory.
3. Run canonical workspace migration. The previous implementation
refuses before it can inspect the restored tree.

**Paperclip version or commit**
Reproduced on `1ca3e8ea2a759e511ab2d2659339c6c770a7a2ba`.

**Deployment mode**
Self-hosted server. This is a core workspace migration bug.

**Relevant logs or output**
`remote_workspace_migration_blocked:repository_preparation_unresolved`

Refs #20416, #20424, #20436. These fixes retain their source, recovery,
and ownership guards.

## What Changed

- Separate strict repository request metadata from filesystem absence
proof.
- Admit only strict candidates backed by a canonical archived Git recipe
to private materialization.
- Verify target absence and safe parents before a new upload and after
authenticated archive restore.
- Lock and recheck current repository rows before authority publication,
including recovered uploaded archives.
- Preserve previous-release recipes, request rows, task selection,
history, provider references, and unresolved recovery obligations. No
persisted schema or public option changes.

## Verification

- Genuine baseline RED: both pending and needs-repair archived requests
fail on unchanged master.
- GREEN: 27 focused real-PostgreSQL/FS/Git tests pass. Includes
partial/symlink refusal before upload, request mutation during upload,
recovered-upload readback, and existing native F/source checks.
- Command: `pnpm exec vitest run
server/src/services/remote-workspace-migration.test.ts -t 'archived
repository intent|unmaterialized repository request|unresolved
repository request|pending repository|unselected archived
recipe|archived prepared source|competing native F owner'`.
- After rebasing onto current master, all six new cases pass on
`0b6854789acc067a44e697acebdc04e51b9afe88`. Server layered typecheck,
module boundaries, and `git diff --check` pass. A review follow-up adds
one pending-path mutation regression (1/1 real-PG pass) without changing
product code. Fresh required CI runs on final head
`2a30a4b444108488ac8b51d0c46c340ee15227b9`; fresh Greptile is 5/5.
Server7 had an unchanged trace-parent assertion failure; that same shard
passed on the previous product-identical head and the linked-source
sibling PR. The original failure remains recorded. The single targeted
server7 retry passed. Final head has 56 successful checks, 4 intentional
skips, and 1 neutral review status.

## Risks

- Metadata admission is only a candidate check. A candidate still fails
unless the private authenticated filesystem proves absence.
- Publication keeps repository rows locked while it checks their current
paths against the owned restored tree. A real pending-relativePath
mutation now tests this final check. Existing workspace/source/native
locks remain in place.
- Absence is proved only in SAVED data reconstructed from the retained
recipe and snapshot. This does not prove that a request never
materialized before archival. Existing Git restore points can exclude
ignored `.paperclip-repositories` paths outside recorded checkouts. This
PR does not change that preexisting coverage or recover bytes that were
never saved.
- The original recipe, restore point and checkout references remain
unchanged. No files are recovered into or removed from the original
directory. No request is marked ready or restored. Partial target files
present in reconstructed saved data remain blocked and retain their
state.

## Model Used

OpenAI GPT-6.1 Codex, with reasoning, repository tools, and code
execution. The host does not expose an exact context-window size.

## 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
- [x] 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-09 20:58:53 -06:00
..