Wado

WEP: Provider Metadata — Source-Bundled Package Artifacts

Context

Two established rules collide at the package boundary:

A generic, higher-order, or trait-based library therefore has no registry distribution path — the API that makes it worth publishing disappears at publish time, leaving git source dependencies as the only channel. Several documents already route around this by citing a "Wado provider metadata" path, but no WEP specifies what that metadata is.

Monomorphization settles the format question. A consumer instantiating a generic needs the body, not just the signature — Rust ships MIR in rlibs, Go ships bodies in export data. Wado must ship bodies too; only the serialization is open. This also means no format buys secrecy: shipping IR instead of source obfuscates, it does not close.

Decision

A published package is a source package with a prebuilt CM binary attached, delivered as one .wasm.

The artifact

The package's Wado source travels in a custom section named wado:package:

Content Purpose
Format version Consumer compatibility gate
Compiler version Producing compiler, for the degradation rule below
wado.toml The package's own dependencies and entry points
The package's .wado sources Bodies for pub items, and everything they reach

The section content is deterministic: sorted file order, no timestamps, fixed compression level. Same input, same bytes, same digest — otherwise integrity and reproducible builds break.

Sources are included whole rather than pruned to the pub-reachable set. A pub generic body calls internal helpers, so most of a package is reachable anyway; pruning can follow if size proves to matter.

A custom section is not instantiated, so this costs distribution bytes only, never runtime size.

Why a section, not a second OCI layer

OCI is the primary registry, and the single-application/wasm-layer convention is what generic OCI and wasm tooling already handles — custom sections propagate unchanged through the toolchain (WIT Bundling). A section also keeps the artifact self-describing outside any registry (path dependencies, https:// imports, release assets), so one rule covers every channel, and integrity stays a single manifest digest with no per-layer verification scope to define.

Consumer selection is all or nothing

Consumer wado:package present and supported Path
Wado Yes Source; the compiled component is unused
Wado No CM canonical ABI, export items only
Other CM CM canonical ABI, export items only

A package is consumed one way or the other, never both. Mixing would compile the same declaration twice into two distinct nominal types — the split identity Module Loader §"Canonical module identity" avoids for local paths — and would put two compiler generations inside one package, so a fix present in one half is absent in the other.

The compiled component is the compatibility floor

Because selection can fall back, the attached binary is not a duplicate of the source: it is what a consumer uses when the section's format or compiler version is out of range. Degradation is narrower than the source path, so it must not be silent when it matters:

Stripping

Transitive dependencies

A source package carries its own wado.toml, so a registry dependency now has transitive Wado dependencies — revising Package Manifest §Registry backend, which states the opposite for prebuilt components. Resolution and locking reuse the git-dependency path unchanged.

Single-file mode has no lock file, so a source package whose manifest carries a version range is an error there, with the same remedy as any other unlockable range: pin exactly, or add a wado.toml.

--no-source

wado publish --no-source emits a CM-only artifact. pub-only items are then unreachable to every consumer — the stated cost of withholding source, not a silent difference.

Consequences

Implementation

References