Skip to content

CU3 — The shape of the execution

g.plan() # how it is going to be walked

Status: closed. 39 tests in Rust, 38 in Python.

The question: are there several ways of executing a graph?

Section titled “The question: are there several ways of executing a graph?”

Yes — local, remote, by turns, in parallel. But the original’s answer is not a trait of executors: it is an enum of ten variants (Sequence | Parallel | Execute | Step | Loop | Branch | Remote | Composite | Stream | Empty) and a single match. Remote is not another executor: it is a variant that wraps a sub-plan.

It is the same principle we had already found — variation as data, not as a subtype — and it has a concrete advantage over a bare function or a trait: when a variant is added, the compiler points at the single place that has to decide what to do with it. A wildcard arm would say nothing.

Between the structure and the engine there is now a step: compile(&Graph, &Catalog) -> Plan. It decides the shape, and along the way everything structural is detected before anything executes. The engine no longer works out where each node’s input comes from: the plan says so.

  1. Plan is an enum, not a trait. Closed, exhaustive, no wildcards.
  2. Executor is a type, not a bare function: executing needs context (today the store; tomorrow a cache and events). That “tomorrow” is what the original calls GraphSession.
  3. Value loses Tensor and gains Number and List. Nobody was producing a shaped tensor, and the round trip to Python has to be symmetric: what goes in as a list comes out as a list.

Plan::Remote. There is no transport, so it would be a variant nobody can execute. What the enum buys is precisely that adding it the day there is a worker is one more variant, and that the compiler points at every place that has to decide. (It arrived in CU12.)