Repository navigation
CM-4: sync-streams.wast:145 overfits wasmtime's scheduler — upstream test-defect filing kit #43
Description
Decision (operator, 2026-08-10)
Source+trace verification (exams/wasmtime-exclusivity/wasmtime-actual-semantics.md, PR pending) showed the CM-4 premise was wrong: wasmtime does NOT release its instance-entry gate at resolution. wasmtime = hold rule (gate spans the whole core invocation, like definitions.py's exclusive_thread) + deferred entry decision (an async-lowered caller learns STARTING only after the instance's runnable work is exhausted; ready gate-holders run to exit first) + FIFO queue. deltic currently ships release-at-resolution + eager start — more permissive than wasmtime (admits same-instance execution during a resolved task's mid-frame park; the IROH-1 RefCell collision is reachable here, unreachable under wasmtime). Under the standing 'wasmtime-becomes-the-spec' assumption, deltic migrates to the wasmtime model.
Target semantics (order-robust formulation)
- Gate lifetime:
exclusiveThreadheld from entry to invocation exit (initial invocation and each callback invocation), NOT released at resolution mid-frame. Reverts the release-at-BLOCK-for-resolved-holders rule. - Entry decision: an async-lowered guest→guest call reports STARTING only if the callee is still unstarted after the instance's runnable work has been drained to quiescence (not FIFO-pop-one — must stay green under DELTIC_SCHED_SEED shuffles, unlike wasmtime's own FIFO-dependent pass).
- DeliverEvent parity: event delivery to a parked-between-invocations callback task is gated the same way as entry (wasmtime concurrent.rs:765).
Affected code (from the release-rule annotations)
- runtime/src/task/mod.ts:337-340 (resolved-holder release at block; needsExclusive/enter/exit)
- runtime/src/exec/boundary.ts:1611-1660 (held-guarded callback loop → returns to always-holding invariant), :627, :1170-1184
- runtime/src/jspi/bridge.ts:540-577 (UPSTREAM DIVERGENCE block — release-at-BLOCK for resolved tasks)
- lower trampolines / scheduler: deferred entry evaluation (design: where the drain runs; JSPI suspendability classification of async-lowered call trampolines; plain-path impact must stay zero for sync-only components per contracts/intrinsics.md)
- harness/src/xfail.ts:321 comment (references the old model)
Gates
- cargo build --workspace; cargo test -p translator-shim -p bindgen -p testgen
- (cd runtime && deno task check && deno task test)
- (cd harness && deno task conformance) — incl. sync-streams.wast green, plus DELTIC_SCHED_SEED=1 and =4242 reruns
- (cd ct-runner && deno task test); wasi-shims, ports as affected
- exams/iroh-endpoint: expected to flip from ~90% trap to deterministic green (the IROH-1 window closes) — rerun and update upstream-consumer-findings.md IROH-1
- New targeted runtime test: pump/poke shape asserting STARTING while a resolved holder is parked-unready, admission only after its exit (the wasmtime-model expectations, NOT cm4-run-tests.patch's release-rule expectations)
Authorities
- exams/wasmtime-exclusivity/wasmtime-actual-semantics.md (trace + line refs, both wasmtime vintages)
- exams/wasmtime-exclusivity/trace-sync-streams-wasmtime-dev.log
- third_party/component-model definitions.py (gate lifetime — now agreed with wasmtime)
- architecture.md §1 corpus-exception clause (corrected wording in the same PR)
Scheduler-core: single-owner track (coder-hard at most) under close orchestrator review, per AGENTS.md.
Activity
CM-4 correction: wasmtime holds the gate and defers entry; switch the…
lann commentedon Aug 10, 2026
Landed via PR #45 (pending checks). Gate results incl. the IROH-1 exam flip recorded in the PR body; IROH-1 marked RESOLVED-BY-HOST in upstream-consumer-findings.md.
#43: hold-rule gate + deferred entry decision (wasmtime's actual mode…
lann commentedon Aug 10, 2026
Final adjudication (operator, 2026-08-10): entry-status timing is not normative — the test overfits
Closes out the investigation arc (#44 corrected the mechanism attribution; #45 migrated the runtime). The
exams/wasmtime-exclusivity/artifact kit is removed from the tree in the follow-up PR — the scope shrank to fit this issue. Everything of substance is distilled below; the full kit stays reachable at4f3351f:exams/wasmtime-exclusivity/.The finding, final form
test/async/sync-streams.wast:145(spec repo) asserts that an async-lowered call to a same-instance callback-lifted export reports STARTED while the previous task is resolved (task.returndelivered) but still parked mid-frame in a sync builtin — and ready to resume. That assertion is schedule-dependent, and scheduling is not normative:definitions.pyexclusive_thread(only release sites: event-loop wait :2187–2188, task exit :506–508); wasmtimeConcurrentInstanceState.do_not_enter— every site is an invocation bracket (enter/exit_instanceconcurrent.rs:2004–2021 [v47.0.3: :1998/:2008]; callback initial invocation :2652/:2662; sync-lift :2696/:2714 with the stackful exemption; per-callback invocation :942/:960;task_returnnever touches it); CanonicalABI.md:3740–3746.canon_lowerinvokes the callee synchronously (definitions.py:2281),canon_liftcreates and resumes the callee thread on the spot (:2211–2212), it parks at the gate (:484–486), and the caller packs whatever state was reached (:2306). Answer in the wast scenario: STARTING, under every schedule the reference can produce.start_call(:3040–3160) queues the callee and suspends the caller until the first status event; a gated callee yieldsStatus::Startingand parks pending (:1497–1522). The ready-to-resume gate holder was queued ahead, runs to invocation exit, releases the gate; only then is the new call's readiness evaluated. Answer: STARTED, deterministic under FIFO. Trace proof (archivedtrace-sync-streams-wasmtime-dev.log):$C.getis resumed, exited, and deleted before$C.set's readiness is ever evaluated.Two conforming scheduling policies over identical gate semantics give two different ABI-visible answers — so the assertion cannot be semantics. The test hard-asserts the outcome of the engine it was co-developed on (the wast corpus's documented runner is wasmtime, while the spec repo's CI runs only
run_tests.pyand never executes the wast corpus against the reference — the contradiction has no upstream detector by construction). Same class as NOTE-1 inupstream-component-model-repo-findings.md(tests assuming the deterministic profile), sharper instance: engine-policy overfit — the reference itself fails it deterministically.Nothing else is defective:
definitions.pyneeds no change, CanonicalABI.md needs no change,test_callback_interleavingneeds no change. Both previously sketched amendments (release-at-resolution, then deferred-entry normativization) are withdrawn.deltic disposition (landed in #45; unchanged by this adjudication)
Store.hasRunnableWork+createAsyncStartCall, pinned byruntime/tests/entry_deferral_test.ts) = a deliberate non-normative scheduler policy: it satisfiessync-streams.wastas written, and — being drain-based rather than FIFO-order-based — it is robust underDELTIC_SCHED_SEEDshuffles, unlike wasmtime's own formulation. It is legal under any upstream adjudication of the test, so there is no flip-back trigger.Proposed upstream fix (to file against WebAssembly/component-model)
Make the
:145region schedule-agnostic. The test's real content is "the sibling call is eventually admitted once the holder exits, and completes correctly" — not "admitted before the caller regains control":waitable-set.waitfor the SUBTASK event (STARTED/RETURNED), then proceed with the existing assertions;Secondary, structural: run the wast corpus against the reference in the spec repo's CI (or at least flag reference-affecting assertions), so reference↔corpus contradictions get a detector.
Filing is tracked by #15. Repro, from the archived kit:
verify-cm4.shlegs 0–1 reproduce the reference-side STARTING answer against pristinedefinitions.py(viacm4-run-tests.patch); the wast side needs a wasmtime dev build (wasmtime wast -W component-model-async=y -W component-model-more-async-builtins=y test/async/sync-streams.wast— 47-era release CLIs cannot parse the post-#655 suite syntax). Spec submodule at73b7ad5; wasmtime refs against main as of 2026-08-10 and v47.0.3.[-]CM-4 correction: migrate entry semantics to wasmtime's hold + deferred-entry model[/-][+]CM-4: sync-streams.wast:145 overfits wasmtime's scheduler — upstream test-defect filing kit[/+]CM-4 adjudicated: entry-status timing is not normative — retire the e…
Merge pull request #111 from lann/cm4-filing-kit-43