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 files exports names Assets a consumer may name, verbatim
Committed Kiln cache records So a consuming build reuses the output, not the generator

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.

Assets travel because consumers name them: a dependency's .g4 feeds a Kiln generator, a template is inlined with #include_str (Package File Exports). They are bytes rather than text, so the section carries them verbatim. A consumer on the CM path has no section, and therefore no files — the same all-or-nothing selection as everything else here.

A package whose Kiln output is committed also carries each <primary>.kiln.json beside the generated .wado files those records describe. Without the record a consuming build cannot tell which generated module an import resolves to, and would run the generator to find out.

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

Roadmap

Known gaps

References