diff --git a/packages/paperclip-runner/README.md b/packages/paperclip-runner/README.md index e1c02e70b8d..92874a80e18 100644 --- a/packages/paperclip-runner/README.md +++ b/packages/paperclip-runner/README.md @@ -6,10 +6,12 @@ production runner direction is Rust; `runner/` is its Cargo workspace. The TypeScript surface remains a control-plane/client reference implementation. 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. Neither phase imports or -starts Paperclip's server, UI, CLI, or production database. +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. -## Phase 0–1 quick start +## Phase 0–2 quick start From the repository root: @@ -33,10 +35,12 @@ Run only the tracer with: pnpm --filter @paperclipai/paperclip-runner trace:phase0 ``` -Replay the Phase 1 happy path in the CLI or open the browser devtool: +Replay the Phase 1 happy path, run a Phase 2 local session, or open the browser +devtool: ```sh pnpm --filter @paperclipai/paperclip-runner replay:phase1 +pnpm --filter @paperclipai/paperclip-runner trace:phase2 -- --scenario happy-path pnpm --filter @paperclipai/paperclip-runner browser:dev --host 127.0.0.1 --port 4179 ``` @@ -44,9 +48,9 @@ pnpm --filter @paperclipai/paperclip-runner browser:dev --host 127.0.0.1 --port | Command | Purpose | |---|---| -| `build` | Compile the TypeScript public surface, Rust workspace, and browser replay. | +| `build` | Compile the TypeScript public surface, Rust workspace, and browser devtool. | | `typecheck` | Check TypeScript, Rust, generated schema sources, and browser types. | -| `test` | Run Rust/TypeScript fixture, mock-contract, stable-output, and negative-boundary tests. | +| `test` | Run Rust/TypeScript fixture, supervisor, fake-driver, live/replay, and boundary tests. | | `check:forbidden-imports` | Reject TypeScript imports and Cargo path dependencies that cross into Paperclip core. | | `check:phase0-parity` | Require byte-for-byte equivalent Rust and TypeScript tracer output. | | `check:phase1-goldens` | Require all reducer snapshots and cross-language summaries to match checked goldens. | @@ -57,8 +61,11 @@ pnpm --filter @paperclipai/paperclip-runner browser:dev --host 127.0.0.1 --port | `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. | -| `test:browser` | Build the browser page, exercise replay states, and capture the screenshot. | -| `verify` | Run the complete Phase 0 and Phase 1 acceptance sequence. | +| `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. | +| `test:browser` | Exercise static replay and live scenarios, then capture screenshots. | +| `verify` | Run the complete Phase 0, Phase 1, and Phase 2 acceptance sequence. | ## Navigate @@ -66,6 +73,8 @@ pnpm --filter @paperclipai/paperclip-runner browser:dev --host 127.0.0.1 --port - [Tutorial index](docs/index.md) - [Phase 0 hand-run tutorial](docs/tutorials/phase-00-standalone-tracer.md) - [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) - [PRP compatibility/versioning policy](docs/protocol-compatibility.md) - [Cumulative end-to-end tutorial](docs/tutorials/end-to-end.md) - [Journal guide](docs/journal.md) @@ -73,7 +82,6 @@ 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 1 remains a static replay checkpoint, not the `paperclip-runnerd` daemon. -Network transport, process supervision, live browser transport, production -Paperclip integration, and real model harnesses remain behind later phase -checkpoints in the implementation plan. +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. diff --git a/packages/paperclip-runner/docs/architecture.md b/packages/paperclip-runner/docs/architecture.md index abe821e6c79..fc98bb968d2 100644 --- a/packages/paperclip-runner/docs/architecture.md +++ b/packages/paperclip-runner/docs/architecture.md @@ -49,8 +49,9 @@ TypeScript schema constants/types -> validator -> deterministic reducer ``` The Rust `runner-core` crate establishes the production language/package -boundary and checks the same fixture summaries; it is not yet the Phase 2 runner -daemon. +boundary and checks the same fixture summaries. Phase 2 adds the package-local +`paperclip-runnerd` and `fake-harness` binaries without changing that dependency +direction. ## Language ownership @@ -131,6 +132,43 @@ Card, and Textarea are source-compatible adaptations of shadcn primitives; all visual values live in its local `styles.css` token layer. It imports the same replay module as the CLI and does not create a browser-only protocol model. +## Phase 2 local process boundary + +```text +TypeScript mock core + | PRP commands over stdin JSONL + v +paperclip-runnerd (Rust supervisor) + | fake-harness commands over stdin JSONL + v +fake-harness (Rust scripted driver) + | typed messages over stdout JSONL + v +paperclip-runnerd -> canonical PRP events -> mock core + | + v + browser NDJSON stream +``` + +The mock core starts one runner process. The runner creates a new process group +for one fake harness and its workers. The runner clears the inherited +environment and restores only the path needed to launch local executables. It +captures stderr and scripted log messages in a bounded tail. + +The controller and harness links use newline-delimited JSON over stdio. This is +the smallest local transport that keeps process ownership clear. The browser +does not connect to the runner. A package-local Vite middleware exposes an HTTP +start/action API and an NDJSON event stream from the TypeScript mock core. + +The runner publishes the structured semantic result before it publishes the +harness process exit fact. It then emits one `run.terminal` event. A non-zero +harness exit can coexist with a valid yielded result. Duplicate commands and +duplicate terminal messages cannot repeat side effects or close the run twice. + +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. + ## 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 3956ec1b60b..de11c505218 100644 --- a/packages/paperclip-runner/docs/index.md +++ b/packages/paperclip-runner/docs/index.md @@ -3,19 +3,21 @@ The tutorials are cumulative and are always run from the repository root. Each tutorial starts with an explanation of what the phase is and what the phase proves. -## Accepted implementation phases +## Implemented phases - [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. - [Cumulative end-to-end tutorial](tutorials/end-to-end.md) — the shortest complete workflow available at the current phase. ## Reference - [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) - [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 authorized and in progress. Add its tutorial when its runnable tracer is ready. -Later tutorials are added only after their phase is authorized and implemented. +Phase 2 is implemented and ready for its human checkpoint. Later tutorials are +added only after their phase is authorized and implemented. diff --git a/packages/paperclip-runner/docs/phase-02-local-protocol.md b/packages/paperclip-runner/docs/phase-02-local-protocol.md new file mode 100644 index 00000000000..bf4877461a2 --- /dev/null +++ b/packages/paperclip-runner/docs/phase-02-local-protocol.md @@ -0,0 +1,103 @@ +# Phase 2 Local Protocol and Supervision Reference + +## Scope + +Phase 2 proves one native local session. It uses no Paperclip service, database, +network provider, or model. The TypeScript mock core, Rust runner, and Rust fake +harness are all inside `packages/paperclip-runner/`. + +## Processes and transports + +| Boundary | Transport | Input | Output | +|---|---|---|---| +| Mock core → runner | stdin JSONL | `paperclip.prp.command.v1` | — | +| Runner → mock core | stdout JSONL | — | `paperclip.runner.stream.v1` | +| Runner → fake harness | stdin JSONL | `paperclip.fake_harness.command.v1` | — | +| Fake harness → runner | stdout JSONL | — | `paperclip.fake_harness.message.v1` | +| Mock core → browser | local HTTP + NDJSON | start/actions | validated events and final trace | + +Stderr is diagnostic input. It never becomes a command or canonical event. + +## Deterministic lifecycle + +1. `run.prepare` creates the harness process group. +2. The harness sends `ready`. +3. `session.open` starts one fake driver session. +4. `turn.start` starts one scripted turn. +5. The harness emits typed events, requests, logs, a semantic result, and a + terminal proposal. +6. The runner waits for the harness process and records `harness.exited`. +7. The runner emits one `run.terminal` event and exits zero. + +The runner gives each canonical event a deterministic source ID, source +sequence, and timestamp. Script delay can be overridden for fast tests. + +## Command rules + +- `controllerSeq` starts at 1 and is contiguous. +- The runner stores the canonical JSON for each accepted `commandId`. +- The same ID and same content returns `duplicate` without repeating an effect. +- The same ID with different content is rejected. +- A sequence gap is rejected. +- Phase 2 supports prepare, open, turn start, request resolution, interruption, + stop, close, and cancel command shapes. A script consumes only the commands it + expects. + +## Fake-driver scripts + +Scripts live under `protocol/fixtures/phase-02/scripts/`. + +| Script | Proof | +|---|---| +| `happy-path` | Lifecycle, tool/command item, file item, logs, result, and success terminal | +| `permission-input` | Permission request and free-text input round-trip | +| `interrupted` | Operator interruption, yielded result, exit 130, and cancelled terminal | +| `error` | Non-zero process exit stays separate from the yielded semantic result | +| `duplicate-terminal` | A second terminal proposal is ignored and diagnosed | +| `linger` | Supervisor terminates the harness and its worker process group | + +## Cleanup and credential boundary + +The runner starts the harness in a new process group on Unix. Normal exit waits +for the process. Controller EOF or explicit cleanup sends `TERM`, waits for the +configured grace time, and then sends `KILL` to the full group. Drop cleanup is +a final guard. + +The mock core passes only a small process environment. The runner also clears +the inherited environment before it starts the fake harness. Paperclip keys, +model keys, and AgentMail keys are not forwarded. + +## Bounded diagnostics + +The runner keeps only the configured number of lines and bytes. It reports the +retained lines, retained bytes, and dropped-line count with `harness.exited`. +This log tail is separate from canonical events and the semantic result. + +## Result and terminal authority + +These facts are independent: + +- `run.result.proposed` is the fake driver's structured work claim; +- `harness.exited` is the operating-system process fact; +- `run.terminal` is the one canonical terminal event for the local trace. + +A scripted error can report useful yielded work and exit 7. An interruption can +report yielded work and exit 130. Neither process fact silently replaces the +semantic result. + +## Browser live mode + +The Vite middleware starts the same TypeScript mock-core controller used by +tests. It streams history plus new events as NDJSON. The browser validates each +event with the Phase 1 schema, checks run/session binding, and applies the Phase +1 reducer. At completion it replays the full event list and compares both final +snapshots. + +The browser reuses package-local shadcn-style Button, Badge, Card, and Textarea +components. All visual values remain in `styles.css`. + +## Deferred work + +Phase 2 has no durable outbox, ACK, reconnect, runner restart recovery, real +harness, production Paperclip bridge, or browser-to-runner connection. Those +items require later authorized phases. diff --git a/packages/paperclip-runner/docs/protocol-compatibility.md b/packages/paperclip-runner/docs/protocol-compatibility.md index a93a7d1c78a..60f7bc7f3ce 100644 --- a/packages/paperclip-runner/docs/protocol-compatibility.md +++ b/packages/paperclip-runner/docs/protocol-compatibility.md @@ -3,15 +3,16 @@ ## Authority The JSON Schema files in [`protocol/schemas/`](../protocol/schemas/) are the -language-neutral source of truth for the Phase 1 executable contract. The +language-neutral source of truth for the Phase 1 and Phase 2 executable contract. The generated TypeScript schema module is checked against those files before every TypeScript typecheck. Rust consumes the same fixtures and must produce the same golden parity summaries. The broader normative protocol remains the [native-runner spike specification](../spec/paperclip-native-runner-spike-spec.md). -Phase 1 intentionally implements only validation and static replay; it does not -add transport, persistence, or live control-plane behavior. +Phase 2 reuses this contract for local live events. It adds package-local stdio +and stream envelopes, but it does not add durable transport, persistence, or +production control-plane behavior. ## Version fields @@ -59,6 +60,25 @@ The CLI and browser import the same `replayPhase1FixtureText` function, so validation, compatibility errors, and final snapshots cannot drift between the two surfaces. +## Phase 2 local envelope rules + +- Mock-core commands use `paperclip.prp.command.v1` over stdin JSONL. +- Runner output uses `paperclip.runner.stream.v1` over stdout JSONL. +- Fake-harness commands use `paperclip.fake_harness.command.v1`. +- Fake-harness output uses `paperclip.fake_harness.message.v1`. +- An equivalent repeated `commandId` returns a duplicate receipt and has no + second driver effect. Reuse with different data is rejected. +- A new command must use the next contiguous `controllerSeq`. +- Harness logs are bounded diagnostic data. They are not canonical PRP events. +- `run.result.proposed`, `harness.exited`, and `run.terminal` are separate facts + and appear in that order when a semantic result exists. +- The live browser rejects an event with an invalid schema, run ID, or session + ID before it reaches the reducer. + +These envelopes are local Phase 2 implementation contracts. Phase 3 may add a +durable outbound transport, but it must preserve the canonical PRP event and +command semantics. + ## Change policy 1. Change JSON Schema first. diff --git a/packages/paperclip-runner/docs/tutorials/end-to-end.md b/packages/paperclip-runner/docs/tutorials/end-to-end.md index 8cded8141e2..1a65ae04808 100644 --- a/packages/paperclip-runner/docs/tutorials/end-to-end.md +++ b/packages/paperclip-runner/docs/tutorials/end-to-end.md @@ -2,13 +2,16 @@ ## What this tutorial is -This tutorial combines each accepted Native Runner phase into one procedure. It currently includes Phase 0 and Phase 1. +This tutorial combines each implemented Native Runner phase into one procedure. It currently includes Phase 0, Phase 1, and Phase 2. ## What this tutorial proves -This tutorial proves that the standalone package boundary and static replay path work together. It does not use a live harness or Paperclip. +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. -The current system includes the Rust mock-core tracer and the shared protocol fixtures. It also includes CLI replay and browser replay. +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. ## Current end-to-end path @@ -24,6 +27,11 @@ The current system includes the Rust mock-core tracer and the shared protocol fi 8. Exercise the duplicate, gap, unknown-field, and unsupported-version fixtures. 9. Open the [Phase 1 journal entry](../../knowledge/journal/2026-08-07-phase-01.md) and its linked verification evidence. +10. Follow [Phase 2: Run the Local Runner and Fake Harness](phase-02-local-runner.md). +11. Run the happy, permission/input, interruption, error, and duplicate-terminal scenarios. +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. The one-command form after installation is: @@ -44,6 +52,14 @@ pnpm --filter @paperclipai/paperclip-runner verify - source gaps are visible and never synthesized away; - CLI and browser paths use the same validator/reducer module; - browser components keep visual values in the package-local token layer. +- the Rust supervisor owns the fake harness process group and cleans it up when the controller closes; +- command IDs are idempotent and controller sequence numbers stay contiguous; +- runtime permission and input requests round-trip over the local protocol; +- process exit is recorded separately from the structured semantic result; +- bounded logs retain only their configured tail; +- 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. -The next phase may extend this tutorial only after its own implementation and -human checkpoint are authorized. +Phase 3 may extend this tutorial only after the Phase 2 human checkpoint is +accepted and the next phase is authorized. diff --git a/packages/paperclip-runner/docs/tutorials/phase-02-local-runner.md b/packages/paperclip-runner/docs/tutorials/phase-02-local-runner.md new file mode 100644 index 00000000000..bd902c43cba --- /dev/null +++ b/packages/paperclip-runner/docs/tutorials/phase-02-local-runner.md @@ -0,0 +1,129 @@ +# Phase 2: Run the Local Runner and Fake Harness + +## What this phase is + +Phase 2 is a local live-run path. A TypeScript mock core starts a Rust runner. +The Rust runner starts a scripted fake harness. The processes use JSON lines over +stdio. + +## What this phase proves + +This phase proves that a native session can run from start to finish without +Paperclip, a network provider, or a real model. It proves cleanup, request +resolution, interruption, bounded logs, one terminal result, and live/replay +parity. + +## Prerequisites + +- Node.js 20 or newer +- pnpm 9 or newer +- a stable Rust toolchain with `cargo` +- a Chromium-compatible browser + +Run every command from the repository root on the +`PAP-16679-paperclip-runner` branch. Install the package dependencies and browser: + +```sh +pnpm install --filter @paperclipai/paperclip-runner --lockfile=false --ignore-scripts --dev +pnpm --filter @paperclipai/paperclip-runner exec playwright install chromium +``` + +On a minimal Linux host, install the browser libraries too: + +```sh +pnpm --filter @paperclipai/paperclip-runner exec playwright install-deps chromium +``` + +## 1. Run the package verification path + +```sh +pnpm --filter @paperclipai/paperclip-runner verify +``` + +Expected: Rust, TypeScript, protocol, boundary, documentation, and browser +checks pass. The final Phase 2 line reports one terminal event and a successful +semantic result. + +## 2. Run the happy path in the CLI + +```sh +pnpm --filter @paperclipai/paperclip-runner trace:phase2 -- --scenario happy-path --quiet +``` + +Expected summary facts: + +- `eventCount` is `18`; +- `terminalCount` is `1`; +- `semanticResult` is `done`; +- harness and runner exit codes are `0`. + +Capture the live trace as a validated replay fixture: + +```sh +pnpm --filter @paperclipai/paperclip-runner record:phase2 +``` + +The command writes +`packages/paperclip-runner/knowledge/evidence/phase-02-happy-path.json`. + +## 3. Run the scripted control flows + +```sh +pnpm --filter @paperclipai/paperclip-runner trace:phase2 -- --scenario permission-input --quiet +pnpm --filter @paperclipai/paperclip-runner trace:phase2 -- --scenario interrupted --quiet +pnpm --filter @paperclipai/paperclip-runner trace:phase2 -- --scenario error --quiet +pnpm --filter @paperclipai/paperclip-runner trace:phase2 -- --scenario duplicate-terminal --quiet +pnpm --filter @paperclipai/paperclip-runner trace:phase2 -- --scenario happy-path --duplicate-turn-command --quiet +``` + +Expected: + +- permission and input finish with `done`; +- interruption exits the harness with `130` and reports `yielded`; +- scripted error exits the harness with `7` and reports `yielded`; +- duplicate terminal still reports `terminalCount: 1`; +- duplicate turn command does not start a second turn. + +## 4. Use the live browser + +Start the package-local server: + +```sh +pnpm --filter @paperclipai/paperclip-runner browser:dev --host 127.0.0.1 --port 4179 +``` + +Open `http://127.0.0.1:4179`, then follow these steps: + +1. Keep `Happy path` selected and choose **Start local run**. +2. Confirm the terminal badge says `succeeded`. +3. Confirm `Harness process exit` is `0` and `Semantic result` is `done`. +4. Confirm `Live and replay reducer output` says `Match`. +5. Select `Permission and input`, start the run, and choose **Allow**. +6. Enter a trace name and choose **Send input**. Confirm the run completes. +7. Select `Interruption`, start the run, and choose **Interrupt turn** when the + button becomes active. +8. Confirm the terminal badge says `cancelled`, the semantic result says + `yielded`, and the timeline contains one `run.terminal` event. +9. Switch to **Static replay** and confirm the Phase 1 fixture path still works. + +Stop Vite with `Ctrl+C`. + +## 5. Inspect the evidence + +- [Complete live run](../../knowledge/evidence/phase-02-live-complete.png) +- [Permission request](../../knowledge/evidence/phase-02-live-permission.png) +- [Interrupted run](../../knowledge/evidence/phase-02-live-interrupted.png) +- [Exact verification record](../../knowledge/evidence/2026-08-07-phase-02-verification.md) +- [Engineering journal](../../knowledge/journal/2026-08-07-phase-02.md) + +## What this proves + +- the Rust runner owns and cleans the fake-harness process group; +- the fake driver emits deterministic live events and requests; +- logs are bounded; +- process exit and semantic result stay separate; +- duplicate commands and terminal proposals do not repeat effects; +- every browser event passes the Phase 1 validator and reducer; +- replay after completion produces the same final snapshot. + +Phase 3 must not begin until the Phase 2 human checkpoint is accepted. diff --git a/packages/paperclip-runner/knowledge/evidence/2026-08-07-phase-01-verification.md b/packages/paperclip-runner/knowledge/evidence/2026-08-07-phase-01-verification.md index e4e73d991dd..33f41bcb17e 100644 --- a/packages/paperclip-runner/knowledge/evidence/2026-08-07-phase-01-verification.md +++ b/packages/paperclip-runner/knowledge/evidence/2026-08-07-phase-01-verification.md @@ -115,8 +115,8 @@ parity, the Rust Phase 0 tracer, and the Phase 1 CLI replay all passed. [Phase 1 static replay screenshot](phase-01-static-replay.png) -- PNG: 1440 × 1137, RGB -- SHA-256: `eecdc71e35c76764916317239c2fd3dd1e2f60ab609ee48d12c2a1b6b67897ce` +- PNG: 1440 × 1201, RGB (refreshed by the Phase 2 browser suite) +- SHA-256: `9e77087e6bc16d3f8b7e730bde70eb2da11e359b71e24cd8ad7402a28f6680d0` - Shows editable happy-path fixture input, validated terminal snapshot, result summary, ordered nine-event timeline, and snapshot JSON disclosure. diff --git a/packages/paperclip-runner/knowledge/evidence/2026-08-07-phase-02-verification.md b/packages/paperclip-runner/knowledge/evidence/2026-08-07-phase-02-verification.md new file mode 100644 index 00000000000..5c1c20804a9 --- /dev/null +++ b/packages/paperclip-runner/knowledge/evidence/2026-08-07-phase-02-verification.md @@ -0,0 +1,154 @@ +--- +type: Verification Evidence +title: Phase 2 verification +description: Exact tools, commands, results, and screenshots for the local runner and fake harness. +tags: [native-runner, phase-2, verification, rust, supervisor, fake-driver, browser] +status: stable +generated: { by: openai/gpt-5, at: 2026-08-07T21:10:00Z } +phase: "2" +--- + +# Environment + +- OS: `Linux 6.17.0-1019-aws aarch64` +- Node.js: `v22.22.2` +- pnpm: `9.15.4` +- Vitest: `4.1.10` +- Vite: `6.4.1` +- Playwright: `1.61.1` +- Rust/Cargo: `1.97.1` in the run scratch directory + +# Commands and observed results + +## 1. Rust formatting, tests, and process cleanup + +```sh +cargo fmt --manifest-path packages/paperclip-runner/runner/Cargo.toml --all -- --check +cargo test --manifest-path packages/paperclip-runner/runner/Cargo.toml --locked --workspace +``` + +Result: exit 0. Rust formatting passed. Fifteen library tests and one supervisor +integration test passed. The cleanup test proved that the harness and spawned +worker process group both stop. + +## 2. TypeScript and live-run conformance + +```sh +pnpm --filter @paperclipai/paperclip-runner test:typescript +pnpm --filter @paperclipai/paperclip-runner typecheck:typescript +pnpm --filter @paperclipai/paperclip-runner typecheck:browser +``` + +Result: exit 0. Seven Vitest files and 38 tests passed. The Phase 2 cases cover +driver lifecycle, command and file items, bounded logs, duplicate commands, +permission/input, interruption, error exit versus semantic result, duplicate +terminal suppression, controller-disconnect cleanup, credentials, and +live/replay parity. + +## 3. CLI scenario matrix + +```sh +for scenario in happy-path permission-input interrupted error duplicate-terminal; do + node packages/paperclip-runner/dist/cli/phase2-mock-core.js --scenario "$scenario" --quiet +done +node packages/paperclip-runner/dist/cli/phase2-mock-core.js \ + --scenario happy-path --quiet --duplicate-turn-command +``` + +Observed facts: + +| Scenario | Events | Terminal | Semantic result | Harness exit | Runner exit | +|---|---:|---:|---|---:|---:| +| happy path | 18 | 1 | `done` | 0 | 0 | +| permission/input | 19 | 1 | `done` | 0 | 0 | +| interrupted | 15 | 1 | `yielded` | 130 | 0 | +| error | 14 | 1 | `yielded` | 7 | 0 | +| duplicate terminal | 14 | 1 | `done` | 0 | 0 | + +The duplicate turn command returned one duplicate receipt and did not create a +second `turn.started` event. + +## 4. Browser build, interactions, and screenshots + +```sh +pnpm --filter @paperclipai/paperclip-runner build:browser +pnpm --filter @paperclipai/paperclip-runner check:browser-tokens +pnpm --filter @paperclipai/paperclip-runner test:browser +``` + +Result: exit 0. Vite transformed 219 modules. The token check passed. Five +Playwright tests passed in 3.5 seconds. They cover Phase 1 static replay, +duplicate/version states, live completion and replay parity, permission/input, +and interruption with one terminal event. + +The minimal host lacked Chromium libraries. The test used Ubuntu packages +extracted under `$PAPERCLIP_RUN_SCRATCH_DIR/playwright-libs` through +`LD_LIBRARY_PATH`; no system library was installed. + +## 5. Boundary and knowledge checks + +```sh +pnpm --filter @paperclipai/paperclip-runner check:forbidden-imports +pnpm --filter @paperclipai/paperclip-runner docs:validate +``` + +Result: exit 0. The standalone boundary passed. Documentation links and the OKF +v0.2 bundle passed validation. + +## 6. Complete package acceptance sequence + +```sh +pnpm --filter @paperclipai/paperclip-runner verify +``` + +Result: exit 0 with the run-scratch Rust and browser-library paths active. The +command built Rust, TypeScript, and browser outputs; ran all typechecks, tests, +goldens, parity, token, boundary, browser, docs, and OKF checks; ran the Phase 0 +tracer and Phase 1 replay; and finished with the Phase 2 happy-path summary. + +# Browser artifacts + +## Completed live run + +[Phase 2 completed run screenshot](phase-02-live-complete.png) + +- PNG: 1440 × 1786, RGB +- SHA-256: `6c49da63df4de4e2d7e5958bd66cdefa492819474526c345328dcd2b575b887a` +- Shows 18 validated events, process exit 0, semantic result `done`, one terminal + event, and live/replay `Match`. + +## Permission request + +[Phase 2 permission screenshot](phase-02-live-permission.png) + +- PNG: 1440 × 1131, RGB +- SHA-256: `192c0b244694d22cfe880e814dade1714ae48ab18a2047aaa2c7714419a0328b` +- Shows the live pending permission request before resolution. + +## Interrupted run + +[Phase 2 interrupted run screenshot](phase-02-live-interrupted.png) + +- PNG: 1440 × 1591, RGB +- SHA-256: `11003e92e776afe670a4a2c958770b4f844ff373115ff93c3aee1e54238b2bd4` +- Shows exit 130, semantic result `yielded`, cancelled terminal state, one + terminal event, and live/replay `Match`. + +# Acceptance mapping + +- Deterministic Rust runner and supervisor: passed. +- Small local harness transport: stdio JSONL passed. +- Timing, error, permission, input, interruption, and terminal scripts: passed. +- Mock-core command/event loop through package contracts: passed. +- Bounded logs and separate process/semantic facts: passed. +- Driver conformance and controller/harness cleanup: passed. +- Duplicate commands and exactly one terminal event: passed. +- Browser live mode with Phase 1 validator/reducer: passed. +- Live/replay parity: passed. +- Package reference, tutorial, cumulative steps, evidence, OKF journal, and + screenshot set: linked and validated. + +# Remaining risk + +The local process and in-memory browser path do not prove Phase 3 durable +delivery or reconnect behavior. Production Paperclip behavior remains unchanged. diff --git a/packages/paperclip-runner/knowledge/evidence/index.md b/packages/paperclip-runner/knowledge/evidence/index.md index 8b16787b11c..a9be2dd18dc 100644 --- a/packages/paperclip-runner/knowledge/evidence/index.md +++ b/packages/paperclip-runner/knowledge/evidence/index.md @@ -5,3 +5,4 @@ * [Phase 0 verification](2026-08-07-phase-00-verification.md) - Clean install, build, tests, boundary, documentation, OKF, and tracer results. * [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. diff --git a/packages/paperclip-runner/knowledge/evidence/phase-01-static-replay.png b/packages/paperclip-runner/knowledge/evidence/phase-01-static-replay.png index 5937e7fb980..9d6bdbfac75 100644 Binary files a/packages/paperclip-runner/knowledge/evidence/phase-01-static-replay.png and b/packages/paperclip-runner/knowledge/evidence/phase-01-static-replay.png differ diff --git a/packages/paperclip-runner/knowledge/evidence/phase-02-live-complete.png b/packages/paperclip-runner/knowledge/evidence/phase-02-live-complete.png new file mode 100644 index 00000000000..d274127043e Binary files /dev/null and b/packages/paperclip-runner/knowledge/evidence/phase-02-live-complete.png differ diff --git a/packages/paperclip-runner/knowledge/evidence/phase-02-live-interrupted.png b/packages/paperclip-runner/knowledge/evidence/phase-02-live-interrupted.png new file mode 100644 index 00000000000..87a9b1bd929 Binary files /dev/null and b/packages/paperclip-runner/knowledge/evidence/phase-02-live-interrupted.png differ diff --git a/packages/paperclip-runner/knowledge/evidence/phase-02-live-permission.png b/packages/paperclip-runner/knowledge/evidence/phase-02-live-permission.png new file mode 100644 index 00000000000..785ee611a8f Binary files /dev/null and b/packages/paperclip-runner/knowledge/evidence/phase-02-live-permission.png differ diff --git a/packages/paperclip-runner/knowledge/journal/2026-08-07-phase-02.md b/packages/paperclip-runner/knowledge/journal/2026-08-07-phase-02.md new file mode 100644 index 00000000000..de58b7043ce --- /dev/null +++ b/packages/paperclip-runner/knowledge/journal/2026-08-07-phase-02.md @@ -0,0 +1,81 @@ +--- +type: Engineering Journal Entry +title: Phase 2 local runner and fake harness +description: Decisions and evidence for deterministic Rust supervision, scripted live sessions, and browser parity. +tags: [native-runner, phase-2, rust, supervisor, fake-driver, live-replay, browser] +status: stable +generated: { by: openai/gpt-5, at: 2026-08-07T21:10:00Z } +entry_kind: phase +phase: "2" +--- + +# Context + +Phase 2 must prove one full native session without Paperclip core, a network +provider, or a real model. It extends the accepted Phase 1 validator and reducer +instead of creating a second live-state contract. + +# Decisions + +1. Use JSONL over stdio for mock-core-to-runner and runner-to-harness traffic. + It is the smallest local transport and makes process ownership explicit. +2. Keep the production-direction supervisor and fake driver in Rust. Keep the + mock core and browser client in TypeScript behind package contracts. +3. Start the fake harness in a new process group. On controller EOF, termination, + or drop, stop the whole group with a bounded TERM-to-KILL grace period. +4. Clear inherited process environments. Restore only the executable path. + Never forward Paperclip, model-provider, or AgentMail credentials. +5. Treat command IDs as idempotency keys and require contiguous controller + sequence numbers before a new effect. +6. Keep log tails bounded by line and byte limits. Logs stay diagnostic and do + not become canonical events. +7. Keep the semantic result, harness process exit, and canonical terminal event + as three facts. Emit exactly one terminal event. +8. Use scripts for happy, request, interruption, error, duplicate-terminal, and + cleanup scenarios. Override delay in tests to keep runs fast. +9. Validate every browser event with the Phase 1 validator and apply the Phase 1 + reducer. Replay the final event list and compare snapshots at completion. +10. Reuse the package's shadcn-style primitives and local token layer. Keep the + live surface dense, left-flowing, and free of duplicate state labels. + +# Evidence + +Exact tool versions, commands, results, CLI summaries, screenshots, and +acceptance mapping live in +[Phase 2 verification evidence](../evidence/2026-08-07-phase-02-verification.md). +The hand-run path is the +[Phase 2 tutorial](../../docs/tutorials/phase-02-local-runner.md). + +# Failures and corrections + +- The current run started without Cargo on `PATH`. The official stable toolchain + was installed only under the run scratch directory. +- Chromium first failed because eight Linux libraries were absent. The system + install path required a sudo password, so the required Ubuntu packages were + downloaded and extracted into run scratch. Playwright then passed without a + system change. +- The first browser attempt could not bind its loopback test port inside the + sandbox. The same package-local test was rerun with the approved local bind. +- Review found that a TypeScript controller error killed only the runner process + and could leave the harness group alive. The controller now closes stdin; the + Rust runner treats EOF as cleanup, terminates the group, records exit, and + emits one terminal event. A regression test covers this path. + +# Known gaps + +- No durable outbox, ACK, reconnect, or process restart recovery. +- No real harness or model session. +- No production Paperclip bridge, database, budget, approval, or status change. +- One runner owns one harness session and one scripted turn. +- The Vite middleware and in-memory live-run registry are development tools, not + a production server. + +# Follow-up questions + +- Which event and command fields must enter the Phase 3 durable outbox before a + reconnect test is meaningful? +- Should Phase 3 persist command receipts separately from canonical events or in + one ordered delivery ledger? +- What bounded replay window should the browser request after reconnect? + +Phase 3 remains deferred until the Phase 2 human checkpoint is accepted. diff --git a/packages/paperclip-runner/knowledge/journal/index.md b/packages/paperclip-runner/knowledge/journal/index.md index da0f2e2a597..4c646070d58 100644 --- a/packages/paperclip-runner/knowledge/journal/index.md +++ b/packages/paperclip-runner/knowledge/journal/index.md @@ -5,3 +5,4 @@ * [Phase 0 boundary, journal, and runnable skeleton](2026-08-07-phase-00.md) - Decisions, implementation evidence, failures, gaps, and next questions for the standalone skeleton. * [Phase 0 Rust boundary correction](2026-08-07-phase-00-rust-boundary-correction.md) - Root cause and corrected Rust/TypeScript ownership after the human checkpoint. * [Phase 1 protocol, fixtures, reducer, and static replay](2026-08-07-phase-01.md) - Executable PRP schemas, deterministic replay decisions, browser findings, and checkpoint gaps. +* [Phase 2 local runner and fake harness](2026-08-07-phase-02.md) - Rust supervision, stdio protocol, scripted driver, live browser, cleanup, and parity decisions. diff --git a/packages/paperclip-runner/knowledge/log.md b/packages/paperclip-runner/knowledge/log.md index b374e1d6f63..0348300593c 100644 --- a/packages/paperclip-runner/knowledge/log.md +++ b/packages/paperclip-runner/knowledge/log.md @@ -5,3 +5,4 @@ * **Creation**: Established the OKF v0.2 bundle, typed Phase 0 journal, verification evidence, template, and progressive-disclosure indexes. * **Rust boundary correction**: Added the production-direction Cargo workspace, shared-fixture parity evidence, negative Cargo boundary coverage, and a superseding journal entry after the Phase 0 checkpoint exposed the TypeScript-only omission. * **Phase 1 static replay**: Added executable PRP v1 schemas, cross-language fixture/golden parity, deterministic reducer, CLI/browser replay, compatibility policy, tutorial, screenshot, and verification evidence. +* **Phase 2 local runner**: Added the deterministic Rust supervisor, stdio fake-harness protocol, scripted scenarios, bounded logs, cleanup and terminal guards, TypeScript mock core, validated live browser mode, screenshots, tutorial, and verification evidence.