You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
id: PoC: one example world running unmodified in a Worker isolate — journal equality vs the native wasmtime host (from #2057) #2271
Audit #2057 (queue task 3359, result posted on that issue 2026-10-29) classified pkgs/id world execution against Workers Wasm reality and defined the portability contract in terms of the existing manifest + limits machinery: guest module unchanged, host surface reimplemented per tier, portability = wasm | native declared in the world manifest and validated against world_limits-style caps. This issue is the proof of concept for the isolate tier. Not the permanent feature (program rule, epic #2056).
PoC scope
Take one existing example world program (suggested: tic-tac-toe or roc-counter — small, turn-based) unmodified as a guest module.
Run it inside a Cloudflare Worker isolate (Durable Object host) with the journal/store/clock host surface reimplemented in TypeScript against DO SQLite.
Play a scripted sequence of turns through the isolate host and through the native wasmtime host; the resulting journals must be identical (same events, same state hashes) — that equality, not "it ran", is the PoC's pass condition.
Enforce the audit's caps in the isolate host (memory declaration check, per-invocation compute bound) and demonstrate a refusal: a manifest declaring portability = native (or memory above the isolate ceiling) is rejected by the hosted loader with the reason named.
Out of scope
The full host surface (presentation/SSH/network rows stay native per the audit), Roc compilation in the isolate (pre-compiled modules only), any production hosted-world offering.
Acceptance criteria
Journal-equality demonstration (scope point 3) passes and is documented on this issue
Manifest refusal case (point 4) demonstrated
Findings note: which host functions the example actually used, and any surface that behaved differently across hosts
No production portability promise claimed or merged under this issue
Expectation: effort class m for triage; "done" = triage findings posted on this issue, acceptance criteria checked for clarity/feasibility, follow-up implementation task enqueued or explicitly deferred with reason.
Triage — #2271 PoC: example world in a Worker isolate, journal equality vs native host (queue task 3426)
Verdict: feasible, and smaller than the issue's framing suggests — with three scope clarifications below that the implementation must follow. No hard blockers. One open question (real Cloudflare deploy vs local workerd) is resolved by recommendation, not escalated: it does not change the pass condition.
Evidence gathered fresh this run against current main (laptop primary ~/git/code, HEAD 7b76c791):
1. The guest needs NO host imports — the "TS host surface" is the plaza ABI, not a host-import reimplementation
pkgs/id/src/sandbox.rs:9-10: "The guest receives no imports: no WASI, filesystem, sockets, clocks, or random source."
pkgs/id/src/sandbox.rs:184-191: Sandbox::compile rejects any module with imports (guest imports are not allowed). Checked-in examples confirm it: examples/roc-counter/README.md — "The module has no Wasm imports."
All interaction is host→guest through the export allowlist (sandbox.rs, compile validation): memory, plaza_alloc, plaza_free, plaza_init(i64)->i32, plaza_update(i32,i32,i32,i32)->i32 (model ptr, participant, event ptr, event len), plaza_view, plaza_layout (optional), plaza_records (optional), plaza_wants (optional), plaza_snapshot/plaza_restore (both or neither), plaza_out_len, plaza_error_ptr/len.
So the isolate host to write in TypeScript is: instantiate the import-free module with WebAssembly.instantiate, drive the plaza_* byte ABI (alloc/write event bytes, call update, read result via plaza_out_len + memory), and persist inputs/outputs. There is no journal/store/clock import surface to port for these guests. The findings-note acceptance item ("which host functions the example actually used") is already answerable: none — zero imports; the host surface exercised is exactly the plaza_* exports above.
2. Example choice: tic-tac-toe primary, roc-counter as pipeline smoke
examples/roc-counter (seed + inc only, view = count=N, records {"count":N}) is the right first smoke — the native sandbox tests already pin its behaviour (src/sandbox.rs: checked_in_roc_counter_compiles_and_initializes_in_the_import_free_sandbox, seed 7 → count 0/1/2).
examples/tic-tac-toe is the right equality subject: pure update(model, pid, event) (pid is ignored; turn = ply parity), occupied/off-board/non-digit/post-win moves are ignored, snapshot = the 9-char board string and restore reconstructs plays+winner from it (examples/tic-tac-toe/main.roc). Suggested scripted sequence (X wins top row, with the edge cases interleaved): 0, 4, 1, 4 (occupied, ignored), 9 (not a move, ignored), 8, 2 (X wins), 3 (after win, ignored) — then snapshot mid/end, restore into a fresh instance on both hosts, and confirm identical continuation.
3. "Journal equality" must be defined as per-step state equality — NOT native journal-file byte equality (scope clarification 1)
The native world journal (src/world/mod.rs, src/world/core.rs) contains server-side entries (membership, capability grants/digests, schedules, provenance/origin metadata) that an isolate host does not and should not reproduce byte-for-byte. The property the #2057 contract actually rests on is: the same input sequence folds to the same state under either host. Define the PoC comparison as, after every scripted input: equality of (view, records, snapshot) and a hash of the snapshot (state hash), for the identical (seed, participant, event-bytes) sequence on both hosts. This matches the packet's stated test ("journal/state-hash comparison") and mirrors the existing native determinism machinery in src/world_fixture.rs (verify replays a fixture and compares records after every event).
4. Cold start is part of the PoC, not an extra (scope clarification 2)
Native hosting keeps one persistent wasmtime instance per world with the model pointer in guest linear memory (sandbox.rs module doc). An isolate/DO instance can be evicted at any time, so the DO's SQLite journal is the source of truth: on cold start the TS host must re-instantiate and either replay the journaled inputs or plaza_restore the last snapshot, then continue. The demonstration must include at least one forced cold start mid-sequence (fresh DO instance / fresh isolate) with equality holding across it — a warm-instance-only pass does not prove the hosted claim.
5. Manifest refusal: the portability field does not exist yet (scope clarification 3)
grep portability over pkgs/id/src and pkgs/id/examples: no hits.src/world_manifest.rsWorldManifest today has module_hash, module_source, seed, grants, ceiling, profile, schedules — no portability declaration. Memory is declared via profile.wasm_memory_bytes (src/world_limits.rs:43-45, validated ≥1 page, clamped to the server ceiling).
Therefore the refusal demo is a hosted-loader behaviour in the PoC: the TS loader reads the manifest, refuses portability = native with the reason named, and refuses a declared wasm_memory_bytes above the id: investigate: world-VM Wasm portability audit — what of the worlds runtime runs inside a Worker #2057 hosted ceiling (64 MB) with the reason named. Adding the validated portability field to the native WorldManifest is a separate small Rust follow-up — it should NOT gate this PoC, and this PoC must not claim it landed.
6. Known behavioural differences to pre-register in the findings note
Fuel: native enforces per-invocation fuel (SandboxLimits::default = 10,000,000; src/sandbox.rs). Workers has no fuel; the bound is CPU time. A guest cannot be fuel-metered identically in the isolate — for the chosen examples fuel use is trivial, but the findings note must state this difference explicitly rather than discovering it later.
Memory ceiling semantics differ: native default sandbox memory is 16 MB with trap_on_grow_failure; the isolate ceiling from the audit is a declared-memory check (≤64 MB) against a 128 MB whole-isolate budget. The refusal in (5) is a manifest check, not a runtime trap equivalence.
7. Infrastructure: greenfield, and local workerd is sufficient
No Workers/wrangler/Durable Object code exists in pkgs/id today (searched: no wrangler config, no DO host). The PoC creates it new (suggest pkgs/id/examples/roc-world/worker/ or a sibling pkgs/id/worker-poc/ — implementer's choice, keep it out of the native crate). Recommendation: run the isolate side under local workerd/Miniflare with DO SQLite emulation. Journal equality is a runtime-semantics question and workerd is the same isolate engine; a real Cloudflare deploy adds an account/credential dependency and proves nothing extra about equality. Real deploy = optional stretch, explicitly not part of the pass condition.
Sizing & routing
Triage outcome: triaged — feasible as scoped above. Implementation is larger than a trivial fix (new TS host + DO journal store + native reference runner + comparison harness): estimate effort l, timebox at the queue max and expect it to span worker shifts via checkpoints.
Follow-on: implementation task enqueued from this triage (id in the closing agent note below). This issue stays open as the tracking issue; its acceptance criteria stand as written, read with clarifications 1–3 above.
Expectation: done = triage findings posted + follow-up routed. Implementation follow-on enqueued as queue task 3950 (small_fix, priority 30); this issue stays open as its tracking issue, labelled queue/queued for that task.
Links: triage findings comment on this issue; queue task 3950
Parked: Queue task 5598 is parked for 30 minutes. Fresh GitHub shows issue #2271 OPEN and PR #3726 OPEN, authored by Drew on the exact task branch queue/5598-2271-worker-isolate-poc. The Drew-owned PR hard stop applies; I did not inspect its reviews/checks, touch its worktree, run tests, merge it, or create competing work.
Resume condition: PR #3726 is merged/closed or task 5598 is explicitly rerouted; revalidate issue and PR fresh before proceeding.
Found via: queue claim (resumed from the PR-opened checkpoint)
Task: PR id(worker-poc): TS isolate host for plaza guests — scaffold + counter smoke (#2271) #3726 merged (merge commit 10e4a89). The one live Codex finding (participant IDs wrapping instead of clamping to i32::MAX, guest.ts) was fixed in 13ac9c8 with a regression smoke; the six earlier findings were verified already fixed on the branch in e68f4cd (the a1a5683 cited in older thread replies is a parallel commit that was never on this branch). Codex re-review of 13ac9c8: completed, no findings.
Expectation: done — PoC acceptance verified on the laptop against the merged tree: compare/compare.mjs PASS (13 steps equal on native and isolate hosts, roc-counter + tic-tac-toe, cold starts included); smoke/counter-smoke.mjs PASS (incl. both hosted-loader refusals); smoke/participant-clamp.mjs PASS; compare/do-cold-start.mjs PASS under wrangler dev (journal restore after /cold-start and after a wrangler restart; DO step-3 snapshot hash equals the native reference). Closing issue id: PoC: one example world running unmodified in a Worker isolate — journal equality vs the native wasmtime host (from #2057) #2271 on this evidence.
Activity
developing-today commentedon Oct 29, 2026
CODE-1134
dezren39 commentedon Oct 30, 2026
🤖 Agent note · picked up
dezren39 commentedon Oct 30, 2026
Triage — #2271 PoC: example world in a Worker isolate, journal equality vs native host (queue task 3426)
Verdict: feasible, and smaller than the issue's framing suggests — with three scope clarifications below that the implementation must follow. No hard blockers. One open question (real Cloudflare deploy vs local workerd) is resolved by recommendation, not escalated: it does not change the pass condition.
Evidence gathered fresh this run against current main (laptop primary
~/git/code, HEAD7b76c791):1. The guest needs NO host imports — the "TS host surface" is the plaza ABI, not a host-import reimplementation
pkgs/id/src/sandbox.rs:9-10: "The guest receives no imports: no WASI, filesystem, sockets, clocks, or random source."pkgs/id/src/sandbox.rs:184-191:Sandbox::compilerejects any module with imports (guest imports are not allowed). Checked-in examples confirm it:examples/roc-counter/README.md— "The module has no Wasm imports."sandbox.rs, compile validation):memory,plaza_alloc,plaza_free,plaza_init(i64)->i32,plaza_update(i32,i32,i32,i32)->i32(model ptr, participant, event ptr, event len),plaza_view,plaza_layout(optional),plaza_records(optional),plaza_wants(optional),plaza_snapshot/plaza_restore(both or neither),plaza_out_len,plaza_error_ptr/len.So the isolate host to write in TypeScript is: instantiate the import-free module with
WebAssembly.instantiate, drive theplaza_*byte ABI (alloc/write event bytes, call update, read result viaplaza_out_len+ memory), and persist inputs/outputs. There is no journal/store/clock import surface to port for these guests. The findings-note acceptance item ("which host functions the example actually used") is already answerable: none — zero imports; the host surface exercised is exactly theplaza_*exports above.2. Example choice: tic-tac-toe primary, roc-counter as pipeline smoke
examples/roc-counter(seed +inconly,view = count=N, records{"count":N}) is the right first smoke — the native sandbox tests already pin its behaviour (src/sandbox.rs:checked_in_roc_counter_compiles_and_initializes_in_the_import_free_sandbox, seed 7 → count 0/1/2).examples/tic-tac-toeis the right equality subject: pureupdate(model, pid, event)(pid is ignored; turn = ply parity), occupied/off-board/non-digit/post-win moves are ignored,snapshot= the 9-char board string andrestorereconstructs plays+winner from it (examples/tic-tac-toe/main.roc). Suggested scripted sequence (X wins top row, with the edge cases interleaved):0, 4, 1, 4 (occupied, ignored), 9 (not a move, ignored), 8, 2 (X wins), 3 (after win, ignored)— then snapshot mid/end, restore into a fresh instance on both hosts, and confirm identical continuation.3. "Journal equality" must be defined as per-step state equality — NOT native journal-file byte equality (scope clarification 1)
The native world journal (
src/world/mod.rs,src/world/core.rs) contains server-side entries (membership, capability grants/digests, schedules, provenance/origin metadata) that an isolate host does not and should not reproduce byte-for-byte. The property the #2057 contract actually rests on is: the same input sequence folds to the same state under either host. Define the PoC comparison as, after every scripted input: equality of(view, records, snapshot)and a hash of the snapshot (state hash), for the identical(seed, participant, event-bytes)sequence on both hosts. This matches the packet's stated test ("journal/state-hash comparison") and mirrors the existing native determinism machinery insrc/world_fixture.rs(verifyreplays a fixture and compares records after every event).4. Cold start is part of the PoC, not an extra (scope clarification 2)
Native hosting keeps one persistent wasmtime instance per world with the model pointer in guest linear memory (
sandbox.rsmodule doc). An isolate/DO instance can be evicted at any time, so the DO's SQLite journal is the source of truth: on cold start the TS host must re-instantiate and either replay the journaled inputs orplaza_restorethe last snapshot, then continue. The demonstration must include at least one forced cold start mid-sequence (fresh DO instance / fresh isolate) with equality holding across it — a warm-instance-only pass does not prove the hosted claim.5. Manifest refusal: the
portabilityfield does not exist yet (scope clarification 3)grep portabilityoverpkgs/id/srcandpkgs/id/examples: no hits.src/world_manifest.rsWorldManifesttoday hasmodule_hash,module_source,seed,grants,ceiling,profile,schedules— no portability declaration. Memory is declared viaprofile.wasm_memory_bytes(src/world_limits.rs:43-45, validated ≥1 page, clamped to the server ceiling).portability = nativewith the reason named, and refuses a declaredwasm_memory_bytesabove the id: investigate: world-VM Wasm portability audit — what of the worlds runtime runs inside a Worker #2057 hosted ceiling (64 MB) with the reason named. Adding the validatedportabilityfield to the nativeWorldManifestis a separate small Rust follow-up — it should NOT gate this PoC, and this PoC must not claim it landed.6. Known behavioural differences to pre-register in the findings note
SandboxLimits::default= 10,000,000;src/sandbox.rs). Workers has no fuel; the bound is CPU time. A guest cannot be fuel-metered identically in the isolate — for the chosen examples fuel use is trivial, but the findings note must state this difference explicitly rather than discovering it later.trap_on_grow_failure; the isolate ceiling from the audit is a declared-memory check (≤64 MB) against a 128 MB whole-isolate budget. The refusal in (5) is a manifest check, not a runtime trap equivalence.7. Infrastructure: greenfield, and local workerd is sufficient
No Workers/wrangler/Durable Object code exists in
pkgs/idtoday (searched: no wrangler config, no DO host). The PoC creates it new (suggestpkgs/id/examples/roc-world/worker/or a siblingpkgs/id/worker-poc/— implementer's choice, keep it out of the native crate). Recommendation: run the isolate side under local workerd/Miniflare with DO SQLite emulation. Journal equality is a runtime-semantics question and workerd is the same isolate engine; a real Cloudflare deploy adds an account/credential dependency and proves nothing extra about equality. Real deploy = optional stretch, explicitly not part of the pass condition.Sizing & routing
🤖 Agent note · triage findings — queue worker (repo-worker-code), lane D, task 3426.
dezren39 commentedon Oct 30, 2026
🤖 Agent note · done
plaza_*ABI; equality defined as per-step (view, records, snapshot) + snapshot hash including a forced cold start; manifestportabilityfield does not exist yet, so refusal is a hosted-loader behaviour in the PoC. Full findings posted above on this issue.queue/queuedfor that task.87 remaining items
dezren39 commentedon Nov 1, 2026
Parked: Queue task 5598 is parked for 30 minutes. Fresh GitHub shows issue #2271 OPEN and PR #3726 OPEN, authored by Drew on the exact task branch
queue/5598-2271-worker-isolate-poc. The Drew-owned PR hard stop applies; I did not inspect its reviews/checks, touch its worktree, run tests, merge it, or create competing work.Resume condition: PR #3726 is merged/closed or task 5598 is explicitly rerouted; revalidate issue and PR fresh before proceeding.
dezren39 commentedon Nov 1, 2026
agent-note:v1 — state: picked-up (small_fix task 5598, OpenChamber scheduled lane)
dezren39 commentedon Nov 1, 2026
agent-note:v1 — state: parked (small_fix task 5598, OpenChamber scheduled lane)
fix(id): clamp worker-poc participant IDs to i32::MAX like the native…
Merge pull request #3726 from developing-today/queue/5598-2271-worker…
dezren39 commentedon Nov 1, 2026
🤖 Agent note · done
compare/compare.mjsPASS (13 steps equal on native and isolate hosts, roc-counter + tic-tac-toe, cold starts included);smoke/counter-smoke.mjsPASS (incl. both hosted-loader refusals);smoke/participant-clamp.mjsPASS;compare/do-cold-start.mjsPASS underwrangler dev(journal restore after /cold-start and after a wrangler restart; DO step-3 snapshot hash equals the native reference). Closing issue id: PoC: one example world running unmodified in a Worker isolate — journal equality vs the native wasmtime host (from #2057) #2271 on this evidence.queue/5598-2271-worker-isolate-pocdezren39 commentedon Nov 2, 2026
Agent note — triage done (task 5152, lane E)
queue/queuedwith no live task at 2026-11-01T06:40Z)queue/queuedlabel is already gone (current labels:priority/high,app/id).id(worker-poc): PlazaGuest.update rejects non-u64-representable parti…