The Executable as an Array

An executable is an ordered array of entries plus the names they bind. Each entry produces one value into one slot, and the names say which of those slots the running code sees as sprite and which it sees as $clock.

That is the whole model. Everything a runner does is walk that array, and everything the system decides about an actor’s authority, its imports, and its start order has already been written into it. Executables is the artifact model this describes, and Artifact Formats is the byte layout; this page is the shape and the reasoning.

Three kinds of entry, and no more

EntryProduces
{value: <any>}a constant — 4, "debug", or an actor token the runtime fills in at start
{unit: <image>, entry: <n>}run this bytecode; the value is what it returns
{native: <key>}load this compiled-in provider

There is no fourth kind, and adding one would be adding a thing the runner has to understand. The list is short because each kind answers a genuinely different question about where a value comes from: it was decided, it is computed by pit, or it is C that the binary was linked with.

A {value} entry is a constant to the runner, whatever its origin. $cores is a number the shop resolved while it was building; $self is the token for this particular actor, which the runtime writes in as the actor comes into existence. The runner does not distinguish them, because the level it works at is “bind this value to that name” — and that is the level that keeps it small. Do not read {value} as “a constant the shop knew”: the shop cannot know an actor’s own token.

The runtime writes those tokens in by being asked, one name at a time. A {value} row whose origin is the runtime names an earlier entry and a name to project out of it, and the engine core is entry 0 of every executable. When the engine’s result is a function, the runner projects by CALLING it with the name; when it is a record, by reading the property. So $self arrives because a row asked for it, and the engine never learns the list of names this executable claims — there is nothing to hand it and nothing to compute. A name no row claims is a call nobody makes, which is also why an engine value nobody asked for is never built.

A {unit} entry names an image and an entry point inside it. Running it is exactly what running any module is — the unit executes once, and what it returns is the value. A {native} entry names a provider by key and the binary answers it out of its static extension table, or out of a dynamic library where the shop arranged one. See Extensions.

An endowment is an entry with a $name

An endowment is a module result bound to a $name instead of a def name. Same instantiation, same array, same slots — the only difference is which side of the $ the name it binds falls on.

That is why the runner holds no table of known names and no built-in constructor for anything. $delay, $clock, $couple and log are units in the array like the modules beside them; $posix_file and $metal are {native} entries like any other compiled-in provider; $cores is a {value}. Asking “is this name one the engine owns?” is a question nobody in the start path has to ask, because there is no set of engine-owned names for it to be asked against.

The gate is still where it always was. What decides whether $metal gets a row is the shop’s answer to the claim, taken when the program was built — see Capabilities and Endowments. What the array changes is only that a granted name arrives by the same mechanism as an imported one.

Slots are what let images be shared

The runner allocates one slot per entry in the new actor’s heap, and the indices were assigned when the executable was finalized. A unit’s bytecode names only what is inside its own image, relatively; a reference that crosses an image boundary is a binding row the realization fills in against that actor’s slots.

So the same image can be instantiated more than once — twice in one actor, or once in each of a hundred actors — without its code knowing, because nothing in the image encodes whose slots it is reading. The image is immutable and shared; the slots are the actor’s own. That separation is what makes a pool mappable read-only and shareable across every actor running it, and it is why the array lives with the actor rather than with the code. See Actors and Memory.

Starting is following rows

Resident freshness is decided before following them

An executable resident in the boot section carries the manifest hash it was derived from as [email protected]_closure. When source is available, the shop realizes the requested locator far enough to obtain today’s manifest hash and compares the two. Equality keeps the resident plan; inequality selects the newly realized plan. The runner still follows exactly one array either way and never performs a source or cache check.

This boundary matters because the executable-manifest hash is stable across target payload forms, while a target-realization key is not. Source freshness is a property of the logical closure. Mapping, pool grouping, and whether the provisional seed arrived as mcode are properties of a particular realization and cannot decide whether source changed.

The array is the plan, and the plan was computed by the shop. The runner does no thinking: it does not compare artifacts, re-check claims, re-authorize anything, or work out an order. It reads rows.

allocate one slot per entry
for each entry, in order
    {value}  →  bind it
    {unit}   →  install this unit's binding rows, invoke the entry, store the result
    {native} →  look up the key, store the provider
