The pending table is window.__craftBridgePending[action], a FIFO per action name (craft-bridge.js:127-129); native replies via __craftBridgeResult(action, payload) which shift()s the head (:33-39), and the zig side echoes no request id — bridge_error.zig:202 formats only the action name and the raw result.
Two failure modes, both silent:
- Cross-bridge collisions — two bridges exposing the same action name mix replies. The file documents this itself (
craft-bridge.js:114-118). - Subtler and worse: two concurrent in-flight calls to the same action are matched in completion order, not call order. Any native handler that answers out of order hands caller A caller B's payload. No error, just wrong data.
Ask: thread a request id. JS generates a monotonic id per _req, sends it in the envelope, native echoes it in __craftBridgeResult, JS resolves by id with the action-name FIFO kept as the fallback for old binaries. Mechanical on both sides, removes the whole bug class — and it is a prerequisite for multi-window (#67), where "which webview asked" joins "which call asked".
🤖 Generated with Claude Code