mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-12 06:10:44 +01:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - When a restart loses a native run's active turn, the run records it as `provider_turn_lost_on_restore` and continues in a same-conversation continuation turn > - #20118 taught the event consumer to skip a stale restart-lost terminal of another turn once a continuation is running. It applied only when the checkpoint already recorded the interruption > - When the checkpoint instead names the lost turn as active (the drain hit right after the first turn was submitted), the consumer starts the continuation on the first lost terminal. If the same lost terminal is then delivered again, it was taken as the run's terminal and failed the run > - This pull request applies the skip to any recovered run once its continuation has started. For a checkpointed interruption it still waits for the startup decision first > - The benefit is that a turn lost on restore always continues, however often its lost terminal is delivered ## Linked Issues or Issue Description Refs #20118 **What happened?** Local restart-chaos K13 regression storm w-20261109T055902-s9402 (master9b71d03215): 94 of 95 passed. In t90 (claude M1 parent), run `e5eab3cb`: 1. The run submitted its first turn at 06:28:25, and a graceful drain followed at 06:28:28. 2. After restore at 06:28:41, the ACPX runner replayed the turn's accept and start, then reported `turn_lab_1abbeca2…` as `provider_turn_lost_on_restore`. 3. The controller started continuation `turn_lab_a3d009c6…`; the saved checkpoint names it as the active turn. 4. The run failed at 06:28:45 with `native_provider_terminal_failed: The runner restored the conversation after process loss, but the previous turn is no longer active.` and needed a Retry. **Expected behavior** Once the continuation is running, a later delivery of the lost turn's terminal is history, not the run's terminal. The run finishes on the continuation. **Steps to reproduce** 1. Recover a run whose checkpoint names the interrupted turn as active (not yet recorded as terminal). 2. Deliver that turn's restart-lost terminal, which starts the continuation, then deliver it again before the continuation completes. 3. Before this change, the second delivery ends the run as failed. **Paperclip version or commit**9b71d03215(wave). Branch rebased on current master. ## What Changed - `native-session-runtime.ts`: `supersededByRestartContinuation` applies to every recovered run. - Once a continuation has started, a restart-lost `turn.failed` for any turn other than that continuation keeps the consumer going. - With a checkpointed interruption, it still waits for the startup decision first. Before this change it excluded the checkpointed interrupted turn itself, which could also end a run if that turn's replayed terminal arrived before the startup continuation began. - `native-session-runtime.test.ts`: - a lost terminal delivered again after the continuation starts; - the checkpointed interrupted turn's own terminal arriving before the continuation starts. ## Verification - Red/green: both new cases fail on master (the run ends failed or on the stale terminal) and pass with the change. The #20118 cases still pass. - `vitest run` over the runner restart, recovery, continuation and terminal test files: 9 files, 389 tests passed. - `PAPERCLIP_TYPECHECK_LOW_MEMORY=1 pnpm run typecheck:typescript` (`packages/paperclip-runner`): passed. ## Risks - Low risk. The skip still requires a recovered run, a recoverable `provider_turn_lost_on_restore` failure, a continuation that actually started, and a terminal for a different turn than that continuation. A loss of the continuation itself, real provider failures, and runs that started no continuation keep their current handling. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`), via Claude Code with tool use (shell, file edits, test execution). ## 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>