Public Scalar WIT Interface v1

September 10, 2026 · View on GitHub

Status: implemented bounded profile; HOSTED GREEN under the v0.4.0 release baseline. Historical local, authoring-time, ignored, device/simulator, or separately provisioned evidence below retains its narrower scope; public promotion, registry publication and broader product completion remain separately gated.

Audience: Project, interoperability, package, and host-tool maintainers.

This specification defines an authority-free public WIT interface artifact for the exact retained Project-v1 scalar export surface. It does not emit or run a WebAssembly Component. The distinction is mandatory: current public scalar Core Wasm reports checked language failures through its existing host/runtime boundary, so presenting a direct canonical lift as a typed WIT result would be false.

Closed admission

The subject is an already admitted immutable ProjectRevision whose manifest has exactly schema semaprax.project.v1 and profile ScalarV1. Its selected surface is the manifest's complete, strictly ordered web_exports list. Each selected stable ID must resolve to one explicit, effect-free monomorphic function in retained HIR with zero through eight value parameters and one value result. Every parameter and result is a Copy scalar admitted by the Public Scalar Export Profile v1: i64, i32, u8, char, f32, f64, or bool. usize and every non-Copy shape stay outside the profile and therefore outside this interface.

Ordinary Project-v1 scalar admission remains authoritative. Unsupported signatures and capacity failures retain SPX-W115 and SPX-W116; the WIT accessor does not replace them with a later interoperability diagnostic. Calling the accessor for Project v2 through v10 fails as SPX-J105 without target emission, filesystem activity, or publication.

Stable WIT projection

The frozen package is semaprax:project-scalar@1.0.0, the interface is exports, and the world is project-scalar-v1. It declares the canonical status record:

record status {
  domain: string,
  code: u32,
  class: u8,
  retryable: option<bool>,
}

Each selected function is named spx- followed by the lowercase hexadecimal UTF-8 bytes of its exact stable declaration ID. Parameter names are the ordinal identities arg-0 through arg-7. Each admitted scalar maps to its canonical WIT primitive — i64 to s64, i32 to s32, u8 to u8, char to char, f32 to f32, f64 to f64, and bool to bool — and every result is wrapped as result<T, status>. Display names, source paths, parameter spelling, declaration order outside web_exports, and lossy punctuation normalization never determine WIT identities.

The complete WIT text is bounded by MAX_SCALAR_WIT_INTERFACE_BYTES = 65,536. Stable-ID encoding is injective, so IDs such as a.b, a-b, and a_b cannot collide.

Descriptor and replay

The canonical descriptor schema is semaprax.project.scalar-wit-interface.v1. It binds:

  • the exact Project schema, name, project revision, workspace revision, and semantic-graph digest;
  • the fixed WIT package, interface, world, mapping and byte limits;
  • the complete selected export order;
  • for each export, its stable ID, derived WIT identity, ordered scalar parameter facts, and scalar result fact; and
  • the exact WIT bytes and their digest.

The descriptor's closed mapping object always binds i64 to s64 and bool to bool, then appends one row for each widened scalar the interface actually projects, in the canonical order i32, u8, char, f32, f64. It binds every function result to result<T, status> and each status field to its exact WIT type. Because the two base rows are frozen and the widened rows appear only when used, a descriptor over an i64/bool interface — and both of its digests — replays byte for byte across this widening. The status schema is semaprax.status.v1; status.domain maps to its domain_id field and retains the exact 1..=255 UTF-8 byte/no-NUL constraint; status codes are nonzero; class ordinals are Contract 1, Arithmetic 2, Import 3, ExplicitClose 4 and Adapter 5; retryability maps false/true/unknown to some(false)/some(true)/none. No runtime adapter or status-code translation implementation is claimed. The descriptor is bounded by MAX_SCALAR_WIT_DESCRIPTOR_BYTES = 262,144. The artifact digest uses a versioned domain and binds the complete descriptor bytes, not the WIT text alone. Construction independently parses and replays the descriptor against the retained manifest, HIR, revisions, graph digest, selected order, derived identities, and regenerated WIT. Mutation, truncation, trailing bytes, cross-subject pairing, or internally consistent reminting fails as SPX-WIT111; exact interface or descriptor capacity failure is SPX-WIT112. Replay never repairs, sorts, or trusts serialized semantic facts.

Authority and compatibility

The API is a library-only read from retained memory. It does not open source, emit Core Wasm, create a Component binary, invoke a compiler or engine, write an artifact, publish a package, or acquire filesystem, process, network, environment, clock, randomness, secret, signing, WASI, or host-callback authority.

A display-only function or parameter rename preserves WIT bytes because stable IDs and ordinals own the public identity. The subject-bound descriptor and its digest correctly change when the retained Project revision changes. Signature, stable-ID, selection, order, or scalar-kind changes alter both the relevant WIT and descriptor facts.

Evidence and nonclaims

Required evidence before promotion includes a six-export calculator, zero- and eight-parameter boundaries, both scalar kinds, canonical selection order, punctuation-collision IDs, display rename stability, signature change, hostile descriptor replay, cross-subject pairing, capacity and wrong-profile precedence, and absence of new target/filesystem effects after the retained Project has been admitted. A default-feature external consumer must be able to read the public artifact without enabling the private Component harness.

The generated WIT must also be parsed by a maintained external WIT parser in an isolated unpublished evidence crate; that parser is not added to the root published dependency graph or Rust 1.85 surface.

This tranche does not provide Component bytes, canonical lowering, runtime or engine execution, WIT imports, resources, application String values, application records or variants, Option, user Result, owned or borrowed handles, capabilities, WASI, host callbacks, async/futures/streams, package publication, version negotiation, or multi-engine conformance. It does not promote or relabel the default-off private WIT/Component v1-v10 harnesses. Those remain separate proof evidence.