Commit Graph
7 Commits
Author SHA1 Message Date
DottaandPaperclip 612d9931a6 Support per-turn Runner sessions on ephemeral web servers (#18932)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The web server controls native Runner sessions in remote sandboxes.
> - An ephemeral web server must recover without its previous local
filesystem.
> - The existing admission rule accepts warm sessions. Managed Claude,
Grok, and OpenCode sessions resolve to per-turn execution.
> - Per-turn execution also needs durable provider-session bytes after
the sandbox is retired.
> - This pull request adds encrypted backup publication and removes the
warm-only admission rule.
> - Both lifecycle modes can use the existing native ownership and
checkpoint contracts during a web deployment.

## Linked Issues or Issue Description

Refs: #18518, #18529, #18826, #18835, #18841, #18864, #18887.

**What existing behavior does this improve?**

Native Runner execution on web servers with
`PAPERCLIP_EPHEMERAL_SERVER=true`.

**Current behavior**

The admission rule requires a warm Runner lifecycle. Managed provider
credentials can resolve an agent to per-turn execution, so enabling the
ephemeral deployment profile blocks those turns. A database controller
checkpoint does not preserve provider files after the old web home and
per-turn sandbox are removed.

**Proposed behavior**

Admit native execution in either resolved lifecycle. Keep provider and
credential choices unchanged. Publish encrypted provider state to shared
storage before sandbox cleanup. Restore it from a fresh web home for the
next turn. Use the existing controller lease and generation checks for
active takeover.

**Reason and benefit**

Operators can remove the web server volume without excluding per-turn
providers or forcing managed accounts into warm sessions. New native
Daytona profiles automatically enter both rolling-deployment
qualification lanes.

**Breaking changes**

The additive migration creates a backup publication ledger. Existing
volume-backed local-disk installations retain their local backup path.
S3 installations publish encrypted backups and require a stable secrets
master key. Existing-volume enrollment must import surviving session
data before detaching the volume.

## What Changed

- Admit native Runner execution independently of its warm or per-turn
lifecycle. Keep host-owned legacy execution excluded from ephemeral
deployments.
- Store private provider state as encrypted objects. Journal uploads
before I/O, read them back, and fence publication against the current
native owner. Keep the previous published backup when storage or
ownership checks fail.
- Restore exact provider bytes into a private cache. Require an exact
durable backup before sandbox cleanup. Extend the existing bounded
retention pass to retire stored objects without adding idle polling.
- Import selected legacy controller and provider state in the existing
offline maintenance process. Preserve queued work, task pointers,
pending recovery, and original files. Prefer canonical database
checkpoints.
- Preserve already-failed legacy controllers with missing original
artifact proof as encrypted archives. These archives do not become
execution authority. Successful retained sessions still require proof.
Report archival and executable imports separately.
- Verify unmanaged Grok API keys through the existing xAI account
validator. The live test exposed a readiness gap that kept remote Grok
agents paused after platform checks. Preserve failed credentials and the
separate runtime warning.
- Ingest Grok whole-prompt usage at the owning ACP boundary. Bind the
receipt to the exact outbound request/session; reject replay, conflicts,
and incomplete authority. Separate turn cost from cumulative session
cost in the sidecar schema and Rust normalization. Preserve managed
billing identity and identify direct xAI API credentials.
- Preserve published workspace directory names across cold allocations,
including destroyed-allocation cleanup. Keep unpublished epoch/lease
directories isolated and refuse to overwrite an occupied preparation.
This fixes the cold-session identity regression exposed by #18922.
- Increase bounded checkpoint-header inspection to 1 MiB. Retain the
aggregate inspection limit.
- Register all nine native Daytona profiles in per-turn and warm
rolling-deployment suites. Delete the entire departing server home,
exercise ordinary reads and writes, require active ownership transfer,
then check a later turn on another fresh server. Permit only exact
notification replay after reconnect.

Ownership stays with the existing modules: Runner validates its protocol
state; Core validates run scope and controller ownership; storage owns
object I/O; the maintenance process owns offline conversion; the E2E
wrapper owns process replacement and probes. No provider protocol is
added to the shared admission rule. Grok receipt parsing stays in its
provider module. The shared sidecar gains an explicit cost basis because
its existing price field means session-cumulative spend, while Grok
reports prompt totals. Existing consumers retain cumulative behavior
when the new field is absent.

## Verification

- Focused native admission, archive validation, publication fencing,
cleanup, readiness, legacy import, and E2E observer tests pass. Real
PostgreSQL cases verify that queued intent and historical recovery rows
stay unchanged.
- Full typecheck and build pass on the rebased branch. The review
follow-up passes server typecheck, 29 focused
PostgreSQL/archive/readiness tests, and module-boundary checks. Revision
fb8d39a7a1 reached 55 successful CI checks and Greptile 5/5 with no
unresolved threads. The Grok follow-up passes Runner/server typechecks,
238 ACP runtime/projection/usage tests, 16 sidecar-schema tests, the
Rust cost regression, and Core billing regression. The e9aae9cf revision
passed all 57 successful checks, with 5 skips and 2 neutral checks, and
exact-head Greptile 5/5. The latest 9cbec30a4f follow-up changes only
E2E catalog/admission controls; its 291 affected tests pass, all 57
check contexts succeeded (5 skips, 2 neutral), and exact-head Greptile
is 5/5 with no open review threads.
- Migration numbering and safety checks pass.
- A local real PostgreSQL/S3 roundtrip preserved 2,870,101,591 payload
bytes across 89,100 archive entries after deleting the source directory.
Restored SHA-256 matched; upload/readback took 56.5 seconds, restore
74.8 seconds, process peak RSS was 1.40 GB, and all fixture resources
were removed.
- Archives preserve contained relative links, reject link
chains/traversal, and enforce independent byte/entry/object limits.
Offline verification streams hashes. Orphaned deleted-run backups stay
on the original volume. Obsolete object retention preserves the selected
backup, live lease references, and pending uploads with owners.
- Isolated API-key Codex deployment: original active runner/session
transferred to the replacement and committed. All 567 reads, 57 writes,
and 57 readbacks succeeded. A second replacement completed a
same-session continuation with all 287 reads and 29 writes succeeding.
The strict cell failed two agent-authored shell commands; this result is
retained as failed.
- Isolated API-key Claude deployment: original active runner/session
transferred and committed. All 584 reads, 59 writes, and 59 readbacks
succeeded. A second replacement completed a same-provider-session
continuation, with 211 reads and 22 writes succeeding. The strict cell
failed an initial completion call that omitted a registered attachment
citation; the agent corrected it. This result is retained as failed.
- Isolated API-key OpenCode deployment: the same active runner/session
transferred and committed. All 481 reads, 49 writes, and 49 readbacks
succeeded. A second replacement retained the provider session and
completed useful work, with 156 reads and 16 writes succeeding. The
strict cell failed agent tool calls: a denied external-directory write,
malformed artifact hashes, and a second completion after the first
result was committed. There was one submitted/completed turn and one
committed result; reconnect notification replay was identical. This
result is retained as failed.
- Grok's real first turn now completes with settled usage and provider
cost ($0.41397); the next turn is admitted normally. That attempt then
exposed a shared workspace-path identity regression before deployment.
Three cold-restore cases reproduced it before the fix; 106
workspace/transport tests and four focused cold-restore cases pass
afterward, including destroyed allocation and occupied-directory
preservation. Server typecheck and build pass. At b5b0dbb03f both
controller switches passed the read/write probe without failure, and the
active runner retained its process while the controller generation
advanced. The third turn exposed an invalid reasoning-token subset
check; ad07e681ba fixes it with the actual receipt regression. Two later
live attempts failed with an upstream Grok rate limit before deployment.
A tiny preflight prompt succeeded before the second attempt, but the
full workload was still rate-limited. The final live gate remains
incomplete. No accounting or identity guard was bypassed. Earlier failed
attempts and their exact resource-cleanup receipts remain recorded.
- Earlier Codex/Claude/OpenCode receipts predate #18922; they establish
their tested revisions. Current-head live qualification remains pending;
#18943 separately preserves pre-enrollment logical/provider workspace
addresses and adds actual legacy migration proof. Its first Codex
migration attempt stopped safely at skill-version verification.
- Earlier attempts remain recorded: missing local provider-pack setup
blocked one Claude launch, and the observer rejected identical reconnect
replay in another. Setup and the observer were corrected before the
latest run.
- Named staging enrollment has not started. Its serving revision and
post-deployment journeys remain separate delivery gates.

- Broader E2E harness validation exposed deployment-catalog and
installed-lane coverage drift; the affected 291 controls now pass.
Twelve other failures reproduce on unchanged base 1a39dea9aa. They
concern cleanup call expectations, dated operating-overhead fixtures, a
Pi profile-version expectation and workflow-security expectations. No
baseline failure is reported as passing.

## Risks

- Provider archives can contain credentials. Objects use authenticated
encryption with scoped associated data and a wrapped data key. The
original stable master key remains required.
- Storage failure prevents publication and sandbox cleanup. Operators
must keep shared storage available and preserve the previous volume
during enrollment.
- Legacy state without verified identity cannot become executable
recovery authority. Archival preserves evidence and existing failures;
it does not recover already-lost provider files or clear blocked tasks.
- Local overlap probes establish the tested application behavior. They
do not establish Railway routing behavior or live managed-subscription
qualification.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, tool use, code execution,
and live integration tests. The exact runtime variant 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
- [ ] 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-04 02:12:51 -06:00
DottaandPaperclip 4a83ba4050 fix(workspaces): isolate unpublished preparation directories (#18922)
Bind new remote preparation directories to the writer epoch and environment lease. Preserve earlier unpublished files and the recorded path for published warm workspaces. Run the interrupted reused-allocation and saved-file lifecycle regressions with owned Postgres by default, and retain the warm-path recovery checks.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-11-03 22:30:48 -06:00
DottaandPaperclip 0a1e4c3d0f fix(workspaces): retry pristine remote setup timeouts (#18852)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A remote task needs a workspace before its model can start.
> - Fresh workspace preparation can reach its transport deadline.
> - Failure handling records that timeout as a generic setup failure and
stops the task.
> - An unpublished workspace has no saved task work to repeat.
> - This change routes that narrow failure through the existing bounded
retry scheduler.
> - Saved work, retained executions, and normal admission gates keep
their existing protection.

## Linked Issues or Issue Description

Refs #18827, which preserves remote timeout diagnostics. This change
builds on that merged repair. Related #16727 concerns controller-managed
clones and optional partial clones; this change keeps remote clone
contents and deadlines unchanged.

**What happened?**

A fresh remote workspace reached its 300-second command limit before
model execution. The task then stopped with `setup_failed` and no
scheduled continuation. A separate full clone completed in 137 seconds
on a disposable Daytona sandbox. The original delay remains unexplained.
This change repairs the missing recovery path; it does not claim to
remove the underlying delay.

**Expected behavior**

A fresh, unpublished workspace preparation timeout can use the existing
two automatic retries. Retry scheduling remains durable and company
scoped. Stop, pause, dependencies, budgets, task ownership, saved work,
and retained native execution must still prevent unsafe work.

**Steps to reproduce**

1. Start preparation for a fresh remote workspace with no saved version
or published allocation.
2. Make its initial directory/clone command return a transport timeout.
3. Observe that the base code records a generic setup failure without
bounded recovery.
4. With this change, the owner validates current workspace authority and
preserves a specific bootstrap failure for the normal retry scheduler.

**Paperclip version or commit**

Base: `e0276e0166`, including #18827.

**Deployment mode**

Native Paperclip Runner with sandbox workspace storage. Verification
uses real PostgreSQL, filesystem commands, and a separate live Daytona
transport probe.

## What Changed

- Recognize only the initial preparation timeout while the same company,
writer, and epoch still own a pristine workspace.
- Keep restore, additional repository, provisioning, save, changed
ownership, dirty workspace, and retained native execution failures
outside this recovery policy.
- Persist the typed failure before using the existing retry scheduler,
admission gates, and attempt budget.
- After successful terminal lease cleanup, reclaim an unpublished
bootstrap-only reservation even when a provider returns no stop receipt.
Preserve receipt requirements for saved/published work, unknown
execution, and native identities; do not synthesize termination
evidence.
- Prevent generic recovery from granting another budget after
exhaustion. Keep a specific recovery notice.
- Add regressions for persistence, concurrent scheduling, restart,
exhaustion, Stop, pause, dependencies, fresh allocation, lost replies,
and saved output after cold restoration.
- Document the recovery contract.

## Verification

- Red: the real-PostgreSQL workspace regression first failed because the
timeout had no recovery classification. The completion regression then
failed because it became `setup_failed`. A retained-native negative
failed before the admission guard. The review follow-up reproduced a
failed successor reservation after production lease release returned
void.
- Green: all 127 transport/archive/real-PostgreSQL workspace cases pass
after the review repair. All 12 receipt/void handoff cases pass against
the final query. The 141 complete completion/retry/recovery cases and
the fresh-allocation selection case pass. Safety cases cover concurrent
scheduling across restart, the two-attempt cap, Stop/pause/dependency
gates, native identities, saved/published files, active leases, failed
cleanup, and cold-restored output.
- `node scripts/typecheck-low-memory.mjs` and `pnpm build` pass at
`ba96cff771707415e4a5e893c8b3a97499ead25b`. `git diff --check` and the
module-boundary check pass. The full local test wrapper completed all
1,835 chat cases across six partitions, then was interrupted during its
serial general-server phase after the complete current-head CI suite
passed. Its interrupted run is not a full local-suite pass; its log is
retained. The owned process tree and database children exited.
- The [complete GitHub Actions
run](https://github.com/paperclipai/paperclip/actions/runs/41718108375)
is successful at this exact head, including all server/workspace/chat
partitions, all nine serialized groups, all eight browser shards, build,
typecheck, native Runner, package, Rust, and release-policy checks. The
first Rust worker shut down during cache restore before tests; one retry
passed without source changes. Expected Storybook skips remain skips.
- Earlier failures remain accounted for: the first typecheck found two
incomplete process-result fixtures, now corrected. An intermediate
completion run exposed a test double that returned no promise and a
teardown timeout; the complete 141-case suites subsequently passed. The
first-head CI had four worker shutdowns and one worker communication
loss. A three-second monitor settlement wait failed in CI and locally,
then all 21 cases passed unchanged at base and head. An earlier CI retry
found a real-process history adoption assertion failure; that exact case
passed locally at base and head. Both server groups pass in final-head
CI. These timing causes remain unknown. [Earlier CI
evidence](https://github.com/paperclipai/paperclip/actions/runs/41713712522).
- Live supporting evidence: unchanged production preparation code
completed a full repository clone in 137 seconds using Daytona SDK
0.203.0, Node 24.22.2, Git 2.39.5, and Linux x86_64, with 1 CPU, 1 GiB
memory, and 1 GiB disk. The approved diagnostic account could not access
the original fleet snapshot, so the probe used public
`node:24-bookworm`. Both probe allocations were deleted and absence
verified. Full task acceptance at the fixed revision remains unverified:
the original fleet snapshot and an explicitly configured disposable
Codex subscription fixture were unavailable. No CLI login or hosted
subscription was copied.
- Greptile is 5/5 at the final head with no actionable findings. The
Paperclip review finding is repaired, replied to, and resolved. The
separate **Paperclip Review** check remains queued. Its task failed
workspace export after publishing the first assessment; the staging
service was then observed showing a workspace recovery page after an
update failure. Subsequent browser rechecks timed out, including a fresh
tab, so the normal recovery control could not be used. Reconcile that
existing export after service access returns, then let the saved
current-head review request run. That external review is the remaining
check; this PR is not yet fully green.
- The original hosted task was last verified blocked. This PR has not
been deployed and the task has not been retried by this work.

Reviewers can run `pnpm test:run`, `node
scripts/typecheck-low-memory.mjs`, and `pnpm build`. The
remote-workspace integration suite additionally needs an owned
disposable PostgreSQL database named `remote_workspace_*test` through
`PAPERCLIP_REMOTE_WORKSPACE_TEST_DATABASE_URL`; otherwise that suite is
skipped.

## Risks

Each retry keeps the existing preparation deadline, so persistent slow
clones can consume the bounded budget before intervention. A retry
receives fresh allocation admission; it does not replay the command
against the old allocation. The workspace owner checks persisted
authority before classifying the failure, and normal admission still
rechecks that authority. Historical generic setup failures do not gain
automatic replay. No database migration, provider-pack update, model
fallback, credential change, or deployment is included.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools, code
execution, and browser tools. The host does not expose a more specific
serving model ID or 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
- [ ] 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-03 15:36:07 -06:00
DottaandPaperclip e0276e0166 fix(workspaces): identify remote command timeouts (#18827)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Remote workspaces prepare repositories and save files through
sandbox commands.
> - Each command has a timeout and a known operation.
> - The transport discarded that information when a command timed out.
> - A failed clone then appeared as the same generic error as other
failures.
> - This pull request keeps the operation and timeout in a fixed
diagnostic.
> - Operators can identify the failed stage without exposing command
output.

## Linked Issues or Issue Description

**What happened?**

A remote workspace setup command reached its 300-second transport limit
before provider work started. The workspace layer reported only
`remote_workspace_operation_failed`. That message concealed the timeout
and the affected operation. A later full clone on the same sandbox image
passed in 107 seconds, so the original clone delay remains unexplained.
This PR repairs the loss of diagnostic information. It does not claim to
prevent the underlying delay.

**Expected behavior**

A transport timeout must remain a failure. Its diagnostic must identify
the operation and configured limit. It must exclude raw output and must
not automatically repeat a command whose remote outcome is unknown.

**Steps to reproduce**

1. Return `timedOut: true` from the sandbox command boundary during
workspace preparation or cleanup.
2. Observe that the base implementation reports only
`remote_workspace_operation_failed`.
3. Apply this change. Preparation reports
`remote_workspace_operation_timed_out: prepare (configured timeout
300000ms)`. Cleanup retains its separate 10-second limit.

**Paperclip version or commit**

The regression was reproduced on master base
`367f29478d14003cc5c0f161b7ce8f3164993634`. The fixed current head is
`be45ce6594254bd6b94023a550d8b655dd704bb0`.

**Deployment mode**

Hosted Paperclip with native Runner and Daytona sandbox execution. Local
acceptance also uses disposable PostgreSQL and filesystem commands.

Related work: #18403 introduced remote workspace authority. #18705 added
a fixed full-disk diagnostic. I searched recent clone and
remote-workspace PRs and found no duplicate timeout-reporting repair.
This is a defect fix and does not add a roadmap feature.

## What Changed

- Give each internal workspace command a closed operation name: prepare,
repository, archive helper, capture, restore, or cleanup.
- Preserve that operation and the configured limit in a typed error when
the transport reports a timeout. Do not claim a measured elapsed time.
- Keep other failure diagnostics and exact safe-message checks
unchanged.
- Preserve typed cleanup timeouts in the operation cleanup journal while
retaining generic diagnostics for untrusted errors.
- Add preparation, cleanup, and real-PostgreSQL lifecycle regressions.
Document the timeout and the need to reconcile saved receipts before
recovery.

## Verification

- Red: both transport regressions failed on the base implementation. A
separate real-PostgreSQL cleanup regression reproduced the review
finding: the operation journal replaced a typed timeout with a generic
error.
- Green: all 62 remote transport and archive tests and all 50
real-PostgreSQL workspace lifecycle cases passed. The lifecycle suite
ran with an explicit disposable database; it was not skipped. Command:
`pnpm exec vitest run --project @paperclipai/server
server/src/services/remote-workspace-transport.test.ts
server/src/services/remote-workspace-snapshot-archive.test.ts`.
- Safety: a timeout with exit code zero still fails. Raw stdout and
stderr stay out of the error. A timeout cannot claim the fixed
unfinished-Git diagnostic. No command retry occurs. Existing saved files
remain unchanged. Existing archive, restore, receipt, symlink,
credential-isolation, and full-disk controls pass. The cleanup lifecycle
cases retain the acknowledged snapshot, preserve working files, avoid
duplicate uploads, record only a safe typed timeout, and settle cleanup
on the next normal reconciliation. An untrusted error that mimics the
timeout prefix stays generic.
- Live acceptance: production transport code ran against actual Daytona
SDK 0.203.0 timeouts on the incident image, with 4 CPUs, 8 GiB RAM, and
a 10 GiB disk. A controlled one-second SDK limit produced the generic
baseline error and the fixed exact preparation timeout. The current
`be45ce6594` code was rechecked for both preparation and cleanup. Each
returned the typed error and its own configured limit (300 seconds and
10 seconds) while the controlled SDK fault remained one second. Each
case made one command call. Each disposable sandbox was deleted before
the next case.
- The first live-probe attempt used an incorrect error-name check. It
failed its acceptance check and remains recorded. The probe was
corrected to use the same SDK timeout base class as production. Its
first sandbox was deleted. This was a probe setup failure, not red
evidence for the repair.
- A separate same-image probe ran the real full repository preparation
successfully in 107 seconds. The affected command path is unchanged
except for error reporting. The original task was retried once through
the product on deployed source
`adb49a44346849e751548b2fb640693dbfad4b6f`. The requested memo and its
first document revision persisted after reload and matched the
downloaded attachment. The run succeeded, the task reached Done, its
execution lock cleared, and final workspace save and result commit
succeeded. The diagnostic PR is not deployed.
- Recursive typecheck and build passed on `be45ce6594`. `git diff
--check` passed. The first full-suite attempt stopped before tests
because the offline install had skipped an embedded PostgreSQL native
postinstall. The package's official symlink hydration fixed `initdb`.
- The next Mac run passed 350 chat cases and hit one unchanged 15-second
chat deadline. That case then passed in isolation, and all six full chat
shards passed. The broader Mac matrix was later stopped as partial when
CI results became available. No full single-command Mac pass is claimed.
- Full Vitest file coverage uses the exact successful CI merge tree,
`d264fd98e7fb6eff4a9e6b00d402f88894cc0e57`. Its canonical inventory has
2,899 files. Passing CI covered 2,057 files. The remaining 842 ran
locally through the standard exact-file harness. The inventory and
selection checks show no unassigned files. All four changed source/test
files are byte-identical between the PR head and that merge tree.
- The first remaining-file run passed 771 files. The database group
passed 68 files and reported four deadline/readiness failures in three
unchanged files. Those same three files passed all 12 cases when run
sequentially on Node 24.22.2, matching CI's major version. Assertions,
readiness limits, and test deadlines did not change. The first attempt
used Node 26.4.0 with a parallel UI workload; this does not isolate the
contribution of runtime version versus load. Both attempts remain
recorded.
- [GitHub
CI](https://github.com/paperclipai/paperclip/actions/runs/41699549115)
is green on current head `be45ce6594`: `ci / verify`, typecheck, build,
all selected server/chat/workspace groups, Runner checks, and all eight
browser shards passed. Greptile is 5/5 with no open threads. The prior
P2 was resolved by removing new code comments.
- Structured Paperclip review remains queued because its own previous
accepted result exhausted workspace export recovery. A fresh
current-head request is saved, but normal Retry returns HTTP 409
(`accepted_result_without_new_input`). Its advisory cleanup finding is
fixed in `be45ce6594` and covered by red/green lifecycle evidence. This
check is informational. The branch requires `ci / verify` and `ci /
e2e`, and both pass. The independent review-service limitation remains
recorded; this PR is not deployed.

## Risks

Timeout error text changes. Consumers that compare the old generic
message may need to accept the new diagnostic. No such production
comparison was found in this repository. API shapes, deadlines, retries,
ownership, credentials, and model selection do not change. A timeout
still does not prove that the remote process stopped or that a save
failed before publication. Existing recovery must reconcile that state.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, code execution, and browser
tools. The host does not expose a more specific model ID or
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-03 14:13:16 -06:00
DottaandPaperclip f7ad1dc7ca fix(workspaces): make attached project repositories writable (#18770)
## Thinking Path

> - Paperclip lets people assign work to AI agents and inspect the
result.
> - A task can use repositories from more than one project.
> - Remote workspace preparation treated every additional project as a
read-only source.
> - This rejected valid Git repositories before the provider started,
even when no source was read-only.
> - The task page then hid the preparation reason behind a generic
failed-attempt notice.
> - This pull request prepares authorized repositories as writable task
copies and shows redacted workspace validation errors.
> - People can work across both projects and see the reason if folder
preparation fails.

## Linked Issues or Issue Description

**What happened?**

A remote task with a selected Git-backed project and another mentioned
Git-backed project failed before provider execution. It reported
`remote_workspace_readonly_sources_unsupported`. Neither project had a
read-only setting. The task notice showed only that the attempt failed.

**Expected behavior**

Each attached repository should be writable inside the task workspace.
This should preserve source access checks and saved work. A workspace
validation failure should explain its cause on the task page.

**Steps to reproduce**

1. Configure remote workspace storage and a native sandbox environment.
2. Select a Git-backed project for a task.
3. Mention another authorized Git-backed project in the task.
4. Start the task. Preparation rejects the additional source before it
starts the provider.

**Paperclip version or commit**

Reproduced against `dc9f387edc`, before this change.

**Deployment mode**

Managed remote workspace storage. Local regression checks use disposable
PostgreSQL and independent filesystem processes.

Related merged work: Refs #18403 and #18504. Those changes established
remote storage and metadata-only references. They still reject
configured cross-project repositories. No duplicate writable-repository
repair was found. Refs #18774 for the test-only retention-fixture repair
reused to unblock CI.

## What Changed

- Add every configured Git repository of an authorized referenced
project to `.paperclip-repositories/` as an editable task copy.
- Retain saved paths, refs, pins and files. Recheck retained project
access and source trust. Keep explicit read-only, local-source import
and remote feature gates.
- Keep committed snapshot repository coverage separate from later
requests. Honor configured default refs, resolve remote branch names,
and publish secondary checkouts only after checkout succeeds. Share
configured-ref resolution between root and attached-repository scripts.
- Include redacted workspace validation messages in the task
interruption projection and existing failure notice. Preserve Retry
permissions and render messages as plain text. Explain retained-folder
access and trust denials while preserving the dedicated low-trust
project-access path.
- Add source, authorization, redaction, UI and save/restore regressions.
Update the implementation contract and workspace maps.
- Reuse the reviewed test-only repair from #18774. Batch the
shared-workspace history fixture, verify its complete privacy-source
map, and drain owned test bodies before cleanup. Production retention
behavior is unchanged.

## Verification

- Red before repair: four source-resolution cases failed with the
reported read-only error. The task-error projection test also failed
because it omitted the cause.
- Green: 49 source and transport tests, 16 task projection and redaction
tests, and 10 UI tests. The assembled preparation check passes. All 48
remote workspace lifecycle tests pass. The full preparation suite passed
all 126 assertions but its cleanup hook exceeded 30 seconds. The
unchanged base reproduces the same cleanup timeout with all 126
assertions passing. The focused preparation check finishes cleanly.
- The real PostgreSQL/Git lifecycle checks cover both first-turn and
later project attachments. They verify the configured release branch,
saved edits, replacement allocations, unchanged source folders,
committed archive contents, and released writers.
- Review regressions were red before repair: the default ref became
null, later attachment failed during restore, non-default remote branch
checkout failed, and invalid secondary refs left partial checkouts. They
now pass.
- The local browser shows the workspace validation explanation and Retry
action. The fixture uses a saved failed run; this proves the error
display, not a successful live sandbox run.
- `pnpm -r typecheck` and `pnpm build` pass. Map, module-boundary and
token checks pass.
- A local two-turn acceptance probe repeated at `17ed67eaa7` used real
Codex CLI 0.165.0, `gpt-6-astra`, and `xhigh` effort. Codex wrote files
in both task repositories. The services saved them, removed the first
allocation and its Git sources, restored another allocation, and Codex
read the saved files and wrote a follow-up in both folders. This uses
the real source resolver and persistence services with a local
command-runner stand-in for sandbox transport. It does not qualify
Daytona, managed subscription forwarding, or the original task. The
first probe waited for stdin; closing the test harness pipe fixed that
setup error before provider work.
- `pnpm test:run` passed the first chat shard, then failed one chat
response concurrency assertion in the second shard. That case passes in
isolation on this head. The same isolated chat case passes on the
unchanged base. Both corresponding unchanged-base chat shards also pass
(351 and 324 tests). The cause of the earlier wider-suite chat failure
is not established. The preparation cleanup timeout and chat failure
remain part of this record.
- CI at `17ed67eaa7`: all other verification jobs passed. Browser shard
6 initially reported a request callback from the preceding test after
teardown; its single unchanged-code retry passed. Server shard 10 timed
out the 2,100-row retention confirmation fixture at 15 seconds on both
attempts. That exact case passes locally, but the repeated CI failure
required a repair. Its setup repeatedly rebuilt a shared-workspace
privacy map. The logs and failures remain part of this record.
- Reused the test-only repair from #18774 without changing its source
file. At `ab774e9418`, all 54 retention tests and all 25 ordinary
production privacy tests pass locally (79 total). Full CI
[41650626903](https://github.com/paperclipai/paperclip/actions/runs/41650626903)
passed on that commit, and its exact-head Greptile review was 5/5. The
fixture preserves its 2,100 rows, query-bound assertions, privacy-source
map, and completed-history test deadlines.
- The additional review identified retained-source access/trust denials
that still bypassed the workspace explanation. Real-resolver regressions
reproduced both plain-403 failures before the correction. Both now yield
a safe workspace validation explanation, while the dedicated low-trust
denial and saved workspace remain unchanged. The optional duplicate
ref-resolution block is also consolidated.
- Final review corrections: 65 source, transport and error-projection
tests passed, followed by all 48 lifecycle cases against an owned
disposable PostgreSQL database (113 total). The initial combined command
skipped the explicitly gated lifecycle suite; the subsequent dedicated
invocation enabled and passed all 48. Full workspace typecheck and build
pass. The first standalone lifecycle launcher lacked the repository
TypeScript loader; rerunning with that loader resolved its import setup
error. At previous head `7be02ea09c4ac76df560e8b517050cdf398f33f0`, full
CI [41654422329, attempt
2](https://github.com/paperclipai/paperclip/actions/runs/41654422329/attempts/2)
passed, Greptile is 5/5 on that exact head, and all review threads are
resolved. The first attempt timed out the unchanged voice-session
report/history case at 15 seconds; 3,027 cases in its shard passed. That
exact case passed locally, then its single unchanged-code shard retry
passed. The wider-suite timeout cause remains unproven. The completed
Paperclip advisory check is neutral; its earlier findings are corrected.
No staging deployment or original-task recovery is claimed.

- Master advanced while checks ran, producing conflicts in two adjacent
test additions. Merged `27d35314be` into this branch as
`d5c8d552939c86056abf8fe10833881b2ade41a4`, preserving both
workspace-error tests and the audited Stop/receipt tests. Kept workspace
maps to minimal corrections under the updated map rule. All 82 source,
transport and interruption cases, all 48 real-database save/restore
lifecycle cases, full typecheck, build, and map checks pass locally on
the combined code. Current-head [CI
41660719214](https://github.com/paperclipai/paperclip/actions/runs/41660719214)
and Greptile are pending; the earlier verified head has not been merged.

## Risks

- Additional remote project repositories are now editable task copies.
Shared source folders and upstream push permissions do not change.
- Snapshot coverage uses existing workspace metadata. Older workspaces
capture their previous inventory at reservation; successful save
publication advances coverage and snapshot identity in one transaction.
No SQL migration is needed.
- A retained copy can contain files from a project that is no longer
mentioned. Preparation rechecks that project's current access and trust
policy before reuse.
- Explicit read-only descriptors still fail. Source-less projects remain
metadata-only. Local folders still require import. No migration or
provider-pack update is needed.
- Error display reads only workspace validation errors. The existing
run-secret registry and username censor run before display truncation. A
redaction failure omits the explanation.
- The retained fixture repair pauses its row trigger only within the
isolated seed transaction, rebuilds the exact source map, and restores
the trigger before commit. A rollback regression and 25 ordinary privacy
cases pass. Its paged-case test budget honors the existing bounded inner
waits; production deadlines are unchanged.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, tool use and code execution.
The exact serving model ID and context-window size are not exposed by
this session. The test-only fixture changes are reused from #18774,
whose model record identifies OpenAI GPT-6.1 Sol. The optional live
acceptance probe uses `gpt-6-astra` with `xhigh` effort through Codex
CLI 0.165.0.

## 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-03 15:33:44 +00:00
DottaandPaperclip 71a20453e1 fix(workspaces): honor inherited remote workspace bindings (#18611)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Task creation can bind a child to its parent's execution workspace.
> - Native sandbox runs reserve that workspace before the provider
starts.
> - Remote reservation rejected inherited isolated workspaces and
operator branches because the original source task differed.
> - This check stopped valid child tasks before their existing access
and writer checks could run.
> - This pull request uses the persisted binding and existing
source-access checks to admit that continuation.
> - The benefit is that authorized child tasks can continue saved work
while the single-writer lock stays effective.

## Linked Issues or Issue Description

**What happened?**

A child inherited an active isolated remote workspace through normal
task creation. Its next run failed during setup with `Workspace
ownership changed.` No provider work started. The reservation guard
treated the original `sourceIssueId` as exclusive ownership, although
task creation had persisted a valid child binding.

**Expected behavior**

A bound child or follow-up can reserve the workspace after the prior
writer saves. Current task/run access, source visibility, trust, company
scope, closed-workspace state, and writer checks must still apply. The
original source task remains provenance.

**Steps to reproduce**

1. Create a task with an active saved remote isolated workspace or
operator branch.
2. Create a child without an explicit workspace override.
3. Confirm that the child inherited the execution workspace ID.
4. Start its native sandbox run. The old reservation guard rejects it
before provider execution.

**Paperclip version or commit**

Reproduced on source based on
`06bc8db75c71142ed108e0f331394c5187015d6a`. The same guard is present at
`1a6017d6460267ad89d7e1784e2b521c28d8e9ac`.

Related: #17156 proposes separate workspaces for child tasks. This
repair preserves the current inheritance contract and enforces the
remote writer lock. #16911 addresses child bindings across repositories.

## What Changed

- Remove the original-task equality restriction for active remote
workspaces. Keep the existing persisted-binding and retained-source
authorization path. Explicit task-root selection follows the existing V1
filesystem contract; task-assignment grants do not define filesystem
permissions.
- Keep closed workspace rejection and unfinished-writer checks.
- Add database-backed regressions for inheritance, replay, competing
children, an unbound task, private source data, company isolation, and
closed records.
- Extend real save/restore tests for inherited isolated workspaces and
operator branches. Keep shared-workspace discovery coverage.
- Update the development guide and workspace maps.

## Verification

- Red: before the repair, the inherited isolated/operator cases fail
with `Workspace ownership changed.` The shared case passes. The unfixed
suite has five failures and four passes.
- Green: 11 reservation cases pass with real PostgreSQL 18 in an
isolated Docker container.
- An earlier run of the four affected workspace/preparation/trust suites
passed 191 tests. The review follow-up passes all 15 selected
reservation/save/restore cases. Inherited cases remove the original
files, use a distinct allocation and target, restore the saved file,
append child work, and independently read that work from the child's new
snapshot. Shared-source discovery stays covered. The filter excludes 42
other integration cases.
- `pnpm -r typecheck`, `pnpm build`, `node scripts/check-maps.mjs`, and
`git diff --check` pass. A direct server typecheck also passes after the
final test edit.
- `pnpm test:run` stopped in its first chat shard: 338 passed, one
Discord receiver-lease setup failure, 1,478 outside the shard. The
failing test passes in isolation on both the unchanged baseline and the
fix. Its suite-order failure is not explained by that retry and remains
recorded. The unchanged baseline also fails three other Discord
publication cases in that chat shard, while its next chat shard passes.
This does not reproduce or explain the original lease failure; both
results remain recorded. CI is complete on `e697f6e1b8`: 54 successful
check runs, one successful legacy status, three skipped checks, and one
neutral check. No check is pending or failed. Greptile gives this commit
5/5 with no remaining findings. The security reviewer accepted the
V1-contract explanation; both review threads are resolved.
- Live sandbox acceptance remains unverified. The available test
credentials could not resolve the required sandbox snapshot. The
provider rejected creation before workspace execution, and a scoped
follow-up found no allocation. No live model turn, deployment, or
original-task recovery is claimed.
- Local environment: macOS arm64, Node 26.4.0, pnpm 9.15.4. Native
PostgreSQL startup hit the host semaphore limit; tests use disposable
Docker databases. No shared database was reset.

## Risks

- A bound child can now write after the prior writer releases the
workspace. Incorrect binding or access checks could expose source data.
Regressions cover unbound, private-source, and foreign-company
rejection.
- Concurrent children must not become two writers. A real transaction
race grants exactly one reservation; saved-file tests keep the second
writer blocked until save completes.
- No schema or migration changes. This PR does not change task-creation
inheritance, requested models, credentials, trust, approval gates, or
recovery budgets.

## Model Used

- OpenAI Codex, based on GPT-6. The exact serving model ID and context
window are not exposed in this session. Used reasoning, tool use, code
execution, and browser diagnostics. No sub-agents were used.

## 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 — the targeted workspace
suites pass; the full local chat-suite failure and baseline comparison
are documented above
- [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-02 09:36:05 -06:00
DottaandPaperclip 5e4cc01073 feat(workspaces): keep remote files off the webserver disk (#18403)
Keep native sandbox workspace files independent of the webserver disk. Use encrypted saved versions and Postgres ownership so a replacement server can recover files and continue work. Enable the path by default for new eligible workspaces when durable storage is configured.

Preserve explicit opt-outs and existing host workspaces. Include safe snapshot repair, Files access, import, migration and retention. Bound saved-Files resources, preserve imported Git recovery, reject unfinished Git operations, publish immutable concurrent captures, and verify permanent object-version deletion.

Validated 471 targeted local controls, build/typechecks, all 40 CI partitions, fresh Greptile 5/5 and security review. The PR records original failed attempts and scoped retries.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-31 14:54:01 -05:00