Core Computational Architecture

Tier: Foundation. The "why and how" of computation in the entity system — the umbrella over GUIDE-COMPUTE.md (the expression-language reference) and GUIDE-COMPUTE-PROGRAMMING.md (the SDK authoring surface). Read this first for the model; read those two for the language and the API.

Status: Active

Spec reference: EXTENSION-COMPUTE.md v3.19c (the value model: kind-tagged scope bindings, navigate-by-kind, construct-materializes-bare, error-as-value at 200); ENTITY-CORE-PROTOCOL.md §6.6 v7.49 (dispatch uniformity), §3.7 (entity-native handlers), §5.8 v7.50 (cross-peer closure transfer, registered).


1. The one frame

The entity system is a distributed compiler. Compute is its portable, content-addressed intermediate representation (IR).

Frontends (host-language builders, pipeline/query DSLs, eventually source languages) → compute IRthe gradient backend (interpreted now; native per local machine later).

Everything in the compute arc is a facet of this single sentence. The rest of this guide unfolds it: what makes compute an IR (§3), how work is placed against it (§4), how the positions compose (§5), how the backend compiles it (§6), what the spec must pin for it to travel (§7), how you author it — from hand-assembly up to languages (§8–§9), and how to choose (§10).

The framing is not an analogy borrowed from LLVM. It is the operational mechanism: a transferable description (the IR, living as content-addressed entities in the tree) is locally expressed as activity (evaluation, eventually native), and the description persists for re-expression elsewhere. Frontend / IR / backend = the transcription / translation / expression of a genome.


2. Why an IR at all

A handler is work. The system has three ways to place work:

The third is the interesting one, because it is the only one that lets computation move between peers and run identically on arrival. That capability is what an IR buys you, and it is the reason compute exists as a layer rather than as "a little expression evaluator." Once computation is a transferable artifact, the system stops being "peers that talk" and becomes "peers that can send each other programs" — a distributed compiler whose object code is the tree.


3. Compute is the IR

A compute graph is an intermediate representation — but unlike LLVM IR or WASM bytecode (opaque, in-memory or binary blobs), this IR is content-addressed entities in the tree. That one difference is the system's character. The IR is:

It is typed-functional, not "simplified LLVM." Compute belongs to the GHC-Core / CPS family, not the SSA-basic-block family (the IR-landscape cross-check confirmed this against LLVM/WASM/MLIR/JVM/Cranelift/GHC-Core). Content-addressing makes SSA's versioning unnecessary — the hash is the version. What looks "missing" relative to an imperative IR is the family's shape, not a hole:

You might expectCompute's form
loopsrecursion + tail-call optimization (TCO)
early exit / exceptionserror-as-value (errors propagate like NaN; §7.2 of the spec)
mutable variableslet bindings + scope
arbitrary CFGnested if / apply (CPS-transformable)
basic-block versioning (SSA)content hash

Understanding this family shape is the difference between fighting the IR and lowering to it cleanly (§9).


4. N / S / T — the language's own structure (and the two axes)

The three ways to place work (§2) are the language's own internal structure — IR / standard-library / FFI:

The two axes (terminology, pinned)

Two orthogonal coordinates describe any piece of work. They have been used loosely in the exploration record; this guide is the place they are stated cleanly. No new names — just the relationship made precise.

A native handler is Class N on the transferability axis and Class 4 on the convergence axis — two coordinates, not synonyms. The earlier "Class 4 ≈ native" shorthand conflated them; read "Class 4" as opacity and "Class N" as placement. Pure interpreted compute is Class T / Class 1. A compute handler compiled to native (§6 Stage 3) stays Class T (the source IR still travels) while sliding toward Class 4 on visibility — which is exactly what the dial means.


5. The drop-down idiom — first-class, not an escape hatch

The three positions are rarely used in isolation. The dominant practical pattern is their composition, and it is first-class:

The drop-down: a compute (IR) expression uses compute/apply to dispatch to a native handler for what is effectful, unbounded, or performance-critical, and threads the result back through the IR. Compute owns the plumbing; native owns the work; compute/apply is the seam.

Experiment C1 measured it: ~3 IR entities of glue around a Go function versus ~25–30 for the same operation in pure compute via cons-cells. This is where the bulk of real handler work lands, and it stays the idiom for effects / FFI / hot paths even now that collection navigation has landed (which closed the pure list-transform cases, not the effectful ones). It is also how Class S handlers are built internally — revision:pull is a spec-contracted op whose implementation drops to native for the network/trie work.

