synth ships 383 spec-style assertions in tests/wast/ and checks none of them. The
only path CI runs against those files asserts that synth compile exits 0 — the
assert_return values are parsed and discarded. Separately, the official
WebAssembly testsuite is absent from this repo, so the compiler has never been
graded against the standard at all.
Sibling comparison is the sharp end: kiln (the interpreter) has a real conformance
gate; synth (the compiler) has none — and synth is the one whose output runs on
target.
Verified on 97bd6db (v0.55.0).
1. The wired path is compile-only
crates/synth-cli/tests/wast_compile.rs is the only consumer of tests/wast/ that
CI executes. Its own header states the scope:
//! Integration tests: compile every WAST file through synth and verify ELF output.
//! Each WAST file in tests/wast/ is compiled with --all-exports --cortex-m.
and every one of its ~59 cases bottoms out in:
assert!(result.status.success(), "synth compile failed for {} ...")
There is no assert_return / expected-value comparison anywhere in the file
(grep -n 'assert_return\|expected' crates/synth-cli/tests/wast_compile.rs → only an
unrelated relocation-count message).
Meanwhile the data those files carry:
in tests/wast/ (25 files) |
count |
assert_return |
381 |
assert_trap |
2 |
| checked by CI |
0 |
So i32_div.wast, i32_rotate.wast, control_factorial.wast etc. are graded on
"did the compiler emit an ELF", not "is the ELF correct". A codegen change that
made i32.rem_s return the wrong value would keep this suite green. That is the
same shape as #911 (cargo test -- <no match> exits 0) and the v0.54
sret_decide_differential.py gate that printed MISMATCH <-- BUG and exited 0 —
but here it is the primary correctness suite of the backend.
2. The runner that can check values is not wired, and can't run in CI as built
crates/synth-test/ genuinely parses assertions — WastTestRunner::parse_file()
yields WastTestCase { args, expected, expected_trap, test_type }, and
runner.rs:174 really does compare ExecutionResult::Return(actual) against the
expected value. The infrastructure is there. Two things stop it from counting:
- Zero references in CI.
grep -rn "synth-test" .github/ scripts/ → 0 hits
(only scripts/mythos/rank.md mentions the path). It is in no workflow, no
bazel target, no gate.
- Renode-only execution.
run_test() opens with
self.controller.as_mut().context("Renode not connected")? and drives Renode over
telnet, so it cannot run on a stock CI runner regardless.
- Its only two
#[test]s (test_parse_simple_wast, test_robot_generation) parse a
3-assertion inline string; neither touches tests/wast/.
Net: the value-checking runner exists, is correct-looking, and has never graded the
381 assertions.
3. The official testsuite is absent
WebAssembly/testsuite is not vendored, submoduled, or fetched anywhere in synth.
The 25 hand-written files are synth's own, so even if they were checked, coverage
would be whatever we happened to write — not the standard.
Suggested fix: adopt kiln's gate, don't build a second one
kiln already solved this in-org and the model is good. Please reuse it rather than
inventing a parallel mechanism:
external/testsuite as a pinned submodule (.gitmodules → WebAssembly/testsuite),
so conformance is reproducible, plus the monthly repin workflow (kiln#360).
safety/wast-conformance-baseline.txt — the known-failing list.
scripts/wast-conformance-gate.sh + .github/workflows/wast-conformance.yml —
fails the build on any file failing that is not in the baseline, and surfaces
newly-passing files as a notice so the baseline ratchets tighter.
For synth the only genuinely new part is the execution backend, since grading a
compiler means running its output. synth-test's parser needs no change — it already
produces args + expected. It needs an executor that works on a CI runner:
- native aarch64 on an arm64 runner is the cheapest honest option — synth's
aarch64 backend output can be linked and called directly, no emulator;
- qemu-system-arm for the thumb-2/cortex-m path (already used elsewhere in the repo);
- keep Renode as the on-target/optional backend it is today.
A frontier note so the gate stays honest: a module synth declines must be reported
as declined, not passed and not failed — otherwise the baseline hides the
frontier. Only accepted-then-wrong should fail.
Why this matters more for synth than for kiln
kiln can be wrong and produce a wrong answer at runtime. synth is wrong in the
artifact that ships, and its consumers are exactly the targets that can't observe the
error. The compiler having weaker conformance evidence than the interpreter is the
wrong way round.
synth ships 383 spec-style assertions in
tests/wast/and checks none of them. Theonly path CI runs against those files asserts that
synth compileexits 0 — theassert_returnvalues are parsed and discarded. Separately, the officialWebAssembly testsuite is absent from this repo, so the compiler has never been
graded against the standard at all.
Sibling comparison is the sharp end: kiln (the interpreter) has a real conformance
gate; synth (the compiler) has none — and synth is the one whose output runs on
target.
Verified on 97bd6db (v0.55.0).
1. The wired path is compile-only
crates/synth-cli/tests/wast_compile.rsis the only consumer oftests/wast/thatCI executes. Its own header states the scope:
and every one of its ~59 cases bottoms out in:
There is no
assert_return/ expected-value comparison anywhere in the file(
grep -n 'assert_return\|expected' crates/synth-cli/tests/wast_compile.rs→ only anunrelated relocation-count message).
Meanwhile the data those files carry:
tests/wast/(25 files)assert_returnassert_trapSo
i32_div.wast,i32_rotate.wast,control_factorial.wastetc. are graded on"did the compiler emit an ELF", not "is the ELF correct". A codegen change that
made
i32.rem_sreturn the wrong value would keep this suite green. That is thesame shape as #911 (
cargo test -- <no match>exits 0) and the v0.54sret_decide_differential.pygate that printedMISMATCH <-- BUGand exited 0 —but here it is the primary correctness suite of the backend.
2. The runner that can check values is not wired, and can't run in CI as built
crates/synth-test/genuinely parses assertions —WastTestRunner::parse_file()yields
WastTestCase { args, expected, expected_trap, test_type }, andrunner.rs:174really does compareExecutionResult::Return(actual)against theexpected value. The infrastructure is there. Two things stop it from counting:
grep -rn "synth-test" .github/ scripts/→ 0 hits(only
scripts/mythos/rank.mdmentions the path). It is in no workflow, nobazel target, no gate.
run_test()opens withself.controller.as_mut().context("Renode not connected")?and drives Renode overtelnet, so it cannot run on a stock CI runner regardless.
#[test]s (test_parse_simple_wast,test_robot_generation) parse a3-assertion inline string; neither touches
tests/wast/.Net: the value-checking runner exists, is correct-looking, and has never graded the
381 assertions.
3. The official testsuite is absent
WebAssembly/testsuiteis not vendored, submoduled, or fetched anywhere in synth.The 25 hand-written files are synth's own, so even if they were checked, coverage
would be whatever we happened to write — not the standard.
Suggested fix: adopt kiln's gate, don't build a second one
kiln already solved this in-org and the model is good. Please reuse it rather than
inventing a parallel mechanism:
external/testsuiteas a pinned submodule (.gitmodules→ WebAssembly/testsuite),so conformance is reproducible, plus the monthly repin workflow (kiln#360).
safety/wast-conformance-baseline.txt— the known-failing list.scripts/wast-conformance-gate.sh+.github/workflows/wast-conformance.yml—fails the build on any file failing that is not in the baseline, and surfaces
newly-passing files as a notice so the baseline ratchets tighter.
For synth the only genuinely new part is the execution backend, since grading a
compiler means running its output.
synth-test's parser needs no change — it alreadyproduces args + expected. It needs an executor that works on a CI runner:
aarch64 backend output can be linked and called directly, no emulator;
A frontier note so the gate stays honest: a module synth declines must be reported
as declined, not passed and not failed — otherwise the baseline hides the
frontier. Only accepted-then-wrong should fail.
Why this matters more for synth than for kiln
kiln can be wrong and produce a wrong answer at runtime. synth is wrong in the
artifact that ships, and its consumers are exactly the targets that can't observe the
error. The compiler having weaker conformance evidence than the interpreter is the
wrong way round.