mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-08 01:57:31 +01:00
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - A native run finishes in two steps: the provider turn, then
finalization. Finalization saves the workspace and commits the result.
> - When finalization exhausts its retries, `recordRetryableFailure`
sets the run to `failed` and blocks the task.
> - That code writes the cause only to `resultJson.failureCode`. It does
not write the run's `errorCode` or `error`.
> - So the run list, inbox, and agent status show a failed run with no
reason. Operators cannot tell why the run failed.
> - This pull request writes the finalizer's terminal failure code and a
readable message to the run row when the finalizer fails the run.
> - The benefit is that every failed run now names its cause.
## Linked Issues or Issue Description
**What happened?**
A hosted instance had 11 assigned native runs with status `failed`,
`errorCode` null, and `error` null in one day. In each run, the provider
turn succeeded. The remote workspace copy-back then failed three times.
The finalizer set the run to `failed` and blocked the task. The run kept
no error code. `resultJson.failureCode` was
`native_workspace_sync_out_retry_exhausted`, but no screen shows that
field as the failure reason.
**Expected behavior**
A failed run has an `errorCode` and an `error`. The failure surfaces
show why the run failed.
**Steps to reproduce**
1. Create a native run with a finalization coordinator.
2. Call `recordNativeFinalizationFailure` three times with
`native_workspace_sync_out_failed` and `failureScope: "workspace"`.
3. Read the run. Its status is `failed`, and its `errorCode` and `error`
are null.
**Paperclip version or commit**
`master` at be20d4ad97.
## What Changed
- `recordRetryableFailure` in
`server/src/services/native-runtime/native-run-finalizer.ts` now sets
`errorCode` to the terminal failure code and `error` to a readable
message when it projects a run to `failed`. This covers
`native_workspace_sync_out_retry_exhausted`,
`native_workspace_sync_out_unrecoverable`, and
`native_finalization_retry_exhausted`.
- The update keeps an earlier root `errorCode` and `error` (`coalesce`).
- The update does not change a run that Stop already cancelled. It uses
the same row-level `case` as the status write.
- The update does not add an error when the finalizer projects the run
as `succeeded` or `cancelled`.
- New tests in `native-run-finalizer-telemetry.test.ts` cover the failed
projection, root-cause retention, concurrent cancellation, a retry that
remains, the provider-scope failure, and the provider-succeeded
projection.
## Verification
- `cd server && npx vitest run
src/services/native-runtime/native-run-finalizer-telemetry.test.ts`
- Before the fix, three tests failed because `errorCode` was null:
"bounds workspace-only retries…", "records the finalization error code
when provider-scope retries fail…", and "blocks immediately when the
sandbox… is gone".
- After the fix, all tests in the file pass.
- Related suites pass: `native-workspace-export-retry`,
`native-run-projection-work`, `explicit-native-continuation`,
`execution-control-work`, `native-status-arbiter-corpus`, and
`workspace-recovery` (971 tests). One `workspace-recovery` test timed
out at 30 s under the parallel load. It passes when run alone.
- Downstream checks: the export retry path
(`native-workspace-export-retry.ts`) and the success projection
(`native-run-projection.ts`) already clear `error` and `errorCode` when
they reopen or succeed a run. A later recovery therefore does not keep a
stale error.
## Risks
- Low risk. The change only writes two columns that were null for these
runs.
- `error` is now also the agent status reason and the lease failure
reason for these runs. Before, the agent reason fell back to
`native_workspace_sync_out_failed`.
- This change does not fix the first cause of the copy-back failures.
The remote capture reports only the generic
`remote_workspace_operation_failed`, because the capture output is
redacted. That cause needs separate work.
> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.
## Model Used
- Anthropic Claude Opus 5.5 (`claude-opus-5-5`), used in Claude Code
with tool use (shell, file edit, read-only browser).
## 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
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>