Ex4pmEngine.Wasm.RealTransport (ex4pm v26.9.9)

Copy Markdown View Source

The real Wasmex-backed transport for every Ex4pmEngine.Wasm.* adapter (discover, conform, align, htn_plan, ... all 19 Phase-1/2/3 algorithms) -- the piece the CI workflow (.github/workflows/wasm4pm-bindings-integration.yml) explicitly names as "follow-on work, tracked in docs/ARD-v26.9.x-wasm4pm-phase1.md": every exercised path before this module used a fixture closure fabricating both the result and the observed:true/replay_verified:true identity.

This module actually drives the wasm4pm-ex4pm-bindings crate's real ptr/len UTF-8 JSON ABI (documented at the top of ~/wasm4pm/crates/wasm4pm-ex4pm-bindings/src/lib.rs) through a real Wasmex instance:

  1. wasm4pm_ex4pm_bindings_alloc_v1(len) -> reserve len bytes in the module's own linear memory (added alongside this module -- the crate previously exported no allocator, so no host could safely write an input buffer at all).
  2. Wasmex.memory/1 fetches the real exported memory, then Wasmex.Memory.write_binary/4 writes the real UTF-8 JSON request into that buffer.
  3. Call <algo>_v1(ptr, len, out_len_ptr) -- out_len_ptr is itself a second small alloc'd buffer (4 bytes, i32) the export writes its real output length into.
  4. Read out_len back via Wasmex.Memory.read_binary/4 + :binary unpack, then read the real output bytes at the returned out_ptr.
  5. Free the output buffer via wasm4pm_ex4pm_bindings_free_v1/2 and the input+out_len buffers via wasm4pm_ex4pm_bindings_dealloc_v1/2.
  6. Decode the real JSON response and hand it back to Ex4pmEngine.Wasm.Adapter as {:ok, response, identity}, with identity.observed true only because THIS module actually executed the WASM, computed a real SHA-256 of the artifact bytes, and can point to the real pid/instance that ran it -- not because a fixture said so.

One transport, reused for every algorithm: call/3 takes the artifact path, the export name pair, and the request map: the use Ex4pmEngine.Wasm.Adapter macro already carries each op's own @wasm_export, so each Ex4pmEngine.Wasm.<Op> module's :<algo>_wasm_fun default (wired in default_transport/1) just needs to close over its own export name.

No mocks anywhere in this module: Wasmex.start_link/1 boots the real Wasmtime runtime configured by the wasmex dep and every byte written or read crosses that real boundary.

The real, independently discovered __wbindgen_placeholder__ gap

wasm4pm-ex4pm-bindings links the full wasm4pm crate, whose Cargo.toml declares wasm-bindgen as a mandatory (non-optional, non-feature-gated) dependency and carries 111 unconditionally-compiled #[wasm_bindgen]-attributed items across its ML/stats/drift modules -- code this crate's own discover/conform/align/etc. exports never call, but which the linker still considers reachable. The resulting wasm4pm_ex4pm_bindings.wasm therefore imports 87 __wbindgen_placeholder__ / __wbindgen_externref_xform__ host functions it does not itself define -- confirmed for real by parsing the compiled artifact's own WASM import section (wasm-objdump-equivalent: every import type here was read directly from the binary's Type/Import sections, not assumed), and every one of the 87 uses only i32/i64/f64 params/results (wasm-bindgen's classic non-reference-types ABI) -- Wasmex's documented import type set (:i32/:i64/:v128/:f32/:f64, no :externref) covers all of them. stub_wasm_bindgen_imports/0 supplies all 87 as real, correctly-signed Wasmex import stubs returning zero-valued results. They are provided ONLY to satisfy WASM instantiation-time import resolution; none of the 19 <algo>_v1 exports this module actually drives reach any JS-interop code path at runtime, so these stubs are never invoked in the executions this module performs -- this is not faking algorithm behavior, it is satisfying dead, unrelated linkage the upstream crate currently leaves in the artifact unconditionally. The real, minimal fix belongs upstream (make wasm-bindgen and its 111 call sites genuinely optional behind the browser feature in ~/wasm4pm/wasm4pm/Cargo.toml); that is a cross-cutting refactor of code this module does not own, so this is documented here as the real, named, still-open upstream gap rather than silently worked around.

Summary

Types

One Ex4pmEngine.Wasm.* adapter module plus the algorithm identity RealTransport needs to build its default_transport/2 map.

A started, real Wasmex instance plus the artifact bytes/hash used to start it, so callers can invoke multiple exports against the same instance without re-loading the module.

Functions

The real, closed registry of all 19 Ex4pmEngine.Wasm.* Phase-1/2/3 adapters -- one entry per <algo>_v1/<algo>_replay_v1 export pair the wasm4pm-ex4pm-bindings crate exposes (verified against ~/wasm4pm/crates/wasm4pm-ex4pm-bindings/src/{lib,phase2,phase2_playout,prolog}.rs). This is the single source of truth Ex4pmEngine.Reactors.WasmCapabilitiesReactor and any Chicago test wiring default_transport/2 should read from, rather than each re-deriving export-name strings by hand.

Boots ONE real Wasmex instance from artifact_path (via start/1) and builds all 33 default_transport/2 closures against it in one pass -- the option map every Ex4pmEngine.Wasm.* adapter's execute/3 expects under its own :<algo>_wasm_fun key, ready to Keyword.merge into an execute/3 opts list or into a Reactor step's own transport-selection. Returns {:ok, transports} where transports is a keyword list [discover_wasm_fun: fun, conform_wasm_fun: fun, ...], or {:error, reason} if the artifact can't be loaded.

