Commit Graph
12 Commits
Author SHA1 Message Date
DottaandPaperclip 3858d2341d fix(recovery): default saved-monitor waits and keep task recovery quiet (#16686)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - A task must keep a durable path to its next action.
> - A provider can save a task monitor, then fail to yield because it
omits internal continuation fields.
> - An interrupted provider-pack check can then be reported as permanent
artifact incompatibility.
> - The task asks its user to certify recovered workspace files, even
though this is an operator responsibility.
> - This pull request derives the saved monitor continuation, bounds
verification retries, and removes that task form.
> - Normal recovery stays quiet. Unresolved holds retain inspection and
the existing safety checks.

## Linked Issues or Issue Description

**What happened?**

A yielded completion without `continuation` is rejected even after the
provider saves an eligible monitor on the task. Repeated attempts cannot
finish. Remote verification also treats timeouts and missing exit status
as artifact incompatibility. The task recovery notice exposes raw
diagnostics and asks the task user to certify infrastructure files.

**Expected behavior**

Use current persisted task state to fill routine continuation fields.
Retry interrupted verification reads within a fixed bound. Keep normal
recovery in the working state. Show a compact notice only when work
cannot safely continue.

**Steps to reproduce**

1. Save an eligible monitor on the active task.
2. Call `paperclip_finish` with `reportedWorkDisposition: "yielded"` and
omit `continuation`.
3. Return a timed-out remote provider-pack command with empty stderr
during recovery. Inspect the resulting task notice.

**Paperclip version or commit**

Source baseline: `aaeff418cf` (master integrated with its current task
visibility and saved-source reconstruction rules).

Related changes: #15824, #16104, #16451, #16493, #16690. This fix
complements saved-result recovery and verified pack reuse. It does not
replace their workspace ownership checks.

## What Changed

- Allow omitted or null continuation at the provider input boundary.
Read current authorized task context and fill a monitor continuation
only for the bound run and an eligible saved monitor. Keep accepted
results strict. Apply this to Codex, OpenCode, both direct and
production-sidecar ACPX paths, and external drivers. Reserve the
semantic call identity during the saved-context read and reject
cancellation or a changed run/turn.
- Bind the shared completion change and continuation helper in a new
Copilot v21 source declaration. Preserve v20 history and its decoder
support. Qualification stays pending.
- Expose the eligible continuation in task context. Completion admission
still checks persisted monitor state. No schedule is created or renewed
by the default.
- Retry read-only provider verification at most twice per command. Hold
exhausted reads with a distinct verification-unavailable cause.
Reattachment cannot renew the read budget through an unchanged
provider-attempt counter. Keep completed verification failures and wrong
versions incompatible.
- Remove the task file-certification form. Hide the notice only for a
matching durable recovery path without an unknown-action replay hold.
Keep missed retries, unsafe outcomes, and unresolved file holds visible.
- Add production-component stories for automatic recovery, blocked and
expired holds, reader access, persisted repair decisions, source
reconstruction, queued continuation, and mobile. Preserve master’s
guarded saved-source reconstruction choice after confirmed source
destruction. Update the execution contract and access maps.

## Verification

- Completion, helper, Codex, OpenCode, ACPX, and profile regressions
pass. After the sidecar review fix, 271 tests across the production
sidecar and three provider suites pass, plus 72 helper/profile tests.
The real sidecar MCP bridge tests cover saved-monitor acceptance,
no-monitor refusal, cancellation, duplicate call identity, and
raw-versus-forwarded semantic receipt hashes. The OpenCode tests also
cover eligible-monitor acceptance and refusal without one.
- The fresh full native executor suite passes all 743 tests. Four
profile, installation-integrity, and ACPX driver suites pass all 168
tests. The earlier CI fingerprint failure required a new immutable
source declaration; its follow-up Docker failure required the matching
context allowlist entry. Both fixes are verified locally. Targeted
server monitor, tool authority, and provider verification suites pass.
The probe tests include a real timed-out subprocess, an unrelated
responsive timer, transport errors, and completed integrity rejections.
- All 90 tests in the merged task notice, reconstruction choice,
recovery display, and lineage suites pass. They cover reader access,
live/missed/mismatched recovery, unknown outcomes, saved messages, retry
refusal, and removal of the file form. Both review findings have
failing-baseline/passing-treatment regressions: identical polling across
retry expiry, and a failed refresh after cached running activity.
- Browser walkthrough passed for automatic recovery, unresolved details,
a 390px mobile story, and the merged saved-source reconstruction and
queued states. The reconstruction control starts disabled and normal
automatic recovery shows only Working. The stories use production
components and fixture API data. They do not prove live cloud recovery.
- Token gates, map checks, and Storybook catalog generation pass. The
exact Docker context integrity command passes locally after adding the
new build declaration to its allowlist.
- Workspace typecheck and build pass on the final source, including the
versioned identity update. The final server and UI guards pass their
focused tests, typechecks, builds, and token gates. The final standalone
Storybook builds. The saved-monitor default retains master’s stricter
child-task visibility filter. Re-review caught an additional
production-sidecar validator before forwarding; the fix now defaults at
that boundary and has passing regression controls. After preserving
master’s new reconstruction capability, 68 targeted reconstruction,
tool-authority, and provider-verification server tests pass. The
current-master integration at `2a80050a0d` has a fresh 5/5 review with
zero unresolved threads. Its complete CI matrix, including Runner tests,
is the merge acceptance record.
- On the final master integration, local typecheck, build, and all 90
recovery UI tests pass. A concurrent runner run hit five 5-second
sidecar startup timeouts; an isolated sidecar run passed 86 tests and
timed out in the unrelated unsupported-bootstrap case. Those local
deadline failures remain recorded; the canonical CI Runner lanes use
their normal deadlines and pass. The unsharded local full-suite attempt
did not complete. It spanned source edits; the fresh native executor run
above passes. An unrelated workspace fixture timed out once and then
failed to reserve 32 contiguous ports on this host. Its unchanged-base
control and CI server suite pass. Full-suite acceptance uses the fresh
latest-head CI matrix; this PR does not claim a passing unsharded local
run.

## Risks

The default applies only to an eligible persisted monitor. An explicit
invalid continuation still fails validation. The added read occurs only
when a yielded report omits its continuation. Admission rechecks current
state after that read.

An interrupted verification command can add one extra 30-second probe.
Completed rejections stay closed. These probes do not change the pack,
launch provider work, or replay external tools. Two inconclusive reads
hold the original run. They do not schedule another reattachment with an
unchanged provider-attempt counter.

This PR’s pending Copilot v21 declaration binds the changed shared
contract, resolver, direct driver, and production sidecar sources. The
previous v20 declaration is immutable and remains decodable, but launch
requires the new exact identity. Qualification remains pending.

Task users lose the file-certification form. Board-authorized
source-only repair remains available through the resolution API with the
original evidence and stop-receipt requirements. This branch does not
deploy or recover historical held runs.

> This is a bug fix and UI polish within existing recovery behavior.
ROADMAP.md was checked.

## Model Used

OpenAI Codex, `gpt-6.1-sol`, xhigh reasoning, with tool use and code
execution. The host does not expose the context-window limit.

## 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 (changed-area suites; the
full local run limitation is recorded 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-10-18 21:43:15 -05:00
DottaandPaperclip bfadb66556 fix(daytona): retain already archived workspaces on stop (#16710)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Stop-only recovery must keep unfinished remote workspace files safe.
> - Daytona can archive a stopped sandbox while those files remain in
object storage.
> - The stop handler sent another Stop request for that archived source.
> - Daytona rejected that request, so recovery could not record its
required receipt.
> - This change accepts the freshly confirmed archived state after
retention is verified.
> - Recovery can proceed while the source stays cold and its files
remain available.

## Linked Issues or Issue Description

Refs: #16583, #16700.

**What happened?**

Stop-only cleanup rejected a retained workspace after Daytona archived
it. The live provider returned `DaytonaValidationError` for Stop while
its state was `archived` and auto-delete was already disabled. The host
correctly kept the recovery gate closed.

**Expected behavior**

Confirm the exact source and its retention policy. Treat an archived
source as having no running process. Record the stop-only receipt
without starting or deleting the source.

**Steps to reproduce**

1. Keep an unfinished native workspace with stop-and-retain intent.
2. Let its stopped Daytona sandbox become archived.
3. Request stop-only cleanup.
4. Observe the rejected Stop request and missing receipt.

## What Changed

- Accept `archived` after a fresh provider read confirms that
auto-delete is disabled.
- Stop the source if that fresh read instead shows it has resumed.
- Add regression cases for confirmed retention, unconfirmed retention,
and a resumed cached handle.
- Update the recovery runbook and capability map.

## Verification

- The new baseline fixture failed on the old handler: 1 failed, 2
passed.
- Daytona provider suites: 417 passed, 6 skipped.
- Full workspace `pnpm -r typecheck`: passed.
- Full workspace `pnpm build`: passed on `fc8b1c1bb8`.
- Maps and Git whitespace checks: passed.
- The live provider rejection was reproduced on the exact retained
source. No model turn, file change or delete was performed. The fixed
source handler was then run against that same archived allocation with
the declared SDK version. It returned the stopped-process receipt while
the provider stayed archived with auto-delete disabled. No process was
started. All 58 exact-head CI checks passed; independent review is 5/5.
A full local run is also in progress on a separate frozen checkout of
this revision; it is not reported as complete.
- [Daytona lifecycle
documentation](https://www.daytona.io/docs/en/sandboxes/) confirms that
archive follows Stop and preserves the filesystem in object storage.

## Risks

- An archived source grants a generic stopped-process receipt. Its
physical provider state stays archived.
- Retention confirmation remains required. A stale archived handle that
has resumed still requires Stop.
- The host still checks the original allocation, ownership, stop receipt
and file-recovery evidence before continuation.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, tool use and code execution.
The session does not expose an exact backend 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-10-18 02:50:49 -05:00
DottaandPaperclip 6bec153410 fix(runtime): retain cancelled workspaces before reconstruction (#16700)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native runs must preserve files when Stop ends a turn before its
result is saved.
> - The cancellation path could skip file retention and leave a prepared
remote workspace active.
> - An older controller could also admit an extra run while an earlier
lost-source hold was unresolved.
> - Rejecting every later run then prevented recovery even after that
extra run was stopped and its files were reconciled.
> - This change retains cancelled workspaces and records the exact proof
for a safely reconciled intervening cancellation.
> - Recovery can proceed without changing cancelled history, replaying
actions, or weakening execution gates.

## Linked Issues or Issue Description

Refs: #16583, #16690, #16696.

**What happened?**

Stop could acknowledge a native turn without recording its unsaved file
obligation. Reconstruction also rejected a later cancelled run after its
exact environment and files had been reconciled. The task could remain
inactive with an `in_progress` status, which the reconstruction endpoint
rejected.

**Expected behavior**

Retain unsaved files after Stop. Permit a board operator to reconstruct
from saved sources only after each intervening cancellation has a
confirmed stop and a file-only repair record. Preserve the original
failed export and the cancelled run.

**Steps to reproduce**

1. Prepare a native workspace and cancel the turn before a structured
result exists.
2. Inspect its file retention and remote lease state.
3. For a task with an older destroyed export, reconcile the later
cancelled run's exact files and unperformed actions.
4. Request reconstruction from verified same-task attachments.

## What Changed

- Pin prepared native files before cancellation settlement. Defer
teardown if pinning fails. Use the existing stop-only cleanup worker.
- Repair active warm and ephemeral sources, plus stopping and
confirmed-stopped historical cancellations in bounded startup and
periodic batches. Preserve the existing exact-source checks. Bound
row-lock waits and advance past a busy source.
- Accept only same-owner native run-only cancellations with no result or
current coordinator, confirmed stopped leases, and board file-only
repair with `not_performed` action outcomes.
- Save hashes of each intervening repair and recheck them at queue claim
and final dispatch. Reject changed evidence or another later run.
- Expose saved-source reconstruction in the issue API for inactive
`blocked` and `in_progress` tasks, and hide it when an execution or
checkout owner exists. Permit the same inactive source at submission.
Keep the source, owner, version, attachment, budget, pause and retry
checks.
- Update the shared evidence type, recovery runbook and capability maps.
Add an optional cancelled-native no-action confirmation to file
recovery, resetting evidence when its source changes. No migration, new
endpoint, permission or dependency.

## Verification

- The new fixture fails on the original validator with
`workspace_reconstruction_stale` after valid cancelled-run file repair.
- Focused source and Stop retention tests: 94 passed before the final
contention case. The subsequent three-suite run passed 123 tests,
including real PostgreSQL lock contention and public
startup/API/final-dispatch paths. The final narrow-query rerun passed
all 123 tests. Review correction: all 143 tests passed across four
suites, including real lock contention through the teardown boundary and
stopping/stopped allocations.
- Six broader cancellation, executor, heartbeat and restart suites: 831
passed, 9 existing skips.
- Final correction: all 145 backend tests and all 36 recovery UI tests
passed. Real contention covers both warm reusable and ephemeral sources.
Optional no-action confirmation defaults to uncertified, and changing
source clears evidence. Workspace `pnpm -r typecheck` and token gates
passed on these sources.
- Maps, module boundaries and Git whitespace checks: passed. Full `pnpm
build` passed on the final `4e8c0e73ac` revision as well as the prior
reviewed heads. A full local run of the preceding fix completed with
21,724 passes, 109 skips and three failures in webhook body limits, a
status-card timeout, and a port-allocation fixture. All three suites
then passed unchanged in an isolated rerun (209 tests). The full local
run remains recorded as failed; the final head's full CI passed (55
completed checks, no failures). A fresh full local run is also in
progress on the frozen reviewed head.
- Preserved failures: the first attempt lacked a built plugin SDK; after
building prerequisites, the regression reached the expected validator
rejection. Treatment tests caught the file-only action's deliberately
null continuation owner. A real lock test then caught the database
driver's wrapped timeout error. Both defects were corrected and
retested. Independent review then found a teardown race after a failed
retention write. A second review found active warm sources excluded by
the historical policy filter; the regression reproduced both warm
failures before correcting the query. Its real-row-lock fixture
reproduced the failure; the fixed release guard and historical
stopping/stopped cases pass. No checks were weakened.
- A pre-deployment walkthrough caught the issue API still hiding
reconstruction for an inactive `in_progress` task. The status/capability
baseline reproduced three failures, including inappropriate capability
flags for execution/checkout owners. The fix uses the same
inactive-state requirements as submission; its positive fixture reads
the assembled issue API before reconstructing. All 117 tests in those
three recovery suites pass, and all 28 heartbeat-recovery tests pass
separately. Full workspace typecheck passed again. Full build passed
with the exact `4e8c0e73ac` stamp; latest-head independent review is 5/5
with no open findings. All 55 latest-head checks completed with no
failures.
- Live tenant acceptance remains pending. No successful reconstruction,
export or warm-process proof is claimed by these local tests.

## Risks

- Stop retains unfinished work, so storage remains until file recovery
and explicit cleanup complete.
- Reconstruction remains held for unknown or performed external actions,
foreign owners, live or rebound environments, accepted results, changed
evidence, and unrelated later runs.
- The sweep examines at most five candidates per pass. It uses a fair
cursor and bounded transaction waits. It performs no provider call and
starts no new turn.
- Intervening verification reads only the needed JSON fields. The source
transaction still serializes recovery for the same task.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, tool use and code execution.
The session does not expose an exact backend 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-10-18 01:33:11 -05:00
DottaandPaperclip 69ac928d2b fix(runtime): preserve bounded retries after workspace reconstruction (#16696)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - An operator can rebuild a destroyed workspace from saved task
attachments.
> - The first reconstruction run must pass current source and execution
checks.
> - A temporary bootstrap failure can create a bounded retry before
provider work starts.
> - The retry has a new run ID, so the first-run-only reconstruction
check rejects it.
> - This change verifies the retry chain back to the approved first run
and keeps current safety checks.

## Linked Issues or Issue Description

Refs #16690.

**What happened?**

After an operator records workspace reconstruction, a safe bootstrap
retry is cancelled before provider startup. The normal retry scheduler
creates the successor. The reconstruction check then rejects its
immediate predecessor because it expects the original failed export run.

**Expected behavior**

A verified automatic retry can continue under the same reconstruction
decision and remaining retry budget. Changed sources, unrelated
executions, uncertain outcomes, pause and later human blocks must still
stop startup.

**Steps to reproduce**

Record reconstruction with a retry budget remaining. Let its first run
fail before provider work starts with recorded bootstrap evidence. Use
the normal bounded retry scheduler and the locked dispatch gate. Before
this change, the scheduler succeeds but dispatch returns false.

## What Changed

- Verify the predecessor chain back to the recovery action's exact first
continuation.
- Check company, task, agent, terminal predecessor state and each
scheduler-owned wake. Reject cycles, foreign parents and forged wakes.
- Exclude only those verified predecessors from the unrelated-newer-run
check. Keep source hashes, original result identity and all current
execution gates.
- Reuse the existing reconciliation proof for failed predecessors. Keep
the original retry limit.
- Add real PostgreSQL scheduler and assembled-heartbeat regressions.
Update the recovery guide and feature map.

## Verification

- The baseline regression failed at final dispatch after the normal
retry scheduler created its successor.
- The corrected focused group passes 133 tests across reconstruction,
retry scheduling and dispatch. It admits two bounded bootstrap retries
and refuses a third. The assembled heartbeat enters the provider once
for an eligible retry and zero times after a controlled post-claim human
block.
- An intermediate negative case exposed missing predecessor-outcome
validation. Reusing the existing reconciliation proof fixes it. Deleted
sources, pause, forged wakes, foreign parents, unrelated runs and new
recovery holds remain refused.
- Full workspace typecheck and build pass on rebased head
`bd301ec8a703fa1cdc9e1db2638440d203e8d57a`. The rebased focused group
passes all 133 tests. All CI gates pass on that exact head, including
general/serialized tests, Runner, build and browser gates. Greptile is
5/5 with no unresolved threads. A clean full local `pnpm test:run` is
running; the local source stays frozen for that run.
- Module boundaries, maps and diff whitespace checks pass. Live staging
acceptance follows the qualified full Cloud deployment.
- The earlier full local run for #16690 failed while files changed and
its PATH hid `lsof`. All five affected suites then passed in a clean
run: 246 passed, three skipped. Those results do not establish a full
local pass for this follow-up.

## Risks

- Retry ancestry is a rare recovery path. Its primary-key reads grow
with the chain and stop at 64 predecessors. Ordinary runs perform no new
ancestry reads.
- Unknown effects and active recovery obligations stay held. This does
not reset budgets, change provider lifecycle policy, grant access or
replay completed actions.
- No schema migration or new API is included.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, tool use and code execution.
The session does not expose an exact backend 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 (focused checks; full-run
scope is recorded 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-10-17 23:48:28 -05:00
DottaandPaperclip 7c7d2d8d2c fix(runtime): continue from saved sources after workspace loss (#16690)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The runtime must preserve saved work and prevent duplicate
execution.
> - Older cleanup could destroy a sandbox before its workspace export
finished.
> - The existing recovery controls require either the original sandbox
or recovered original files.
> - Surviving attachments can support a rebuild, but they do not prove
that missing edits were recovered.
> - This pull request adds an explicit reconstruction decision and one
fresh continuation through the normal execution gates.
> - Operators can continue useful work while the original failed run
remains truthful.

## Linked Issues or Issue Description

**What happened?**

A historical failed export can have an accepted result, a prepared
workspace descriptor, and a confirmed destroyed sandbox. Its notice can
also say `new_source_execution_path` and disappear. The task then has
neither a truthful original-file repair path nor a supported
reconstruction path.

**Expected behavior**

Keep the missing-file obligation visible. Let an authorized operator
choose surviving task attachments and record lost work and external
action outcomes. Start one fresh continuation after current execution
checks. Keep the old result and failed export intact.

**Steps to reproduce**

1. Seed a failed native export with a prepared descriptor and an exact
destroyed-lease receipt.
2. Resolve its notice with the historical `new_source_execution_path`
bookkeeping value.
3. Read the task. The baseline hides the hold even though no source
reconciliation exists.
4. With this change, choose **Continue from saved sources** and submit a
reconstruction decision.

Related public work: #16451 preserves healthy warm sessions. #16583
prevents destructive cleanup of unexported work. This change handles
historical source loss that those fixes cannot undo. Searches of open
and closed work found no equivalent reconstruction endpoint.

## What Changed

- Add a board-only reconstruction endpoint with `runtime:manage` and
task visibility checks.
- Validate the exact run, result, descriptor and destroyed lease. Reject
active copyback, competing owners, newer work, stale task status, and
foreign attachments.
- Record attachment hashes, missing work, and external action outcomes.
Preserve the original failed run, accepted result, prepared descriptor
and terminal failure.
- Hold other continuation paths until the durable reconstruction intent
admits its successor. Record that successor in the same transaction and
preserve the retry count.
- Add an operator control that distinguishes reconstruction from
original-file recovery. Update the recovery runbook and capability maps.

## Verification

- Exact baseline source returns no blocker for the destroyed-source
fixture. The same fixture returns a required recovery hold with this
change.
- New real PostgreSQL and assembled API/heartbeat suite: 25/25 pass. It
covers duplicate submissions, lost acknowledgement, context reset,
source identity, task ownership, concurrent execution attachment scope,
later human blocks, deleted sources and agent pause.
- Existing export retry, explicit continuation and recovery-action
suites: 386 cases pass. One new-fixture constraint error in the combined
run was corrected; the full new suite then passed.
- UI recovery suites: 46/46 pass across three files. They cover disabled
actions, loss acknowledgement, failure retention and runtime authority.
- `pnpm -r typecheck` and `pnpm build` pass. The first sandboxed
typecheck attempt could not open the TypeScript IPC socket; the
authorized rerun passed.
- Module boundaries, map checks, token gates and diff whitespace checks
pass.
- OpenAPI route coverage: 21/21 pass. The first CI head exposed a
missing endpoint registration; this head adds the registration and the
focused suite passes.
- Review identified a missing dispatch-time check and an isolated
attachment cache. Both are fixed. Claim and final handoff recheck the
exact successor, sources and current execution gates. A controlled
post-claim operator block prevents the assembled heartbeat from entering
the provider. The shared attachment cache refreshes uploads and removes
deleted selections.
- Final focused run: 180/180 pass across six suites, including
reconstruction, existing dispatch/stale-queue contracts and UI recovery.
- A second review reproduced cancellation by an already satisfied
historical connection card while the task was `todo`. Read-only
connection availability now works before checkout; active-task mutation
checks remain strict. The baseline failed two cases; after the fix all
74 connection and reconstruction tests pass, including revoked access,
pending questions and pending approvals.
- All current-head CI gates pass on
`9d197236da11fa24f1ceadf5589cb2b81179d824`, including general/serialized
tests, Runner, build and browser gates. Greptile is 5/5 for that exact
head with no unresolved threads. The full local `pnpm test:run` is still
running its serial server group; no full local pass is claimed. Live
staging recovery is pending deployment.

## Risks

- Reconstruction cannot restore missing bytes. The operator must
identify surviving sources and actions that must not be repeated. The
agent must verify those attachments before rebuilding.
- This path is limited to exact, confirmed destroyed remote sources with
an accepted result. Retained or uncertain sources keep their existing
repair path.
- No schema migration, credential change, budget increase or
warm-session policy change is included. Normal pause, ownership, budget,
approval and dispatch gates still apply.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, tool use and code execution.
The session does not expose an exact backend 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 (focused suites; full local
run limitation recorded 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-10-17 22:57:10 -05:00
Devin FoleyandPaperclip 79c34058cd fix(native): retain unexported workspaces after execution failure (#16397)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native agents can edit files in a remote sandbox before they submit
a result.
> - A process identity or startup failure can end the run before file
export.
> - Cleanup can then delete the sandbox and its unpublished files.
> - This pull request retains the exact source and records a file repair
action before cleanup.
> - Operators can recover the files without replaying the failed turn or
changing the task owner.

## Linked Issues or Issue Description

**What happened?**
A native remote process had completed local edits when process identity
recovery failed. The run still had a prepared workspace reference and no
accepted result. Cleanup deleted the source sandbox. No file recovery
card appeared. A restarted run can hit the same path during setup,
before the native executor starts.

**Expected behavior**
Retain the exact unexported source. Show the existing file recovery
card. Require source stop and file recovery evidence. Keep task
ownership, status, and external action reconciliation separate from file
repair.

**Steps to reproduce**
1. Run a native agent in a remote ephemeral workspace and make
unpublished edits.
2. Fail process identity recovery before result acceptance or file
export.
3. Allow failure handling and lease cleanup to run.
4. Before this change, cleanup can destroy the source without a file
repair action.

Refs: #16341 for related process identity diagnostics. Refs: #16349 for
startup ownership fencing. This change addresses file retention after
failure.

## What Changed

- Record source retention and a file recovery action in the terminal
native failure transaction.
- Cover restarted preparation failures before the terminal setup writer
and cleanup run.
- Require the exact company, run, lease, provider allocation, and
workspace binding. Require the exact live recovery claim to settle an
owned preparation failure. Refuse stale or competing claims.
- Reuse the existing stop-only cleanup and file-only reconciliation
path. Leave accepted results and scheduled same-run recovery on their
existing paths.
- Document the retention rule and add database and runtime boundary
regressions.

## Verification

- All 1,242 tests passed across the full heartbeat recovery suite,
native executor, native source retention, runtime teardown, run
completion, and legacy file recovery.
- The integrated missing-descriptor regression fails before the
inner-handler fix and passes after it. The runtime retention and owned
restart regressions also reproduce their prior failures.
- The tests cover exact source identity, current and stale claims,
atomic rollback, cancellation, idempotence, and file-only repair on a
completed task.
- `pnpm -r typecheck` passed on the final code.
- `pnpm build` passed on the final code.
- Full repository CI passed on
`3945eb2ba5c228c5d4992da02b765dcf2e634cb8`: 54 successful checks and two
skipped Storybook checks.
- Apex scored 5/5 on that exact commit. Both earlier findings are fixed
and all review threads are resolved.
- The unsharded local `pnpm test:run` is still in progress. It is not
counted as a local full-suite pass; complete suite coverage is verified
in CI.

## Risks

- Failed runs can retain a sandbox that needs operator cleanup after
file recovery. This uses the existing retention policy and recovery
controls.
- This does not recover files from allocations that were already
deleted.
- No schema migration, UI change, or telemetry change is required.

## Model Used

- OpenAI GPT-6 through Codex. Tool use, code execution, and reasoning
assisted this change. The environment identifies the model as GPT-6; it
does not expose a more specific serving snapshot 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-10-14 23:07:15 -07:00
DottaandPaperclip aa04c5c2a7 fix(runtime): keep the copyback lock transaction active (#16340)
Keep the dedicated workspace-copyback transaction active with bounded SELECT 1 probes while filesystem work runs. Preserve existing connection, owner-token, takeover and publication fences.

Verified head 7fb0ad45bf: full CI, E2E, Superagent, legacy statuses and Apex 5/5; no unresolved review findings. Real PostgreSQL idle-timeout reproduction and 71 affected cases pass. Strengthened disabled-timeout controls fail when their guard is removed.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-14 17:52:26 -05:00
0b0e53029f fix: recover saved workspace results automatically (#15824)
## Thinking Path

- Paperclip preserves accepted agent results before workspace copyback
and result commitment.
- A replaced controller can leave a physical copyback owner receipt
behind. A lost database lock or expired lease cannot prove that its
tar/Git children stopped.
- Infrastructure recovery should belong to the runtime and deployment
harness; task users should not investigate processes or attest shutdown.
- New receipts record the exact deployment. The harness independently
verifies that deployment fully stopped and signs a short-lived proof
bound to the stack, run, owner and deployment.
- The existing guarded reconciler then finishes the same accepted result
without a new agent turn. Legacy receipts retain the documented
administrator API after independent platform verification.

## Linked Issues or Issue Description

**What happened?**

An accepted native result can remain at `workspace_finalizing` with an
abandoned physical copyback owner. Repeated recovery sweeps could
replace specific instructions with advice to start new agent work. The
first version of this PR exposed a shutdown-evidence form in the task;
that asks end users to resolve infrastructure details.

**Expected behavior**

Automatically verify and recover the exact stopped deployment, preserve
the original accepted result and existing approval/monitor waits, and
show only a quiet task status. Unknown or live workers must remain
fenced. Older receipts without platform identity need independently
verified operator assistance through the administrator API.

**Steps to reproduce**

1. Persist an accepted native result and a copyback receipt from a prior
controller.
2. Replace that deployment before workspace finalization commits.
3. Let the normal finalization reconciler revisit the saved result.
4. With a platform-bound receipt and a fully stopped deployment,
recovery should finish automatically. With missing, live, unverifiable
or changed ownership, it must not write files or create another provider
turn.

Related public work: #14402 introduced copyback ownership; #9687 handles
dead-run finalize barriers; #15795 handles terminal stale-run cleanup.
This change addresses an accepted result whose physical copyback owner
prevents commitment.

## What Changed

- Record Railway project, environment, service and deployment identity
on new physical copyback owners.
- Request read-only platform verification from the managed cloud
harness. Require an Ed25519 stop receipt with a disjoint purpose,
configured signing key, exact stack/run/owner/deployment binding and
valid expiry.
- Keep live, unknown, malformed, unavailable and legacy owners fenced.
Compare the whole prior receipt during ownership takeover, under the
existing dedicated advisory lock.
- Persist platform proof and audit automatic takeover. Resume normal
finalization of the same saved result, preserving task ownership,
approved boundaries, monitors and pending confirmations.
- Remove process metadata, shutdown evidence, confirmation checkboxes
and infrastructure-repair forms from task views. Suppress the duplicate
technical owner-recovery card. Show “Restoring saved work…” only from
server-confirmed recovery or queued operator recovery; platform identity
alone shows the operator-assistance fallback. Remove the status when
recovery resolves.
- Share current-task, current-running-execution, accepted-result,
authoritative-reviewer and newer-execution checks between automatic and
operator recovery. Validate after the provider lookup, atomically with
the owner claim, and again before file publication; closed or superseded
tasks cannot start copyback.
- Keep the separately authorized exact-owner API for operator recovery
of legacy receipts, with active-lock, live-controller, stale-result and
newer-execution rejection. Generic dismissal cannot bypass the copyback
fence.
- Replace obsolete form stories with production-backed automatic,
queued, legacy, completed and mobile examples; retain stable suite IDs.
Update the operator runbook and scoped Storybook catalog.

## Verification

- Red/green: new platform-proof tests failed before implementation; the
database takeover regression failed against the original ownership
guard; reduced-UI assertions failed against the original form. All pass
after the changes.
- Passed: 59 physical-owner/finalization database tests using isolated
PostgreSQL, including real reconciler commitment from all three
saved-result phases through both automatic and operator recovery. They
preserve result identity, exact saved file bytes, pending approval and
overdue monitor waits, and create no new run or wake request. Unknown
evidence and changed ownership remain fenced.
- Passed: 162 focused proof, cloud identity, recovery route,
recovery-card and reduced-UI tests.
- Passed: full workspace typecheck and build, final server/UI
typechecks, token gates, and Storybook build.
- Browser inspection: desktop task composition shows only the quiet
status; completed example removes it and retains the approval-wait
message. Mobile shows the existing bottom navigation with no horizontal
overflow. These are fixture UI observations, not live provider
acceptance.
- A companion harness change implements the actual provider check,
signed receipts, server-token authentication and bounded/coalesced
provider reads. Its full typecheck and test suite passed: 3,240 passed,
92 skipped, zero failures. This application alone cannot enable platform
verification.
- The updated full application `pnpm test:run` was stopped after
repeated local embedded-Postgres startup failures; it is not claimed
green. The same affected recovery suites pass against isolated
PostgreSQL. CI passed on final head `9ad5c3529e`: 54 successful checks,
two intentional skips, and successful legacy Snyk status. Greptile is
5/5 with no unresolved findings.
- Global Storybook catalog validation is green: 225 files, 2,224
stories. Its 17 catalog/index tests pass. Master was merged and the
inherited index metadata was reconciled after source review.
- Review correction red/green: two UI and two database assertions
reproduced misleading progress / missing server recovery state; all pass
after server-confirmed state was added. All 153 focused server tests and
68 UI tests pass on the final recovery code, including repeated-sweep
idempotence. Full workspace typecheck/build, token gates and Storybook
build also pass.
- Safety regression red/green: stale-task copyback and publication tests
failed against the previous guard. The final suite covers changes during
proof lookup, closed/cancelled tasks, replaced execution/checkout, newer
and queued legacy runs, reassignment and rejected/unbound results, plus
the real reconciler selecting closed or superseded tasks. Files remain
untouched and no workspace operation starts.
- No staging mutations, deployment, live provider probes or live
production recovery were performed. The three historical receipts lack
deployment identity and still require independent operator proof.

## Risks

Automatic takeover requires the companion harness release and configured
runtime-identity keys. Deploying only this application leaves
unavailable evidence fenced. Legacy receipts are not retrospectively
assigned a deployment identity. An authorized operator can still make an
incorrect attestation through the fallback API; its administrator gate
and exact-owner safeguards remain. Provider history that is missing or
deeper than the bounded lookup defers automatic recovery. Copyback can
still fail under its existing retained-workspace policy.

No migration, telemetry change or cloud provider credential delivery is
required. The companion harness PR also has passing CI and a 5/5 review;
neither branch is deployed.

## Model Used

OpenAI Codex, GPT-6, with repository inspection, browser verification,
tool use and code execution. The exact serving model ID and
context-window size were 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 and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run the relevant 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>
Co-authored-by: Paperclip <paperclip@paperclip.ing>
Co-authored-by: Devin Foley <devin@paperclip.ing>
2026-10-13 10:14:45 -05:00
83e13db8fa fix(inbox): keep automatic recovery cleanup out of personal participation (#16063)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The personal inbox uses issue activity to identify a person's
participation.
> - Issue reads can cancel stale recovery actions and record that
cleanup as the reader's action.
> - This adds unrelated tasks to the inbox and refreshes their activity
timestamps.
> - A workspace owner hold can also alternate between creation and
cancellation after a task finishes.
> - This pull request corrects cleanup attribution, excludes historical
read cleanup, and retains one exact owner hold.
> - Agents can read authorized issue activity to diagnose the same
problem themselves.

## Linked Issues or Issue Description

Refs #15742 excludes logs by the execution-recovery actor from activity
timestamps. This PR covers reader-attributed stale recovery cleanup,
personal inbox participation, exact workspace owner holds, and sandbox
issue activity access. I searched open issues and PRs for recovery inbox
and activity bridge fixes. I found no duplicate for this defect.

**What happened?**

Loading issue lists cancels stale recovery actions under the reader's
identity. The personal inbox treats those rows as user participation.
One completed issue had hundreds of such rows and no edits or comments
by the affected reader. A retained native workspace owner repeatedly
creates a verification action that read projections then cancel. Sandbox
agents cannot inspect the issue activity because the reverse bridge
rejects the route.

**Expected behavior**

Automatic cleanup belongs to the system and does not add an issue to a
reader's inbox. Historical cleanup rows remain auditable but do not
count as participation or recent activity. An unresolved physical
workspace owner keeps one stable verification action. Agents can inspect
activity only for issues their identity may read.

**Steps to reproduce**

1. Finish a task whose native run retains an unverifiable workspace
owner receipt.
2. Repeat workspace recovery checks and GET requests for issue detail,
compact lists, and recovery actions.
3. Observe new recovery action IDs and reader-attributed cancellations
in the activity history.
4. Query the personal inbox for that reader and observe the unrelated
task.
5. From a sandbox agent, request GET /api/issues/:id/activity and
observe Route not allowed.

**Paperclip version or commit**

Observed at f5346c05b9. Regression tests
use current master behavior.

**Deployment mode**

Authenticated hosted instance with native and legacy sandbox agents. The
inbox defect is independent of the adapter.

## What Changed

- Attribute automatic stale recovery cleanup to the recovery system
actor.
- Exclude exact historical read cleanup rows from personal inbox
membership, unread counts, and both activity timestamp queries. Keep all
audit rows and explicit user recovery decisions.
- Retain owner verification holds only while the exact company, run,
issue, and owner fingerprint still match. Apply the same rule to reads
and background recovery.
- Make repeated checks for the same owner hold leave its identity,
attempts, and timestamps unchanged. Keep physical takeover blocked.
- Allow GET issue activity through the sandbox bridge. Keep the existing
company and issue-read authorization and reject broader audit routes.
- Add regressions and update the runtime API and recovery documentation.
Refresh generated source references for the documentation edits. Update
the paired activity, inbox, and recovery maps.

## Verification

- Focused Vitest verification: 315 tests pass across five files. The
updated terminal owner hold regression also passes. The files cover
issue service, recovery routes, activity authorization, sandbox callback
bridge, and native workspace finalization.
- `pnpm -r typecheck` and `pnpm build` pass locally. The full general
and serialized unit test matrix passes in CI on the latest commit. The
duplicate local `pnpm test:run` was stopped after about 30 minutes once
that full CI coverage passed; it did not report a local full-suite pass.
- `node scripts/check-maps.mjs` passes for all paired areas and
capability IDs.
- Apex is 5/5 on commit 44c3787888. Its
access map finding is fixed and resolved. All CI checks are green on
this commit.
- The new regression repeats reads and background sweeps for done and
cancelled tasks. It checks one unchanged hold, zero physical copyback,
zero personal inbox participation, and system cleanup after the exact
receipt is cleared.
- Historical cleanup tests preserve explicit recovery decisions,
nullable metadata, unread counts, and the original audit rows.
- Authorization tests permit an authorized agent and reject
cross-company or issue-boundary reads. Bridge tests reject write
methods, extra path segments, and company-wide audit routes.

## Risks

Existing inbox items can disappear if their only participation evidence
was automatic read cleanup. No data migration or audit deletion is
needed. An unresolved workspace owner remains visible after task
completion; this preserves the physical writer fence. A stale or cleared
owner does not retain the hold. Issue activity access expands only the
sandbox transport allowlist and still uses existing controller
authorization.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository inspection, code
editing, shell execution, and test tools. The session identifies the
model family as GPT-6. A more specific runtime model ID and context
window size are 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>
Co-authored-by: Amy (Opus) <noreply@anthropic.com>
2026-10-12 19:25:15 -07:00
Devin FoleyandPaperclip 7e10dbe652 fix(server): retain stopped ephemeral workspaces after failed copy-back (#15790)
## Thinking Path

> - Paperclip manages work performed by agents.
> - A remote adapter must copy workspace changes back after execution.
> - Cancellation can stop and release an ephemeral sandbox before
copy-back fails.
> - The recovery recorder previously considered only active or already
held leases.
> - This change carries the original host lease into the recorder and
checks both stop receipts.
> - The exact stopped source receives a board repair obligation without
replaying work.

## Linked Issues or Issue Description

**What happened?**

A legacy remote run can report `workspaceRestoreFailure` after its
dedicated stop has released the source lease. The recorder misses that
source and does not create its file-repair action. Related prior work:
#15637 adds bounded transfer diagnostics; #15718 protects native
accepted finalization. This change addresses the separate legacy
recording order.

**Expected behavior**

Preserve the exact eligible source and record the existing board repair
obligation. Preserve cancellation, later task progress, and newer
execution ownership.

**Steps to reproduce**

1. Acquire an ephemeral remote lease for a legacy run.
2. Complete the dedicated stop-and-retain lifecycle and persist both
stop receipts.
3. Report a workspace copy-back failure from the original adapter
invocation.
4. Observe that the old recorder omits the released source. The
PostgreSQL regression reproduces this order.

**Paperclip version or commit**

de042e79ef.

**Deployment mode**

Server with PostgreSQL and a sandbox provider. The regression uses
disposable local PostgreSQL and synthetic provider receipts.

## What Changed

- Clone the realized host lease before adapter dispatch and carry it
into restore recording.
- Admit a released source only when its original and current policies
are ephemeral, its full ownership and workspace identity match, and its
dedicated retention receipt agrees with the independent
stopped-execution receipt.
- Reject reusable, expired, destroyed, rebound, competing, or
insufficiently proved sources. Preserve release state and receipts when
recording the existing no-replay repair action.
- Cover the actual stop-before-copy-back lifecycle, cleanup retries,
built-in dispatch, rollback, repeated recording, newer owners, and
ownership/receipt failures. Document the narrow scope.

## Verification

- `pnpm exec vitest run
server/src/__tests__/legacy-workspace-restore-recovery.test.ts
server/src/services/legacy-execution-recovery.test.ts`: 80 passed.
- Existing Grok confirmed-stop/copy-back boundary test: passed.
- The new PostgreSQL regression fails on the baseline because the
recovery marker is absent.
- Guard-removal controls fail when either the ephemeral-policy gate or
original-source identity checks are removed.
- `pnpm --filter @paperclipai/server typecheck`: passed.
- Additional competing-owner/lifecycle checks: 6 passed, including older
stopped and destroyed allocation owners.
- `pnpm -r typecheck` and `pnpm build`: passed.
- Independent review approved the final source. The exact ephemeral
regression fails on the baseline; policy/identity guard-removal controls
fail their intended assertions.
- Compatibility with #15789 was checked in a disposable combined
checkout: both commit orders yield the same tree. The earlier broad run
passed 136 cases; the final guard/SDK delta passed 9 cases.
- Greptile: 5/5 on the current head, with no review threads.
- Exact-head CI: 53 successful checks and 2 expected skips; no failures
or pending checks. This includes all test shards and Canary Dry Run.
- The duplicate local `pnpm test:run` aggregate was stopped after full
CI passed. It is not reported as a completed local suite.
- No live provider calls, historical data repair, run replay, or
deployment was performed.

## Risks

No schema or API change. A qualifying source remains held for manual
file repair and eventual removal, which can retain provider storage
longer. This fix does not recover historical files or establish that the
provider still holds the bytes. Reusable sources remain excluded from
this new path because provider resume can start before the database
handoff. Existing active-source and previously recorded recovery
behavior is unchanged.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository tools, and
independent agent review. The exact model revision and context-window
size are not exposed to 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
- [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-10-10 01:27:03 -07:00
Devin FoleyandPaperclip 7a58591721 fix(recovery): preserve accepted workspace finalization during reaping (#15718)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A native run saves its accepted result before it copies workspace
changes back.
> - A restart can leave that copyback under an unverified physical
owner.
> - The generic orphan reaper can mistake the exited provider for lost
work and release the source lease.
> - Recovery must preserve the accepted result and let the existing
finalizer settle its remaining work.
> - This pull request checks that authority at the conditional
process-loss write and preserves the matching recovery hold.

## Linked Issues or Issue Description

Related: #15475 added bounded process-loss evidence. The earlier #9687
addresses dead-run finalize barriers with synthetic receipts. This
change preserves an existing accepted native result and requires real
workspace settlement.

**What happened?**

After a server restart, the native finalizer required operator
verification of unfinished copyback. The generic orphan reaper then
marked the run `process_lost` and released its source lease. A new
execution path also made the recovery reconciler clear the copyback hold
before physical ownership was verified.

**Expected behavior**

An accepted result bound to the same company, issue, and run keeps its
unfinished workspace suffix under native finalization. The generic
reaper must not discard its source. The existing finalizer must still
complete the work, apply its bounded failure policy, or require operator
verification.

**Steps to reproduce**

1. Accept a native result and leave its coordinator in
`workspace_finalizing`.
2. Stop the controller before copyback completes, leaving its physical
owner receipt.
3. Start recovery, then run the generic orphan and lease cleanup sweeps.
4. Before this change, the run can fail with `process_lost` despite its
accepted result and explicit copyback hold.

**Paperclip version or commit**

Reproduced against `011e5669`; the same recovery code remains at base
`1602512820`.

**Deployment mode**

A hosted server with PostgreSQL and native runner execution. The tests
use only isolated local PostgreSQL and synthetic fixtures.

## What Changed

- Check the exact accepted result and `workspace_finalizing` coordinator
before generic process-loss cleanup.
- Repeat the check in the conditional status write. Compare the
heartbeat tuple version to reject a result publisher that commits while
the update waits on its row lock.
- Preserve nonterminal copyback holds when another execution path
appears. Resolve only the matching run's hold after verified
finalization commits.
- Add fourteen real PostgreSQL service regressions and document the
recovery boundary.

## Verification

- `pnpm -r typecheck` passed.
- `pnpm exec vitest run
server/src/__tests__/heartbeat-process-recovery.test.ts -t 'native
finalization'`: 14 passed. The test filter excluded 383 existing tests.
- Tests cover startup, repeated reaper and cleanup sweeps, malformed and
foreign owners, an expired old controller, exact database bindings,
legacy and unsupported states, verified settlement, and unchanged
terminal-task dispositions.
- The concurrent publisher test uses the real accepted-result
transaction and proves the reaper update is blocked by its row lock
before the publisher commits.
- The local `pnpm test:run` aggregate was stopped after setup timeouts
in the chat and tool-access files and a damaged-epoch Runner test
failure. It is not a full local pass.
- The chat file passed all 1,145 tests when run alone. The tool-access
file then passed 419 of 420; one case returned `socket hang up`. That
single case passed on its isolated rerun. The cause of the socket
failure is not established here.
- The damaged-epoch Runner case still fails locally at its existing
completion assertion. The same assertion failed on untouched baseline
`556daf9a` before this patch; its test and Runner sources are unchanged.
Exact-head CI passes this coverage. No workaround for that local fixture
is included.
- `pnpm build` passed.
- Independent review approved this exact commit. All 14 new PostgreSQL
regressions and 181 existing recovery/finalizer cases passed. One
existing suite needed an isolated rerun after a setup timeout.
- Independent negative controls reproduced the original bug. Removing
only the tuple-version guard reproduced the blocked-row race. Removing
only the hold exclusion cleared the safety hold too early. Restoring
this patch passed all three checks.
- GitHub CI passed all 53 applicable checks. The two Storybook jobs were
skipped as expected. Greptile scored this commit 5/5 with no unresolved
review threads.
- Local runtime: Node 25.6.1. GitHub CI supplies the repository's Node
24 checks.
- `git diff --check`, Gitleaks, and a local diff scan for secrets and
private data passed.

## Risks

- PostgreSQL tuple versions are used only as an optimistic fence for
`process_lost`. Both accepted-result publishers lock and update that
heartbeat in their result transaction.
- The guard requires the bound accepted result and the durable
coordinator state. A heartbeat phase or arbitrary owner JSON alone
cannot suppress ordinary process loss.
- Existing finalizer retries, ownership verification, explicit
cancellation, and terminal-task dispositions remain unchanged. A
physical owner can still require operator verification.
- This change does not replay provider work or restore a source already
destroyed by an older controller. No migration or runtime operation is
included.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository tools, code
execution, and independent agent review. The exact service model ID and
context-window size are not exposed in this worker 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
- [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-10-09 12:28:16 -07:00
DottaandPaperclip 14795136f5 fix(runtime): finalize and recover sandbox workspace exports safely (#14402)
Serialize native workspace finalization, validate streamed archives within bounded limits, and quietly recover unsafe exports from saved results. Preserve exact allocations for exhausted transient failures and provide export-only retry without rerunning the provider.

Consolidates #14314, #14315, #14329, and #14334 while preserving the already-merged finalization label changes.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-28 10:57:32 -05:00