mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-13 07:12:00 +01:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Native runs report their result through a completion report. The server checks the report before it accepts it. > - When the Paperclip server pauses or restarts, the agent's Paperclip tool calls stay unanswered. They return later, all together. > - The agent can read that silence as an outage. It then reports a blocker owned by a "Paperclip ... service" with reasonCode `external_service_unavailable`. > - The server accepts that report. The task rests blocked with no Retry. Paperclip's own stall stops the task. Our rule says that must not happen. > - This pull request rejects that blocker report one time per run. The correction tells the agent that Paperclip is reachable now and to re-check. > - The benefit is that the agent continues in the same turn and reports the real outcome. ## Linked Issues or Issue Description **What happened?** In a restart-chaos test, the server was paused (SIGSTOP) for about 2 to 5 minutes while a Codex agent saved a task document. `write_document` and `read_document` did not return during the pause. After the pause, the save had succeeded, but the agent reported a blocker: owner "Paperclip document service", reasonCode `external_service_unavailable`. The run succeeded with disposition `blocked`. The task rested blocked with `canRetry=false` and no automatic recovery. A second test (two long server holds, then a same-run resume) gave the same result. **Expected behavior** A Paperclip stall or restart must not leave a task stuck. The agent must re-check Paperclip after it is reachable and finish the task. **Steps to reproduce** 1. Start a native Codex task that saves a task document. 2. Pause the server process with SIGSTOP for about 2 minutes during the save, then resume it. 3. The agent reports a blocker owned by a Paperclip service. The task rests blocked with no Retry. **Paperclip version or commit** master at62b7733161(test base) andeb75c9bb85. ## What Changed - `nativeCompletionFeedback` now rejects a `blocked` report one time per run when all of these are true: the blocker owner kind is `system`, the owner name contains "Paperclip", the reasonCode is `external_service_unavailable`, the run is still running, and it owns the task. - The correction tells the agent: Paperclip answered this report, so it is reachable now. Re-read the current state before writing again. Repeat a needed write with the same `idempotencyKey`. Report blocked only if a fresh Paperclip call fails now. - The second identical report in the same run is accepted as before, so a persistent real failure still rests blocked. - Added a regression test. It also covers concatenated owner names such as "PaperclipAI document service" and "paperclip_runner" (the match is a case-insensitive substring). ## Verification - `cd server && npx vitest run src/services/native-runtime/native-completion-feedback.test.ts` passes (32 tests). - Red on master: the new test fails with `promise resolved "'Blocker report accepted. ...'" instead of rejecting`. Green with this change. - `cd server && npx tsc --noEmit -p tsconfig.json` passes. ## Risks - Low risk. The change only adds one correction message inside the same turn. It does not change a status, a database row, or a schedule. - The once-per-run limit is kept in process memory. After a server restart, a run can get the correction one more time. This is bounded and harmless. - The match uses the agent's own owner name. That only selects the correction. It does not prove anything or replay a side effect. The agent's next Paperclip calls give the real proof. Writes use idempotency keys, so a repeated write does not apply twice. - This does not add a Retry to a task that already rests blocked from an older report. That is a separate product decision. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, used through Claude Code with tool use (shell, file edits, test runs). ## 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 (no user docs change; the behavior is explained in code comments) - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green (pending on the latest head) - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups (pending on the latest head) - [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 <noreply@anthropic.com>