Summary
The translator accepts components that Component Model validation requires
rejecting: two [method] (or [static]) extern names in one scope that are
identical after case-folding, e.g. [method]r.a-b + [method]r.a-B.
Explainer.md §Name Uniqueness defines strongly-unique as lowercase-the-acronyms
→ strip the [...] prefix → compare, and its example list explicitly calls
adding [method]foo.BAR next to [method]foo.bar "a validation error";
Binary.md:280-283 applies strongly-unique to all instance/component
import/export names. Our translator inherits a wasmparser gap and validates
such components, so they flow through to the runtime, where the conventions
layer silently routes both members to the same JS name (the unguarded
methods/statics paths of #185). Per the parity policy (docs/architecture.md
§1: spec is the semantic tie-breaker, wasmtime corroborating — never the
other way), wasmtime agreeing with wasmparser here does not make it correct.
Root cause (upstream)
wasmparser folds case for plain labels — KebabStr's Eq/Hash compare
to_ascii_lowercase() — but ResourceFunc (the a.b payload of
method/static names) derives Eq/Hash/Ord on the raw string
(src/validator/names.rs; identical in 0.251/0.252/0.256). So plain-label
and record-field folded collisions are rejected, method/static ones are not.
Recorded in upstream-component-model-repo-findings.md §Out of scope as a
candidate bytecodealliance/wasm-tools issue (filing is the operator's call).
wit-parser's text parser checks none of this either, so the invalid pair is
reachable from WIT source, not just hand-written WAT:
interface i {
resource r {
a-b: func();
a-B: func();
}
}
Evidence (2026-08-22, wasm-tools 1.247 / wasmtime 47 / translator-shim @ wasmparser 0.252)
| probe (same scope) |
wasm-tools validate |
wasmtime compile |
our translator |
instance exports a-b + a-B |
reject |
reject |
reject ([validation]) |
record fields a-b + a-B |
reject |
— |
reject |
[method]r.a-b + [method]r.a-B |
accept |
accept |
accept (plan produced) |
Repro for row 3:
(component
(import "test:i/i" (instance
(export "r" (type $r (sub resource)))
(export "[method]r.a-b" (func (param "self" (borrow $r))))
(export "[method]r.a-B" (func (param "self" (borrow $r))))
))
)
deno run --allow-read --allow-write tools/translate/main.ts <that>.wasm
produces a plan; it should fail with a phase: "validation" error.
Suggested fix
Add our own strongly-unique enforcement for [method]/[static] extern
names in translator-shim, after wasmparser validation (walk every
instance-type/component-type scope; fold per Explainer.md §Name Uniqueness;
report through the existing phase: "validation" error taxonomy,
crates/translator-shim/src/error.rs:6-9). Scope it to exactly the wasmparser
gap — plain labels and record/flag/variant/enum labels are already covered —
and remove it when upstream ResourceFunc folds case (upstream-tracking).
Relation to #185
Complementary, not overlapping: #185 extends the conventions-layer
NameCollisionError guards, which are still required for spec-valid
collisions (is-XML vs is-x-m-l both camelCase to isXML — validation
correctly accepts those, only the casing layer can refuse). This issue
restores validation parity so spec-invalid components stop reaching the
runtime at all. Validation record:
#185 (comment)
Provenance
Found validating #185 against the spec and wasmtime/wasm-tools (2026-08-22).
Audit/testing regime: #175. Tracker entry: PR #237.
Summary
The translator accepts components that Component Model validation requires
rejecting: two
[method](or[static]) extern names in one scope that areidentical after case-folding, e.g.
[method]r.a-b+[method]r.a-B.Explainer.md §Name Uniqueness defines strongly-unique as lowercase-the-acronyms
→ strip the
[...]prefix → compare, and its example list explicitly callsadding
[method]foo.BARnext to[method]foo.bar"a validation error";Binary.md:280-283 applies strongly-unique to all instance/component
import/export names. Our translator inherits a wasmparser gap and validates
such components, so they flow through to the runtime, where the conventions
layer silently routes both members to the same JS name (the unguarded
methods/statics paths of #185). Per the parity policy (docs/architecture.md
§1: spec is the semantic tie-breaker, wasmtime corroborating — never the
other way), wasmtime agreeing with wasmparser here does not make it correct.
Root cause (upstream)
wasmparser folds case for plain labels —
KebabStr'sEq/Hashcompareto_ascii_lowercase()— butResourceFunc(thea.bpayload ofmethod/static names) derives
Eq/Hash/Ordon the raw string(
src/validator/names.rs; identical in 0.251/0.252/0.256). So plain-labeland record-field folded collisions are rejected, method/static ones are not.
Recorded in
upstream-component-model-repo-findings.md§Out of scope as acandidate bytecodealliance/wasm-tools issue (filing is the operator's call).
wit-parser's text parser checks none of this either, so the invalid pair is
reachable from WIT source, not just hand-written WAT:
Evidence (2026-08-22, wasm-tools 1.247 / wasmtime 47 / translator-shim @ wasmparser 0.252)
a-b+a-B[validation])a-b+a-B[method]r.a-b+[method]r.a-BRepro for row 3:
deno run --allow-read --allow-write tools/translate/main.ts <that>.wasmproduces a plan; it should fail with a
phase: "validation"error.Suggested fix
Add our own strongly-unique enforcement for
[method]/[static]externnames in translator-shim, after wasmparser validation (walk every
instance-type/component-type scope; fold per Explainer.md §Name Uniqueness;
report through the existing
phase: "validation"error taxonomy,crates/translator-shim/src/error.rs:6-9). Scope it to exactly the wasmparser
gap — plain labels and record/flag/variant/enum labels are already covered —
and remove it when upstream
ResourceFuncfolds case (upstream-tracking).Relation to #185
Complementary, not overlapping: #185 extends the conventions-layer
NameCollisionErrorguards, which are still required for spec-validcollisions (
is-XMLvsis-x-m-lboth camelCase toisXML— validationcorrectly accepts those, only the casing layer can refuse). This issue
restores validation parity so spec-invalid components stop reaching the
runtime at all. Validation record:
#185 (comment)
Provenance
Found validating #185 against the spec and wasmtime/wasm-tools (2026-08-22).
Audit/testing regime: #175. Tracker entry: PR #237.