mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-09 07:10:34 +01:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Online workspace migration must preserve local files before it assigns remote authority. > - A task directory can contain a Git repository below its root. > - The source inspector treated that directory as ordinary, but the archive owner correctly required a shared Git source fence. > - This change includes each nested repository in the existing source ownership and locking checks. > - The archive still captures the full task directory, including sibling files and staged and unstaged Git work. ## Linked Issues or Issue Description Related: #19688 and #19409. Those changes cover physical source fences and nested Git archive reconstruction. This change repairs source classification for an ordinary wrapper that contains a repository. No duplicate fix was found. **What happened?** Online migration admitted a managed task directory whose root had no `.git` marker. A repository below `.review/repository` then reached the archive owner without a shared Git source fence. Capture failed with `remote_workspace_archive_online_source_git_requires_shared_fence`. Its operation and pending snapshot remained available for canonical resume. **Expected behavior** Migration must include the nested Git stores and all their source owners in the existing physical fence. It must preserve the wrapper directory and sibling files. It must refuse foreign aliases, unowned stores, busy shared sources, and source changes. **Steps to reproduce** 1. Create a managed ordinary task directory with a sibling file. 2. Create a real Git repository below `.review/repository` and leave staged and unstaged edits. 3. Run canonical online workspace migration. 4. Observe the shared-fence refusal, instead of a durable archive that can restore all the work. ## What Changed - Add a bounded metadata walk for nested Git roots. Reuse the existing strict Git pointer, common-directory, and alternate-store reader. - Add nested source identities to the existing alias closure, company checks, source locks, and metadata fingerprints. Keep the wrapper as the capture root. - Validate bounded Git-maintained reverse references in selected and borrowed stores. Require stable two-way pointers and containment by included registered workspaces. Bind the listings and pointer receipts into publication revalidation. - Add seventeen integration cases for fresh migration, pending-journal resume, shared linked and alternate stores, unrelated progress, foreign and unowned stores, and late metadata changes. ## Verification - Genuine baseline RED: both fresh and pending-journal cases failed at the existing archive shared-fence guard before the source fix. - The first treatment passed six of seven cases. The late-change case correctly failed at the earlier recapture guard; its expected-error assertion was corrected. The final test also verifies that the canonical Git fingerprint changed. - Head `8bb9f5a3ce`: real PostgreSQL, all **187 tests passed** in 59.22 seconds across `remote-workspace-migration.test.ts` and `workspace-git-source-roots.test.ts`. The canonical wrapper creates disposable databases and completed cleanup. Run from `server/`: ```sh node ../cli/node_modules/tsx/dist/cli.mjs ../packages/db/src/test-postgres-command.ts -- node ../node_modules/vitest/vitest.mjs run src/services/remote-workspace-migration.test.ts src/services/workspace-git-source-roots.test.ts --hookTimeout 90000 --maxWorkers 1 --no-file-parallelism --fsModuleCache ``` - Required alias RED: both hidden ordinary-wrapper cases failed before the reverse-reference fix. The shared case bypassed its held writer lock; the foreign case was incorrectly eligible. Both now pass. A further RED proved the same omission through a borrowed store; its hidden writer is now included too. - Review RED: a repository below `.review/.paperclip-runtime` reached the archive guard. Discovery now excludes the runtime name only at the capture root, matching the archive. - The positive cases download the authenticated immutable archive, remove the disposable source, and cold restore the sibling file, HEAD, index content, and working content. Resume retains the exact operation and pending snapshot IDs. - Resume fidelity: migration, snapshot, and layout owners are byte-identical to source revision `2d4f80504e`. Source kind comes from the workspace row, not online classification. The unchanged serializer writes the same empty source, source fingerprint, marker, fixed empty child scope, and pending generation-1/epoch-1 snapshot at the tested failure boundary. The test asserts that shape and retains the exact IDs on resume. The fixture injects the failure at that unchanged boundary; it does not execute the old binary. - Shared-store cases hold a real PostgreSQL source lock. The related import is refused before a journal exists, while an unrelated ordinary import completes. - Invalid-link controls reject foreign and unregistered roots, malformed pointers, and symlinked metadata before a journal exists. A new detached worktree after upload changes the listing fingerprint and blocks authority publication. - Final head `e525b6b1a5`: all 17 focused real PostgreSQL cases pass in 16.23 seconds after the enclosing-host-repository review fix. Its true RED first showed the valid managed wrapper as ineligible. The cold restore now excludes the ancestor Git directory and host-only file and leaves the host HEAD unchanged. Server TypeScript passes again. - Server TypeScript and module boundary checks pass. Canonical agent preflight passes. Environment: macOS arm64, Node 24.22.2, real PostgreSQL and Git. - A first test launch lacked the built plugin SDK, and a later sandbox launch could not open TSX IPC. Both were setup failures, not regression results. The existing dependency build and permitted isolated test runner resolved them. - Final exact-head CI passes: [run 42363940320](https://github.com/paperclipai/paperclip/actions/runs/42363940320). The final gate has 56 successful checks, four skipped checks, one neutral check, and no pending or failed checks. Greptile reviewed this head at 5/5, with zero open review threads. No hosted workspace was changed or imported by this PR work. ## Risks - Nested discovery and reverse-reference checks add bounded directory metadata I/O. Reverse listings allow at most 256 worktrees per store, and all links must resolve to registered physical workspace roots. Stale or unsupported links fail closed. - Nested discovery refuses more than 100,000 entries, 64 directory levels, or 64 repositories. A large or unsupported tree remains ineligible. This includes dependency or build trees that exceed those limits. No broad directory skip or metadata cache bypasses final source checks. - The archive guard, source lock owner, runtime writer checks, publication checks, and recovery predicates remain required. This change grants no permission to retire source work or ignore a held journal. - No schema, API, runtime setting, provider lifecycle, or background worker changes. - This PR documents the internal source-classification contract above. It adds no operator command or configuration to document separately. ## Model Used OpenAI `gpt-6.1-sol` through Codex, with reasoning, repository tools, code execution, and regression tests. The context window size is not exposed. ## 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>