mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-27 02:44:50 +01:00
docs(runner): document Phase 2 verification
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
f32331a567
commit
7e0c8632da
17 files changed
+581
-27
No files matched your search
@@ -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.
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 129 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 135 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 120 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 95 KiB |
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
Reference in new issue
Block a user