No new primitive is needed for this: compute/apply over a registered handler (or a system/compute/builtins/* path) already is the seam. An SDK authoring surface must make this seam frictionless on day one (§8). One wrinkle the SDK must absorb: a handler-mode compute/apply returns its result wrapped in compute/result {value, expression} (the SA-4 contract), so consuming the inner value in further compute means a field("value", …) (or an unwrap helper) — see GUIDE-COMPUTE-PROGRAMMING §2/§7.


6. The gradient is the backend

How fast compute runs is a backend question, and the backend is a gradient — the same IR, compiled progressively further down per local machine:

StageWhat it isStatus
1Interpreted entity-graph walk. Always works; baseline correctness.Today (entity-core-go/ext/compute).
2Content-addressed memoization at the key/lookup layer — "free and structural." Pure sub-expressions collapse once across all dispatches; reactive recomputation skips unchanged subtrees.Unbuilt (core-go track).
3Native compilation per architecture — compile a handler's IR once at register time, run native per dispatch (the chain-step payoff, where Stage 2's top frame misses by design).Unbuilt.
4Machine code.Future.

Three load-bearing properties hold across the gradient:


7. Transferability ⇒ MUST (the standard-IR floor)

The IR's whole value is that an artifact authored on one peer evaluates identically on any COMPUTE-bearing peer. That carries a principle the spec now enforces:

Every standard-library capability the transferable IR depends on must be (a) MUST-given-COMPUTE — present on every peer that implements COMPUTE — and (b) cross-impl-deterministic — spec-pinned semantics, not implementation-owned. MAY-level or impl-owned-semantics is incompatible with transferability: it means "the same expression may behave differently, or not run, on another peer," which is the one thing the IR exists to prevent.

The sharp test for what must be pinned (the stopping condition): does the spec fix the capability's semantic behavior — output value, error type, side-effect shape — observable from a transferable artifact? → MUST-given-COMPUTE + pinned. Is it a resource bound — depth, budget, timeout — or opt-in per program? → stays flexible. Semantic outputs are non-negotiable; resource bounds are universally negotiable.

The v3.14–v3.18 floor applied this: compute/index/compute/length + the map/filter/fold stdlib + entity-native handler evaluation + store all converged to MUST-given-COMPUTE; the integer model (WASM/LLVM/JVM: sign-agnostic add/sub/mul, signed-default div/mod/compare, signed-canonical encoding, point-of-use numeric-cast) pins integer arithmetic; cascade-depth (a resource bound) stayed flexible. The discipline generalizes into a recurring transferability-MAY audit across the other extensions (CONTINUATION / SUBSCRIPTION / REVISION / …) — compute went first.


8. The authoring stack: from IR assembly to languages

Here is the part the synthesis called "framed, not defined," now framed concretely — and where the genuine design opportunity is.

Today we author the IR by hand. The S1 builder (ap.Compute() in workbench-go; GUIDE-COMPUTE-PROGRAMMING §2) is typed IR assembly: Literal, LookupTree, Arithmetic, Apply, Let, Lambda, … each constructor emits one IR node, you compose them, .Build() puts the graph bottom-up. That is the right floor — it closes the hand-assembly friction (F1–F8) and gives every higher layer something to target. But it is assembly. You would not, in the end, write programs this way — a compiler would emit this.

The opportunity is not to "build a language." It is to build the functional decomposition a language frontend needs. A conventional frontend is lexer → parser → AST → semantic analysis → lowering to IR. The first stages are language-specific and well-understood; the last stage — turning parsed structure into correct compute IR — is the part that is specific to this IR and is reusable across every frontend. So the high-leverage product is the lowering toolkit: the reusable, composable decompositions that translate language constructs into compute graphs. Build that, and:

The three authoring layers, then:

  1. IR assembly (the builder). Typed constructors, one per IR node. The floor. Built and tested (S1).
  2. The lowering toolkit (the functional decompositions). The reusable translations: how to lower a conditional, an iteration, a pattern-match, a data-structure access, a binding, a function call, signed/unsigned integer semantics. This is the layer to design next — it is "what a language would need," factored out of any particular language. §9 is its first content.
  3. Frontends. Parsers/surfaces that produce IR via the toolkit: the shell as the smallest meaningful DSL (compute build <expr>); a type-system hook that lifts typed SDK functions into compute (depends on 4-B, §11); panels that render and author; multi-language frontends (Rust/Python authoring SDKs are separate, unscheduled tracks). The validate-driver's typed helpers are the proto-frontend.

The invariant from §6 applies at every layer: each layer ultimately emits source compute entities in the tree; none emits compiled-only output.


9. Lowering patterns

Lowering is where frontends meet the IR's family shape (§3). The recurring decompositions — the seed of the §8 layer-2 toolkit:

Two more pitfalls a frontend/toolkit must encode (from the S1 reference design, grounded in the evaluator):


10. The decision guide — "I want to do X"

Start from what the work is; choose the position; weigh the trade-off (including what has an SDK surface today).

If the work is…UseWhy / trade-off
a single-value reshape between two dispatchestransform_ops in the continuation steptrivial, total, declarative. No compute needed.
a conditional, scalar, or struct transformcompute (dispatched from a chain, or installed reactive)visible, bounded, transferable (Class T/1). Authored via the S1 builder.
iteration over a collection / arraypure computeindex/length + the MUST map/filter/fold; drop down to native via compute/apply for effectful / perf-critical per-element workpure-compute iteration is expressible today; the drop-down (~3 entities of glue) is the idiom for effects/FFI/hot-paths, not a workaround.
a canonical, federation-wide recipe over standard primitivesnamed cross-impl op (Class S)portable-by-spec, native speed, clean contract — but every conformant peer must ship it, and it is harder to evolve than a local handler.
real I/O, FFI, genuinely unbounded work, or a hot pathnative handler (Class N / Class 4)the genuine escape; opaque. You can't force these into compute — they are the cliffs.

Then orient on the axes (§4): must it be transferablebehaviorally (→ S) or as data to any compute peer (→ T, the only option that sidesteps op-presence) — or is it inherently local (→ N)? Must it be visible/convergent (→ Class 1–2) or is opacity an acceptable trade for isolation/speed (→ Class 4)? And — the pragmatic gate — does the position you want have an SDK surface yet?

The composability contract: positions compose through compute/apply and through continuation steps; a compute handler is a verb-op (a typed, dispatchable function) indistinguishable at the dispatch boundary from a native one (V7 §6.6 dispatch uniformity). That uniformity is what lets a chain step, a panel, or another handler call any position without knowing which it is.


11. Settled vs open

Settled:

Open — and explicitly wanting more test cases / confirmation before we call it closed:


12. References


Foundation-tier guide. The entity system is a distributed compiler; compute is its portable, content-addressed IR. Frontends lower to it, the gradient compiles it, the tree holds it. We assemble the IR by hand today; the work ahead is the lowering toolkit that lets languages target it — and the test cases that confirm the data-structure and translation story end to end.