Module bundle

Module bundle 

Source
Expand description

The compiled slice of one component, in the form a client can execute — Mode B’s payload.

docs/05-tier-lowering.md §5.1: a Mode-B component is “the component’s pure code compiled to WASM … fine-grained signal graph, local speculative fold + seq-based reconciliation”. This module is the payload half of that: what a browser has to be given before it can render the page and guess the next state for itself.

Four roles cross, and each is here for a reason a Mode-A client does not have:

  • view — because in Mode B the browser renders. This is the only per-component role; the other three belong to the application, which is why two components of one program share everything but this.
  • validate and fold — because optimism is not a trick. “The browser applies the expected event to its local copy speculatively — legitimate because it runs the same pure fold the server runs” (docs/10-decisions.md D5). The same Core, not a second implementation of it.
  • init — so a client that has never spoken to the server has a state to render, which is what an offline cold start is (D7).

Plus the definitions those four reach, transitively: Core refers to top-level definitions by name (CoreKind::Global), so a role without them is not executable. That closure is the component’s slice, and it is why a bundle is smaller than a program.

§What a bundle is not

It is not a program. There is no Placed, no signal graph, no type table, no test — nothing the client would need only in order to check something, because the client checks nothing. The program was checked on the way in; the bundle is what is left when the only remaining question is how to run it.

§Why a mirror type rather than #[derive(Serialize)] on Core

crate::repr’s argument, one layer up: a concrete type is where the decisions about what crosses become visible and reviewable rather than implied by whatever fields a struct happens to have. Two decisions are taken here, and neither should be able to change by accident:

  • Types are dropped. A Core node carries the Ty the checker inferred, and the evaluator never reads it — it dispatches on values. Carrying resolved types would roughly double the payload to say something the only consumer cannot use. A compiling client backend would need them, and that is a format version rather than a field somebody adds quietly: FORMAT is checked on load.
  • Spans are kept. They are three integers and they are the difference between “the fold failed” and “the fold failed at todo.beck:47” in a browser console.

§Why the bundle names the compiler that made it

Prim is encoded as its position in the primitive table, which is the compact encoding — and which silently means something different if the table changes. So a bundle carries shape_id: a digest of every primitive’s name and number. A kernel built from a different compiler refuses the bundle instead of executing a str_len that used to be a list_len. It is the same rule crate::repr’s FORMAT states for the log — “a misread log is worse than an unreadable one” — applied to code rather than to data.

Structs§

Bundle
A component’s slice: the code, and nothing else.

Enums§

BadBundle
Why a bundle could not be read.

Constants§

FORMAT
The bundle format version, stamped into every bundle and checked on load.

Functions§

shape_id
A digest of the primitive table: every primitive’s name and the number this compiler gives it.