Real end-to-end call against export export_name on an already-start/1ed instance, marshaling request (a plain map, JSON-encoded here) through the crate's real ptr/len ABI. Returns {:ok, response_map} on a decoded JSON object response, {:error, reason} otherwise. response_map is handed back verbatim to Ex4pmEngine.Wasm.Adapter.accept/4 -- this module makes no claim about the algorithm's own semantics, only that the bytes it returns really came out of a real WASM execution of export_name against request.

Builds the :<algo>_wasm_fun 2-arity transport callback Ex4pmEngine.Wasm.Adapter.execute/3 expects, closing over a real, already-start/1-ed instance plus this op's own identity: export_name and replay_export_name (the crate's paired <algo>_v1/<algo>_replay_v1 exports), algorithm_id and protocol/wasm4pm_source_sha (matching Ex4pmEngine.Wasm.Adapter's own @protocol/wasm4pm_source_sha/0 so accept/4's admit_source/2 check passes for real rather than being bypassed).

Real replay check: re-invokes <algo>_replay_v1 (per the crate's own self-check contract -- see ~/wasm4pm/crates/wasm4pm-ex4pm-bindings/src/lib.rs module doc) against the SAME request bytes and returns {:ok, true | false} reflecting the export's own real u32 return (1/0), or {:error, reason}.

Boots a real Wasmex instance from the compiled wasm4pm-ex4pm-bindings artifact at path. Returns {:ok, instance} with the real SHA-256 of the artifact bytes (via Ex4pm.Core.Hash), or {:error, reason} if the file is missing/unreadable or Wasmex fails to instantiate it.

Types

algo_spec()

@type algo_spec() :: %{
  module: module(),
  algorithm_id: atom(),
  export_name: String.t(),
  replay_export_name: String.t()
}

One Ex4pmEngine.Wasm.* adapter module plus the algorithm identity RealTransport needs to build its default_transport/2 map.

instance()

@type instance() :: %{
  pid: pid(),
  artifact_hash: String.t(),
  artifact_path: String.t()
}

A started, real Wasmex instance plus the artifact bytes/hash used to start it, so callers can invoke multiple exports against the same instance without re-loading the module.

Functions

algo_specs()

@spec algo_specs() :: [algo_spec()]

The real, closed registry of all 19 Ex4pmEngine.Wasm.* Phase-1/2/3 adapters -- one entry per <algo>_v1/<algo>_replay_v1 export pair the wasm4pm-ex4pm-bindings crate exposes (verified against ~/wasm4pm/crates/wasm4pm-ex4pm-bindings/src/{lib,phase2,phase2_playout,prolog}.rs). This is the single source of truth Ex4pmEngine.Reactors.WasmCapabilitiesReactor and any Chicago test wiring default_transport/2 should read from, rather than each re-deriving export-name strings by hand.

all_transports(artifact_path)

@spec all_transports(String.t()) :: {:ok, keyword()} | {:error, term()}

Boots ONE real Wasmex instance from artifact_path (via start/1) and builds all 33 default_transport/2 closures against it in one pass -- the option map every Ex4pmEngine.Wasm.* adapter's execute/3 expects under its own :<algo>_wasm_fun key, ready to Keyword.merge into an execute/3 opts list or into a Reactor step's own transport-selection. Returns {:ok, transports} where transports is a keyword list [discover_wasm_fun: fun, conform_wasm_fun: fun, ...], or {:error, reason} if the artifact can't be loaded.

call(map, export_name, request)

@spec call(instance(), String.t(), map()) :: {:ok, map()} | {:error, term()}

Real end-to-end call against export export_name on an already-start/1ed instance, marshaling request (a plain map, JSON-encoded here) through the crate's real ptr/len ABI. Returns {:ok, response_map} on a decoded JSON object response, {:error, reason} otherwise. response_map is handed back verbatim to Ex4pmEngine.Wasm.Adapter.accept/4 -- this module makes no claim about the algorithm's own semantics, only that the bytes it returns really came out of a real WASM execution of export_name against request.

default_transport(instance, algo)

@spec default_transport(instance(), map()) :: (map(), keyword() ->
                                           {:ok, map(), map()}
                                           | {:error, term()})

Builds the :<algo>_wasm_fun 2-arity transport callback Ex4pmEngine.Wasm.Adapter.execute/3 expects, closing over a real, already-start/1-ed instance plus this op's own identity: export_name and replay_export_name (the crate's paired <algo>_v1/<algo>_replay_v1 exports), algorithm_id and protocol/wasm4pm_source_sha (matching Ex4pmEngine.Wasm.Adapter's own @protocol/wasm4pm_source_sha/0 so accept/4's admit_source/2 check passes for real rather than being bypassed).

Every call performs TWO real WASM invocations -- the algorithm itself via call/3, then a real <algo>_replay_v1 re-execution via replay/3 -- so identity.replay_verified reflects a genuinely recomputed digest match, not an asserted true. Ex4pmEngine.Wasm.Adapter.accept/4 only awards :alive (vs. :partial_alive) when this real replay agrees.

replay(map, replay_export_name, request)

@spec replay(instance(), String.t(), map()) :: {:ok, boolean()} | {:error, term()}

Real replay check: re-invokes <algo>_replay_v1 (per the crate's own self-check contract -- see ~/wasm4pm/crates/wasm4pm-ex4pm-bindings/src/lib.rs module doc) against the SAME request bytes and returns {:ok, true | false} reflecting the export's own real u32 return (1/0), or {:error, reason}.

start(path)

@spec start(String.t()) :: {:ok, instance()} | {:error, term()}

Boots a real Wasmex instance from the compiled wasm4pm-ex4pm-bindings artifact at path. Returns {:ok, instance} with the real SHA-256 of the artifact bytes (via Ex4pm.Core.Hash), or {:error, reason} if the file is missing/unreadable or Wasmex fails to instantiate it.