Files
PaperClipAI/doc
DottaandPaperclip 9c634e42e4 fix(workspace): bound queued source-lock admission for imports (#20370)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Existing local workspaces need durable imports before a volume-free
deployment.
> - Imports must acquire the same source locks as workspace writers.
> - Try-only admission can repeatedly lose to background maintenance,
even when each writer finishes.
> - This pull request adds an optional bounded wait to the canonical
migration APIs.
> - Operators can join the source-lock queue while all existing
preservation checks remain active.

## Linked Issues or Issue Description

**What happened?**

An online import can repeatedly return `workspace_source_busy` while
background workspace maintenance reacquires its project source lock. The
import does not join the PostgreSQL lock queue.

**Expected behavior**

An administrative import can wait for a finite writer to finish. One
wait budget covers the complete source scope. Timeout or cancellation
must release acquired locks before the import reserves a journal.

**Steps to reproduce**

1. Hold the source lock for an eligible local workspace.
2. Start an online import while the writer holds that lock.
3. Release the writer. Before this change, the import has already
refused admission. With `sourceLockWaitMs`, the import acquires the
source scope and commits normally.

**Paperclip version or commit**

Reproduced on master `0e3fdebea8257bdff11573081c76b306f12db230`.

**Deployment mode**

External PostgreSQL with an online workspace import. Related
preservation work: https://github.com/paperclipai/paperclip/pull/20311.

## What Changed

- Add optional `sourceLockWaitMs` to singleton and cohort migration
APIs. Omitted options keep current admission behavior.
- Queue the sorted source keys with one decreasing wait budget. Abort
cancels only the dedicated backend identified by PID and backend start
time.
- Use an independent source transaction for queued singleton imports.
Keep lifecycle checks, fresh source checks, journal ownership, and
publication after commit.
- Document the canonical API option. Add real PostgreSQL importer
regressions for release, timeout, abort, and partial-key cleanup.
- Correct the inherited task-case lookup summary so the existing
search-discovery regression passes without changing its assertion or
search algorithm.

## Verification

- Baseline RED: the new singleton regression fails on the unchanged
product because the import returns busy without queueing.
- `pnpm exec vitest run
server/src/services/remote-workspace-migration.test.ts -t 'queued|bounds
the whole source queue'`: 20 passed, including five new cases.
- `pnpm exec vitest run
server/src/services/isolated-remote-workspace-source-lock.test.ts`: 4
passed.
- Server layer typecheck, `node scripts/check-module-boundaries.mjs`,
and `git diff --check` passed.
- Tests used Node 24.22.2 and the existing embedded PostgreSQL fixture.
Hosted rollout verification remains pending.
- CI build, typecheck, browser suites, all serialized suites, and the
other general shards passed. The final server shard failed only the
inherited `case-history-api-discovery.test.ts:14` search-ranking
assertion. Its unchanged local regression reproduces on the base and
passes 3/3 with a separate one-line route-summary correction. The shared
one-line summary correction is included in follow-up commit
`8163ffa9d4728134676b84c8c242a5bf62c802b5`; the unchanged case-discovery
suite passes 3/3 locally. The original CI attempt remains failed:
https://github.com/paperclipai/paperclip/actions/runs/42704666536/job/129458605783.

## Risks

Queued admission can hold earlier source keys while it waits for a later
key. The caller controls the finite budget. The abort path opens a
short-lived dedicated cancellation connection. If cancellation cannot
connect, PostgreSQL's remaining lock timeout still bounds the wait. This
option must be called at the root of administrative work; an external
scope that already holds the same source locks can cause
self-contention. The existing pre-held journal-resume path must keep its
omitted-option behavior.

## Model Used

OpenAI Codex, based on GPT-6, with tool use and code execution. The
exact deployment identifier and context-window size are not exposed in
this session.

## 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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-09 16:29:53 -06:00
..
…
…
…
…
…
…