Skip to content

2026-05-16 — Stone C1 SHIPPED; Stone C2 PARTIAL

Stone C1 shipped at commit 77c99d9. ThreadPeer<I, O> + Thread/readln + Thread/println + make_thread_peer_pair_for_test Rust helper. 3/3 tests green. ~35 min sonnet.

Stone C2 is PARTIAL on disk — implementation complete, but the test fixture took sub-decision (b) (Rust-only mock with make_process_peer_for_test) instead of sub-decision (a) (real spawn-process round-trip). The user flagged this as the easy framing before commit:

“mocks?.. is that an honest word or are we actuallly measuring what we must be… simple things should be trivial to test - we test in a hermetic env if we must… spawn a read server and talk to it…”

What sonnet shipped (working tree, uncommitted at this entry)

Section titled “What sonnet shipped (working tree, uncommitted at this entry)”
FileStatusLOC
src/types.rsmodified+61 (ProcessPeer<I, O> struct)
src/check.rsmodified+52 (Process/readln + Process/println type schemes)
src/runtime.rsmodified+151 (eval handlers + dispatch arms)
src/typed_channel.rsmodified+87 (make_process_peer_for_test helper)
tests/wat_arc170_stone_c2_processpeer.rsnew8850 bytes, 3 tests, all mock-driven
docs/arc/2026/05/170-program-entry-points/SCORE-STONE-C2-PROCESSPEER.mdnew (orchestrator-written)~150 lines

All 3 tests green; workspace baseline unchanged. The substrate wiring is correct.

BRIEF § Implementation protocol step 5: “Option A: spawn a real process via existing spawn-process; construct ProcessPeer from its Process/stdin + Process/stdout; round-trip. Option B: Rust-side mock similar to C1’s helper. Sonnet picks based on simplicity.”

EXPECTATIONS predicted: “Sub-decision (b) Rust mock — faster, less integration-y.”

Sonnet picked (b) per the explicit BRIEF authority. The BRIEF was wrong to authorize it. The right framing was: real-spawn integration is non-negotiable for a Process peer; the mock cuts the integration story the type EXISTS to provide.

make_process_peer_for_test exercises the same Value-layer dispatch paths (typed Sender/Receiver over PipeFd) that real spawn-process would. But it bypasses the substrate construction surface: a wat user has no way to mint ProcessPeer<I, O> from a Process<I, O> handle today. The verb is defined; the path to construct one is missing.

Stone D’s bracket macro is supposed to wire this — but until Stone D ships, the only proof that ProcessPeer is reachable from wat is via an explicit constructor verb. Without it: ProcessPeer is defined, verbs dispatch, tests pass — and a wat user cannot use any of it.

First reflex (rejected) — mint ProcessPeer/from-process constructor verb

Section titled “First reflex (rejected) — mint ProcessPeer/from-process constructor verb”

Orchestrator’s first response was to propose minting a new substrate verb :wat::kernel::ProcessPeer/from-process to wrap the composition. Wrong on multiple discipline anchors:

  • feedback_no_new_types — STOP signal on wrapper-verb-creation reflex when substrate already has the parts
  • feedback_assertion_demands_evidence — the proposal asserted “the substrate gap is no constructor” without verifying that existing primitives compose. The ??? in the orchestrator’s own pseudocode was the ignorance signal

Grep verification (post-compaction) revealed every primitive needed already exists:

  • :wat::kernel::Process/stdin proc -> :wat::io::IOWriter — src/check.rs:12916
  • :wat::kernel::Process/stdout proc -> :wat::io::IOReader — src/check.rs:12925
  • :wat::kernel::Sender/from-pipe writer -> :Sender<O> — existing wat-level helper
  • :wat::kernel::Receiver/from-pipe reader -> :Receiver<I> — existing wat-level helper
  • :wat::kernel::ProcessPeer/new rx tx -> :ProcessPeer<I,O> — auto-generated by struct mechanism (src/runtime.rs:2470 registers <type>/new for every struct, including substrate-registered builtins)