bind the names to their slots
run the root unit last

Dependency order is calculated when the executable is built and merely realized at start, so there is nothing left to decide and therefore nothing to refuse. A row that cannot be followed means something upstream is broken, and it disrupts like any other bug rather than taking a designed refusal path.

$image makes the plan real

The rows name images by content hash. Turning a hash into code an actor can call is $image, the endowment over the image provider, and it is held by boot.

$image   authorize with the realization you were handed
         open a pool by content hash, validated
         pin its placement
         bind its declared cross-image imports through the realization's rows
         resolve an entry function
         unpin, close

The first step is the one that makes the rest unforgeable. authorize takes the realization a runner was handed and returns an opaque value; opening, binding and entry lookup all require it, and source code cannot construct one. It decides nothing — it marks that these operations came from a realization rather than from ordinary data, which is exactly the distinction the rest of this page rests on.

C keeps the mechanics — mapping, validation, the pin table, everything that touches address space — and pit holds every policy question about which image is brought in and when. At cold boot the runtime pins the boot cart’s engine image itself, because there is no pit yet to ask; on a target where the cart is already addressable it is resident by construction. Every image after that is brought in from pit, by boot and the clerk, following realization rows. The realization is the plan; $image is how the plan is made real, never how the plan is made. The interface is specified in Artifact Formats.

A pool’s bytes are ordinary store content and anything holding the store may read them. What $image gates is executable placement — turning bytes into something a frame can run — which is why it is one endowment rather than a property of the store.

Eviction is the absence of traced references. A closure traces the binding it came from, a binding retains its pin, and a pin is a refcount over an immutable pool. So an image becomes evictable exactly when the last actor holding anything from it stops, and no stop-the-world pass or quiescence point is needed to discover that.

“Holding anything from it” is broader than holding a function. A record built by code in a pool lives in the actor’s own heap, but its shape is a row in the pool — so an actor’s heap cannot even be walked once the pool is gone. An image an actor is still being torn down around is therefore still referenced: it leaves the live set at once, and its address space is released when the heap is.

On a banked target, pinning and bank selection stay distinct: a pin keeps a placement valid for as long as an actor can reference it, and selecting which pinned placement is visible right now is the scheduler’s business at turn dispatch. By the time a bank is switched there is no decision left — the placement rows already made it. Boot takes a turn for genuine decisions only: mount, fetch, evict, arriving as ordinary messages. See Cartridges.

Unused means absent

Because a value exists only where the array has a row, and a row exists only because some unit claimed the thing it names, an actor carries nothing it did not ask for. An actor that never sends a message has no send; one that never waits has no $delay; one that never starts a child has no $start, and the code behind it is not in the build to be found.

The claim is the liveness analysis. No pass walks the program looking for what can be removed, because nothing unclaimed was ever added — and a stripping pass would be a second answer to a question the claims already answer exactly. That is what makes a shipped artifact small by construction rather than by pruning.

This is what the engine’s own standard library rides on. The engine holds the walk above and nothing else; logging, message send and reply, requestors, and the implementations behind $clock and $start are ordinary modules that reach an actor as entries in its array, so a console cart that uses three of them pays for three. The engine is not trimmed for that target — it never contained them. See Booting.

The one exception is deliberate and is named where it is taken: a build may link an provider package whole, so a playground can grant what nobody has claimed yet. Such a build carries providers nothing asked for and is gated at its policy actor rather than by absence. See Endowments.

Where each decision was made

QuestionAnswered byWhen
which units are in the closurethe builder, resolving use()building the manifest
does this name exist in this buildthe shop, mechanicallybuilding the manifest
may this closure hold itthe policy actorbuilding the manifest
which images cover those unitsthe link planfinalizing the realization
which slot each entry fills, and in what orderthe realizationfinalizing the realization
which pinned placement is visible right nowthe schedulerturn dispatch

Nothing in that table is answered twice, and nothing in it is answered by the runner. An executable stays deliberately nebulous — a manifest names modules and knows nothing about blobs — and a realization freezes one covering of it, fine-grained for a development build that wants to reload a module at a time, fused for a shipped one. Because grouping is a linking choice, the covering is picked ahead of time, which is the reason starting can be following rows at all. See Build and Artifacts.