Files
PaperClipAI/packages
Nicky LeachandPaperclip 08f3e7ebec Retain passive Codex output while Core reconnects (#19029)
## Thinking Path

> - Paperclip manages work that AI agents execute through a Runner.
> - Core controls the work while the Runner owns the provider process.
> - Core can restart while an admitted provider turn is active.
> - Reconnect waits used to leave provider output in the process pipe.
> - Ordinary provider polling can also wait on a provider RPC before
Core reconnects.
> - This pull request drains passive local Codex output into bounded
durable storage between reconnect attempts.
> - Core receives the original events after recovery and keeps authority
over tools and approvals.

## Linked Issues or Issue Description

Refs #17594. Related work: merged #19353 supplies the Codex
receipt-limit fence and deadline-aware reconnect scheduler.

This PR now contains only shared passive intake and the already-live
native Codex adapter. A controller outage must preserve admitted work
and event identity without restoring a provider, sending a provider RPC,
or executing a tool during reconnect.

## What Changed

- Add a default no-op disconnected-poll hook. Managed providers and ACPX
retain that default.
- Drain passive frames from the existing local Codex process between
reconnect attempts. Requests, terminal reconciliation and lineage checks
wait for the connected path.
- Persist each accepted event before acknowledging the provider queue.
Soft-limit pressure retains the rejected suffix until Core ACKs free
space. Hard failures stop the owned provider and preserve the durable
prefix.
- Preserve credential observations and the existing lease, runtime,
grace and provider deadline bounds. Document the intake contract and
test replay through the real PRP controller.

## Verification

The slice was replayed onto master `bf10bc695a`. `git range-diff
f453509e6f..20626230b9 bf10bc695a..HEAD` reports an unchanged patch. The
diff has 11 files and contains no ACPX adapter or sidecar changes.

Targeted local checks on this head:

- `cargo test --manifest-path
packages/paperclip-runner/runner/Cargo.toml --locked -p
paperclip-runner-core --lib disconnected -- --test-threads=1`: 12
passed. These cover passive deferral, no restoration, the real managed
HTTP worker, durable backpressure, oversized output and existing
receipt-limit cleanup.
- The 10 `credential_observer::tests::` checks passed. The Runner daemon
and recovery example build, and workspace Rust formatting passes.
- `vitest run src/control-plane/runner-recovery-fixture.test.ts
--maxWorkers=1`: four passed. Both controller replacement modes retain
the same process and replay event identities. The deadline and
silent-handshake cases also pass.
- `vitest run src/live/runnerd-codex-transport.test.ts -t
late-remote-release-error --maxWorkers=1`: one passed. Whitespace and
added-line secret checks pass.

Earlier review found that disconnected ordinary polling could perform
synchronous managed history reads. The real-worker regression retained
here proves no history or stream-reopen request occurs until connected
polling. Earlier slice preparation hit a sandbox loopback denial and a
missing local daemon; the permitted loopback test and the test after
building the daemon both passed. The current-base checks above run with
those prerequisites in place.

Historical CI on the old combined head failed an unordered
AI-connections migration comparison. The faithful full-file local check
passed 158 tests, and the failure remains recorded
[here](https://github.com/paperclipai/paperclip/actions/runs/42112385671/job/127543554397).
Earlier receipt-limit delivery failures are addressed by merged #19353.
Previous review scores belong to the old combined diff. On current head
`b92d4b604ee6992eeefbc02c8d41ec4f2a608a4d`, [CI run
42125840239](https://github.com/paperclipai/paperclip/actions/runs/42125840239)
passed. All 59 checks completed with 55 successes and four intentional
skips. Standard review 13 and Apex review 14 each scored 5/5 on this
exact head, with zero comments and no unresolved threads. The single
Apex request is [recorded
here](https://github.com/paperclipai/paperclip/pull/19029#issuecomment-6671993072).

## Risks

During an outage, native Codex intake uses 25 ms ticks between reconnect
attempts. A provider request or terminal waits for Core. Saturation can
pause intake or produce a failure. Managed remote streams retain their
existing limits. Tests use controlled local providers; live provider
qualification and deployment are separate.

## Model Used

OpenAI GPT-6.1 Sol (`gpt-6.1-sol`), high reasoning effort, through
Codex. Used source inspection, local native and PRP tests, and code
review.

## 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 15:29:38 -08:00
..