mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-13 04:02:28 +02:00
## Thinking Path > - Paperclip manages AI agents and their work. > - The experimental Runner owns provider processes and durable sessions. > - Pi needs working task execution and human controls. > - The five-PR stack must preserve changes already on master. > - Each layer now carries the complete integrated source for a safe sequential fallback. > - This PR belongs to native GitHub stack #15602, ending at #14956. ## Linked Issues or Issue Description Refs #14436, #14631, #14743 and #14956. Ship Pi 1.0 through the experimental Paperclip Runner. The five PRs are #14921, #14922, #14923, #14924 and #14956. The user authorized the complete merge after checks pass. Existing `pi_local` execution is unchanged. Accounting and wider provider/platform qualification remain deferred. ## What Changed - Recover missing final replies after workspace finalization changes owners, using accepted-turn evidence without rerunning work or granting external-chat publication. - Preserve the admitted Pi instruction root across warm runs, while retaining changed-root rejection. - Give Pi a bounded 15-second default shutdown grace so stop, drain acknowledgement and durable suspension can complete. Explicit deadlines and other providers retain their existing behavior. - Integrate the Pi 1.0 runtime and master contracts. - Use Pi profile 22. Preserve explicit caller-selected models and exact native thinking levels. Keep Pi's wrapper, helper, extension and question/control behavior unchanged from the qualified profile-19 runtime. - Preserve master's Dot lifecycle and consent fields, configured task environment, status guards and current Codex/Claude dependency versions. Cursor stays qualified. Copilot stays pending; profile 17 binds the changed shared protocol validation sources. - Exclude general AWS IAM credentials from Pi static/custom provider bindings and selected task projections; preserve the provider-scoped Bedrock bearer key. Profile 21 is retained as historical provenance. Rust and cloud install probes use the current declaration. - Patch bundled brace-expansion 5.0.9 to the exact official 5.0.12 payload. Pin the patch and complete runtime closures. Include the patch in normal installed setup tooling. Keep the upstream Pi shrinkwrap as provenance and permit only this exact security correction. - Include current attestation files in the Docker build context. Keep the repository lockfile unchanged from master. CI and private image builds resolve manifest changes before their frozen installation. ## Verification - Full local `pnpm -r typecheck` passes, including Runner Rust, server and UI. Focused integration checks pass: 194 Runner admission/environment tests, 63 profile/credential tests with one expected skip, 152 Dot/UI configuration tests, and Pi transcript/notice tests. - Full local `pnpm build` passes on the final source. - Fresh final-source checks pass: all 698 Rust workspace tests (32 binaries), 156 credential/profile/controller tests with one expected skip, Runner TypeScript typecheck, and 20 package/setup/sandbox tests. - The profile-21 Pi materializer passes on the native host with the official pinned Node 24.21.0 and its npm. It verifies all 150 locked packages, the patched dependency and the exact closure. Setup/package bundle tests and UI token gates pass. - The old hashes were reproduced for all three supported targets before calculating the patched graph. New closure hashes are darwin-arm64 `282022db10150c6632b3444df421342e7d534bdf5d5fb1097a2e79d0625a2bcf`, darwin-x64 `64e251e19009f755c0b04f73ce2138246faab71a961b0f13d75ebfcc34bef12e`, and linux-x64 `713b1fdff42fb56a1518bdc084f181d70bee8ebadc3e4b1d76321ed9108c8410`. Independent native platform execution is separate from graph identity reproduction. - Historical cloud qualification remains unchanged: all seven core cases pass on shipping source `10dc43c9ec65d88c2f782d62afb296d09494f215`, harness `1a4408a48cfb5a1f094a311141c257c92cd7a893`, image `sha256:5b3a775b383591bda1b0c1889e509acc70ce7f37c53f09733c81d59037f02280`, and accepted Sonnet 4.6/low fixture. All 215 canonical files and all seven cleanup checks pass independent verification. These are profile-19 results and are not relabeled as fresh profile-22 runs. - Current Pi digest: `sha256:e92078bee3c23bec4100aa589013a44613d054cd686826534025d8019e9f39a9`. [The readiness plan](https://github.com/paperclipai/paperclip/blob/codex/pi-production-readiness/doc/plans/2026-10-02-pi-production-readiness.md) preserves campaign and failed-attempt provenance. - Merge only after every PR's current-head CI and fresh review pass. Linux CI covers the full suites, build and browser tests. The local embedded Postgres API-authority suite cannot start on this macOS/Node 26 host, so Linux CI must confirm that suite. ### Fresh profile-22 core qualification — 2026-10-08 All seven accepted core cases pass canonically on Pi profile 22, with `openrouter/anthropic/claude-sonnet-4.6` and native-confirmed low thinking. This model is a fixture; production accepts the caller's explicit Pi provider/model. Runtime/install source: `3241a992f2a7703e59e97ed0fd3e5d6405de4401`. Frozen accepted harness: `1a4408a48cfb5a1f094a311141c257c92cd7a893`. Immutable cloud image: `ghcr.io/paperclipai/paperclip-daytona-runner@sha256:506f22db7edd78f37c0c40bec1cc084af1850455026dbf467194bfbb8fcef141`. Pi digest: `sha256:e92078bee3c23bec4100aa589013a44613d054cd686826534025d8019e9f39a9`. [Hosted Linux image and clean-install verification](https://github.com/paperclipai/paperclip/actions/runs/37868328023) passes, including all 20 source-bound archives, normal CLI/Pi setup, companion import and the production pack reader. This exact installation source includes the latest master integration and the corrected Pi warm instruction-root fence. Full local typecheck/build and current-head hosted CI verify the final stack. All 13 focused real-root regressions pass. The full local executor suite passed 662 tests; 15 database tests could not start the Mac embedded PostgreSQL service. Hosted Linux CI passes the full required verification and E2E checks. These fresh results keep their own source identity; profile-19 results remain historical. | Core path | Canonical campaign | Retained archive SHA-256 | | --- | --- | --- | | File edit, validation, download and Done | `pi-core22-replyfix-0-1791511228` | 23 files; `a473e8603a3dd4737863291f8d3d1e392391f0b16d433c3e0e0e9d8baf7a97b0` | | Pending question and controller restart | `pi-core22-replyfix-1-1791511376` | 33 files; `6b829c4eb74e1f32a89c692a4ae7130dbfc1c6d3cf13915effe2103d9e242c8e` | | Three-turn session/process/workspace continuity | `pi-core22-replyfix-2-1791511587` | 23 files; `7a87021f8f9a3fdd3c58bb4467f8d82c635e3ea4795d6e75f144d9aa14818df8` | | Four typed questions and browser reconnects | `pi-core22-replyfix-3-1791511881` | 42 files; `9e31755252be1f4f9cb0626c984c142d4d1ae5f5bee3a7af08444db8d12c280a` | | Plan approval and completion | `pi-core22-replyfix-4-1791512031` | 22 files; `a0383ce1aab38e7b5a25ce0e9dd3bebea5c037ebd96ae6b29dae19015da2ae2c` | | Same-turn steering and permission denial | `pi-core22-replyfix-5-1791512261` | 39 files; `c929b8c7070f0b66aedc17e65ca46e6beab1e363926ac9f7e2a75fb250f05949` | | Stop during pending permission | `pi-core22-replyfix-6-1791512390` | 33 files; `7f0a58ae0f4d5bfc76149435f4e322537089c5bd16e7ffe9b5ad71f10a621a07` | All 215 canonical files (28714587 bytes) are independently hash-verified. All seven cleanup grades pass, with no owned runtime process or temporary root after each case. Automatic retries are zero. The owned cloud host stopped normally after retention. The prior profile-22 warm attempt remains failed and separately retained: archive SHA-256 `1e54eba5ec72b50cee1534b23d1d1d4f21a090006b8a64501ba70db972abfde5`. Its original canonical classification is preserved. Diagnosis reproduced a product bug comparing an agent-files root against an unset checkpoint-only field. The fix stores the admitted physical root separately from the adopted per-run collection capability. The real-root regression fails before the fix and passes afterward, including rejection of a changed physical root. Fixture, grader, model and all seven accepted case IDs are unchanged; this fresh campaign tests final-reply publication after file registration first. The intermediate restart attempt also remains failed and retained: archive SHA-256 `5dcaefdf1d17cf4cd54fd4cf810f45e736667392339b8ce7caf08bb4e225277f`. Its original canonical classification is preserved. Pi resumed, wrote the verified answer and completed its task; exact runner suspension was proven, but idle stop consumed about 5.2s and left under 3s for the drain acknowledgement. The Pi-only default shutdown grace is now 15s, preserving a full 5s drain round trip and a finite suspension reserve. Explicit caller deadlines, other provider defaults, literal drain receipts and exact suspension identity checks remain unchanged. The timing regression fails before this correction and passes afterward; all 18 focused settlement tests and Runner typecheck pass. The final-source file attempt is also preserved as failed (`candidate_failure`), archive SHA-256 `db6767b6773ea618997927ac77bdb005a5ac81492c7b9c0ffbc900449f829bc9`. Native edit, validation, exact downloadable artifact and Done/succeeded all passed, and the exact final reply was durably recorded. A workspace recovery owner completed before the live heartbeat reached presentation, leaving that reply absent from task chat. Recovery now materializes only a completed final reply from the accepted turn of an ordinary internal Done task, preserving issue/run/contract binding, suppression, external-chat authorization and same-run deduplication. The database regression covers the generated file-preparation receipt, suppression, unapproved external continuation and replay. Server typecheck and all 49 response-selection tests pass; hosted Linux verifies the database regression because embedded PostgreSQL cannot start on this Mac. The delayed-final-answer database regression passes on [the final root-source Linux server shard](https://github.com/paperclipai/paperclip/actions/runs/37868262553/job/113628594152), alongside 1,108 passing tests. The first root Runner shard had one unchanged durable-resume test exceed its 5-second timeout; the identical top-source shard and the isolated exact test passed. One rerun of that failed job and its required aggregate passed without source or test changes. The original failed job log and the single-rerun receipt remain retained. ### October 9 merge verification Current merge head: `5a8fe63512a7166aaef5cf50065a25008aa8b44b`. All current-head checks pass, including `ci / verify` and `ci / e2e`; exact-head Greptile review is 5/5 with no unresolved threads. Current master conflicts are resolved. The user authorized the maintainer override of the code-owner review gate after these checks. The seven retained live core cases remain bound to source `3241a992f2a7703e59e97ed0fd3e5d6405de4401` and its recorded cloud image. ## Risks - The security correction changes the dependency closure and profile identity. Old sessions must reopen on the new profile. Exact identities and credential bindings fail closed. - The runner remains experimental and requires explicit selection. Legacy Pi Local is unchanged. Caller model IDs pass through; the E2E model is a fixture. - Accounting and the broad platform/provider matrix remain deferred. This merge does not publish a release or deploy a service. ## Model Used OpenAI GPT-6 through Codex assisted with reasoning, repository inspection, editing and tool use. The exact serving ID and context window are not exposed in this session. Final live qualification uses Pi 1.0.0 with `openrouter/anthropic/claude-sonnet-4.6` and native-confirmed low thinking. ## 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 #` 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>
298 lines
16 KiB
Markdown
298 lines
16 KiB
Markdown
# PRP Compatibility and Versioning Policy
|
|
|
|
## Authority
|
|
|
|
The JSON Schema files in [`protocol/schemas/`](../protocol/schemas/) are the
|
|
language-neutral source of truth for the Replay and Local runner executable contract. The
|
|
generated TypeScript schema module is checked against those files before every
|
|
TypeScript typecheck. Rust consumes the same fixtures and must produce the same
|
|
golden parity summaries.
|
|
|
|
The reviewable architecture and trust boundaries are defined in
|
|
[`architecture.md`](./architecture.md); durable transport and recovery behavior
|
|
is defined in [`durable-recovery.md`](./durable-recovery.md). Local runner reuses
|
|
the protocol contract for local live events. It adds package-local stdio and
|
|
stream envelopes, but it does not add durable transport, persistence, or
|
|
production control-plane behavior.
|
|
|
|
## Version fields
|
|
|
|
| Field | Replay support | Compatibility rule |
|
|
|---|---:|---|
|
|
| `protocolVersion` | `1` | Required. Negotiate the highest overlapping version; no overlap fails closed. |
|
|
| `fixtureVersion` | `1` | Required by the conformance corpus. Unknown values fail closed. |
|
|
| `event.schemaVersion` | `1` | Required on every event. Unknown values fail closed before reduction. |
|
|
| `capabilities.semanticTools.schemaVersion` | `1` | Optional advertisement. When present, an unknown required version fails closed. |
|
|
| `payload.semantic_tool.schemaVersion` | `1` | Optional on paired semantic tool input/result events. When present, an unknown required version fails closed. |
|
|
| `terminal.stopReason.schemaVersion` | `1` | Optional budget/cost receipt. When present, an unknown required version fails closed. |
|
|
| Typed `schema` discriminators | `*.v1` | Required. Unknown required schema identities fail JSON Schema validation. |
|
|
|
|
Wire protocol versions and fixture-corpus versions are independent. A fixture
|
|
format can evolve without changing PRP, and a future PRP version can be
|
|
represented only after the consumer advertises support for it.
|
|
|
|
## Forward compatibility
|
|
|
|
- Unknown object properties are accepted and preserved by validation. Reducers
|
|
ignore fields they do not understand until a later schema version gives those
|
|
fields defined behavior.
|
|
- Unknown required versions, schema discriminators, enum values, and required
|
|
fields fail closed. A consumer must never guess at their semantics.
|
|
- Scripted fixtures bind every event to the fixture run/session, require
|
|
contiguous controller command order, exactly one unique proposed result, and
|
|
exactly one unique terminal event.
|
|
- The top-level fixture result must equal the `run.result.proposed` payload after
|
|
canonical key ordering. Repeated `sourceEventId` deliveries must be
|
|
byte-equivalent after the same normalization.
|
|
|
|
The forward-compatibility fixture proves that optional fields survive validation
|
|
without changing the v1 snapshot. The unsupported-version fixture proves that a
|
|
required v2 protocol cannot be replayed by this consumer.
|
|
|
|
## Within-turn checklist snapshots
|
|
|
|
`plan.updated` / `paperclip.plan.updated.v1` is a complete, ordered snapshot of
|
|
the provider's checklist for one active turn. It is not a Paperclip Plan
|
|
document and must never be inferred from assistant prose, Codex proposed-plan
|
|
items, or generic TodoWrite output. Every replacement uses the provider turn ID
|
|
as `planId`; PRP `sourceSeq`, not an optional provider revision, determines
|
|
snapshot order. An empty step array clears the checklist, and `complete` is true
|
|
only when a non-empty snapshot contains only `completed` steps. The legacy
|
|
document-coupling fields are always `syncStatus: "not_applicable"` and
|
|
`documentRevision: null`.
|
|
|
|
| Qualified adapter profile | Checklist support |
|
|
|---|---|
|
|
| Direct Codex App Server | `turn/plan/updated` |
|
|
| ACPX Codex | Structured ACP `plan` entries |
|
|
| ACPX Claude | Structured ACP `plan` entries |
|
|
| ACPX Pi | Unavailable; no production-qualified profile is exposed |
|
|
| OpenCode | Unsupported until it exposes a structured plan event |
|
|
|
|
Codex `turn/diff/updated` is normalized separately as the latest same-turn
|
|
`workspace.change.updated` snapshot. Together these two independent event
|
|
families can drive a turn-status UI without changing the public PRP family or
|
|
adding a control-plane endpoint.
|
|
|
|
## Provider-neutral semantic receipts
|
|
|
|
- `capabilities.semanticTools` advertises stable operation IDs, availability,
|
|
required claims, and redaction disposition without naming a provider API.
|
|
- `mcp_app.tool_input` and `mcp_app.tool_result` may carry paired
|
|
`semantic_tool` envelopes. Correlation IDs must match the containing event;
|
|
operation ID and idempotency key must match across the pair.
|
|
- Content is represented by a canonical SHA-256 digest plus allowlisted typed
|
|
references. Raw credentials, provider payloads, and hidden identifiers do not
|
|
belong on the wire.
|
|
- Result receipts distinguish success, denial, conflict, exact duplicate,
|
|
unavailable, and failure. They can name the authorization boundary, safe
|
|
revision, artifact/work-product refs, immutable governed targets, and bounded
|
|
wake/monitor causality.
|
|
- `terminal.stopReason` records budget/cost kind, stable code, retryability,
|
|
limit class, safe aggregate, and decision receipt.
|
|
|
|
These fields are trace evidence only. The v1 reducer ignores `semantic_tool`
|
|
payloads, so adding or extending the optional envelope has no projection
|
|
effect. Eval `trace_completeness` treats PRP wire receipts as authoritative when
|
|
present and retains the pre-existing scalar fallback for live evidence that has
|
|
not yet emitted them.
|
|
|
|
## Provider-neutral structured input
|
|
|
|
Harness-initiated forms cross PRP as `paperclip.runtime_request.v2` with
|
|
`requestKind: "runtime"`, `type: "input"`, and an embedded
|
|
`paperclip.question_set.v1`. A submission is always
|
|
`{ "action": "submit", "response": paperclip.question_response.v1 }`.
|
|
Codex answer objects, OpenCode answer arrays, and ACP typed content exist only
|
|
inside their adapters; `origin` may retain the provider method and adapter name
|
|
for diagnostics but never provider response data.
|
|
|
|
Text-mode questions may include `initialText` (at most 100,000 Unicode code points,
|
|
within the existing 196 KiB question-set bound). It supplies an editable starting
|
|
draft, including empty text and whitespace. ACP plain-string `default` values map
|
|
without trimming; numeric defaults become editable numeric text. Select questions
|
|
do not accept this field. The UI preserves saved drafts and existing responses
|
|
ahead of provider defaults. Initial text never submits or resolves a request:
|
|
the operator must explicitly submit, and all existing response validation still
|
|
applies. Canonical text answers retain submitted whitespace and literal escape
|
|
sequences; legacy and select custom answers retain their existing normalization.
|
|
JSON Schema, TypeScript and Rust count draft Unicode code points alike. Existing
|
|
submitted-answer limits still count UTF-16 code units; a draft can require editing
|
|
before it satisfies those limits or field-specific constraints. Required blank
|
|
answers remain invalid. Redaction, company scope and durable
|
|
replay rules remain in force.
|
|
|
|
Question and option order is significant, while answers are keyed by stable
|
|
question IDs and selections reference stable option IDs. The canonical modes
|
|
are `text`, `single_select`, and `multi_select`. Text validation is repeated at
|
|
the untrusted server edge and again against the persisted question set before a
|
|
provider receives the translated response.
|
|
|
|
Every harness adapter must add a
|
|
`paperclip.question_adapter_fixture.v1` fixture proving its native request
|
|
normalizes to the canonical shape and its canonical response can be translated
|
|
back. The shared fixture format deliberately contains both native and canonical
|
|
objects so adding a provider does not change PRP or the UI contract.
|
|
|
|
V1 runtime requests and their legacy resolutions remain accepted during the
|
|
migration. A request that contains no structured form stays on the legacy path;
|
|
once a provider supplies a form, malformed or unsupported fields fail closed
|
|
instead of silently degrading. ACPX sidecars advertise only form elicitation
|
|
and use sidecar protocol v2 `runtime.input_requested` / `input.resolve` frames.
|
|
|
|
The live lifecycle pauses and resumes the same provider turn. If the provider
|
|
process is lost first, Paperclip emits one non-replayable
|
|
`runtime_request.expired` fact and materializes an idempotent durable
|
|
`ask_user_questions` interaction using the identical question set. Explicit
|
|
cancellation and already-resolved requests never create that fallback.
|
|
|
|
## Native execution permission compatibility
|
|
|
|
`paperclip.native-execution-input.v4` pins the effective harness permission
|
|
policy in the closed provider configuration: `approvalPolicy` for Codex and
|
|
`permissionMode` for OpenCode and ACPX. The pinned value participates in
|
|
provider-session identity, so an incompatible idle or recovered session is
|
|
replaced on the next execution. An active turn is never mutated in place.
|
|
|
|
`paperclip.native-execution-input.v5` is the current input format. It retains
|
|
the v4 permission pinning and adds optional completion-source references;
|
|
`paperclip.native-model-envelope.v3` is the corresponding explicit model
|
|
projection. Readers continue to accept persisted v1-v4 inputs, and v5 readers
|
|
must preserve the historical behavior of inputs that do not carry the new
|
|
optional fields. Missing Codex and OpenCode policy fields retain their
|
|
historical effective behavior. Legacy ACPX `permissionPolicy: "interactive"`
|
|
is interpreted as `approve-reads`, while new v4 and v5 ACPX executions default
|
|
to `approve-all` at the server boundary.
|
|
|
|
When a healthy provider session is resumed, its persisted v4 or v5 input format
|
|
is retained even if the newly built input uses the other format. This avoids
|
|
rotating an active session for a presentation-only schema change. A safe
|
|
rollback from v5 to v4 removes only the optional completion-source references;
|
|
it retains the task, contract, provider, workspace, and permission fields.
|
|
Format changes still go through the normal provider-session identity checks,
|
|
and an active turn is never mutated in place.
|
|
|
|
See [Adding a harness](adding-a-harness.md) for the permission catalog,
|
|
isolation rules, and provider conformance requirements.
|
|
|
|
Seven conformance fixtures cover artifact success, redacted denial without
|
|
fallback, stale conflict plus duplicate retry, governed target and continuation
|
|
causality, budget/cost stop, unknown optional fields, and rejection of an
|
|
unknown required version. The six accepted fixtures have shared TypeScript and
|
|
Rust golden parity summaries.
|
|
|
|
## Replay semantics
|
|
|
|
- Events are applied in fixture order and ordered independently by
|
|
`(sourceKind, sourceInstanceId, sourceSeq)`.
|
|
- A repeated source event ID has no second projection effect.
|
|
- A forward source-sequence gap is recorded explicitly; the reducer never
|
|
invents a missing event.
|
|
- An event at or behind the committed source cursor is ignored and recorded as
|
|
out of order.
|
|
- Replaying an already-applied batch leaves the snapshot unchanged.
|
|
|
|
The CLI and browser import the same `replayReplayFixtureText` function, so
|
|
validation, compatibility errors, and final snapshots cannot drift between the
|
|
two surfaces.
|
|
|
|
## Local envelope rules
|
|
|
|
- Mock-core commands use `paperclip.prp.command.v1` over stdin JSONL.
|
|
- Runner output uses `paperclip.runner.stream.v1` over stdout JSONL.
|
|
- Fake-harness commands use `paperclip.fake_harness.command.v1`.
|
|
- Fake-harness output uses `paperclip.fake_harness.message.v1`.
|
|
- An equivalent repeated `commandId` returns a duplicate receipt and has no
|
|
second driver effect. Reuse with different data is rejected.
|
|
- A new command must use the next contiguous `controllerSeq`.
|
|
- Harness logs are bounded diagnostic data. They are not canonical PRP events.
|
|
- `run.result.proposed`, `harness.exited`, and `run.terminal` are separate facts
|
|
and appear in that order when a semantic result exists.
|
|
- The live browser rejects an event with an invalid schema, run ID, or session
|
|
ID before it reaches the reducer.
|
|
|
|
These envelopes are local Local runner implementation contracts.
|
|
|
|
## Durable wire rules
|
|
|
|
- The runner opens loopback `ws://` or hostname-verified `wss://`, or accepts a
|
|
preview-proxy connection on its fixed listener, and completes the PRP v1
|
|
authenticated handshake before any command result or event.
|
|
- A one-use bootstrap bearer capability returns a short-lived connection lease
|
|
in `welcome`. Later connections use that lease. Neither raw capability is
|
|
durable state.
|
|
- `welcome.payload.connectionLeaseRenewalVersion: 1` opts into authenticated
|
|
`lease_renew` / `lease_renewed` control frames. Renewal extends the persisted
|
|
expiry on the same live authority without restarting provider work. Identity,
|
|
protocol, and revocation epoch remain fixed; expired or revoked leases cannot
|
|
renew. See [durable recovery](durable-recovery.md#execution-duration-and-operation-deadlines)
|
|
for retry and warm-handoff rules. Peers lacking this capability retain their
|
|
original lease expiry.
|
|
- `hello.resume` reports the last processed controller sequence, next source
|
|
sequence, cumulative ACK cursor, and current unacknowledged range.
|
|
- `welcome` selects the one overlapping protocol version, returns the core's
|
|
cumulative ACK cursor, and carries at most one durable pending command.
|
|
- An event is durable before send. Event IDs and source sequences stay stable
|
|
across replay and process restart.
|
|
- An ACK is cumulative. The runner rejects a cursor behind its durable ACK or
|
|
beyond its produced source cursor.
|
|
- An equal repeated command ID and canonical digest returns its stored result.
|
|
Reuse with different bytes fails closed and cannot repeat an effect.
|
|
- Frames are bounded at 1 MiB and upgrade headers at 16 KiB. Unknown or invalid
|
|
required protocol data fails closed; malformed JSON is a bounded diagnostic.
|
|
|
|
Runnerd build-metadata contract v2 advertises the exact transport inventory:
|
|
`dial_ws_loopback`, `dial_wss`, and `listen_ws`. Plaintext dial destinations
|
|
must resolve entirely to loopback. Public dial targets require TLS trust and
|
|
hostname validation; a private CA bundle augments the platform roots and must
|
|
be a bounded, private, regular file. Listener mode binds to `0.0.0.0` and a
|
|
single run-bound path. The optional `--listen-port` selects a port in
|
|
`1..=65535` and defaults to `43127`. Warm attachments retain the existing
|
|
listening port. All modes retain the same message/frame bounds and PRP authentication.
|
|
|
|
These are package-local Durable recovery and transport rules. Control-plane
|
|
admission and deployment policy remain separately reviewed work.
|
|
|
|
## Change policy
|
|
|
|
1. Change JSON Schema first.
|
|
2. Regenerate the TypeScript schema module.
|
|
3. Add or revise a shared fixture and its golden snapshot/summary.
|
|
4. Prove TypeScript and Rust parity.
|
|
5. Update this policy and the normative spike specification when behavior
|
|
changes.
|
|
|
|
Breaking changes require a new required version. Additive optional fields may
|
|
remain in v1 only when old consumers can safely ignore them.
|
|
|
|
## Package-level compatibility
|
|
|
|
PRP is one independently versioned component of the runner bundle. Catalog,
|
|
runner-client, control-plane-adapter, testkit, and eval-corpus compatibility is
|
|
declared by `PAPERCLIP_RUNNER_COMPATIBILITY` and checked before execution by
|
|
`assertPaperclipRunnerCompatibility`. A mismatch fails with
|
|
`paperclip_runner_incompatible` and stable per-issue codes; a provider-specific
|
|
tool error is not a compatibility negotiation mechanism.
|
|
|
|
See [ADR 0001](adr/0001-runner-testing-eval-package-boundaries.md) for the
|
|
component rules and clean-consumer packaging gate.
|
|
|
|
## Evals integration negotiation
|
|
|
|
The packed `./evals` entry point adds a stricter execution preflight for the
|
|
App/Evals join. `assertPaperclipRunnerEvalCompatibility` requires simultaneous
|
|
agreement on package semver, runnerd build metadata, a common PRP version,
|
|
semantic catalog version and SHA-256 digest, harness-driver contract and
|
|
required capabilities, and the native-execution version. It reports
|
|
`paperclip_runner_eval_incompatible` with expected/received values for every
|
|
mismatch and must run before launching a provider.
|
|
|
|
runnerd itself reports `paperclip-runner/runnerd-build-metadata/v1` from
|
|
`--build-metadata`. The consumer passes its path and expected content digest to
|
|
`resolvePaperclipRunnerdArtifact`; implicit PATH or source-tree discovery is
|
|
not part of the contract. Native attempt output is
|
|
`paperclip-runner/native-execution/v1`, whose parser accepts unknown additive
|
|
fields but rejects unknown required versions and inconsistent terminal,
|
|
semantic-denial, usage, or transcript facts. Full fields and the deterministic
|
|
gate are exercised by the package-local deterministic conformance suite.
|