Skip to content

ltm: support Loops That Matter on the wasm simulation backend #636

@bpowers

Description

@bpowers

Summary

LTM (Loops That Matter) is VM-only: Model.simulate({engine:'wasm', enableLtm:true}) is rejected up front and getLinks() throws on a wasm sim. The wasm backend lowers the salsa CompiledSimulation bytecode opcode-for-opcode, so the LTM synthetic equations (link/loop scores, $⁚ltm⁚agg nodes) are "just more equations" and should lower with little-to-no new codegen. Enable LTM on the wasm engine.

Why it isn't free today (three gaps)

LTM has a numeric half (synthetic equations run during simulation) and an analytic half (post-sim Rust: polarity, detected loops, relative-score normalization, discovery). The wasm gaps:

  1. The wasm compile path never enables LTM. compile_datamodel_to_artifact (src/simlin-engine/src/wasmgen/module.rs:114) syncs a fresh SourceProject (default ltm_enabled = false) and never calls set_project_ltm_enabled, so the synthetic vars are never generated and the WasmLayout contains none of them.
  2. Zero parity coverage. tests/simulate_ltm.rs is VM-only and the tests/simulate.rs parity hook runs the non-LTM compile. Nothing proves the LTM equations lower without WasmGenError::Unsupported (LTM augmentation multiplies array/var counts and can trip MAX_UNROLL_UNITS; the engine-wasm-sim contract is no fallback) or that they match the VM numerically.
  3. The analytic half is bound to the VM's in-memory Results. simlin_analyze_get_links (src/libsimlin/src/analysis.rs:288) and simlin_analyze_get_relative_loop_score read $⁚ltm⁚* series out of sim_ref.state.results. The wasm blob writes results into its own JS-owned linear memory that is never handed back to libsimlin, so the existing analysis code structurally cannot see them. (Note: model_detected_loops, scoreless links, and polarity are backend-independent salsa structural queries — already reachable via the model handle.)

Proposed work

  1. Thread LTM into the wasm compile. Add ltm_enabled/ltm_discovery_mode to compile_datamodel_to_artifact + simlin_model_compile_to_wasm; set them via set_project_ltm_enabled. Synthetic vars then land in the bytecode and the WasmLayout.
  2. Add an LTM wasm-parity harness (TDD). A simulate_ltm.rs twin that runs LTM models through both backends under the DLR-FT interpreter, ratcheting a floor like simulate.rs; surfaces every Unsupported/divergence. Heavy models stay #[ignore]d to respect the 3-minute cargo test cap.
  3. Keep the analytic half in Rust, fed by the blob's series (option 3a). Add a small, orthogonal FFI (e.g. simlin_analyze_links_from_series) that ingests the host-produced result slab / $⁚ltm⁚* columns and runs the existing ltm_post/ltm_finding/polarity code. Analysis is on-demand (not the per-frame scrub hot path), so handing the slab back across the FFI is acceptable. Do not reimplement the analysis in TypeScript — that invites the divergent-implementation bug class of ts: two divergent canonicalize implementations (@simlin/core incomplete vs @simlin/engine Rust-faithful) #624. Relative loop scores (post-sim, not synthetic) and discovery mode must go through this Rust path; only raw link/loop-score series come from the blob.

Wire the TS side to drop the up-front rejections (src/engine/src/direct-backend.ts:463, :670) for the now-supported path.

Done / acceptance criteria

  • AC1: Model.simulate({engine:'wasm', enableLtm:true}) succeeds; the blob's WasmLayout contains the $⁚ltm⁚* series.
  • AC2: getLinks() on a wasm sim returns links whose scores match the VM within existing tolerances; loop scores and relative loop scores match the VM; discovery mode (when enabled) matches.
  • AC3: an LTM model the wasm backend genuinely cannot lower returns an explicit WasmGenError (no silent VM fallback) — clean error, never a panic or silently-wrong result.
  • AC4: LTM parity harness runs LTM corpus models through both backends (heavy ones #[ignore]d); a regression that drops a previously-supported model fails the suite.
  • AC5: 95%+ coverage on new code via TDD; FFI surface stays small/orthogonal (no bulk/batch endpoint).

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    engineIssues with the rust-based simulation engineenhancementNew feature or requestltmLoops that Matter (LTM) analysis subsystem

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions