# Fixed Javy/Wasm runtime adapter — not qualified This new module is a standalone runtime plugin. It does not import QQQ, modify the existing TypeScript compiler or change `qbit-scripting-worker/1`. No product provider may advertise it as qualified until the exact built artifact and complete host lifecycle pass the required tests. ## Dependency and build boundary Javy CLI release9.1.0 corresponds to public runtime crate `javy8.1.0`, using `rquickjs0.12.0` ([tagged Cargo.toml](https://github.com/bytecodealliance/javy/blob/v9.1.0/crates/javy/Cargo.toml)). This module uses those public crates directly. **It requires no Javy CLI, Wizer or author snapshot.** `Runtime::new` constructs a new QuickJS runtime during each invocation. The external host caches the common compiled Wasm code; publication caches contain only private bytecode and immutable identity metadata. Rust1.97.1 is pinned. Direct dependencies are exact-version pins in Cargo.toml. Root resolved the 73-package Cargo.lock (SHA256 `F077884125E23E5989D158FE6FE86DF9009F5842076609CEDF2DA6F4951021A1`); the rquickjs facade is0.12.0 and its compatible core/sys dependencies resolve to0.12.2. Root owns public tool acquisition, Linux/WASI SDK/libclang setup and actual Wasm execution. Building rquickjs requires its documented C/WASI compiler and bindgen prerequisites; do not silently substitute an engine or crate version. Planned root commands after the pinned environment is ready: ```text cargo generate-lockfile cargo fmt --check cargo test --locked --test trusted_contract cargo clippy --all-targets --locked -- -D warnings cargo build --locked --release --target wasm32-wasip1 ``` The native tests execute only fixed trusted fixtures. Native tests cannot qualify Wasm import capabilities, fuel, actual fresh Store state or host cancellation. A subsequent exact-Wasm run must verify those independently. The common Wasm plugin must be instantiated with no WASI preopens, no inherited environment/stdin credentials, no network capability, bounded linear memory/fuel and an outer deadline. Native tests are not permission to run author submissions. ## Private supervisor ABI Extism export `run() -> i32` reads and writes one UTF-8 JSON frame through the ordinary Extism input/output ABI. Exactly one call is permitted per Wasm instance; the host must free that Plugin/Store before reporting RETIRED. Return zero means a private result was produced; a nonzero return is a refusal/trap with no successful result. Prepare input (cold path): ```json {"operation":"prepare","runtimeSha256":"","artifactSha256":"","bundle":""} ``` Prepare returns `profile`, `runtimeSha256`, `artifactSha256`, `entryPoint`, sorted `modules[{path,bytecode,sha256}]` and `preparedSha256`. Bytecode is canonical standard base64; the prepared hash is domain-separated and length-framed across all immutable fields. This digest proves consistency, not authorization: the supervisor must verify the actual loaded runtime binary and original publication, and retain the resulting bytecode itself. **Never accept arbitrary client-supplied bytecode merely because its self-declared hashes match.** QuickJS's public `Module::load` is an unsafe bytecode reader; only the trusted compiler's exact output is an allowed input, inside the Wasm boundary. Run input (hot path): ```json {"operation":"run","runtimeSha256":"","preparedSha256":"","prepared":{},"request":{}} ``` `prepared` is the complete cached prepare result. `request` is the existing execute object **without bundle**, matching the persistent transport's INVOKE shape; it retains digest, `.ts` entrypoint, request ID, event/payload, fresh opaque capability token and limits. Run output is `{message,guestWallMillis}`. `message` has the existing executeResult fields but deliberately omits `usage`. The supervisor adds authoritative CPU/wall usage before forwarding the unchanged WorkerProtocol result. Guest wall time is diagnostic, not CPU accounting or a trusted enforcement signal. Imported application function: `extism:host/user::qqq_broker(i64 requestOffset) -> i64 responseOffset`. Offsets refer to Extism-owned memory, not host pointers. Input is existing bounded broker JSON; output must be a newly allocated existing brokerResult JSON block. The plugin copies and frees both allocations; returning the request allocation itself is refused. The supervisor callback runs synchronously on the active invocation thread and supplies current authority from that invocation only. It must validate frames and enforce its own I/O deadline. Zero offset is refusal. No callback, token or actor is retained in compiled code/cache. ## Semantic/resource contract Preparation verifies the existing emitted artifact hash, validates the closed path/module set and calls Javy `compile_to_bytecode`, which declares/writes modules without evaluation. Execution installs a restricted relative resolver and loads those exact modules. It awaits module evaluation and exported `main` until actually settled; pending with no work, detached rejection, job failure and bounded job exhaustion are failures. It does not use default Javy invoke's pending-Promise success behavior. The trusted SDK factory captures its primitives before author evaluation, returns a frozen Promise-based `qqq.query` and preserves one-pending-call and call-count constraints. The opaque token remains in the native broker closure, not a guest global. Broker denial and author errors produce generic host-owned error text. Output is a bounded JSON object. QuickJS heap is capped by the requested memory limit, stack at256KiB; wall checks and engine interrupt cover interpretation. A fixed10,000 pending-job-turn ceiling is an additional explicit runtime profile bound. Extism/Wasmtime must separately enforce linear-memory/fuel, and the supervisor must enforce actual CPU and whole-operation wall limits including initialization and broker waits. Fuel does not meter native host callback work. One Engine slot has one active invocation; ambiguous cancellation retires the slot rather than reusing it speculatively. The few `unsafe` blocks are narrowly documented public FFI/bytecode boundaries, required by the chosen APIs. There is no engine fork, reflection or raw host-pointer access. This is an explicit scoped exception to the personal default of forbidding unsafe Rust; it does not permit unchecked external bytecode. ## Current evidence Twelve fixed trusted native tests pass with `cargo +1.97.1 test --offline --locked --test trusted_contract`, including fresh state/time/random, relative imports/live bindings/TLA, awaited broker, Unicode source above1MiB UTF-8, pending/error refusal and attributed-import rejection. `cargo-native-serialization-red.log` preserves the demonstrated toJSON detached-rejection bug; `cargo-native-serialization-verification.log` records all12 passing after adding the final bounded job/rejection check after serialization. No Wasm execution, performance or hostile-code qualification has passed for this module yet. The earlier Extism JS-PDK runtime-floor experiment is **not** evidence for this implementation. Exact-Wasm proof must include these semantics, one-call-per-instance refusal, and actual fuel/memory/deadline/cancel retirement behavior. ### Pinned bytecode import-attribute compatibility The resolved rquickjs-sys0.12.2 `quickjs/quickjs.c` has SHA256 `CE9A95D3C011F255C1FACB7D4361C71209E71BA58D84ACD3281A755D0686A285`. `JS_WriteModule` at38038–38042 writes requested module names without attributes. `JS_ReadModule` at39124–39142 allocates zeroed entries and passes their attribute value to the import resolver without initializing it to JS_UNDEFINED. The public rquickjs wrapper therefore supplies `Some` with a non-object value for ordinary bytecode imports; enumerating it throws. The initial native test and reduced relative-import fixture both failed on this path. `load_bytecode` uses a runtime-local RAII `BytecodePhase` to ignore that placeholder only during synchronous loading of exact supervisor-owned bytecode. Nested loads restore the prior phase; evaluation occurs outside it. Source compilation rejects actual attributes for every module, including unused files, before producing a prepared result. Dynamic imports remain subject to the normal attribute check; regression tests prove attributed dynamic imports fail after nested loading while ordinary dynamic imports succeed. There is no engine modification, global flag, guest-visible toggle or acceptance of client-supplied bytecode. This workaround remains tied to the pinned dependency behavior and needs re-review on an engine upgrade.