The mechanical engine
Use of semantics declared what the schema means; Nodes & types and Nodes & Relations are the things that meaning describes — a node on its own, and nodes wired to each other. This page is the other half of the pairing: the executor that reads those declarations and does the work. It compiles, it derives, it cascades, and it carries no type-specific code — it asks the semantic engine what a property is and acts generically.
Acting on meaning
The mechanical engine is three jobs, each of which reads the semantics rather than hardcoding it:
- Compiling reads a property’s
kindto decide what to do with a reference — embed a child in full (compose), project a small identity (link), or pull values back from the other end (aggregate). - Deriving reads the
inverseto know where an aggregate lands. InboundReviews become areview[]array and anaggregateRatingon the Place’s inverse property — values no editor typed. One shared routine does this for the live compile and the editor’s preview alike, so the two can never drift apart. - The cascade reads the topology index and the kinds to know exactly which documents a change must rebuild, and stops the moment it reaches nodes that don’t depend on it.
Special cases stop being special
Because the rules are read rather than written, the hard cases collapse into one. A polymorphic range, an inbound roll-up, a cardinality limit, the choice to embed versus project — each is the same general operation parameterised by a different declaration, not a separate branch in the code. Add a new type or a new property and the engine already knows what to do with it; there is no matching if to go and write. That is the whole payoff of putting meaning in one place: the machinery gets simpler, not more complex, as the schema grows.
The compiled–queried line, precisely
The engine is also where the compiled-versus-queried split gets its exact definition. The compiler materialises only what is schema-true of a node as a single entity: its own properties, its composed children, and its direct inbound (scope: this node). Anything that needs looking across many nodes — every review of every place in a region — is a different question, answered live and never baked.
Cardinality is what keeps that honest. A node has many reviews, but a review names one itemReviewed; the same review never lives on two nodes, so rolling reviews upward is a scoped derive, not a second attribution. This is why the compiled JSON-LD stays trustworthy for a search engine while richer cross-node roll-ups still render in the HTML.
Borrowed, not invented
None of this is novel machinery. A reverse index instead of a stored back-list is how Datomic reads relationships; a derived value kept in step with its source is incremental view maintenance; an entity store paired with a separate query layer is Wikidata’s shape; a declarative relationship directive is Gatsby’s @link; a class-driven picker is SHACL. CTXR already had the primitives — typed nodes, a topology index, a compiler — and the two engines simply name the meaning they were always acting on, so the mechanics can stop guessing.
With the data model and the engine that drives it in hand, the rest of the chapter is hands-on building on top of them — starting with The build folder.