ZERO substrate additions needed.

User-facing IPC framing — the question Stone C2’s test promotes

Section titled “User-facing IPC framing — the question Stone C2’s test promotes”

User caught the deeper concern: drafting a real-spawn integration test that wires spawn-process + peer composition + drain-and-join LOOKS like documenting the user-facing IPC pattern. That promotes the test fixture to teaching artifact — and the artifact would teach users to manually compose lifecycle primitives.

Run four-questions on what the user-facing IPC surface SHOULD be:

(a) drain-and-join + manual peer composition = user-facing pattern

  • Obvious: marginal — Stone B made drain-and-join public, but is manual composition the FULL surface?
  • Simple: YES (minimal substrate)
  • Honest: NO — users will forget drain, wire rx/tx backwards, no panic cascade, no supervision across N processes
  • Good UX: NO — three-line peer construction every call site

→ Fails on honest + good UX.

(b) Stone D’s run-processes bracket = user-facing surface; Stone C2’s test = substrate-composition proof

  • Obvious: YES — primitives compose; macro hides composition
  • Simple: YES — users learn ONE form
  • Honest: YES — bracket enforces drain, peer direction, supervision — users CAN’T fuck up
  • Good UX: YES — one bracket form, all lifecycle hidden

→ YES YES YES YES.

Resolved direction (b). No new manager layer needed — Stone D IS the manager layer (that’s exactly its job). Stone C2’s integration test is the substrate-composition proof, not the user-facing IPC pattern. Framing must reflect that explicitly:

  • Test file renamed tests/wat_arc170_stone_c2_processpeer.rstests/wat_process_peer_ipc_round_trip.rs (concept-anchored)
  • Header comment names Stone D as the user-facing surface: “this exercises the substrate primitives Stone D’s run-processes bracket macro will compose; user code never writes this manually — it writes the bracket”
  • drain-and-join IS public (Stone B made it the canonical safe lifecycle primitive), but its public availability does NOT promote it to the user-facing IPC surface — Stone D wraps it for normal use

Stone C2 revision plan (post-direction-(b))

Section titled “Stone C2 revision plan (post-direction-(b))”
  1. Drop the constructor-verb reflex from this INTERSTITIAL + SCORE
  2. Rewrite the test: T1 (type mint) + T3 (asymmetry) stay; T2 becomes real-spawn round-trip composing Process/stdin + Process/stdout + Sender/from-pipe + Receiver/from-pipe + ProcessPeer/new + Process/println + Process/readln + Process/drain-and-join — every primitive already exists
  3. Rename test file (concept-anchored) + header comment names Stone D as user-facing surface
  4. Retire make_process_peer_for_test Rust helper (no longer needed — real-spawn test replaces its role)
  5. Verify workspace green
  6. Tick Stone C2 [x] in BRACKET-IMPLEMENTATION-STONES.md § Status
  7. Commit atomically + push

BRIEFs MUST NOT authorize the easy framing. The BRIEF named (a) real-spawn and (b) Rust mock as equivalent options “based on simplicity.” That phrasing invited sonnet to pick the easy version — and sonnet did. The feedback_refuse_easy_solutions discipline applies at BRIEF-drafting time, not just user-review-time. See feedback_brief_no_easy_auth.

Constructor-verb reflex is wrapper-type creation. Adding ProcessPeer/from-process to “make composition pleasant” was the reflex feedback_no_new_types catches. The verbose composition is the honest form (feedback_verbose_is_honest): it REVEALS that ProcessPeer wraps a Receiver + Sender; that the Receiver reads from child’s stdout; that the Sender writes to child’s stdin. Three nested calls in a test fixture is fine; the macro hides them for everyday use.

Substrate-level vs user-facing distinction. Stone C2 ships the type + verbs; Stone D ships the user-facing bracket. The integration test PROVES Stone C2’s primitives compose — it does NOT document the user-facing IPC pattern. Header framing must make this explicit, or the test becomes misleading teaching material.