Reaktor graph theory — the model and its boundaries
Reaktor describes a software system as a typed, attributed, nested port hypergraph plus arbitrary Kotlin common logic. Nodes identify things; ports state how they participate; relations bind named roles; regions define composition boundaries. Kotlin functions implement algorithms and effects through the runtime's contracts. The drawing is a view of that system, not its execution schedule.
Read this chapter first, then Nodes, Ports, Hyperedges, Nested graphs, Subgraph views, visitors and traversals, the Kotlin graph language, distribution and change, and precedents. The interactive atlas contains thirty worked designs, with the same Blueprint cards, pins, frames, semantic zoom and theme used by Manna Atlas.
A small example before the notation
A conversation feature contains a route, a Surface, common Kotlin logic, a service and a message authority. The route opens a conversation. A typed service port supplies a send operation. A policy decides whether the caller may invoke that operation for this conversation. A successful storage receipt names the accepted operation and revision. Telemetry records an observation of that invocation.
Those relationships answer different questions. A navigation relation does not authorize sending a message. A dependency binding does not promise network delivery. An observation of a successful request does not prove that every request succeeds. Keeping those distinctions allows humans and tools to ask precise questions.
Explore the community app design and its complete declaration.
Formal structure
For a fixed definition revision, let
G = (N, P, R, H, I, owner, parent, type, facets, boundary)
| Component | Meaning |
|---|---|
| N | Finite set of identified nodes in this definition snapshot |
| P | Identified ports, each owned by exactly one node |
| R | Identified regions with acyclic containment |
| H | Identified semantic relations, including binary and multi-party relations |
| I(h) | Ordered incidence records (role, ordinal, endpoint) for relation h |
| owner | Maps each port to its node and each node to its containing region |
| parent | Optional containing region; this is a forest, not arbitrary ownership cycles |
| type | Dialect-qualified node family, port profile, contract and relation schema references |
| facets | Versioned domain attributes such as effects, authority requirements, clocks, placement and evidence |
| boundary | Explicit exported endpoints, aliases and their adapter/compatibility contracts |
An endpoint is a qualified pair (nodeId, portId). For example, messaging.send names the send port of one identified messaging node. The port ID is local to its owner; the qualified endpoint is unambiguous within the definition revision.
An incidence is not merely membership in a set. In a quorum, voter[0], voter[1] and voter[2] are separately identified roles. The same endpoint can legitimately participate more than once when a schema allows it. Distinct (role, ordinal) slots preserve multiplicity. Swapping positions is legal only when the dialect declares them interchangeable.
A snapshot can be finite while its implemented program supports recursion, loops, dynamically allocated data and new activations. A node family catalog therefore does not limit the language to finite DAG execution.
Identity, revision and activation
A definition ID names a semantic entity across edits. A definition revision identifies its exact content and linked contract/source references. A runtime activation names one instantiated execution of a definition; its epoch fences replacement or migration. Layout coordinates and inspector selection identify a view.
Two replicas can instantiate the same definition revision with different activation IDs. One definition ID can have old and new revisions active during a release. A deployment artifact must bind source, contracts, runtime profile and generated bytes. A diagram may display all of them, but cannot merge their identities.
The teaching definitions publish content hashes and separate their ELK layouts. The GraphDefinition DTO and Kotlin builder in reaktor-graph-port check structural references and preserve serialization. The current runtime still has PortGraph, provider/consumer ports, runtime Graph.shape() and the legacy editor's GraphDocument; these are not automatically migrated to this definition IR. A structural check is not a dialect verifier, effect proof, activation engine or deployment receipt.
Composition and nested regions
A region packages nodes, contracts and selected exported ports. Internal nodes remain identified; their details can be folded in a view without being deleted from the model. Composition joins compatible exported interfaces under an explicit mapping. It must preserve source ownership, revisions and incidence roles.
A name alias is not a transport. Crossing a process, machine, memory domain or principal boundary requires an adapter that specifies serialization, resource ownership, failure, deadlines and authority. Containment also does not mean every member shares a transaction or clock.
Nested regions are useful for feature modules, UI containers, service clusters and robot-local controllers. A region can be a legal candidate for partitioning or code push only after the relevant constraints are checked. The nested navigation design demonstrates containment and exports separately from invocation.
Open dialects and orthogonal facets
The 40 node families, 24 port profiles and 36 hyperedge patterns are a design vocabulary. They are not 100 mandatory runtime subclasses. A service can have an actor state facet, an auth requirement, telemetry policy and placement constraints without becoming a combinatorial AuthenticatedObservedDistributedServiceNode type.
The kernel owns identity, references, containment and structural change. Domain dialects own the laws of their operations and relations. Unknown dialects can be preserved and inspected, but cannot be assumed executable. A target admission plan must reject unsupported required semantics or expose a qualified opaque boundary.
For arbitrary Kotlin or foreign implementations, declarations and observations identify the analysis boundary. A declared effect set is a contract to verify or mediate; it is not evidence that hidden effects are impossible.
Four views of one system
| View | Useful question | What it must not imply |
|---|---|---|
| Definition | What entities and contracts are intended at this revision? | That they are running |
| Source/artifact | Which implementation and built bytes own this behavior? | That arbitrary source can be reconstructed from its diagram |
| Runtime/observation | Which activations and sampled effects were observed at this time? | That unobserved paths were checked |
| Diagram | Which region, ports and relation roles help this reader understand the system? | That a junction is an extra compute node or a wire is a network guarantee |
RAG and agents receive stable document/section IDs, definition IDs, revisions, relation kinds and participant roles. Static diagrams have corresponding endpoint tables and JSON. Questions should cite the exact section and distinguish a design example from source-qualified behavior.
Implementation boundary
The common definition DSL and its thirty representative declarations compile and validate in the graph-port module. Kotlin/JS compilation checks the common source path. The shared Blueprint incidence adapter draws every relation as a junction and retains every role slot. JSON, Kotlin declarations, static SVGs, prose and interactive examples derive from one authored catalog.
Runtime dialect verification, general source extraction, arbitrary-logic effect checking, signed target admission and universal subgraph deployment remain separate implementation work. Their required laws are defined in this theory section; the existence of a diagram does not close them.
A small structural core
The current portable IR has six records: GraphDefinition, RegionDefinition, NodeDefinition, PortDefinition, RelationDefinition and Incidence. Graphs carry identity/revision; regions carry acyclic containment; nodes carry identity, kind and owned ports; ports carry profile/contract references and polarity; relations carry kind and role-preserving incidences. This structure can describe cyclic dependencies, repeated participants and nested regions without a runtime class for every vocabulary label.
The formal model above includes intended facets and boundary contracts. The serialized DTO does not yet provide a general facet registry, effect checker or contract resolver. Existing examples express boundary, ownership and constraint relationships explicitly and use contract identifiers; those declarations require target-specific verification before execution.
Keep behavior, protocol, payload, ownership, authority, placement and evidence as independent concerns. The node classification, port classification and relation classification account for every source vocabulary ID while avoiding 100 mandatory kernel variants.
Coverage and target admission
| Target/task | Composition in the model | Required adapter or law |
|---|---|---|
| Mobile apps and websites | Surface/state, form/decision, RouteNode, service calls, offline state | Presentation binding, route lifecycle, authority on effects, conflict/version policy |
| Distributed services | Actors, authorities, RPC, broker resources, subscription/quorum/partition profiles | Serialization, idempotency, backpressure, membership epochs, fencing and consistency |
| Native media and FFI | Adapter/resource nodes, calls/streams, owned or borrowed memory | ABI/codec qualification, bounds, memory domain, allocator and lifetime |
| Workflows and commerce | Saga/control composition, durable receipts, atomic authority scopes | Retry/compensation policy, unknown outcomes and business invariant checks |
| Multiplayer systems | Session protocol, authoritative actor, tick source, snapshot/prediction | Membership/sequence rules, clock/tick law, divergence and reconciliation policy |
| Robotics and IoT | Device adapters, streams, clock mapping, local actors and placement | Hardware safety boundary, resource budgets, time uncertainty and disconnected behavior |
| Build, release and code push | Artifact/source records, dependencies, evidence, admission and migration | Exact target/revision evidence, signed provenance where required, ABI/state compatibility, drain and rollback policy |
| Agents, RAG and debugger | Principal-scoped evidence cuts, bounded visitors, typed proposals, Shadow scenarios | Retrieval authorization before expansion, coverage/provenance, source maps and isolated effect adapters |
All these tasks are expressible as graph structure plus arbitrary Kotlin/common logic. Expressibility is not complete target implementation. Unknown/foreign logic can remain an opaque boundary with declared interfaces, but the graph cannot infer its hidden effects, reconstruct arbitrary source or prove safety. Kotlin/JS deployment and reaktor-ffi bindings must admit the exact target and adapter; current structural examples do not establish universal polyglot or code-push support.
Missing checks, rather than missing business node types
The main gaps are versioned profile/schema compatibility, law/cardinality checking, implementation/source binding, effect and principal scope, ownership and memory safety, clock uncertainty, activation identity/fencing, dynamic membership and consistency, and evidence coverage. Adding an AuthenticatedNavigationTelemetryFfiNode would hide those gaps. A contract resolver and dialect admission checks should own them, with concrete runtime evidence for each target.
Arbitrary algorithms stay in Kotlin functions and classes alongside normal multiplatform code. The DSL composes graph declarations, selectors and admitted commands; it does not require translating loops, parsing, numerical algorithms or business logic into one node per instruction. Context propagation is a useful precedent for product-flow visitors: shared causality metadata is required, and graph connectivity alone is insufficient.