Skip to content

conveyor-engine: wasm backend does not support conveyor/queue models (loud reject today; needs plan + parity coverage) #884

Description

@bpowers

Discovered during branch review of conveyor-engine (the in-flight XMILE conveyor+queue implementation; specs docs/design/conveyors.md + docs/design/queues.md). Filing so the gap is tracked regardless of whether it is addressed on-branch before merge.

Summary

The wasm code-generation backend (src/simlin-engine/src/wasmgen/) does not lower the conveyor/queue side-table passes. init_belts, publish_container_values, and run_coupled_passes are implemented only for the bytecode VM path (src/simlin-engine/src/vm.rs, conveyor.rs, conveyor_compile.rs, queue_compile.rs); a grep for those symbols under src/simlin-engine/src/wasmgen/ returns nothing. So a conveyor/queue model cannot be simulated through the wasm backend today.

This does not cause a silent divergence: a conveyor/queue model reaching the wasm entry points (compile_datamodel_to_wasm at src/simlin-engine/src/wasmgen/module.rs:146, which routes through compile_project_incremental) is loudly rejected by the ConveyorNotExpanded / QueueNotExpanded guard in src/simlin-engine/src/db.rs (the main-model arms at db.rs:1097-1104 and db.rs:1118-1127). That guard is a genuine safety net — an un-expanded special stock integrated as a plain stock would mis-simulate. But two problems remain:

(a) The guard's error text points at the VM build path, confusing for a wasm caller

The main-model reject messages are hardcoded to the VM path:

  • conveyor (db.rs:1100-1103): "conveyor stock '{}' reached the ordinary compile path un-expanded; conveyor simulation must go through conveyor_compile::build_vm"
  • queue (db.rs:1122-1125): "queue stock '{}' reached the ordinary compile path un-expanded; queue simulation must go through queue_compile::build_vm"

A caller who invoked compile_datamodel_to_wasm (or compile_simulation, module.rs:438) and hits this guard is told to "go through ..._compile::build_vm" — a VM-only build path that does not produce a wasm blob. The diagnostic misdirects a wasm consumer instead of stating the real limitation ("conveyor/queue models are not yet supported by the wasm backend").

(b) No tracked plan or parity coverage for wasm-backend conveyor/queue support

  • No integration test feeds a conveyor/queue model through the wasm parity hook. The default tests/integration/simulate.rs + simulate_systems.rs corpora run every VM-simulated model through the wasm backend via an inline hook (AC3.2: an Unsupported for a core-simulation model is a hard failure), but the conveyor/queue fixtures are simulated only on the VM path (queue_compile::build_vm / build_compiled), so they never exercise the wasm hook and there is no VM-vs-wasm parity signal for these constructs.
  • The engine's own wasmgen documentation is now stale on this point. src/simlin-engine/CLAUDE.md (item 9, src/wasmgen/) states: "The remaining unlowerable constructs are: a true-runtime-range subscript (ViewRangeDynamic, GH wasm-backend Phase 5: broadcast-iteration opcode family is unreached dead code; ViewRangeDynamic unsupported by design (neither in corpus) #612) returns Unsupported, and array unrolling is bounded by MAX_UNROLL_UNITS..." — it does not mention conveyor/queue at all, so a reader is told the only unlowerable constructs are ViewRangeDynamic and the unroll cap. Conveyor/queue models are a third (whole feature) class the backend cannot lower, and the doc should say so.

Why it matters

  • The wasm backend exists for fast repeated re-simulation (interactive parameter scrubbing). Any model using a conveyor or queue is silently excluded from that path — an interactive host that instantiates the wasm blob cannot scrub a conveyor/queue model at all.
  • Correctness of the coupling: run_coupled_passes is what keeps a queue feeding a discrete conveyor (and queue outflow priority/overflow) consistent per Euler step. Without lowering it, there is no wasm equivalent, so the two backends are not at parity for this feature and never will be until the passes are lowered (or the limitation is made explicit and permanent).
  • The stale doc actively misleads a future implementer into believing the backend is complete except for two narrow constructs.

Components affected

  • src/simlin-engine/src/wasmgen/ — the code-gen backend that lacks conveyor/queue lowering (no init_belts / publish_container_values / run_coupled_passes emitters).
  • src/simlin-engine/src/db.rs — the ConveyorNotExpanded / QueueNotExpanded guard (db.rs:1097-1104, db.rs:1118-1127) whose message names the VM build path.
  • src/simlin-engine/CLAUDE.md — the wasmgen section (item 9) whose "remaining unlowerable constructs" list is now stale (omits conveyor/queue).

Possible approaches

  1. Decide scope: either (i) lower the conveyor/queue side-table passes in the wasm backend (real per-step coupling emission, then wire the conveyor/queue corpus through the AC3.2 parity hook + a floor gate like the LTM EXPECTED_SUPPORTED_LTM_MODELS one), or (ii) declare wasm conveyor/queue support explicitly out of scope for now.
  2. Regardless of scope, make the reject honest for a wasm caller: when the guard trips on the wasm path, phrase the diagnostic around "not yet supported by the wasm backend" (or surface it as a WasmGenError::Unsupported, matching how ViewRangeDynamic / MAX_UNROLL_UNITS are handled) instead of pointing at ..._compile::build_vm.
  3. Fix the stale doc: update the src/simlin-engine/CLAUDE.md wasmgen "remaining unlowerable constructs" list to include conveyor/queue models (with whichever disposition edit variable names #1 lands on).

Context

Identified during review of the conveyor-engine branch. Related but distinct: #612 (wasm-backend other unlowerable constructs — ViewRangeDynamic / broadcast dead code) and #881 (keep-docs-current violations on the conveyor/queue branch — that one covers the engine module map, the libsimlin simlin_sim_new description, and the docs/README.md queues index, but not the stale wasmgen "unlowerable constructs" list).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions