From 486069e369d8c0ea4d0427bcaadeb8e51c8e8187 Mon Sep 17 00:00:00 2001 From: Dotta Date: Fri, 7 Aug 2026 23:37:40 +0000 Subject: [PATCH] docs(runner): record Phase 3 recovery evidence Co-Authored-By: Paperclip --- packages/paperclip-runner/README.md | 22 +- .../paperclip-runner/docs/architecture.md | 27 + packages/paperclip-runner/docs/index.md | 5 +- .../docs/phase-03-durable-transport.md | 203 +++++ .../docs/protocol-compatibility.md | 27 +- .../docs/tutorials/end-to-end.md | 25 +- .../docs/tutorials/phase-03-break-recovery.md | 194 +++++ .../2026-08-07-phase-03-verification.md | 78 ++ .../knowledge/evidence/index.md | 1 + .../evidence/phase-03-fault-matrix.json | 423 +++++++++++ .../evidence/phase-03-faults/drain.json | 399 ++++++++++ .../phase-03-faults/duplicate-command.json | 561 ++++++++++++++ .../phase-03-faults/harness-restart.json | 704 ++++++++++++++++++ .../phase-03-faults/lease-expiry.json | 603 +++++++++++++++ .../evidence/phase-03-faults/lost-ack.json | 561 ++++++++++++++ .../phase-03-faults/malformed-input.json | 561 ++++++++++++++ .../evidence/phase-03-faults/none.json | 559 ++++++++++++++ .../evidence/phase-03-faults/revoke.json | 528 +++++++++++++ .../phase-03-faults/runner-restart.json | 601 +++++++++++++++ .../evidence/phase-03-faults/socket-drop.json | 561 ++++++++++++++ .../phase-03-faults/storage-pressure.json | 443 +++++++++++ .../phase-03-recovery-diagnostics.png | Bin 0 -> 69766 bytes .../evidence/phase-03-recovery-trace.json | 561 ++++++++++++++ .../knowledge/journal/2026-08-07-phase-03.md | 69 ++ .../knowledge/journal/index.md | 1 + packages/paperclip-runner/knowledge/log.md | 1 + ...rclip-native-runner-implementation-plan.md | 2 +- .../paperclip-native-runner-spike-spec.md | 2 +- 28 files changed, 7701 insertions(+), 21 deletions(-) create mode 100644 packages/paperclip-runner/docs/phase-03-durable-transport.md create mode 100644 packages/paperclip-runner/docs/tutorials/phase-03-break-recovery.md create mode 100644 packages/paperclip-runner/knowledge/evidence/2026-08-07-phase-03-verification.md create mode 100644 packages/paperclip-runner/knowledge/evidence/phase-03-fault-matrix.json create mode 100644 packages/paperclip-runner/knowledge/evidence/phase-03-faults/drain.json create mode 100644 packages/paperclip-runner/knowledge/evidence/phase-03-faults/duplicate-command.json create mode 100644 packages/paperclip-runner/knowledge/evidence/phase-03-faults/harness-restart.json create mode 100644 packages/paperclip-runner/knowledge/evidence/phase-03-faults/lease-expiry.json create mode 100644 packages/paperclip-runner/knowledge/evidence/phase-03-faults/lost-ack.json create mode 100644 packages/paperclip-runner/knowledge/evidence/phase-03-faults/malformed-input.json create mode 100644 packages/paperclip-runner/knowledge/evidence/phase-03-faults/none.json create mode 100644 packages/paperclip-runner/knowledge/evidence/phase-03-faults/revoke.json create mode 100644 packages/paperclip-runner/knowledge/evidence/phase-03-faults/runner-restart.json create mode 100644 packages/paperclip-runner/knowledge/evidence/phase-03-faults/socket-drop.json create mode 100644 packages/paperclip-runner/knowledge/evidence/phase-03-faults/storage-pressure.json create mode 100644 packages/paperclip-runner/knowledge/evidence/phase-03-recovery-diagnostics.png create mode 100644 packages/paperclip-runner/knowledge/evidence/phase-03-recovery-trace.json create mode 100644 packages/paperclip-runner/knowledge/journal/2026-08-07-phase-03.md diff --git a/packages/paperclip-runner/README.md b/packages/paperclip-runner/README.md index 16d1a901f85..2eca4573895 100644 --- a/packages/paperclip-runner/README.md +++ b/packages/paperclip-runner/README.md @@ -8,10 +8,12 @@ Phase 0 runs both implementations against one language-neutral fixture. Phase 1 adds executable PRP schemas, a cross-language conformance corpus, deterministic static replay, and a standalone browser reference page. Phase 2 adds the Rust runner process, process-group supervision, a scripted fake harness over stdio -JSONL, a TypeScript mock core, and validated live browser replay. These phases do -not import or start Paperclip's server, UI, CLI, or production database. +JSONL, a TypeScript mock core, and validated live browser replay. Phase 3 adds +the Rust outbound WebSocket client, private durable state, replay and restart +recovery, and safe CLI/browser diagnostics. These phases do not import or start +Paperclip's server, UI, CLI, or production database. -## Phase 0–2 quick start +## Phase 0–3 quick start From the repository root: @@ -49,6 +51,7 @@ devtool: ```sh pnpm --filter @paperclipai/paperclip-runner replay:phase1 pnpm --filter @paperclipai/paperclip-runner trace:phase2 -- --scenario happy-path +pnpm --filter @paperclipai/paperclip-runner trace:phase3 -- --fault lost-ack pnpm --filter @paperclipai/paperclip-runner browser:dev --host 127.0.0.1 --port 4179 ``` @@ -68,12 +71,13 @@ pnpm --filter @paperclipai/paperclip-runner browser:dev --host 127.0.0.1 --port | `trace:phase0` | Run the Rust mock-core tracer, print the stable result, and exit. | | `trace:phase0:typescript` | Run the TypeScript reference tracer directly. | | `replay:phase1` | Validate and reduce a fixture to a final snapshot. | -| `browser:dev` | Open the editable fixture/static replay reference page. | | `trace:phase2` | Run one native local session through the Rust runner and fake harness. | | `record:phase2` | Capture a validated happy-path live trace as a replay fixture. | -| `browser:dev` | Start the standalone live/replay browser devtool. | +| `trace:phase3` | Run the Rust runner against the mock core with a selected recovery fault. | +| `record:phase3` | Regenerate the complete Phase 3 fault matrix and exact per-fault traces. | +| `browser:dev` | Start the standalone live/replay/recovery browser devtool. | | `test:browser` | Exercise static replay and live scenarios, then capture temporary screenshots under ignored test output. | -| `verify` | Run the complete Phase 0, Phase 1, and Phase 2 acceptance sequence. | +| `verify` | Run the complete Phase 0 through Phase 3 acceptance sequence. | | `verify:rootless` | Extract Debian/Ubuntu browser libraries without root, then run `verify`. | ## Navigate @@ -84,6 +88,8 @@ pnpm --filter @paperclipai/paperclip-runner browser:dev --host 127.0.0.1 --port - [Phase 1 hand-run tutorial](docs/tutorials/phase-01-static-replay.md) - [Phase 2 hand-run tutorial](docs/tutorials/phase-02-local-runner.md) - [Phase 2 local protocol reference](docs/phase-02-local-protocol.md) +- [Phase 3 break-it-on-purpose tutorial](docs/tutorials/phase-03-break-recovery.md) +- [Phase 3 durable transport reference](docs/phase-03-durable-transport.md) - [PRP compatibility/versioning policy](docs/protocol-compatibility.md) - [Cumulative end-to-end tutorial](docs/tutorials/end-to-end.md) - [Journal guide](docs/journal.md) @@ -91,6 +97,4 @@ pnpm --filter @paperclipai/paperclip-runner browser:dev --host 127.0.0.1 --port - [Implementation plan](spec/paperclip-native-runner-implementation-plan.md) - [Normative spike specification](spec/paperclip-native-runner-spike-spec.md) -Phase 2 is local and deterministic. It does not add durable network transport, -reconnect, production Paperclip integration, or a real model harness. Those -capabilities remain behind later checkpoints in the implementation plan. +Phase 3 adds package-local durable network recovery. Production Paperclip integration and a real model harness remain deferred. diff --git a/packages/paperclip-runner/docs/architecture.md b/packages/paperclip-runner/docs/architecture.md index fc98bb968d2..e273a3b6de5 100644 --- a/packages/paperclip-runner/docs/architecture.md +++ b/packages/paperclip-runner/docs/architecture.md @@ -169,6 +169,33 @@ Every browser event passes `validatePrpEvent` and `applyPrpEvent`. When the run ends, the browser reduces the complete event list again and compares the replay snapshot with the live snapshot. +## Phase 3 durable transport boundary + +```text +TypeScript mock core + | one-time ticket -> short-lived connection lease + | PRP v1 hello/welcome, commands, events, cumulative ACKs + v +paperclip-runnerd (Rust WebSocket client) + | atomic private JSON state + +-- durable outbox and processed-command cache + +-- stable runner/session/turn/item identities + +-- Phase 2 fake-harness process for restart proof +``` + +The runner initiates the loopback WebSocket. The bootstrap ticket is present +only in the runner process environment. The returned connection-lease token is +kept only in runner memory. The mock core stores SHA-256 digests of capabilities +and the runner state stores neither capability. The runner writes each event and +command result before network delivery, then removes outbox events only after a +valid cumulative ACK. + +The TypeScript peer is a package-local test controller, not production +Paperclip. It injects lost ACKs, socket loss, malformed input, process restarts, +lease expiry, storage pressure, drain, and revoke. The browser recovery page +calls that peer through guarded package-local Vite middleware and renders only +safe trace fields. + ## Future integration rule The [implementation plan](../spec/paperclip-native-runner-implementation-plan.md) diff --git a/packages/paperclip-runner/docs/index.md b/packages/paperclip-runner/docs/index.md index de11c505218..07074a0b531 100644 --- a/packages/paperclip-runner/docs/index.md +++ b/packages/paperclip-runner/docs/index.md @@ -8,6 +8,7 @@ Each tutorial starts with an explanation of what the phase is and what the phase - [Phase 0: standalone tracer](tutorials/phase-00-standalone-tracer.md) — install the workspace, validate its Rust/TypeScript boundary and knowledge bundle, then run the deterministic Rust mock-core path and cross-language parity check. - [Phase 1: static PRP replay](tutorials/phase-01-static-replay.md) — validate the shared schema/fixture corpus, reduce a fixture in the CLI, and inspect the same final snapshot in the standalone browser page. - [Phase 2: local runner and fake harness](tutorials/phase-02-local-runner.md) — run a supervised Rust process, exercise scripted live scenarios, resolve requests, interrupt a turn, and confirm live/replay parity. +- [Phase 3: break recovery on purpose](tutorials/phase-03-break-recovery.md) — lose an ACK, drop the socket, restart the runner side, replay durable events, and inspect recovery diagnostics. - [Cumulative end-to-end tutorial](tutorials/end-to-end.md) — the shortest complete workflow available at the current phase. ## Reference @@ -15,9 +16,9 @@ Each tutorial starts with an explanation of what the phase is and what the phase - [Architecture and dependency boundary](architecture.md) - [PRP compatibility and versioning policy](protocol-compatibility.md) - [Phase 2 local protocol and supervision](phase-02-local-protocol.md) +- [Phase 3 durable transport and recovery](phase-03-durable-transport.md) - [Engineering journal guide](journal.md) - [Dated shadcn/ui and AI Elements compatibility note](research/2026-08-07-ui-library-compatibility.md) - [Package README](../README.md) -Phase 2 is implemented and ready for its human checkpoint. Later tutorials are -added only after their phase is authorized and implemented. +Phase 3 is implemented and ready for its review and human checkpoint. Later tutorials remain deferred. diff --git a/packages/paperclip-runner/docs/phase-03-durable-transport.md b/packages/paperclip-runner/docs/phase-03-durable-transport.md new file mode 100644 index 00000000000..1c2434b0f1d --- /dev/null +++ b/packages/paperclip-runner/docs/phase-03-durable-transport.md @@ -0,0 +1,203 @@ +# Phase 3 Durable Transport and Recovery + +Phase 3 adds a real outbound WebSocket path to the standalone package. The +Rust `paperclip-runnerd` process is the client. The TypeScript mock core is the +remote peer. Neither side imports Paperclip server, UI, database, or shared +control-plane code. + +This is a local reliability proof. The mock uses `ws://127.0.0.1` so tests do +not need certificates. A production bridge must use `wss://` and remains a +later, separately reviewed phase. + +## Connection and authentication + +The connection starts in this order: + +1. The mock core creates a random bootstrap ticket with a five-second lifetime. +2. The ticket is passed to the runner through + `PAPERCLIP_RUNNER_BOOTSTRAP_TICKET`. It is not a command-line argument. +3. The runner opens an outbound WebSocket and sends the ticket in the HTTP + `Authorization` header. +4. The runner sends a PRP v1 `hello` envelope. It names the stable runner and + environment lease, approved runner version and digest, platform, + capabilities, and durable resume cursors. +5. The mock core consumes the ticket once and sends a `welcome` envelope. The + welcome selects PRP v1, returns a short-lived connection lease, reports the + cumulative committed event cursor, and carries at most one pending command. +6. Later connections authenticate with the connection lease. A real runner + process restart receives a new one-time bootstrap ticket and loads the same + durable state before it connects. + +The runner keeps the live connection lease token in memory only. Its state file +does not contain the bootstrap ticket or connection lease token. The mock core +persists only SHA-256 digests of those capabilities. A used or expired ticket is +rejected with `401`. The mock also rejects a changed runner identity, environment +lease, runner version, or runner digest. + +The daemon captures and removes the bootstrap environment variable before it +parses arguments or starts child work. Secret buffers are overwritten when they +are dropped. It resolves the destination once before sending a bearer value and +accepts only concrete loopback addresses. Userinfo, query strings, fragments, +wildcards, private-network addresses, public addresses, and mixed DNS answers +fail closed. + +## WebSocket limits + +The package client implements the RFC 6455 upgrade and masked client text +frames with Node-free Rust standard-library code. The mock core validates the +upgrade and parses bounded masked frames. + +- Maximum HTTP upgrade headers: 16 KiB. +- Maximum PRP frame: 1 MiB. +- Unknown frame opcodes and unmasked client frames close the connection. +- Malformed JSON is recorded as a bounded diagnostic. Durable state remains + available for reconnect. +- WebSocket ping/pong and PRP diagnostic pong state are supported. + +## Durable runner state + +The runner writes `runner-state.json` below its private state directory. The +directory uses mode `0700` and the file uses mode `0600` on Unix. Every update +is written to an exclusive unpredictable sibling file, synchronized, atomically +renamed, and followed by a parent-directory sync. Symlinked directories or state +files, wrong ownership, and wrong modes fail closed. + +The state contains: + +- stable runner, environment lease, run, session, turn, and item IDs; +- next source event sequence and cumulative acknowledged source sequence; +- unacknowledged event envelopes and their byte counts; +- a processed-command cache with a non-secret command digest and prior result; +- lifecycle, reconnect, backpressure, harness generation, and recovery facts; +- bounded, redacted diagnostics. + +Authentication capabilities and arbitrary command bodies are not stored. A +command is represented by an FNV-1a comparison digest, its stable ID and +controller sequence, the redacted result, and the logical-effect count. + +## Event delivery and ACKs + +The runner writes an event to the outbox before it sends the event. Event IDs +and source sequence numbers do not change after reconnect or restart. + +The mock core commits or deduplicates an event before it sends this cumulative +ACK: + +```json +{ + "kind": "ack", + "payload": { "ackedSourceSeq": 9 } +} +``` + +The ACK means that every source event through sequence 9 is committed or +deduplicated. The runner rejects an ACK that moves backward or beyond its +produced source cursor. It removes only events at or below a valid ACK. + +For the lost-ACK fault, the mock commits an event, drops the ACK and socket, and +reports the prior cursor once after reconnect. The runner sends the same bytes +again. The mock increments delivery count, keeps one logical event, and sends +the committed cumulative ACK. + +## Command delivery and effects + +Mock-core commands are durable before delivery. Only the lowest pending +controller sequence is sent. A command result advances the queue. + +The runner stores a command result before it sends the result. When a result or +socket is lost, the same command is delivered again. An equal command ID and +digest returns the stored result. It does not add events or repeat a process +effect. Reusing the ID with different bytes is rejected. + +The trace records `logicalEffectCount`. Every completed command has exactly one +logical effect. A policy rejection, such as a new turn during drain or storage +pressure, has zero effects. + +## Restart and reconciliation + +A socket drop keeps the same Rust process and in-memory lease. The process +reconnects and reloads the mock-core command and event cursor. + +A runner restart kills the real Rust process with unacknowledged work. A new +Rust process receives a fresh ticket, reads the same state file, emits a P0 +`runner.reconciled` event, and continues the same runner, session, turn, item, +command, and source-event identities. + +The harness-restart fault starts the real Phase 2 `fake-harness` child, waits +for its ready message, terminates its process group, and starts a second child. +The runner then emits `harness.exited`, `harness.ready`, and +`session.reconciled` events with the same normalized session, turn, and item +IDs. + +If a lease expires, reconnect fails closed. The runner records +`lease_expired_requires_bootstrap` and exits with its state intact. The mock +then gives the replacement runner a fresh ticket. Recovery continues from the +same cursor. + +If recovery cannot be truthful, state names the outcome. For example, failure +to reserve storage for a P0 event records `p0_storage_exhausted` and the +`unrecoverable` lifecycle. It never reports a fresh session as resumed. + +## Backpressure and bounded storage + +The runner has a byte limit and a reserved P0 region. + +- P2 item deltas coalesce before delivery. +- P1 events cannot consume the P0 reserve. +- New turns are rejected while backpressure is active. +- A P0 `runner.backpressure` event explains the state. +- P0 events are never dropped to make room. +- The state records peak outbox bytes so the final empty outbox does not hide a + limit violation. + +The storage-pressure trace emits 250 P2 updates. They become one coalesced +event, all P0 facts reach the mock core, peak bytes remain below the configured +limit, and the next turn is rejected without an effect. + +## Drain and revoke + +`runner.drain` persists the `draining` lifecycle and a P0 +`runner.draining` event. It rejects later `turn.start` commands but continues to +deliver the existing outbox. `runner.shutdown` stops only after the outbox is +acknowledged. + +A `revoke` envelope persists the `revoked` lifecycle. The runner flushes any +existing durable events and exits. It does not accept new work or delete +unacknowledged facts. + +## Diagnostics + +Run a fault and print operator-safe diagnostics: + +```sh +pnpm --filter @paperclipai/paperclip-runner trace:phase3 -- --fault lost-ack +``` + +Supported fault names are: + +```text +none +socket-drop +lost-ack +duplicate-command +runner-restart +harness-restart +malformed-input +lease-expiry +storage-pressure +drain +revoke +``` + +Use `--json` for the complete trace or `--output ` to write it. The CLI +and browser show connection counts, safe lease ID and expiry, stable identities, +source and ACK cursors, outbox current/peak bytes, command delivery/effect +counts, replay counts, restart counts, outcomes, and redaction assertions. + +They never show bootstrap tickets or connection lease tokens. + +Regenerate the checked fault matrix and every exact per-fault trace with: + +```sh +pnpm --filter @paperclipai/paperclip-runner record:phase3 +``` diff --git a/packages/paperclip-runner/docs/protocol-compatibility.md b/packages/paperclip-runner/docs/protocol-compatibility.md index 60f7bc7f3ce..c2df62eb30f 100644 --- a/packages/paperclip-runner/docs/protocol-compatibility.md +++ b/packages/paperclip-runner/docs/protocol-compatibility.md @@ -75,9 +75,30 @@ two surfaces. - The live browser rejects an event with an invalid schema, run ID, or session ID before it reaches the reducer. -These envelopes are local Phase 2 implementation contracts. Phase 3 may add a -durable outbound transport, but it must preserve the canonical PRP event and -command semantics. +These envelopes are local Phase 2 implementation contracts. + +## Phase 3 durable wire rules + +- The runner opens an outbound WebSocket and sends PRP v1 `hello` 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. +- `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. + +These are package-local Phase 3 rules. Production TLS, control-plane admission, +and deployment policy remain separately reviewed work. ## Change policy diff --git a/packages/paperclip-runner/docs/tutorials/end-to-end.md b/packages/paperclip-runner/docs/tutorials/end-to-end.md index 71f31c090d5..11fb0d43126 100644 --- a/packages/paperclip-runner/docs/tutorials/end-to-end.md +++ b/packages/paperclip-runner/docs/tutorials/end-to-end.md @@ -2,16 +2,19 @@ ## What this tutorial is -This tutorial combines each implemented Native Runner phase into one procedure. It currently includes Phase 0, Phase 1, and Phase 2. +This tutorial combines each implemented Native Runner phase into one procedure. +It currently includes Phase 0 through Phase 3. ## What this tutorial proves This tutorial proves that the standalone package boundary, static replay path, -and local live-run path work together. It does not use Paperclip or a real model. +local live-run path, and durable recovery path work together. It does not use +Paperclip or a real model. The current system includes the Rust mock-core tracer, shared protocol fixtures, the Rust supervisor, a scripted fake harness, CLI live runs, and browser live and -replay modes. +replay modes. It also includes the Rust outbound WebSocket client, durable +outbox, package-local mock core, recovery CLI, and recovery browser view. ## Current end-to-end path @@ -32,6 +35,10 @@ replay modes. 12. Open the browser live mode and confirm the completed run says `Match` for live and replay output. 13. Open the [Phase 2 journal entry](../../knowledge/journal/2026-08-07-phase-02.md) and its linked verification evidence and screenshots. +14. Follow [Phase 3: Break Recovery on Purpose](phase-03-break-recovery.md). +15. Confirm that the recovered runner and session IDs stay the same. +16. Confirm that the outbox is empty after replay and cumulative acknowledgement. +17. Open the [Phase 3 journal entry](../../knowledge/journal/2026-08-07-phase-03.md). The one-command form after installation is: @@ -67,6 +74,14 @@ pnpm --filter @paperclipai/paperclip-runner verify:rootless - exactly one terminal event closes every completed local trace; - every live browser event passes the Phase 1 validator and reducer before display; - replaying the completed live event list produces the same final snapshot. +- a lost cumulative ACK replays the same durable event ID without a second + logical event; +- repeated commands return the stored result and cause one logical effect; +- runner and harness restarts preserve runner, session, turn, and item IDs; +- backpressure bounds local storage without dropping P0 events; +- lease expiry, drain, revoke, and unrecoverable storage outcomes are explicit; +- CLI and browser diagnostics do not expose bootstrap or connection-lease + tokens. -Phase 3 may extend this tutorial only after the Phase 2 human checkpoint is -accepted and the next phase is authorized. +Phase 4 remains uncreated until the Phase 3 review and human checkpoint are +complete. diff --git a/packages/paperclip-runner/docs/tutorials/phase-03-break-recovery.md b/packages/paperclip-runner/docs/tutorials/phase-03-break-recovery.md new file mode 100644 index 00000000000..6e062e33561 --- /dev/null +++ b/packages/paperclip-runner/docs/tutorials/phase-03-break-recovery.md @@ -0,0 +1,194 @@ +# Phase 3: Break It on Purpose + +## What this phase is + +Phase 3 adds a durable outbound WebSocket connection. + +The Rust runner connects to a package-local mock core. The runner stores events +before it sends them. It stores each command result before it replies. + +This phase does not use the Paperclip server, UI, database, or a real model. + +## What this phase proves + +This tutorial proves that a broken connection does not create a false new +session. + +You will drop a socket. You will lose an acknowledgement. You will restart the +real Rust runner process. You will also restart the real fake-harness child. + +Each test keeps the same runner, session, turn, item, command, and event IDs. +Repeated delivery causes one logical effect. P0 events are not lost. The +diagnostics do not show authentication secrets. + +## Before you start + +From the repository root, build the package binaries: + +```sh +pnpm --filter @paperclipai/paperclip-runner build:typescript +pnpm --filter @paperclipai/paperclip-runner build:phase2-binaries +``` + +The commands below use only loopback network access. They create temporary +state below the Paperclip run scratch directory when it is available. The CLI +removes that state after each successful proof. + +## Step 1: Drop the socket + +Run: + +```sh +pnpm --filter @paperclipai/paperclip-runner trace:phase3 -- --fault socket-drop +``` + +Confirm: + +- `Outcome: recovered` is shown. +- The connection count is at least 2. +- The runner ACK and core ACK are equal. +- Every assertion says `PASS`. + +## Step 2: Lose one ACK + +Run: + +```sh +pnpm --filter @paperclipai/paperclip-runner trace:phase3 -- --fault lost-ack +``` + +Confirm: + +- the output shows at least one replay delivery; +- the outbox ends with 0 pending events; +- `P0 lost 0` is shown; +- `PASS no duplicate logical events` is shown; +- the runner, session, turn, and item IDs are unchanged. + +The network may deliver one event more than once. The mock core keeps one +logical event and advances one cumulative cursor. + +## Step 3: Restart the Rust runner + +Run: + +```sh +pnpm --filter @paperclipai/paperclip-runner trace:phase3 -- --fault runner-restart +``` + +Confirm: + +- the output shows 1 runner restart; +- the output shows 2 fresh bootstraps; +- a replay delivery is present; +- every assertion says `PASS`. + +The test kills `paperclip-runnerd` while an event is unacknowledged. The next +process reads the same private state file. It emits `runner.reconciled` and +continues the same durable source cursor. + +## Step 4: Restart the fake harness + +Run: + +```sh +pnpm --filter @paperclipai/paperclip-runner trace:phase3 -- --fault harness-restart +``` + +Confirm: + +- the output shows 1 harness restart; +- `PASS stable identity` is shown; +- `PASS source cursor continuity` is shown. + +The test starts a real fake-harness child, stops its process group, and starts a +second child. The normalized session, turn, and item IDs do not change. + +## Step 5: Repeat a command + +Run: + +```sh +pnpm --filter @paperclipai/paperclip-runner trace:phase3 -- --fault duplicate-command +``` + +Confirm: + +- the output shows at least one duplicate command delivery; +- `PASS one logical effect per accepted command` is shown; +- `workspace.ready` exists one time in JSON output when you add `--json`. + +## Step 6: Apply storage pressure + +Run: + +```sh +pnpm --filter @paperclipai/paperclip-runner trace:phase3 -- --fault storage-pressure +``` + +Confirm: + +- backpressure is active in JSON output; +- peak storage is below the maximum; +- the next turn is rejected; +- `PASS P0 events preserved` is shown; +- `PASS bounded storage` is shown. + +## Step 7: Test lease expiry, drain, and revoke + +Run: + +```sh +pnpm --filter @paperclipai/paperclip-runner trace:phase3 -- --fault lease-expiry +pnpm --filter @paperclipai/paperclip-runner trace:phase3 -- --fault drain +pnpm --filter @paperclipai/paperclip-runner trace:phase3 -- --fault revoke +``` + +Confirm: + +- lease expiry uses a fresh bootstrap and resumes the same cursor; +- drain reports `Outcome: drained` and rejects new work; +- revoke reports `Outcome: revoked`; +- all three traces finish with an empty acknowledged outbox; +- every security assertion passes. + +## Step 8: Open the browser recovery view + +Run: + +```sh +pnpm --filter @paperclipai/paperclip-runner browser:dev --host 127.0.0.1 --port 4179 +``` + +Open `http://127.0.0.1:4179/`. Select **Recovery**. Select +**Run Phase 3 recovery**. + +Confirm: + +- recovery status becomes **complete**; +- connection, lease, outbox, ACK, replay, storage, and outcome fields appear; +- **Same runner and session** says **Preserved**; +- **Secrets redacted** says **Yes**; +- no bootstrap ticket or connection lease token appears. + +## Step 9: Run the package verification path + +Run: + +```sh +pnpm --filter @paperclipai/paperclip-runner verify +``` + +The verification path builds TypeScript, Rust, and the browser. It runs unit, +integration, browser, boundary, documentation, parity, and tracer checks for +Phases 0 through 3. + +## Evidence + +- [Phase 3 verification record](../../knowledge/evidence/2026-08-07-phase-03-verification.md) +- [Phase 3 recovery screenshot](../../knowledge/evidence/phase-03-recovery-diagnostics.png) +- [Phase 3 OKF journal entry](../../knowledge/journal/2026-08-07-phase-03.md) +- [Phase 3 transport reference](../phase-03-durable-transport.md) + +Phase 4 remains uncreated. A human must accept the Phase 3 checkpoint before +later work starts. diff --git a/packages/paperclip-runner/knowledge/evidence/2026-08-07-phase-03-verification.md b/packages/paperclip-runner/knowledge/evidence/2026-08-07-phase-03-verification.md new file mode 100644 index 00000000000..7c9638d7ec9 --- /dev/null +++ b/packages/paperclip-runner/knowledge/evidence/2026-08-07-phase-03-verification.md @@ -0,0 +1,78 @@ +--- +type: Verification Evidence +title: Phase 3 durable transport verification +description: Package-only evidence for lost-ACK replay, restart recovery, command deduplication, and redacted diagnostics. +tags: [native-runner, phase-3, websocket, recovery, evidence] +status: stable +generated: { by: openai/gpt-5, at: 2026-08-07T23:31:00Z } +--- + +# Scope + +This evidence covers the package-local mock core and runner transport. It does not use the Paperclip server or UI. + +# Required checks + +```sh +pnpm --filter @paperclipai/paperclip-runner typecheck +pnpm --filter @paperclipai/paperclip-runner test +pnpm --filter @paperclipai/paperclip-runner check:browser-tokens +pnpm --filter @paperclipai/paperclip-runner check:forbidden-imports +pnpm --filter @paperclipai/paperclip-runner docs:validate +pnpm --filter @paperclipai/paperclip-runner record:phase3 +pnpm --filter @paperclipai/paperclip-runner verify:rootless +``` + +# Acceptance mapping + +- The runner uses an outbound loopback WebSocket. +- A one-time bootstrap ticket creates a connection lease. +- A lost acknowledgement keeps one event in the durable outbox. +- A restarted runner loads the same identity and sends the event again. +- The mock core records one logical event and one duplicate delivery. +- The runner records one repeated command and one command effect. +- The terminal event uses the same runner and session IDs. +- Drain and revoke states are visible. +- CLI and browser diagnostics do not contain the ticket or lease token. + +# Recorded outputs + +- [CLI recovery trace](phase-03-recovery-trace.json) +- [Complete fault matrix](phase-03-fault-matrix.json) +- [Per-fault exact outputs](phase-03-faults/) +- [Browser recovery screenshot](phase-03-recovery-diagnostics.png), 1440 by + 1000 pixels, SHA-256 + `2c79ea7a9834943ee9dc3dfc6a5c4eb9359518cf773882dc75882031710f84d0`. + +# Local verification result + +- TypeScript tests: 61 passed. +- Rust tests: 34 passed, including fourteen Phase 3 transport, storage, + deduplication, secret-lifecycle, destination, and state-file tests. +- Focused Phase 3 and browser-middleware tests: 21 passed. +- Phase 3 fault tests: 14 passed, including one-time ticket reuse rejection, + cross-runner credential rejection, and symlink-safe mock-core state. +- Browser tests: 7 passed with the rootless Linux library path. +- TypeScript, Rust, and browser typechecks passed. +- Browser token, package boundary, documentation link, and OKF checks passed. +- All eleven recorded fault traces passed all seven assertions. +- The complete package `verify` path passed through `verify:rootless`. +- Destination tests reject public, private, wildcard, mixed-answer, userinfo, + query, fragment, and malformed WebSocket targets before a capability is sent. +- State tests reject symlinks, preserve an attacker-chosen sibling target, and + verify private file modes. A real child-process test proves the captured + bootstrap capability is absent from inherited environment data. + +The first browser attempt found missing host libraries. The rootless package +script supplied private copies without changing the host. + +The first documentation pass also found the linked Phase 3 screenshot was not +yet in the evidence directory. The passing browser run produced it, it was +visually inspected, and the final verification used the checked evidence file. + +# Review state + +- Security review: pending. +- UX review: pending. +- QA tutorial run: pending. +- Human checkpoint: pending. diff --git a/packages/paperclip-runner/knowledge/evidence/index.md b/packages/paperclip-runner/knowledge/evidence/index.md index a9be2dd18dc..f71610a37cb 100644 --- a/packages/paperclip-runner/knowledge/evidence/index.md +++ b/packages/paperclip-runner/knowledge/evidence/index.md @@ -6,3 +6,4 @@ * [Phase 0 Rust correction verification](2026-08-07-phase-00-rust-correction-verification.md) - Rust build/tests, cross-language parity, and corrected boundary evidence. * [Phase 1 verification](2026-08-07-phase-01-verification.md) - Schema, golden, reducer, Rust parity, CLI, browser, token, boundary, and screenshot evidence. * [Phase 2 verification](2026-08-07-phase-02-verification.md) - Rust supervisor, fake-driver scenarios, cleanup, live/replay parity, browser flows, screenshots, and complete package verification. +* [Phase 3 verification](2026-08-07-phase-03-verification.md) - Lost-ACK replay, restart recovery, command deduplication, storage, and redacted diagnostics. diff --git a/packages/paperclip-runner/knowledge/evidence/phase-03-fault-matrix.json b/packages/paperclip-runner/knowledge/evidence/phase-03-fault-matrix.json new file mode 100644 index 00000000000..7c9ce11f432 --- /dev/null +++ b/packages/paperclip-runner/knowledge/evidence/phase-03-fault-matrix.json @@ -0,0 +1,423 @@ +{ + "schema": "paperclip.runner.phase3.evidence.v1", + "traces": [ + { + "fault": "none", + "outcome": "recovered", + "connectionCount": 1, + "replayDeliveries": 8, + "runnerRestarts": 0, + "harnessRestarts": 0, + "commands": { + "issued": 4, + "completed": 4, + "rejected": 0, + "logicalEffects": 4, + "duplicateDeliveries": 0 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 5315, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 5, + "p0Lost": 0 + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } + }, + { + "fault": "socket-drop", + "outcome": "recovered", + "connectionCount": 2, + "replayDeliveries": 8, + "runnerRestarts": 0, + "harnessRestarts": 0, + "commands": { + "issued": 4, + "completed": 4, + "rejected": 0, + "logicalEffects": 4, + "duplicateDeliveries": 0 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 5314, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 5, + "p0Lost": 0 + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } + }, + { + "fault": "lost-ack", + "outcome": "recovered", + "connectionCount": 2, + "replayDeliveries": 9, + "runnerRestarts": 0, + "harnessRestarts": 0, + "commands": { + "issued": 4, + "completed": 4, + "rejected": 0, + "logicalEffects": 4, + "duplicateDeliveries": 1 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 6023, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 5, + "p0Lost": 0 + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } + }, + { + "fault": "duplicate-command", + "outcome": "recovered", + "connectionCount": 2, + "replayDeliveries": 8, + "runnerRestarts": 0, + "harnessRestarts": 0, + "commands": { + "issued": 4, + "completed": 4, + "rejected": 0, + "logicalEffects": 4, + "duplicateDeliveries": 1 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 5314, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 5, + "p0Lost": 0 + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } + }, + { + "fault": "runner-restart", + "outcome": "recovered", + "connectionCount": 2, + "replayDeliveries": 10, + "runnerRestarts": 1, + "harnessRestarts": 0, + "commands": { + "issued": 4, + "completed": 4, + "rejected": 0, + "logicalEffects": 4, + "duplicateDeliveries": 1 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 6883, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 6, + "p0Lost": 0 + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } + }, + { + "fault": "harness-restart", + "outcome": "recovered", + "connectionCount": 1, + "replayDeliveries": 11, + "runnerRestarts": 0, + "harnessRestarts": 1, + "commands": { + "issued": 5, + "completed": 5, + "rejected": 0, + "logicalEffects": 5, + "duplicateDeliveries": 0 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 6827, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 8, + "p0Lost": 0 + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } + }, + { + "fault": "malformed-input", + "outcome": "recovered", + "connectionCount": 2, + "replayDeliveries": 8, + "runnerRestarts": 0, + "harnessRestarts": 0, + "commands": { + "issued": 4, + "completed": 4, + "rejected": 0, + "logicalEffects": 4, + "duplicateDeliveries": 0 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 5314, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 5, + "p0Lost": 0 + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } + }, + { + "fault": "lease-expiry", + "outcome": "recovered", + "connectionCount": 2, + "replayDeliveries": 9, + "runnerRestarts": 1, + "harnessRestarts": 0, + "commands": { + "issued": 4, + "completed": 4, + "rejected": 0, + "logicalEffects": 4, + "duplicateDeliveries": 0 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 5314, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 6, + "p0Lost": 0 + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } + }, + { + "fault": "storage-pressure", + "outcome": "recovered", + "connectionCount": 1, + "replayDeliveries": 4, + "runnerRestarts": 0, + "harnessRestarts": 0, + "commands": { + "issued": 5, + "completed": 4, + "rejected": 1, + "logicalEffects": 4, + "duplicateDeliveries": 0 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 2326, + "maxBytes": 16384, + "backpressure": true, + "p0Committed": 3, + "p0Lost": 0 + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } + }, + { + "fault": "drain", + "outcome": "drained", + "connectionCount": 1, + "replayDeliveries": 3, + "runnerRestarts": 0, + "harnessRestarts": 0, + "commands": { + "issued": 5, + "completed": 4, + "rejected": 1, + "logicalEffects": 4, + "duplicateDeliveries": 0 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 1478, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 3, + "p0Lost": 0 + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } + }, + { + "fault": "revoke", + "outcome": "revoked", + "connectionCount": 1, + "replayDeliveries": 4, + "runnerRestarts": 0, + "harnessRestarts": 0, + "commands": { + "issued": 4, + "completed": 3, + "rejected": 1, + "logicalEffects": 3, + "duplicateDeliveries": 0 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 5315, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 4, + "p0Lost": 0 + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } + } + ] +} diff --git a/packages/paperclip-runner/knowledge/evidence/phase-03-faults/drain.json b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/drain.json new file mode 100644 index 00000000000..f09e7f6bf0f --- /dev/null +++ b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/drain.json @@ -0,0 +1,399 @@ +{ + "schema": "paperclip.runner.phase3.trace.v1", + "diagnostics": { + "schema": "paperclip.runner.phase3.diagnostics.v1", + "fault": "drain", + "connection": { + "state": "stopped", + "connectionCount": 1, + "reconnectCount": 0, + "leaseId": "connection_lease_0c922c88-0cfe-4a1f-b58d-15278a816adf", + "leaseExpiresAt": "2026-08-07T23:36:40.794Z" + }, + "identity": { + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable" + }, + "cursors": { + "runnerAckedSourceSeq": 4, + "runnerNextSourceSeq": 5, + "coreAckedSourceSeq": 4, + "highestCommittedSourceSeq": 4 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 1478, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 3, + "p0Lost": 0 + }, + "commands": { + "issued": 5, + "completed": 4, + "rejected": 1, + "logicalEffects": 4, + "duplicateDeliveries": 0 + }, + "recovery": { + "replayDeliveries": 3, + "runnerRestarts": 0, + "harnessRestarts": 0, + "malformedFrames": 0, + "freshBootstraps": 1, + "outcome": "drained", + "reason": "drain_completed" + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "committedEvents": [ + { + "sourceSeq": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "eventType": "workspace.ready", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000001", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.001Z", + "eventType": "workspace.ready", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 1, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.001Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 2, + "sourceEventId": "event_runner_phase3_stable_000002", + "eventType": "session.started", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000002", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.002Z", + "eventType": "session.started", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "driverSessionId": "driver_phase3_fake", + "normalizedSessionId": "session_phase3_stable", + "resumed": false + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000002", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 2, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.002Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 3, + "sourceEventId": "event_runner_phase3_stable_000003", + "eventType": "runner.draining", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000003", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.003Z", + "eventType": "runner.draining", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "newWorkAccepted": false + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000003", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 3, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.003Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 4, + "sourceEventId": "event_runner_phase3_stable_000004", + "eventType": "runner.stopped", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000004", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.004Z", + "eventType": "runner.stopped", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "afterDurableFlush": true + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000004", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 4, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.004Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 1, + "logicalEffectCount": 1 + } + ] + }, + "runnerState": { + "schema": "paperclip.runner.phase3.state.v1", + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable", + "lifecycle": "stopped", + "nextSourceSeq": 5, + "ackedSourceSeq": 4, + "lastControllerCommandSeq": 5, + "reconnectCount": 0, + "maxOutboxBytes": 65536, + "peakOutboxBytes": 1478, + "outbox": [], + "processedCommands": { + "command_phase3_001": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "commandDigest": "fnv1a64:c19dfbbf86a3dbb4", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_002": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "commandDigest": "fnv1a64:b5198f3ce67ce88e", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_003": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "commandDigest": "fnv1a64:978d0ca44be61a36", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "runner draining", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_004": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "commandDigest": "fnv1a64:34d91505a30f60fb", + "status": "rejected", + "logicalEffectCount": 0, + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "new turns are disabled while draining or backpressured", + "logicalEffectCount": 0, + "status": "rejected" + } + }, + "command_phase3_005": { + "commandId": "command_phase3_005", + "controllerSeq": 5, + "commandDigest": "fnv1a64:533318a30fba6d22", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_005", + "controllerSeq": 5, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + }, + "diagnostics": [], + "backpressure": false, + "recoverableFailure": null, + "unrecoverableOutcome": null, + "harnessGeneration": 1, + "stopAfterFlush": true + }, + "commands": [ + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_001", + "controllerSeq": 1, + "type": "run.prepare", + "issuedAt": "2026-08-07T23:30:01.000Z", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_002", + "controllerSeq": 2, + "type": "session.open", + "issuedAt": "2026-08-07T23:30:02.000Z", + "payload": { + "reuse": "same_session" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_003", + "controllerSeq": 3, + "type": "runner.drain", + "issuedAt": "2026-08-07T23:30:03.000Z", + "payload": {}, + "status": "completed", + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "runner draining", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_004", + "controllerSeq": 4, + "type": "turn.start", + "issuedAt": "2026-08-07T23:30:04.000Z", + "payload": { + "turnId": "turn_phase3_stable", + "text": "Prove Phase 3 durable recovery." + }, + "status": "rejected", + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "new turns are disabled while draining or backpressured", + "logicalEffectCount": 0, + "status": "rejected" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_005", + "controllerSeq": 5, + "type": "runner.shutdown", + "issuedAt": "2026-08-07T23:30:05.000Z", + "payload": {}, + "status": "completed", + "result": { + "commandId": "command_phase3_005", + "controllerSeq": 5, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + ], + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } +} diff --git a/packages/paperclip-runner/knowledge/evidence/phase-03-faults/duplicate-command.json b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/duplicate-command.json new file mode 100644 index 00000000000..e87daec3b97 --- /dev/null +++ b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/duplicate-command.json @@ -0,0 +1,561 @@ +{ + "schema": "paperclip.runner.phase3.trace.v1", + "diagnostics": { + "schema": "paperclip.runner.phase3.diagnostics.v1", + "fault": "duplicate-command", + "connection": { + "state": "stopped", + "connectionCount": 2, + "reconnectCount": 1, + "leaseId": "connection_lease_2e6357a8-6a17-4450-a782-7aa4ca543a9c", + "leaseExpiresAt": "2026-08-07T23:36:39.046Z" + }, + "identity": { + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable" + }, + "cursors": { + "runnerAckedSourceSeq": 9, + "runnerNextSourceSeq": 10, + "coreAckedSourceSeq": 9, + "highestCommittedSourceSeq": 9 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 5314, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 5, + "p0Lost": 0 + }, + "commands": { + "issued": 4, + "completed": 4, + "rejected": 0, + "logicalEffects": 4, + "duplicateDeliveries": 1 + }, + "recovery": { + "replayDeliveries": 8, + "runnerRestarts": 0, + "harnessRestarts": 0, + "malformedFrames": 0, + "freshBootstraps": 1, + "outcome": "recovered", + "reason": "duplicate_command_completed" + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "committedEvents": [ + { + "sourceSeq": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "eventType": "workspace.ready", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000001", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.001Z", + "eventType": "workspace.ready", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 1, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.001Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 2, + "sourceEventId": "event_runner_phase3_stable_000002", + "eventType": "session.started", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000002", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.002Z", + "eventType": "session.started", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "driverSessionId": "driver_phase3_fake", + "normalizedSessionId": "session_phase3_stable", + "resumed": true + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000002", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 2, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.002Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 3, + "sourceEventId": "event_runner_phase3_stable_000003", + "eventType": "turn.accepted", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000003", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.003Z", + "eventType": "turn.accepted", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "sameSession": true, + "turnId": "turn_phase3_stable" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000003", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 3, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.003Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 4, + "sourceEventId": "event_runner_phase3_stable_000004", + "eventType": "item.started", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000004", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.004Z", + "eventType": "item.started", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "kind": "assistant_message" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000004", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 4, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.004Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 5, + "sourceEventId": "event_runner_phase3_stable_000005", + "eventType": "item.delta", + "priority": 2, + "envelope": { + "envelopeId": "envelope_event_000005", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.005Z", + "eventType": "item.delta", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Prove Phase 3 durable recovery." + }, + "priority": 2, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000005", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 5, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.005Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 6, + "sourceEventId": "event_runner_phase3_stable_000006", + "eventType": "item.completed", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000006", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.006Z", + "eventType": "item.completed", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Durable recovery completed." + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000006", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 6, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.006Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 7, + "sourceEventId": "event_runner_phase3_stable_000007", + "eventType": "run.result.proposed", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000007", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.007Z", + "eventType": "run.result.proposed", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "schema": "paperclip.prp.result.v1", + "status": "succeeded", + "summary": "Phase 3 durable transport recovered without duplicate effects." + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000007", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 7, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.007Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 8, + "sourceEventId": "event_runner_phase3_stable_000008", + "eventType": "run.terminal", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000008", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.008Z", + "eventType": "run.terminal", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "runTerminalState": "succeeded", + "schema": "paperclip.prp.terminal.v1", + "turnTerminalState": "completed" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000008", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 8, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.008Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 9, + "sourceEventId": "event_runner_phase3_stable_000009", + "eventType": "runner.stopped", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000009", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.009Z", + "eventType": "runner.stopped", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "afterDurableFlush": true + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000009", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 9, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.009Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 1, + "logicalEffectCount": 1 + } + ] + }, + "runnerState": { + "schema": "paperclip.runner.phase3.state.v1", + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable", + "lifecycle": "stopped", + "nextSourceSeq": 10, + "ackedSourceSeq": 9, + "lastControllerCommandSeq": 4, + "reconnectCount": 1, + "maxOutboxBytes": 65536, + "peakOutboxBytes": 5314, + "outbox": [], + "processedCommands": { + "command_phase3_001": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "commandDigest": "fnv1a64:c19dfbbf86a3dbb4", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_002": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "commandDigest": "fnv1a64:b5198f3ce67ce88e", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_003": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "commandDigest": "fnv1a64:fb3b206fe67e1dc8", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_004": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "commandDigest": "fnv1a64:d11bf8308f863bad", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + }, + "diagnostics": [ + "WebSocket connection closed: failed to fill whole buffer" + ], + "backpressure": false, + "recoverableFailure": null, + "unrecoverableOutcome": null, + "harnessGeneration": 1, + "stopAfterFlush": true + }, + "commands": [ + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_001", + "controllerSeq": 1, + "type": "run.prepare", + "issuedAt": "2026-08-07T23:30:01.000Z", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_002", + "controllerSeq": 2, + "type": "session.open", + "issuedAt": "2026-08-07T23:30:02.000Z", + "payload": { + "reuse": "same_session" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_003", + "controllerSeq": 3, + "type": "turn.start", + "issuedAt": "2026-08-07T23:30:03.000Z", + "payload": { + "turnId": "turn_phase3_stable", + "text": "Prove Phase 3 durable recovery." + }, + "status": "completed", + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_004", + "controllerSeq": 4, + "type": "runner.shutdown", + "issuedAt": "2026-08-07T23:30:04.000Z", + "payload": {}, + "status": "completed", + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + ], + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } +} diff --git a/packages/paperclip-runner/knowledge/evidence/phase-03-faults/harness-restart.json b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/harness-restart.json new file mode 100644 index 00000000000..9ef6cff0207 --- /dev/null +++ b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/harness-restart.json @@ -0,0 +1,704 @@ +{ + "schema": "paperclip.runner.phase3.trace.v1", + "diagnostics": { + "schema": "paperclip.runner.phase3.diagnostics.v1", + "fault": "harness-restart", + "connection": { + "state": "stopped", + "connectionCount": 1, + "reconnectCount": 0, + "leaseId": "connection_lease_6de7f5ec-7f92-4c7c-806a-d262e02b2271", + "leaseExpiresAt": "2026-08-07T23:36:39.644Z" + }, + "identity": { + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable" + }, + "cursors": { + "runnerAckedSourceSeq": 12, + "runnerNextSourceSeq": 13, + "coreAckedSourceSeq": 12, + "highestCommittedSourceSeq": 12 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 6827, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 8, + "p0Lost": 0 + }, + "commands": { + "issued": 5, + "completed": 5, + "rejected": 0, + "logicalEffects": 5, + "duplicateDeliveries": 0 + }, + "recovery": { + "replayDeliveries": 11, + "runnerRestarts": 0, + "harnessRestarts": 1, + "malformedFrames": 0, + "freshBootstraps": 1, + "outcome": "recovered", + "reason": "harness_restart_completed" + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "committedEvents": [ + { + "sourceSeq": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "eventType": "workspace.ready", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000001", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.001Z", + "eventType": "workspace.ready", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 1, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.001Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 2, + "sourceEventId": "event_runner_phase3_stable_000002", + "eventType": "session.started", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000002", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.002Z", + "eventType": "session.started", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "driverSessionId": "driver_phase3_fake", + "normalizedSessionId": "session_phase3_stable", + "resumed": false + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000002", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 2, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.002Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 3, + "sourceEventId": "event_runner_phase3_stable_000003", + "eventType": "harness.exited", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000003", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.003Z", + "eventType": "harness.exited", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "generation": 1, + "reason": "fault_injection_restart", + "recoverable": true + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000003", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 3, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.003Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 4, + "sourceEventId": "event_runner_phase3_stable_000004", + "eventType": "harness.ready", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000004", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.004Z", + "eventType": "harness.ready", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "driverKind": "fake", + "generation": 2 + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000004", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 4, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.004Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 5, + "sourceEventId": "event_runner_phase3_stable_000005", + "eventType": "session.reconciled", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000005", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.005Z", + "eventType": "session.reconciled", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "outcome": "same_session_resumed", + "turnId": "turn_phase3_stable" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000005", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 5, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.005Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 6, + "sourceEventId": "event_runner_phase3_stable_000006", + "eventType": "turn.accepted", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000006", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.006Z", + "eventType": "turn.accepted", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "sameSession": true, + "turnId": "turn_phase3_stable" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000006", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 6, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.006Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 7, + "sourceEventId": "event_runner_phase3_stable_000007", + "eventType": "item.started", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000007", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.007Z", + "eventType": "item.started", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "kind": "assistant_message" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000007", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 7, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.007Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 8, + "sourceEventId": "event_runner_phase3_stable_000008", + "eventType": "item.delta", + "priority": 2, + "envelope": { + "envelopeId": "envelope_event_000008", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.008Z", + "eventType": "item.delta", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Prove Phase 3 durable recovery." + }, + "priority": 2, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000008", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 8, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.008Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 9, + "sourceEventId": "event_runner_phase3_stable_000009", + "eventType": "item.completed", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000009", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.009Z", + "eventType": "item.completed", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Durable recovery completed." + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000009", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 9, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.009Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 10, + "sourceEventId": "event_runner_phase3_stable_000010", + "eventType": "run.result.proposed", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000010", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.010Z", + "eventType": "run.result.proposed", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "schema": "paperclip.prp.result.v1", + "status": "succeeded", + "summary": "Phase 3 durable transport recovered without duplicate effects." + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000010", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 10, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.010Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 11, + "sourceEventId": "event_runner_phase3_stable_000011", + "eventType": "run.terminal", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000011", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.011Z", + "eventType": "run.terminal", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "runTerminalState": "succeeded", + "schema": "paperclip.prp.terminal.v1", + "turnTerminalState": "completed" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000011", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 11, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.011Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 12, + "sourceEventId": "event_runner_phase3_stable_000012", + "eventType": "runner.stopped", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000012", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.012Z", + "eventType": "runner.stopped", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "afterDurableFlush": true + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000012", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 12, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.012Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 1, + "logicalEffectCount": 1 + } + ] + }, + "runnerState": { + "schema": "paperclip.runner.phase3.state.v1", + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable", + "lifecycle": "stopped", + "nextSourceSeq": 13, + "ackedSourceSeq": 12, + "lastControllerCommandSeq": 5, + "reconnectCount": 0, + "maxOutboxBytes": 65536, + "peakOutboxBytes": 6827, + "outbox": [], + "processedCommands": { + "command_phase3_001": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "commandDigest": "fnv1a64:c19dfbbf86a3dbb4", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_002": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "commandDigest": "fnv1a64:b5198f3ce67ce88e", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_003": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "commandDigest": "fnv1a64:284c1f5778b929c4", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "harness restarted and reconciled", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_004": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "commandDigest": "fnv1a64:34d91505a30f60fb", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_005": { + "commandId": "command_phase3_005", + "controllerSeq": 5, + "commandDigest": "fnv1a64:533318a30fba6d22", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_005", + "controllerSeq": 5, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + }, + "diagnostics": [], + "backpressure": false, + "recoverableFailure": null, + "unrecoverableOutcome": null, + "harnessGeneration": 2, + "stopAfterFlush": true + }, + "commands": [ + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_001", + "controllerSeq": 1, + "type": "run.prepare", + "issuedAt": "2026-08-07T23:30:01.000Z", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_002", + "controllerSeq": 2, + "type": "session.open", + "issuedAt": "2026-08-07T23:30:02.000Z", + "payload": { + "reuse": "same_session" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_003", + "controllerSeq": 3, + "type": "fault.harness_restart", + "issuedAt": "2026-08-07T23:30:03.000Z", + "payload": {}, + "status": "completed", + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "harness restarted and reconciled", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_004", + "controllerSeq": 4, + "type": "turn.start", + "issuedAt": "2026-08-07T23:30:04.000Z", + "payload": { + "turnId": "turn_phase3_stable", + "text": "Prove Phase 3 durable recovery." + }, + "status": "completed", + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_005", + "controllerSeq": 5, + "type": "runner.shutdown", + "issuedAt": "2026-08-07T23:30:05.000Z", + "payload": {}, + "status": "completed", + "result": { + "commandId": "command_phase3_005", + "controllerSeq": 5, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + ], + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } +} diff --git a/packages/paperclip-runner/knowledge/evidence/phase-03-faults/lease-expiry.json b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/lease-expiry.json new file mode 100644 index 00000000000..9e3e834c77d --- /dev/null +++ b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/lease-expiry.json @@ -0,0 +1,603 @@ +{ + "schema": "paperclip.runner.phase3.trace.v1", + "diagnostics": { + "schema": "paperclip.runner.phase3.diagnostics.v1", + "fault": "lease-expiry", + "connection": { + "state": "stopped", + "connectionCount": 2, + "reconnectCount": 2, + "leaseId": "connection_lease_42900de0-4a64-47c1-b20c-d14890a9be42", + "leaseExpiresAt": "2026-08-07T23:36:40.312Z" + }, + "identity": { + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable" + }, + "cursors": { + "runnerAckedSourceSeq": 10, + "runnerNextSourceSeq": 11, + "coreAckedSourceSeq": 10, + "highestCommittedSourceSeq": 10 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 5314, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 6, + "p0Lost": 0 + }, + "commands": { + "issued": 4, + "completed": 4, + "rejected": 0, + "logicalEffects": 4, + "duplicateDeliveries": 0 + }, + "recovery": { + "replayDeliveries": 9, + "runnerRestarts": 1, + "harnessRestarts": 0, + "malformedFrames": 0, + "freshBootstraps": 2, + "outcome": "recovered", + "reason": "lease_expiry_completed" + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "committedEvents": [ + { + "sourceSeq": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "eventType": "runner.reconciled", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000001", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.001Z", + "eventType": "runner.reconciled", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "outcome": "same_durable_session_resumed", + "runnerInstanceId": "runner_phase3_stable", + "turnId": "turn_phase3_stable" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 1, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.001Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 2, + "sourceEventId": "event_runner_phase3_stable_000002", + "eventType": "workspace.ready", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000002", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.002Z", + "eventType": "workspace.ready", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000002", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 2, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.002Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 3, + "sourceEventId": "event_runner_phase3_stable_000003", + "eventType": "session.started", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000003", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.003Z", + "eventType": "session.started", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "driverSessionId": "driver_phase3_fake", + "normalizedSessionId": "session_phase3_stable", + "resumed": true + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000003", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 3, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.003Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 4, + "sourceEventId": "event_runner_phase3_stable_000004", + "eventType": "turn.accepted", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000004", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.004Z", + "eventType": "turn.accepted", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "sameSession": true, + "turnId": "turn_phase3_stable" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000004", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 4, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.004Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 5, + "sourceEventId": "event_runner_phase3_stable_000005", + "eventType": "item.started", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000005", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.005Z", + "eventType": "item.started", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "kind": "assistant_message" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000005", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 5, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.005Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 6, + "sourceEventId": "event_runner_phase3_stable_000006", + "eventType": "item.delta", + "priority": 2, + "envelope": { + "envelopeId": "envelope_event_000006", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.006Z", + "eventType": "item.delta", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Prove Phase 3 durable recovery." + }, + "priority": 2, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000006", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 6, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.006Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 7, + "sourceEventId": "event_runner_phase3_stable_000007", + "eventType": "item.completed", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000007", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.007Z", + "eventType": "item.completed", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Durable recovery completed." + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000007", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 7, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.007Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 8, + "sourceEventId": "event_runner_phase3_stable_000008", + "eventType": "run.result.proposed", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000008", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.008Z", + "eventType": "run.result.proposed", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "schema": "paperclip.prp.result.v1", + "status": "succeeded", + "summary": "Phase 3 durable transport recovered without duplicate effects." + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000008", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 8, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.008Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 9, + "sourceEventId": "event_runner_phase3_stable_000009", + "eventType": "run.terminal", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000009", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.009Z", + "eventType": "run.terminal", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "runTerminalState": "succeeded", + "schema": "paperclip.prp.terminal.v1", + "turnTerminalState": "completed" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000009", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 9, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.009Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 10, + "sourceEventId": "event_runner_phase3_stable_000010", + "eventType": "runner.stopped", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000010", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.010Z", + "eventType": "runner.stopped", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "afterDurableFlush": true + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000010", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 10, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.010Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 1, + "logicalEffectCount": 1 + } + ] + }, + "runnerState": { + "schema": "paperclip.runner.phase3.state.v1", + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable", + "lifecycle": "stopped", + "nextSourceSeq": 11, + "ackedSourceSeq": 10, + "lastControllerCommandSeq": 4, + "reconnectCount": 2, + "maxOutboxBytes": 65536, + "peakOutboxBytes": 5314, + "outbox": [], + "processedCommands": { + "command_phase3_001": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "commandDigest": "fnv1a64:c19dfbbf86a3dbb4", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_002": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "commandDigest": "fnv1a64:b5198f3ce67ce88e", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_003": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "commandDigest": "fnv1a64:fb3b206fe67e1dc8", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_004": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "commandDigest": "fnv1a64:d11bf8308f863bad", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + }, + "diagnostics": [ + "WebSocket connection closed: failed to fill whole buffer", + "connection lease expired; a fresh bootstrap may resume this state", + "runner process restored the same durable identity" + ], + "backpressure": false, + "recoverableFailure": null, + "unrecoverableOutcome": null, + "harnessGeneration": 1, + "stopAfterFlush": true + }, + "commands": [ + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_001", + "controllerSeq": 1, + "type": "run.prepare", + "issuedAt": "2026-08-07T23:30:01.000Z", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_002", + "controllerSeq": 2, + "type": "session.open", + "issuedAt": "2026-08-07T23:30:02.000Z", + "payload": { + "reuse": "same_session" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_003", + "controllerSeq": 3, + "type": "turn.start", + "issuedAt": "2026-08-07T23:30:03.000Z", + "payload": { + "turnId": "turn_phase3_stable", + "text": "Prove Phase 3 durable recovery." + }, + "status": "completed", + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_004", + "controllerSeq": 4, + "type": "runner.shutdown", + "issuedAt": "2026-08-07T23:30:04.000Z", + "payload": {}, + "status": "completed", + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + ], + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } +} diff --git a/packages/paperclip-runner/knowledge/evidence/phase-03-faults/lost-ack.json b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/lost-ack.json new file mode 100644 index 00000000000..12f74f6211e --- /dev/null +++ b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/lost-ack.json @@ -0,0 +1,561 @@ +{ + "schema": "paperclip.runner.phase3.trace.v1", + "diagnostics": { + "schema": "paperclip.runner.phase3.diagnostics.v1", + "fault": "lost-ack", + "connection": { + "state": "stopped", + "connectionCount": 2, + "reconnectCount": 1, + "leaseId": "connection_lease_db423713-98d6-4a86-940b-ec2f0f6cd6e3", + "leaseExpiresAt": "2026-08-07T23:36:38.759Z" + }, + "identity": { + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable" + }, + "cursors": { + "runnerAckedSourceSeq": 9, + "runnerNextSourceSeq": 10, + "coreAckedSourceSeq": 9, + "highestCommittedSourceSeq": 9 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 6023, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 5, + "p0Lost": 0 + }, + "commands": { + "issued": 4, + "completed": 4, + "rejected": 0, + "logicalEffects": 4, + "duplicateDeliveries": 1 + }, + "recovery": { + "replayDeliveries": 9, + "runnerRestarts": 0, + "harnessRestarts": 0, + "malformedFrames": 0, + "freshBootstraps": 1, + "outcome": "recovered", + "reason": "lost_ack_completed" + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "committedEvents": [ + { + "sourceSeq": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "eventType": "workspace.ready", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000001", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.001Z", + "eventType": "workspace.ready", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 1, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.001Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 3, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 2, + "sourceEventId": "event_runner_phase3_stable_000002", + "eventType": "session.started", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000002", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.002Z", + "eventType": "session.started", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "driverSessionId": "driver_phase3_fake", + "normalizedSessionId": "session_phase3_stable", + "resumed": false + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000002", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 2, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.002Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 3, + "sourceEventId": "event_runner_phase3_stable_000003", + "eventType": "turn.accepted", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000003", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.003Z", + "eventType": "turn.accepted", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "sameSession": true, + "turnId": "turn_phase3_stable" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000003", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 3, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.003Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 4, + "sourceEventId": "event_runner_phase3_stable_000004", + "eventType": "item.started", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000004", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.004Z", + "eventType": "item.started", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "kind": "assistant_message" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000004", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 4, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.004Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 5, + "sourceEventId": "event_runner_phase3_stable_000005", + "eventType": "item.delta", + "priority": 2, + "envelope": { + "envelopeId": "envelope_event_000005", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.005Z", + "eventType": "item.delta", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Prove Phase 3 durable recovery." + }, + "priority": 2, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000005", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 5, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.005Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 6, + "sourceEventId": "event_runner_phase3_stable_000006", + "eventType": "item.completed", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000006", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.006Z", + "eventType": "item.completed", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Durable recovery completed." + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000006", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 6, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.006Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 7, + "sourceEventId": "event_runner_phase3_stable_000007", + "eventType": "run.result.proposed", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000007", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.007Z", + "eventType": "run.result.proposed", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "schema": "paperclip.prp.result.v1", + "status": "succeeded", + "summary": "Phase 3 durable transport recovered without duplicate effects." + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000007", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 7, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.007Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 8, + "sourceEventId": "event_runner_phase3_stable_000008", + "eventType": "run.terminal", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000008", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.008Z", + "eventType": "run.terminal", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "runTerminalState": "succeeded", + "schema": "paperclip.prp.terminal.v1", + "turnTerminalState": "completed" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000008", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 8, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.008Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 9, + "sourceEventId": "event_runner_phase3_stable_000009", + "eventType": "runner.stopped", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000009", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.009Z", + "eventType": "runner.stopped", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "afterDurableFlush": true + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000009", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 9, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.009Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 1, + "logicalEffectCount": 1 + } + ] + }, + "runnerState": { + "schema": "paperclip.runner.phase3.state.v1", + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable", + "lifecycle": "stopped", + "nextSourceSeq": 10, + "ackedSourceSeq": 9, + "lastControllerCommandSeq": 4, + "reconnectCount": 1, + "maxOutboxBytes": 65536, + "peakOutboxBytes": 6023, + "outbox": [], + "processedCommands": { + "command_phase3_001": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "commandDigest": "fnv1a64:c19dfbbf86a3dbb4", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_002": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "commandDigest": "fnv1a64:b5198f3ce67ce88e", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_003": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "commandDigest": "fnv1a64:fb3b206fe67e1dc8", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_004": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "commandDigest": "fnv1a64:d11bf8308f863bad", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + }, + "diagnostics": [ + "WebSocket frame write failed: Broken pipe (os error 32)" + ], + "backpressure": false, + "recoverableFailure": null, + "unrecoverableOutcome": null, + "harnessGeneration": 1, + "stopAfterFlush": true + }, + "commands": [ + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_001", + "controllerSeq": 1, + "type": "run.prepare", + "issuedAt": "2026-08-07T23:30:01.000Z", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_002", + "controllerSeq": 2, + "type": "session.open", + "issuedAt": "2026-08-07T23:30:02.000Z", + "payload": { + "reuse": "same_session" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_003", + "controllerSeq": 3, + "type": "turn.start", + "issuedAt": "2026-08-07T23:30:03.000Z", + "payload": { + "turnId": "turn_phase3_stable", + "text": "Prove Phase 3 durable recovery." + }, + "status": "completed", + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_004", + "controllerSeq": 4, + "type": "runner.shutdown", + "issuedAt": "2026-08-07T23:30:04.000Z", + "payload": {}, + "status": "completed", + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + ], + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } +} diff --git a/packages/paperclip-runner/knowledge/evidence/phase-03-faults/malformed-input.json b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/malformed-input.json new file mode 100644 index 00000000000..46a4feb6e87 --- /dev/null +++ b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/malformed-input.json @@ -0,0 +1,561 @@ +{ + "schema": "paperclip.runner.phase3.trace.v1", + "diagnostics": { + "schema": "paperclip.runner.phase3.diagnostics.v1", + "fault": "malformed-input", + "connection": { + "state": "stopped", + "connectionCount": 2, + "reconnectCount": 1, + "leaseId": "connection_lease_51b9ac50-5fdc-4f68-a289-6e6e76711bbf", + "leaseExpiresAt": "2026-08-07T23:36:39.957Z" + }, + "identity": { + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable" + }, + "cursors": { + "runnerAckedSourceSeq": 9, + "runnerNextSourceSeq": 10, + "coreAckedSourceSeq": 9, + "highestCommittedSourceSeq": 9 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 5314, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 5, + "p0Lost": 0 + }, + "commands": { + "issued": 4, + "completed": 4, + "rejected": 0, + "logicalEffects": 4, + "duplicateDeliveries": 0 + }, + "recovery": { + "replayDeliveries": 8, + "runnerRestarts": 0, + "harnessRestarts": 0, + "malformedFrames": 1, + "freshBootstraps": 1, + "outcome": "recovered", + "reason": "malformed_input_completed" + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "committedEvents": [ + { + "sourceSeq": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "eventType": "workspace.ready", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000001", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.001Z", + "eventType": "workspace.ready", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 1, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.001Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 2, + "sourceEventId": "event_runner_phase3_stable_000002", + "eventType": "session.started", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000002", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.002Z", + "eventType": "session.started", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "driverSessionId": "driver_phase3_fake", + "normalizedSessionId": "session_phase3_stable", + "resumed": true + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000002", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 2, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.002Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 3, + "sourceEventId": "event_runner_phase3_stable_000003", + "eventType": "turn.accepted", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000003", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.003Z", + "eventType": "turn.accepted", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "sameSession": true, + "turnId": "turn_phase3_stable" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000003", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 3, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.003Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 4, + "sourceEventId": "event_runner_phase3_stable_000004", + "eventType": "item.started", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000004", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.004Z", + "eventType": "item.started", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "kind": "assistant_message" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000004", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 4, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.004Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 5, + "sourceEventId": "event_runner_phase3_stable_000005", + "eventType": "item.delta", + "priority": 2, + "envelope": { + "envelopeId": "envelope_event_000005", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.005Z", + "eventType": "item.delta", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Prove Phase 3 durable recovery." + }, + "priority": 2, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000005", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 5, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.005Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 6, + "sourceEventId": "event_runner_phase3_stable_000006", + "eventType": "item.completed", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000006", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.006Z", + "eventType": "item.completed", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Durable recovery completed." + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000006", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 6, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.006Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 7, + "sourceEventId": "event_runner_phase3_stable_000007", + "eventType": "run.result.proposed", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000007", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.007Z", + "eventType": "run.result.proposed", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "schema": "paperclip.prp.result.v1", + "status": "succeeded", + "summary": "Phase 3 durable transport recovered without duplicate effects." + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000007", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 7, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.007Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 8, + "sourceEventId": "event_runner_phase3_stable_000008", + "eventType": "run.terminal", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000008", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.008Z", + "eventType": "run.terminal", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "runTerminalState": "succeeded", + "schema": "paperclip.prp.terminal.v1", + "turnTerminalState": "completed" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000008", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 8, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.008Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 9, + "sourceEventId": "event_runner_phase3_stable_000009", + "eventType": "runner.stopped", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000009", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.009Z", + "eventType": "runner.stopped", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "afterDurableFlush": true + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000009", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 9, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.009Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 1, + "logicalEffectCount": 1 + } + ] + }, + "runnerState": { + "schema": "paperclip.runner.phase3.state.v1", + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable", + "lifecycle": "stopped", + "nextSourceSeq": 10, + "ackedSourceSeq": 9, + "lastControllerCommandSeq": 4, + "reconnectCount": 1, + "maxOutboxBytes": 65536, + "peakOutboxBytes": 5314, + "outbox": [], + "processedCommands": { + "command_phase3_001": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "commandDigest": "fnv1a64:c19dfbbf86a3dbb4", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_002": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "commandDigest": "fnv1a64:b5198f3ce67ce88e", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_003": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "commandDigest": "fnv1a64:fb3b206fe67e1dc8", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_004": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "commandDigest": "fnv1a64:d11bf8308f863bad", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + }, + "diagnostics": [ + "malformed WebSocket JSON: EOF while parsing a value at line 1 column 8" + ], + "backpressure": false, + "recoverableFailure": null, + "unrecoverableOutcome": null, + "harnessGeneration": 1, + "stopAfterFlush": true + }, + "commands": [ + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_001", + "controllerSeq": 1, + "type": "run.prepare", + "issuedAt": "2026-08-07T23:30:01.000Z", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_002", + "controllerSeq": 2, + "type": "session.open", + "issuedAt": "2026-08-07T23:30:02.000Z", + "payload": { + "reuse": "same_session" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_003", + "controllerSeq": 3, + "type": "turn.start", + "issuedAt": "2026-08-07T23:30:03.000Z", + "payload": { + "turnId": "turn_phase3_stable", + "text": "Prove Phase 3 durable recovery." + }, + "status": "completed", + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_004", + "controllerSeq": 4, + "type": "runner.shutdown", + "issuedAt": "2026-08-07T23:30:04.000Z", + "payload": {}, + "status": "completed", + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + ], + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } +} diff --git a/packages/paperclip-runner/knowledge/evidence/phase-03-faults/none.json b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/none.json new file mode 100644 index 00000000000..ef42c9b62cc --- /dev/null +++ b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/none.json @@ -0,0 +1,559 @@ +{ + "schema": "paperclip.runner.phase3.trace.v1", + "diagnostics": { + "schema": "paperclip.runner.phase3.diagnostics.v1", + "fault": "none", + "connection": { + "state": "stopped", + "connectionCount": 1, + "reconnectCount": 0, + "leaseId": "connection_lease_469ad2f3-1655-434c-a12b-85718229ea67", + "leaseExpiresAt": "2026-08-07T23:36:38.211Z" + }, + "identity": { + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable" + }, + "cursors": { + "runnerAckedSourceSeq": 9, + "runnerNextSourceSeq": 10, + "coreAckedSourceSeq": 9, + "highestCommittedSourceSeq": 9 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 5315, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 5, + "p0Lost": 0 + }, + "commands": { + "issued": 4, + "completed": 4, + "rejected": 0, + "logicalEffects": 4, + "duplicateDeliveries": 0 + }, + "recovery": { + "replayDeliveries": 8, + "runnerRestarts": 0, + "harnessRestarts": 0, + "malformedFrames": 0, + "freshBootstraps": 1, + "outcome": "recovered", + "reason": "none_completed" + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "committedEvents": [ + { + "sourceSeq": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "eventType": "workspace.ready", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000001", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.001Z", + "eventType": "workspace.ready", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 1, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.001Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 2, + "sourceEventId": "event_runner_phase3_stable_000002", + "eventType": "session.started", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000002", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.002Z", + "eventType": "session.started", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "driverSessionId": "driver_phase3_fake", + "normalizedSessionId": "session_phase3_stable", + "resumed": false + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000002", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 2, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.002Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 3, + "sourceEventId": "event_runner_phase3_stable_000003", + "eventType": "turn.accepted", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000003", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.003Z", + "eventType": "turn.accepted", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "sameSession": true, + "turnId": "turn_phase3_stable" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000003", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 3, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.003Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 4, + "sourceEventId": "event_runner_phase3_stable_000004", + "eventType": "item.started", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000004", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.004Z", + "eventType": "item.started", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "kind": "assistant_message" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000004", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 4, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.004Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 5, + "sourceEventId": "event_runner_phase3_stable_000005", + "eventType": "item.delta", + "priority": 2, + "envelope": { + "envelopeId": "envelope_event_000005", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.005Z", + "eventType": "item.delta", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Prove Phase 3 durable recovery." + }, + "priority": 2, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000005", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 5, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.005Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 6, + "sourceEventId": "event_runner_phase3_stable_000006", + "eventType": "item.completed", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000006", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.006Z", + "eventType": "item.completed", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Durable recovery completed." + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000006", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 6, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.006Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 7, + "sourceEventId": "event_runner_phase3_stable_000007", + "eventType": "run.result.proposed", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000007", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.007Z", + "eventType": "run.result.proposed", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "schema": "paperclip.prp.result.v1", + "status": "succeeded", + "summary": "Phase 3 durable transport recovered without duplicate effects." + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000007", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 7, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.007Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 8, + "sourceEventId": "event_runner_phase3_stable_000008", + "eventType": "run.terminal", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000008", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.008Z", + "eventType": "run.terminal", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "runTerminalState": "succeeded", + "schema": "paperclip.prp.terminal.v1", + "turnTerminalState": "completed" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000008", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 8, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.008Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 9, + "sourceEventId": "event_runner_phase3_stable_000009", + "eventType": "runner.stopped", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000009", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.009Z", + "eventType": "runner.stopped", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "afterDurableFlush": true + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000009", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 9, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.009Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 1, + "logicalEffectCount": 1 + } + ] + }, + "runnerState": { + "schema": "paperclip.runner.phase3.state.v1", + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable", + "lifecycle": "stopped", + "nextSourceSeq": 10, + "ackedSourceSeq": 9, + "lastControllerCommandSeq": 4, + "reconnectCount": 0, + "maxOutboxBytes": 65536, + "peakOutboxBytes": 5315, + "outbox": [], + "processedCommands": { + "command_phase3_001": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "commandDigest": "fnv1a64:c19dfbbf86a3dbb4", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_002": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "commandDigest": "fnv1a64:b5198f3ce67ce88e", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_003": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "commandDigest": "fnv1a64:fb3b206fe67e1dc8", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_004": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "commandDigest": "fnv1a64:d11bf8308f863bad", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + }, + "diagnostics": [], + "backpressure": false, + "recoverableFailure": null, + "unrecoverableOutcome": null, + "harnessGeneration": 1, + "stopAfterFlush": true + }, + "commands": [ + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_001", + "controllerSeq": 1, + "type": "run.prepare", + "issuedAt": "2026-08-07T23:30:01.000Z", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_002", + "controllerSeq": 2, + "type": "session.open", + "issuedAt": "2026-08-07T23:30:02.000Z", + "payload": { + "reuse": "same_session" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_003", + "controllerSeq": 3, + "type": "turn.start", + "issuedAt": "2026-08-07T23:30:03.000Z", + "payload": { + "turnId": "turn_phase3_stable", + "text": "Prove Phase 3 durable recovery." + }, + "status": "completed", + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_004", + "controllerSeq": 4, + "type": "runner.shutdown", + "issuedAt": "2026-08-07T23:30:04.000Z", + "payload": {}, + "status": "completed", + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + ], + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } +} diff --git a/packages/paperclip-runner/knowledge/evidence/phase-03-faults/revoke.json b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/revoke.json new file mode 100644 index 00000000000..444ac734a27 --- /dev/null +++ b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/revoke.json @@ -0,0 +1,528 @@ +{ + "schema": "paperclip.runner.phase3.trace.v1", + "diagnostics": { + "schema": "paperclip.runner.phase3.diagnostics.v1", + "fault": "revoke", + "connection": { + "state": "revoked", + "connectionCount": 1, + "reconnectCount": 0, + "leaseId": "connection_lease_8fe123ed-6a53-42e1-bdc7-315a93568cbd", + "leaseExpiresAt": "2026-08-07T23:36:41.005Z" + }, + "identity": { + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable" + }, + "cursors": { + "runnerAckedSourceSeq": 8, + "runnerNextSourceSeq": 9, + "coreAckedSourceSeq": 8, + "highestCommittedSourceSeq": 8 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 5315, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 4, + "p0Lost": 0 + }, + "commands": { + "issued": 4, + "completed": 3, + "rejected": 1, + "logicalEffects": 3, + "duplicateDeliveries": 0 + }, + "recovery": { + "replayDeliveries": 4, + "runnerRestarts": 0, + "harnessRestarts": 0, + "malformedFrames": 0, + "freshBootstraps": 1, + "outcome": "revoked", + "reason": "revoke_completed" + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "committedEvents": [ + { + "sourceSeq": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "eventType": "workspace.ready", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000001", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.001Z", + "eventType": "workspace.ready", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 1, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.001Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 2, + "sourceEventId": "event_runner_phase3_stable_000002", + "eventType": "session.started", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000002", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.002Z", + "eventType": "session.started", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "driverSessionId": "driver_phase3_fake", + "normalizedSessionId": "session_phase3_stable", + "resumed": false + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000002", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 2, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.002Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 3, + "sourceEventId": "event_runner_phase3_stable_000003", + "eventType": "turn.accepted", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000003", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.003Z", + "eventType": "turn.accepted", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "sameSession": true, + "turnId": "turn_phase3_stable" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000003", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 3, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.003Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 1, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 4, + "sourceEventId": "event_runner_phase3_stable_000004", + "eventType": "item.started", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000004", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.004Z", + "eventType": "item.started", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "kind": "assistant_message" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000004", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 4, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.004Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 1, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 5, + "sourceEventId": "event_runner_phase3_stable_000005", + "eventType": "item.delta", + "priority": 2, + "envelope": { + "envelopeId": "envelope_event_000005", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.005Z", + "eventType": "item.delta", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Prove Phase 3 durable recovery." + }, + "priority": 2, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000005", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 5, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.005Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 1, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 6, + "sourceEventId": "event_runner_phase3_stable_000006", + "eventType": "item.completed", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000006", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.006Z", + "eventType": "item.completed", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Durable recovery completed." + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000006", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 6, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.006Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 1, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 7, + "sourceEventId": "event_runner_phase3_stable_000007", + "eventType": "run.result.proposed", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000007", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.007Z", + "eventType": "run.result.proposed", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "schema": "paperclip.prp.result.v1", + "status": "succeeded", + "summary": "Phase 3 durable transport recovered without duplicate effects." + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000007", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 7, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.007Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 1, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 8, + "sourceEventId": "event_runner_phase3_stable_000008", + "eventType": "run.terminal", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000008", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.008Z", + "eventType": "run.terminal", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "runTerminalState": "succeeded", + "schema": "paperclip.prp.terminal.v1", + "turnTerminalState": "completed" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000008", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 8, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.008Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 3, + "logicalEffectCount": 1 + } + ] + }, + "runnerState": { + "schema": "paperclip.runner.phase3.state.v1", + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable", + "lifecycle": "revoked", + "nextSourceSeq": 9, + "ackedSourceSeq": 8, + "lastControllerCommandSeq": 4, + "reconnectCount": 0, + "maxOutboxBytes": 65536, + "peakOutboxBytes": 5315, + "outbox": [], + "processedCommands": { + "command_after_revoke": { + "commandId": "command_after_revoke", + "controllerSeq": 4, + "commandDigest": "fnv1a64:fd10e64f32894219", + "status": "rejected", + "logicalEffectCount": 0, + "result": { + "commandId": "command_after_revoke", + "controllerSeq": 4, + "detail": "connection capability is revoked; commands have no logical effect", + "logicalEffectCount": 0, + "status": "rejected" + } + }, + "command_phase3_001": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "commandDigest": "fnv1a64:c19dfbbf86a3dbb4", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_002": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "commandDigest": "fnv1a64:b5198f3ce67ce88e", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_003": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "commandDigest": "fnv1a64:fb3b206fe67e1dc8", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + } + }, + "diagnostics": [ + "connection lease revoked; flushing durable events" + ], + "backpressure": false, + "recoverableFailure": null, + "unrecoverableOutcome": null, + "harnessGeneration": 1, + "stopAfterFlush": true + }, + "commands": [ + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_001", + "controllerSeq": 1, + "type": "run.prepare", + "issuedAt": "2026-08-07T23:30:01.000Z", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_002", + "controllerSeq": 2, + "type": "session.open", + "issuedAt": "2026-08-07T23:30:02.000Z", + "payload": { + "reuse": "same_session" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_003", + "controllerSeq": 3, + "type": "turn.start", + "issuedAt": "2026-08-07T23:30:03.000Z", + "payload": { + "turnId": "turn_phase3_stable", + "text": "Prove Phase 3 durable recovery." + }, + "status": "completed", + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_after_revoke", + "controllerSeq": 4, + "type": "turn.start", + "issuedAt": "2026-08-07T23:30:04.000Z", + "payload": { + "turnId": "turn_phase3_stable", + "text": "must be rejected after revoke" + }, + "status": "rejected", + "result": { + "commandId": "command_after_revoke", + "controllerSeq": 4, + "detail": "connection capability is revoked; commands have no logical effect", + "logicalEffectCount": 0, + "status": "rejected" + } + } + ], + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } +} diff --git a/packages/paperclip-runner/knowledge/evidence/phase-03-faults/runner-restart.json b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/runner-restart.json new file mode 100644 index 00000000000..3e751401863 --- /dev/null +++ b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/runner-restart.json @@ -0,0 +1,601 @@ +{ + "schema": "paperclip.runner.phase3.trace.v1", + "diagnostics": { + "schema": "paperclip.runner.phase3.diagnostics.v1", + "fault": "runner-restart", + "connection": { + "state": "stopped", + "connectionCount": 2, + "reconnectCount": 1, + "leaseId": "connection_lease_dcd257e4-0a30-4bb8-8674-0446c617e29f", + "leaseExpiresAt": "2026-08-07T23:36:39.391Z" + }, + "identity": { + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable" + }, + "cursors": { + "runnerAckedSourceSeq": 10, + "runnerNextSourceSeq": 11, + "coreAckedSourceSeq": 10, + "highestCommittedSourceSeq": 10 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 6883, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 6, + "p0Lost": 0 + }, + "commands": { + "issued": 4, + "completed": 4, + "rejected": 0, + "logicalEffects": 4, + "duplicateDeliveries": 1 + }, + "recovery": { + "replayDeliveries": 10, + "runnerRestarts": 1, + "harnessRestarts": 0, + "malformedFrames": 0, + "freshBootstraps": 2, + "outcome": "recovered", + "reason": "runner_restart_completed" + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "committedEvents": [ + { + "sourceSeq": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "eventType": "workspace.ready", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000001", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.001Z", + "eventType": "workspace.ready", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 1, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.001Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 3, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 2, + "sourceEventId": "event_runner_phase3_stable_000002", + "eventType": "session.started", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000002", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.002Z", + "eventType": "session.started", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "driverSessionId": "driver_phase3_fake", + "normalizedSessionId": "session_phase3_stable", + "resumed": false + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000002", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 2, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.002Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 3, + "sourceEventId": "event_runner_phase3_stable_000003", + "eventType": "runner.reconciled", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000003", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.003Z", + "eventType": "runner.reconciled", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "outcome": "same_durable_session_resumed", + "runnerInstanceId": "runner_phase3_stable", + "turnId": "turn_phase3_stable" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000003", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 3, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.003Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 4, + "sourceEventId": "event_runner_phase3_stable_000004", + "eventType": "turn.accepted", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000004", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.004Z", + "eventType": "turn.accepted", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "sameSession": true, + "turnId": "turn_phase3_stable" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000004", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 4, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.004Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 5, + "sourceEventId": "event_runner_phase3_stable_000005", + "eventType": "item.started", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000005", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.005Z", + "eventType": "item.started", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "kind": "assistant_message" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000005", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 5, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.005Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 6, + "sourceEventId": "event_runner_phase3_stable_000006", + "eventType": "item.delta", + "priority": 2, + "envelope": { + "envelopeId": "envelope_event_000006", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.006Z", + "eventType": "item.delta", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Prove Phase 3 durable recovery." + }, + "priority": 2, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000006", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 6, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.006Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 7, + "sourceEventId": "event_runner_phase3_stable_000007", + "eventType": "item.completed", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000007", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.007Z", + "eventType": "item.completed", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Durable recovery completed." + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000007", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 7, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.007Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 8, + "sourceEventId": "event_runner_phase3_stable_000008", + "eventType": "run.result.proposed", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000008", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.008Z", + "eventType": "run.result.proposed", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "schema": "paperclip.prp.result.v1", + "status": "succeeded", + "summary": "Phase 3 durable transport recovered without duplicate effects." + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000008", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 8, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.008Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 9, + "sourceEventId": "event_runner_phase3_stable_000009", + "eventType": "run.terminal", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000009", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.009Z", + "eventType": "run.terminal", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "runTerminalState": "succeeded", + "schema": "paperclip.prp.terminal.v1", + "turnTerminalState": "completed" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000009", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 9, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.009Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 10, + "sourceEventId": "event_runner_phase3_stable_000010", + "eventType": "runner.stopped", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000010", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.010Z", + "eventType": "runner.stopped", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "afterDurableFlush": true + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000010", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 10, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.010Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 1, + "logicalEffectCount": 1 + } + ] + }, + "runnerState": { + "schema": "paperclip.runner.phase3.state.v1", + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable", + "lifecycle": "stopped", + "nextSourceSeq": 11, + "ackedSourceSeq": 10, + "lastControllerCommandSeq": 4, + "reconnectCount": 1, + "maxOutboxBytes": 65536, + "peakOutboxBytes": 6883, + "outbox": [], + "processedCommands": { + "command_phase3_001": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "commandDigest": "fnv1a64:c19dfbbf86a3dbb4", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_002": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "commandDigest": "fnv1a64:b5198f3ce67ce88e", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_003": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "commandDigest": "fnv1a64:fb3b206fe67e1dc8", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_004": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "commandDigest": "fnv1a64:d11bf8308f863bad", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + }, + "diagnostics": [ + "runner process restored the same durable identity" + ], + "backpressure": false, + "recoverableFailure": null, + "unrecoverableOutcome": null, + "harnessGeneration": 1, + "stopAfterFlush": true + }, + "commands": [ + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_001", + "controllerSeq": 1, + "type": "run.prepare", + "issuedAt": "2026-08-07T23:30:01.000Z", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_002", + "controllerSeq": 2, + "type": "session.open", + "issuedAt": "2026-08-07T23:30:02.000Z", + "payload": { + "reuse": "same_session" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_003", + "controllerSeq": 3, + "type": "turn.start", + "issuedAt": "2026-08-07T23:30:03.000Z", + "payload": { + "turnId": "turn_phase3_stable", + "text": "Prove Phase 3 durable recovery." + }, + "status": "completed", + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_004", + "controllerSeq": 4, + "type": "runner.shutdown", + "issuedAt": "2026-08-07T23:30:04.000Z", + "payload": {}, + "status": "completed", + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + ], + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } +} diff --git a/packages/paperclip-runner/knowledge/evidence/phase-03-faults/socket-drop.json b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/socket-drop.json new file mode 100644 index 00000000000..7133c0466f9 --- /dev/null +++ b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/socket-drop.json @@ -0,0 +1,561 @@ +{ + "schema": "paperclip.runner.phase3.trace.v1", + "diagnostics": { + "schema": "paperclip.runner.phase3.diagnostics.v1", + "fault": "socket-drop", + "connection": { + "state": "stopped", + "connectionCount": 2, + "reconnectCount": 1, + "leaseId": "connection_lease_efd9f53a-cc91-4232-8ec8-1a5d5963dad4", + "leaseExpiresAt": "2026-08-07T23:36:38.467Z" + }, + "identity": { + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable" + }, + "cursors": { + "runnerAckedSourceSeq": 9, + "runnerNextSourceSeq": 10, + "coreAckedSourceSeq": 9, + "highestCommittedSourceSeq": 9 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 5314, + "maxBytes": 65536, + "backpressure": false, + "p0Committed": 5, + "p0Lost": 0 + }, + "commands": { + "issued": 4, + "completed": 4, + "rejected": 0, + "logicalEffects": 4, + "duplicateDeliveries": 0 + }, + "recovery": { + "replayDeliveries": 8, + "runnerRestarts": 0, + "harnessRestarts": 0, + "malformedFrames": 0, + "freshBootstraps": 1, + "outcome": "recovered", + "reason": "socket_drop_completed" + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "committedEvents": [ + { + "sourceSeq": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "eventType": "workspace.ready", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000001", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.001Z", + "eventType": "workspace.ready", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 1, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.001Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 2, + "sourceEventId": "event_runner_phase3_stable_000002", + "eventType": "session.started", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000002", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.002Z", + "eventType": "session.started", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "driverSessionId": "driver_phase3_fake", + "normalizedSessionId": "session_phase3_stable", + "resumed": true + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000002", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 2, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.002Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 3, + "sourceEventId": "event_runner_phase3_stable_000003", + "eventType": "turn.accepted", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000003", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.003Z", + "eventType": "turn.accepted", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "sameSession": true, + "turnId": "turn_phase3_stable" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000003", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 3, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.003Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 4, + "sourceEventId": "event_runner_phase3_stable_000004", + "eventType": "item.started", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000004", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.004Z", + "eventType": "item.started", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "kind": "assistant_message" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000004", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 4, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.004Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 5, + "sourceEventId": "event_runner_phase3_stable_000005", + "eventType": "item.delta", + "priority": 2, + "envelope": { + "envelopeId": "envelope_event_000005", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.005Z", + "eventType": "item.delta", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Prove Phase 3 durable recovery." + }, + "priority": 2, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000005", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 5, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.005Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 6, + "sourceEventId": "event_runner_phase3_stable_000006", + "eventType": "item.completed", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000006", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.006Z", + "eventType": "item.completed", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "text": "Durable recovery completed." + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000006", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 6, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.006Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 7, + "sourceEventId": "event_runner_phase3_stable_000007", + "eventType": "run.result.proposed", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000007", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.007Z", + "eventType": "run.result.proposed", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "schema": "paperclip.prp.result.v1", + "status": "succeeded", + "summary": "Phase 3 durable transport recovered without duplicate effects." + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000007", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 7, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.007Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 8, + "sourceEventId": "event_runner_phase3_stable_000008", + "eventType": "run.terminal", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000008", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.008Z", + "eventType": "run.terminal", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "reportedWorkDisposition": "done", + "runTerminalState": "succeeded", + "schema": "paperclip.prp.terminal.v1", + "turnTerminalState": "completed" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000008", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 8, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.008Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 9, + "sourceEventId": "event_runner_phase3_stable_000009", + "eventType": "runner.stopped", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000009", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.009Z", + "eventType": "runner.stopped", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "afterDurableFlush": true + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000009", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 9, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.009Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 1, + "logicalEffectCount": 1 + } + ] + }, + "runnerState": { + "schema": "paperclip.runner.phase3.state.v1", + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable", + "lifecycle": "stopped", + "nextSourceSeq": 10, + "ackedSourceSeq": 9, + "lastControllerCommandSeq": 4, + "reconnectCount": 1, + "maxOutboxBytes": 65536, + "peakOutboxBytes": 5314, + "outbox": [], + "processedCommands": { + "command_phase3_001": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "commandDigest": "fnv1a64:c19dfbbf86a3dbb4", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_002": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "commandDigest": "fnv1a64:b5198f3ce67ce88e", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_003": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "commandDigest": "fnv1a64:fb3b206fe67e1dc8", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_004": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "commandDigest": "fnv1a64:d11bf8308f863bad", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + }, + "diagnostics": [ + "WebSocket connection closed: failed to fill whole buffer" + ], + "backpressure": false, + "recoverableFailure": null, + "unrecoverableOutcome": null, + "harnessGeneration": 1, + "stopAfterFlush": true + }, + "commands": [ + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_001", + "controllerSeq": 1, + "type": "run.prepare", + "issuedAt": "2026-08-07T23:30:01.000Z", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_002", + "controllerSeq": 2, + "type": "session.open", + "issuedAt": "2026-08-07T23:30:02.000Z", + "payload": { + "reuse": "same_session" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_003", + "controllerSeq": 3, + "type": "turn.start", + "issuedAt": "2026-08-07T23:30:03.000Z", + "payload": { + "turnId": "turn_phase3_stable", + "text": "Prove Phase 3 durable recovery." + }, + "status": "completed", + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "turn completed", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_004", + "controllerSeq": 4, + "type": "runner.shutdown", + "issuedAt": "2026-08-07T23:30:04.000Z", + "payload": {}, + "status": "completed", + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + ], + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } +} diff --git a/packages/paperclip-runner/knowledge/evidence/phase-03-faults/storage-pressure.json b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/storage-pressure.json new file mode 100644 index 00000000000..253628c02cf --- /dev/null +++ b/packages/paperclip-runner/knowledge/evidence/phase-03-faults/storage-pressure.json @@ -0,0 +1,443 @@ +{ + "schema": "paperclip.runner.phase3.trace.v1", + "diagnostics": { + "schema": "paperclip.runner.phase3.diagnostics.v1", + "fault": "storage-pressure", + "connection": { + "state": "stopped", + "connectionCount": 1, + "reconnectCount": 0, + "leaseId": "connection_lease_d78971e6-232f-4e78-955f-9de455589f8c", + "leaseExpiresAt": "2026-08-07T23:36:40.583Z" + }, + "identity": { + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable" + }, + "cursors": { + "runnerAckedSourceSeq": 5, + "runnerNextSourceSeq": 6, + "coreAckedSourceSeq": 5, + "highestCommittedSourceSeq": 5 + }, + "outbox": { + "events": 0, + "bytes": 0, + "peakBytes": 2326, + "maxBytes": 16384, + "backpressure": true, + "p0Committed": 3, + "p0Lost": 0 + }, + "commands": { + "issued": 5, + "completed": 4, + "rejected": 1, + "logicalEffects": 4, + "duplicateDeliveries": 0 + }, + "recovery": { + "replayDeliveries": 4, + "runnerRestarts": 0, + "harnessRestarts": 0, + "malformedFrames": 0, + "freshBootstraps": 1, + "outcome": "recovered", + "reason": "storage_pressure_completed" + }, + "security": { + "bootstrapTicketPersisted": false, + "connectionLeaseTokenPersisted": false, + "secretLeakCount": 0 + }, + "committedEvents": [ + { + "sourceSeq": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "eventType": "workspace.ready", + "priority": 1, + "envelope": { + "envelopeId": "envelope_event_000001", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.001Z", + "eventType": "workspace.ready", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "priority": 1, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000001", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 1, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.001Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 2, + "sourceEventId": "event_runner_phase3_stable_000002", + "eventType": "session.started", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000002", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.002Z", + "eventType": "session.started", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "driverSessionId": "driver_phase3_fake", + "normalizedSessionId": "session_phase3_stable", + "resumed": false + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000002", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 2, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.002Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 3, + "sourceEventId": "event_runner_phase3_stable_000003", + "eventType": "item.delta", + "priority": 2, + "envelope": { + "envelopeId": "envelope_event_000003", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.003Z", + "eventType": "item.delta", + "itemId": "item_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "coalescedCount": 250, + "latest": { + "chunk": "bounded-progress-249", + "secretToken": "[REDACTED]" + } + }, + "priority": 2, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000003", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 3, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.003Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 4, + "sourceEventId": "event_runner_phase3_stable_000004", + "eventType": "runner.backpressure", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000004", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.004Z", + "eventType": "runner.backpressure", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "maxOutboxBytes": 16384, + "newTurnsAccepted": false, + "p0ReserveBytes": 8192, + "reason": "outbox_soft_limit" + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000004", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 4, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.004Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 2, + "logicalEffectCount": 1 + }, + { + "sourceSeq": 5, + "sourceEventId": "event_runner_phase3_stable_000005", + "eventType": "runner.stopped", + "priority": 0, + "envelope": { + "envelopeId": "envelope_event_000005", + "kind": "event", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "emittedAt": "2026-08-07T23:00:00.005Z", + "eventType": "runner.stopped", + "normalizedSessionId": "session_phase3_stable", + "payload": { + "afterDurableFlush": true + }, + "priority": 0, + "runId": "run_phase3_stable", + "schema": "paperclip.prp.event.v1", + "schemaVersion": 1, + "sourceEventId": "event_runner_phase3_stable_000005", + "sourceInstanceId": "runner_phase3_stable", + "sourceKind": "runner", + "sourceSeq": 5, + "turnId": "turn_phase3_stable" + }, + "protocol": "paperclip.runner", + "runId": "run_phase3_stable", + "runnerInstanceId": "runner_phase3_stable", + "sentAt": "2026-08-07T23:00:00.005Z", + "turnId": "turn_phase3_stable", + "version": 1 + }, + "deliveryCount": 1, + "logicalEffectCount": 1 + } + ] + }, + "runnerState": { + "schema": "paperclip.runner.phase3.state.v1", + "runnerInstanceId": "runner_phase3_stable", + "environmentLeaseId": "environment_lease_phase3_stable", + "runId": "run_phase3_stable", + "normalizedSessionId": "session_phase3_stable", + "turnId": "turn_phase3_stable", + "itemId": "item_phase3_stable", + "lifecycle": "stopped", + "nextSourceSeq": 6, + "ackedSourceSeq": 5, + "lastControllerCommandSeq": 5, + "reconnectCount": 0, + "maxOutboxBytes": 16384, + "peakOutboxBytes": 2326, + "outbox": [], + "processedCommands": { + "command_phase3_001": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "commandDigest": "fnv1a64:c19dfbbf86a3dbb4", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_002": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "commandDigest": "fnv1a64:b5198f3ce67ce88e", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_003": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "commandDigest": "fnv1a64:778efd982aadc99f", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "storage pressure applied with P2 coalescing", + "logicalEffectCount": 1, + "status": "completed" + } + }, + "command_phase3_004": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "commandDigest": "fnv1a64:34d91505a30f60fb", + "status": "rejected", + "logicalEffectCount": 0, + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "new turns are disabled while draining or backpressured", + "logicalEffectCount": 0, + "status": "rejected" + } + }, + "command_phase3_005": { + "commandId": "command_phase3_005", + "controllerSeq": 5, + "commandDigest": "fnv1a64:533318a30fba6d22", + "status": "completed", + "logicalEffectCount": 1, + "result": { + "commandId": "command_phase3_005", + "controllerSeq": 5, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + }, + "diagnostics": [], + "backpressure": true, + "recoverableFailure": null, + "unrecoverableOutcome": null, + "harnessGeneration": 1, + "stopAfterFlush": true + }, + "commands": [ + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_001", + "controllerSeq": 1, + "type": "run.prepare", + "issuedAt": "2026-08-07T23:30:01.000Z", + "payload": { + "workspace": "phase-03-durable-fixture" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_001", + "controllerSeq": 1, + "detail": "run prepared", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_002", + "controllerSeq": 2, + "type": "session.open", + "issuedAt": "2026-08-07T23:30:02.000Z", + "payload": { + "reuse": "same_session" + }, + "status": "completed", + "result": { + "commandId": "command_phase3_002", + "controllerSeq": 2, + "detail": "session bound", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_003", + "controllerSeq": 3, + "type": "fault.storage_pressure", + "issuedAt": "2026-08-07T23:30:03.000Z", + "payload": {}, + "status": "completed", + "result": { + "commandId": "command_phase3_003", + "controllerSeq": 3, + "detail": "storage pressure applied with P2 coalescing", + "logicalEffectCount": 1, + "status": "completed" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_004", + "controllerSeq": 4, + "type": "turn.start", + "issuedAt": "2026-08-07T23:30:04.000Z", + "payload": { + "turnId": "turn_phase3_stable", + "text": "Prove Phase 3 durable recovery." + }, + "status": "rejected", + "result": { + "commandId": "command_phase3_004", + "controllerSeq": 4, + "detail": "new turns are disabled while draining or backpressured", + "logicalEffectCount": 0, + "status": "rejected" + } + }, + { + "schema": "paperclip.prp.command.v1", + "commandId": "command_phase3_005", + "controllerSeq": 5, + "type": "runner.shutdown", + "issuedAt": "2026-08-07T23:30:05.000Z", + "payload": {}, + "status": "completed", + "result": { + "commandId": "command_phase3_005", + "controllerSeq": 5, + "detail": "runner will stop after durable flush", + "logicalEffectCount": 1, + "status": "completed" + } + } + ], + "assertions": { + "stableIdentity": true, + "sourceCursorContinuous": true, + "oneLogicalEffectPerAcceptedCommand": true, + "noDuplicateLogicalEvents": true, + "p0Preserved": true, + "boundedStorage": true, + "secretsRedacted": true + } +} diff --git a/packages/paperclip-runner/knowledge/evidence/phase-03-recovery-diagnostics.png b/packages/paperclip-runner/knowledge/evidence/phase-03-recovery-diagnostics.png new file mode 100644 index 0000000000000000000000000000000000000000..00b6a3d4937e557ffd505f96eb9e47b453c204a1 GIT binary patch literal 69766 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