RichEdit stream callback ownership

$edit_stream_call acquires synchronous invocation ownership before writing the guest stack, EIP, or execution controls. It retains the child token and root as i64 locals and the synchronous depth as an i32 local. After the bounded callback loop, all three must still match before sync_depth_leave or any interrupted-context restoration. This includes the 64-round timeout path, which still returns error 1 when ownership is valid. Null callbacks still return 1 without entering.

This follows the reviewed ICM wrapper change 066436de903151fb03194884f63ab72e0f9071dc; it does not modify ICM. Core invocation_current validates the thread, epoch, and published root. Core sync_depth_enter acquires a child before changing depth/spill state; capacity failure precedes guest writes. The core leave helper alone checks the current child, so this wrapper's retained identity is necessary to reject a replaced child. Invalid ownership traps without popping or restoring stale state; process reset owns recovery.

Run node test/test-edit-stream-ownership.js. The test parses the production WAT and executes the wrapper AST with modeled run/ownership/memory boundaries. It covers argument order, saved registers/control state, slices, fresh siblings, nested success and nested timeout, capacity and entry failures before writes, wrong child/root/depth (including differences above 32 bits), callback traps, and ordinary timeout. Guard-removal and late-acquisition mutations must fail. An optional source-path argument allows baseline rejection testing.

These are local JS source conformance tests, not a WAT build, fullVM test, or Circus compatibility claim. Actual x86 callbacks, spill pinning, SEH, async parking, and thread/epoch lifetime enforcement require separately authorized runtime qualification. No CRT jump API is enabled.

Independent paired review, 2026-10-20

Reviewed against fetched main 7ddcd0572b132759c9122c80492e9f9c161a047a and the actual 04-cache.wat invocation/synchronous-depth helpers. Acquisition validates and allocates the child before pinning spill state or increasing depth. The wrapper captures identity after acquisition and checks it before leave; invocation_sync_leave alone cannot detect replacement because it passes the current identity to invocation_leave. Caller registers and execution controls are restored only after successful validation and retirement. A run trap propagates without retirement/restoration. The existing 64-slice abandonment returns error 1 after valid retirement; this review does not qualify asynchronous service or resumability of the abandoned guest callback.

No additional production defect was demonstrated in this bounded review. The original test did not clobber most saved registers, leaving restoration coverage weaker than its description. Added all-register/control clobbers on ordinary return, return on slice 64, and timeout, plus removal mutations for all 13 restores. The dedicated suite now passes 23 cases and 17 mutation controls. Evidence and replay: scratch/runs/20261020-callback-pair-review/. Acceptance remains source-only.