Files
PaperClipAI/packages
DottaandClaude Opus 5.5 a8bbdf237c fix(runner): reopen the ACPX session at turn.start when it can be safely reopened (#20110)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - A native Claude ACPX run must survive restarts and suspensions. A
turn stopped for suspension drops the live ACPX session and leaves the
saved lifecycle `prepared`
> - The next `turn.start` checked for a live session before anything
else, so it failed with "ACPX session is not open". That happened even
though the saved session was safe to reopen
> - In restart chaos this made a Claude approval task (G1 t03) need a
Retry after repeated restores
> - This pull request makes `turn.start` reopen a reopenable session
before it starts the turn
> - The benefit is that a suspended or restored Claude run keeps going
on its own, with no Retry

## Linked Issues or Issue Description

Refs #20089

**What happened?**
In a local restart-chaos G1 (approval) wave, Claude ACPX task t03 failed
after repeated restores with `ACPX session is not open` and needed a
Retry. The Retry overwrote the session directory, so the exact sequence
could not be read back. The same error reproduces directly with
`turn.stop` (suspension) followed by `turn.start` on the same session:
the stop clears the live session and sets the lifecycle to `prepared`,
and `turn.start` never reopens it.

**Expected behavior**
When the saved session can be reopened, `turn.start` reopens it, the
same way `session.open` does, and then starts the turn. "Can be
reopened" means: the conversation identity is recorded, the provider
exit is confirmed, the session belongs to this run, and the lifecycle is
`prepared`, `suspended` or `session_open`. A session that was closed on
purpose, or whose provider exit is unconfirmed, still fails.

**Steps to reproduce**
1. `run.prepare`, `session.open`, then `turn.start`.
2. `turn.stop` (suspension stop).
3. `turn.start` again. Before this change, it fails with "ACPX session
is not open".

**Paperclip version or commit**
master at f789f3e2af. Branch rebased on current master.

## What Changed

- `acpx_provider_backend.rs`: `turn.start` checks whether there is no
live session and the saved state is reopenable. If so, it reopens
through `open_session` first, and the reopen's `session.resumed` event
comes before the turn's events. The previous body moved unchanged into
`start_turn_in_open_session`.
- `tests/acpx_warm_attachment.rs`: a new test,
`reopens_the_conversation_for_a_turn_after_a_suspension_stop`. It drives
prepare, open, turn, stop, turn and expects the second turn to be
accepted with `session.resumed`. It also checks that after
`session.close`, `turn.start` still fails.

## Verification

- Red/green: the new test fails on master with "ACPX session is not
open" and passes with the change. `cargo test -p runner-core --test
acpx_warm_attachment`: 3/3 passed.
- I also ran the full `runner-core` crate suite. Five tests failed: four
`task_memory` monitor tests and `unconfirmed_suspension_state...`. Each
of them passes on an unchanged master checkout, and the ACPX one also
passes when rerun in this branch, so they are timing-dependent and not
caused by this change.

## Risks

- Low risk. A reopen happens only under the same conditions in which
`session.open` would already succeed for this run. A closed session and
an unconfirmed provider exit stay fail-closed. The order of events
changes only by adding `session.resumed` ahead of the turn's events.

## 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>
2026-11-08 15:46:11 -06:00
..