Files
PaperClipAI/doc
DottaandPaperclip 499712c68b fix(runner): restore cold state before inspecting completed handoffs (#19254)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native Runner saves provider sessions and controller state across
turns.
> - A completed warm handoff leaves a receipt in the controller journal.
> - A later cold continuation must restore external Runner state before
it can inspect that receipt.
> - The transport read the missing physical file before it called the
restore hook.
> - This pull request prepares admitted external state before that
inspection for completed handoffs.
> - Live Runner adoption and pending transitions retain their existing
ownership checks. The provider thread can continue after a cold restore.

## Linked Issues or Issue Description

Related: #19225 and #19157. This fix changes the shared transport read
order. It does not depend on the open source-reconciliation extension in
#19157.

**What happened?**

A cold continuation after a completed warm handoff could fail with
`runner_remote_state_unavailable`. The saved controller journal was
valid. The physical Runner state was absent because its restore hook had
not run yet. A later automatic reattachment could then fail an
allocation identity check.

**Expected behavior**

Restore admitted external state before inspecting a completed handoff.
Retain the original provider thread. Refuse a denied restore or foreign
session without starting provider work.

**Steps to reproduce**

1. Open a Codex session and complete a warm handoff to a second run.
2. Suspend the session and retain the controller journal and provider
backup.
3. Start a third run with no physical Runner state until the external
preparation hook restores it.
4. Read the retained thread. Before this fix, the read fails before
preparation.

## What Changed

- Prepare external Runner state before inspecting a completed
warm-handoff receipt.
- Keep live Runner adoption, pending attachments, and active warm
transitions on the existing exact-state path.
- Add a real Runner and controlled Codex regression for successful
restore, denied restoration, and a foreign restored session.
- Document the cold-continuation order in the execution contract.

## Verification

- Red: the new real-process regression fails on unpatched source because
resume reads the absent `runner-state.json` before preparation.
- Green: all three new cases pass. The restored thread keeps its
identity. The controlled provider starts one thread and resumes it once.
No turn is replayed.
- Adjacent safety suites: 60 cases passed across warm attachment,
interrupted attachment recovery, suspension, and cold restore. The new
foreign-session case also passes separately.
- Runner TypeScript and generated protocol checks passed.
- Full workspace typecheck and build passed. Runner TypeScript checks
passed again after the live-adoption guard. The full local test command
remains in progress; all required CI test jobs passed on the current
head.
- The first CI run found two live-adoption regressions: an already
completed staged handoff must not restore a backup while its Runner is
live. The guard now excludes live adoption. All six cases across cold
restore and staged handoff pass locally. The original CI failure remains
recorded in run 42047027346.
- Greptile reviewed the corrected head
`f33a041c8902c39ca52b995d53128fc23b0b5499` at 5/5. There are no review
threads or findings. All current-head CI gates passed.
- Live staging verification remains pending normal deployment. No pinned
serving image or bulk migration is part of this PR.

## Risks

The change calls an existing external preparation hook earlier for
completed handoffs. That hook must remain idempotent and must enforce
restore authority. Live adoption, pending attachments, and active
transitions do not gain this earlier call. The negative regressions
assert that a refused restore and a foreign session start no provider
work and do not change the authority journal.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, tool use, and code
execution. The host does not expose the exact serving 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-11-05 09:14:10 -06:00
..
2026-02-16 14:25:00 -06:00