doc/architecture/paperclip-runner-compatibility.md
This document defines compatibility rules for introducing the experimental Paperclip Runner. These rules are acceptance criteria for each implementation change. They are not a migration plan for existing adapters.
The server resolves and persists the runtime once, before provider launch.
| Persisted runtime | Adapter | Flag | Result |
|---|---|---|---|
| none | Any direct adapter | off or on | Use the existing direct path. |
| none | paperclip_runner with Codex | off | Reject the fresh start with a stable rollout-disabled error. |
| none | paperclip_runner with Codex | on | Use PRP v1 and runnerd. |
| none | paperclip_runner with another provider | on | Reject the unsupported provider before runnerd starts. |
| direct | Any | changed later | Keep the persisted direct path. |
| native | Any | changed later | Keep the persisted native path for read, cancel, recovery, and finalization. |
The server must not fall back from a selected paperclip_runner start to
codex_local. A configuration or rollout error must be visible. Silent fallback
would hide the runtime that executed the task.
This rule applies to every built-in and plugin direct adapter. It includes:
codex_local;claude_local;opencode_local;Adding Paperclip Runner must not add runner imports or runner branches inside a direct adapter implementation. The heartbeat coordinator may select the explicit runner adapter at one narrow seam. All other adapters continue through their existing code.
For a flag-off codex_local heartbeat, compatibility proof must show:
When the rollout flag is off:
paperclip_runner;paperclip_runner;paperclip_runner selection;When the rollout flag is on:
paperclip_runner only with provider
codex and valid Codex configuration;Server validation is the authority in both states. Import files and API clients cannot bypass the flag or provider allowlist.
The following data remains readable independent of the current flag:
If the flag is disabled during an in-flight native run, the server may reconnect, cancel, reconcile, and finalize that same run. It must not use that recovery as authority to start a new native run.
Recovery must remain idempotent. Repeating it cannot add a second final reply, interaction, wake, status decision, or application effect.
The task page uses one provider-neutral thread projection. Runtime facts may add runner event groups, semantic receipts, usage, and structured questions. They must not replace classic direct-adapter content.
Direct-adapter coverage must include:
The existing composer remains usable for direct adapters. A direct run does not show reconnect, runner cancel, semantic receipt, or other runner-only controls. Final replies continue to use the existing issue-comment behavior.
New structured questions use paperclip.question_set.v1 and the matching
response contract. Provider-specific question objects remain inside their
drivers.
Legacy unstructured interaction records remain readable and resolvable. A structured form fails closed when its required schema, question mode, question ID, option ID, or response value is invalid. The implementation must not silently convert malformed structured input to a legacy text prompt.
PRP wire versions, fixture versions, event schema versions, and typed schema discriminators are independently versioned.
Breaking meaning requires a new required version. A provider error is not a protocol negotiation result.
Catalog generation and production authorization are separate steps.
Each runner-related pull request updates only rows that it can execute. The complete first-wave matrix must cover:
| Area | Required cases |
|---|---|
| Runtime selection | Every built-in direct adapter, explicit runner selection, unsupported provider, flag on, and flag off. |
| Direct regression | Flag-off codex_local invocation count, byte-stable result/finalization, and zero native rows. |
| Configuration | Enabled and disabled create, import, edit, read, export, and adapter switch. |
| Recovery | Persisted native run after flag disable, reconnect, duplicate event, duplicate command, cancellation, and server restart. |
| Protocol security | Cross-company binding, ticket replay, ticket expiry, malformed frame, unsupported version, and revoked lease. |
| Semantic actions | Discovery denial, unbound action, duplicate call, conflicting retry, redaction, and governed action. |
| Task page | Active, settled, empty transcript, interaction, and classic direct-adapter states. |
| Structured input | Valid response, malformed response, stale response, duplicate response, provider loss, and cancellation. |
Every implementation pull request must:
Generated files land with their source and a drift check. pnpm-lock.yaml is
owned by CI and is not part of these pull requests.