Reaktor Graph — Data-oriented Substrate and Typed Maps
Design proposal · 8 September 2026 · ecosystem update: 9 September 2026 · implementation status: proposed. Evolve Reaktor's existing heterogeneous port graph into a small, immutable semantic kernel with compact storage, typed capability tables, compiled execution plans and a familiar Kotlin authoring surface. Keep the expressive node/port model; separate its data from live behavior, resource ownership and authorization.
One graph means one identity, contract and composition model across the ecosystem. It supports many owned partitions, runtime instances, physical stores and execution engines. Every module can describe its part of the system using the same substrate. A phone does not load every server's graph, and a service call does not consult a central graph server before executing.
This document refines the unified system graph, stable foundations and formal-methods program into a graph-specific architecture. The Living Graph atlas remains the product/design contract. The living UI/UX audit remains the implementation ledger. Nothing here closes an operational workflow merely by specifying an interface.
Ecosystem integration update: Section 22 maps all 34 framework module/build directories, all 13 desktop mode values and all 74 authored subpanes onto this substrate. It specifies module contributions, runtime hooks, observation feeds, shared Workbench context, ownership and integration acceptance. This is the required adoption contract for the complete framework and desktop, including the parts that do not currently import reaktor-graph.
Wire form: GraphPatch, ChangeProtocol and the revision model below are carried across a process boundary by Reaktor Graph Protocol — the substrate defines the values, the protocol defines how a workbench, an agent or a peer runtime reads and commits them.
1. Decisions that hold the design together
| Decision | Consequence |
|---|---|
| Nodes, ports and edges are data; capabilities are typed data facets | A bare entity owns no coroutine, lifecycle machine, DI scope, socket or database connection. |
| Runtime behavior is registered separately | A route, screen or actor remains convenient to author; its runtime resources exist only when its host activates them. |
| Stable semantic IDs and schema IDs cross boundaries | Labels, Kotlin class names, source paths, canvas coordinates and dense array indices are never durable identity. |
| Maps select and derive facts over the same skeleton | Auth, navigation, telemetry, analytics and IDE tools can be composed without copying the application's structure into competing graphs. |
| A connection points from consumer to provider | Preserve existing dependency/invocation semantics. Value delivery and traversal direction are specified separately. |
| Traversals are bounded strategies; visitors return findings, values or patches | Navigation setup, wiring, authorization analysis and agent work share inspectable passes. Effects execute through runtime capabilities or the control plane. |
| Services carry an interface plus an execution profile | Local, remote, native, streaming and durable delivery have explicit failure, ownership and completion contracts. |
| Async uses channels and subscriptions as ordinary graph entities | Pubsub, queues, mailboxes and durable workflows remain distinguishable and inspectable. |
| Kotlin authors typed IR; portable behavior has explicit semantics | Excellent native DX and a code-pushable language can coexist without promising arbitrary Kotlin hot replacement. |
| Definition changes and operational commands are different | Atomic local graph publication is achievable. A deployment, database migration or distributed cutover needs an execution/reconciliation protocol. |
| Verification and benchmarks are first-class evidence | Correctness, portability, memory and speed claims attach to exact artifacts and targets. |
The design deliberately keeps the core vocabulary small. Screens, routes, actors, topics, tests, services and database tables are module-defined node capabilities. Navigation, dependency, authorization, ownership and delivery relations are module-defined edge capabilities. The kernel does not acquire a growing enum containing every Reaktor product concept.
2. What the current system gives us
Review scope and source status
The review inventoried the entire local ReaktorWeb Markdown corpus: 101 documents, approximately 69,000 lines, including archived/private material. It also scanned 3,455 source files in the sibling workspace for graph/portgraph references and found 290 matching files across Reaktor, BestBuds, GymBuddy, Manna and shibasis.dev. These are corpus and dependency inventories, not a claim that every line, provider implementation or application path has been exhaustively verified. The architecture below uses targeted reads of the primary implementations, their consumers and the relevant foundation/module/design documents.
Source baseline for this proposal: Reaktor 57e8385642df3bc0c01552ca2e8b2beec8c5e7d6; BestBuds 727054b0fa8687c402b8ceda93f75ee975cb1571. Research was checked on 8 September 2026. Historical audit findings are treated as leads; the current source determines current behavior.
| Evidence in current source | Preserve | Architectural pressure |
|---|---|---|
reaktor-graph/.../core/Graph.kt, node/Node.kt, BasicNode.kt | Nested graph composition and concise creation helpers | Even a basic node inherits lifecycle/concurrency machinery. Graph construction also creates DI and navigation state. Definition inspection can require runtime construction. |
reaktor-graph-port/.../graph/PortGraph.kt, port/Port.kt | Typed keyed ports and practical lookup APIs | Concurrent object maps, repeatedly flattened collections, and Type identity involving strings/KClass are unsuitable as the universal wire/storage model. |
.../edge/Edge.kt, graph/connect.kt | Consumer-to-provider binding and direct typed calls | Constructing an edge mutates endpoints. Bulk wiring can mutate earlier connections before a later failure. Semantic changes need batch validation and atomic publication. |
| Both graph visitor implementations | Selectors and reusable passes | DFS is recursive; BFS ignores the exit closure that DFS invokes. A visitor relying on a push/pop hierarchy stack is not valid under both. Traversal event contracts must be explicit. |
RouteNode.kt, NavigationEdge.kt, ActorNode.kt | Typed route payloads, navigation bindings, bounded actor mailboxes, convenient state and message APIs | Runtime identity, binding objects and jobs are mixed with topology. An in-memory mailbox is not automatically a durable queue. |
reaktor-service/.../Service.kt, ServiceTransport.kt | Existing graph-neutral request/response service API | A transport enum containing PUBSUB/QUEUE/WORKFLOW does not implement their semantics. Operation contracts and adapter guarantees need validation. |
reaktor-auth/.../AuthNode.kt, SecuredPort.kt | Graph-neutral auth kernel plus optional context/policy ports | Connection checks are useful but do not by themselves establish authorization for every later invocation, revocation or remote caller. |
reaktor-telemetry/.../GraphTelemetry.kt | Lifecycle, navigation and port instrumentation seams | Runtime observation needs stable definition/activation links and incremental attachment; telemetry volume must not become graph definition churn. |
reaktor-ffi/.../Invokable.kt, switch/Switch.kt | Existing byte-oriented cross-language seam | Raw buffer/handle results need explicit schema, lifetime, cancellation, failure and ownership contracts. |
reaktor-flow/.../document/GraphDocument.kt | Existing serializable editor document and additive wire compatibility | Document kind, node metadata, scope paths and optional edge ports are an editor contract, not the new canonical semantic IR. Keep a versioned adapter. |
reaktor-compiler/.../ReaktorProcessor.kt | Compiler tooling seam | process() currently returns immediately. It is not an existing portable graph compiler. Other processors must be evaluated independently. |
BestBuds already proves why the current graph is worth evolving. BestBuds.kt composes nested feature graphs, repositories/interactors, routes, bindings and actors. ChatActor.kt consumes session, operations, timeline, analytics, socket and typing contracts while exposing useful ordinary Kotlin methods. MessagingService.kt defines concrete typed HTTP operations such as message reads, sends, reactions and read cursors. PubSubHello.kt separately declares topics and subscriptions. NotificationDispatchGateway.kt addresses named Durable Objects. FeatureFlags.kt hydrates configuration before graph initialization. These are related semantics currently spread across source and runtimes; the redesign must connect them without forcing all their internals into visual nodes.
GymBuddy's TodayGraph and CalendarGraph demonstrate a second requirement: repeated instances of similar interactors with different ownership and route contexts. Manna's minimal Graph plus Compose entry point establishes a small-app adoption case. The import census also found shibasis.dev; its full application behavior was not qualified in this review.
Reconcile the existing documents
| Existing design family | Binding input to this proposal |
|---|---|
| Framework overview, essays, kernel analysis, refinement, visitors | Small composable vocabulary, ordinary code inside durable primitives, typed composition outside. This proposal clarifies purity and traversal semantics where earlier sketches conflate data and behavior. |
| Stable foundations, verified foundations, formal methods | Immutable IR, transactional patches, explicit effects, bounded claims and evidence. Existing audits remain traceable; their proposed APIs are not automatically shipped contracts. |
| Unified graph, graph sources, hierarchical UI, atlas | Owned runtime islands, source authority, one context, semantic zoom, exact port selection and truthful coverage. |
| Core, capability, lifecycle, actors, distributed actors | Separate data capability, executable behavior, authority and host/resource lifetime. Preserve graph-neutral library APIs. |
| Service, bus mesh, work, FFI, FlexBuffers | Typed contracts, transport-specific guarantees, durable work and versioned encoding. A shared envelope must not erase provider differences. |
| Auth, multitenancy, data, server, telemetry/analytics | Tenant-aware authority and data ownership; physical stores and telemetry remain authoritative for their domain. |
| Agentic tooling, Conductor, UI/UX audit | Humans and agents use the same query/proposal/plan/execute/receipt path. A workbench feature is accepted through a real developer journey. |
3. Lessons from related systems
These are design inputs, not proposed dependency purchases or claims of feature parity.
| System / primary reference | Useful idea | Reaktor decision |
|---|---|---|
| Unreal Blueprint pins, functions, debugger | Typed data pins, explicit execution flow, reusable code primitives, breakpoints and pin-value watches | Distinguish contract bindings, value flow and control flow. Preserve source maps and execution identity so a displayed value names the run that produced it. |
| Unreal MassEntity | Data-only fragments/entities, batch processors, chunk storage and deferred composition changes | Use compact data and batched passes; do not make every capability combination a mandatory archetype. Reaktor's sparse heterogeneous relations need their own measured layout. |
| n8n queue mode | Trigger reception, execution IDs, workers and persistent execution results are separate concerns | Expose trigger, placement, queue, execution and result as connected entities. A visual workflow is incomplete without a real runner and inspectable failures. |
| Temporal execution/replay | Workflow definitions differ from executions; replay checks emitted commands against recorded history | Durable work requires deterministic decisions, recorded effect outcomes, pinned program versions and explicit migration. A suspend function alone does not supply durability. |
| Google Maps Data layer, Pixxel bands | Common spatial reference, selectable measurements, feature-based styling and derived visualizations | Use a common semantic reference system with typed overlays. Preserve the difference between measured data, a derived result and a color/style. |
| Kotlin builders, KSP | Receiver-based builders and generated declarations improve DX | Builders emit typed IR. @DslMarker controls receiver scope, not purity. KSP is not a general body-expression compiler. |
| WebAssembly WIT | Interface contracts, typed values and explicit resource ownership across languages | Generate compatible service/FFI facades from schema. Evaluate Wasm as one execution target; it does not replace Reaktor's graph or prove Kotlin/Native portability. |
| Alloy specification, TLA+ | Relational constraints and state-machine reasoning solve different classes of problems | Use a verification portfolio with precise scopes and assumptions, tied back to executable kernel laws. |
The hyperspectral analogy is especially useful when taken literally enough: an auth band answers a different question from a latency band, and each has its own units, coverage, resolution and freshness. Combining them should compute a declared result, such as “reachable operations denied for this principal and observed above this latency threshold.” It should not merely stack decorative colors. The analogy does not imply that software has one natural two-dimensional geographic embedding; layout is a projection.
4. HLD: one semantic model, several execution planes
The pipeline is:
- Author or extract. Kotlin DSL, supported visual edits, manifests and provider adapters produce typed definitions or provenance-bearing observations. A legacy runtime adapter can expose existing graphs during migration.
- Normalize and validate. Resolve stable IDs, schemas, capability requirements, ownership, port contracts and source authority. Produce a deterministic canonical representation and a revision digest.
- Publish locally. The semantic store atomically publishes immutable revisions of an owned partition. Snapshot readers retain a stable view. Runtime plans are derived artifacts keyed by revision and target profile.
- Query and compose maps. Indexed query plans select entities, join observations and produce typed derived claims with coverage and lineage. Workbench, IDEs, MCP and tests use this same service.
- Activate and execute. Runtime islands bind installed implementations, allocate resources required by capabilities and execute validated plans. Effects are authorized at their boundaries.
- Observe and reconcile. Execution events, traces, measurements, test results and command receipts join back through semantic IDs and activation references. Observations do not silently rewrite desired definitions.
Module placement
| Layer | Responsibility | Forbidden dependency |
|---|---|---|
Proposed pure reaktor-kernel | IDs, schemas, graph records, patch algebra, invariant contracts, deterministic normalization | Compose, DI, databases, clocks, networking, default jobs |
Evolved reaktor-graph-port | Typed graph facade, contract compatibility, indexed traversal APIs and legacy adapters | App shell or provider-specific operational logic |
Evolved reaktor-graph runtime | Activation, installed behavior, routing/actor integration and execution plans | Workbench layout or app-owned policy |
| Compiler/tooling | DSL lowering, schema/stub generation, source maps, validation and evidence | Production runtime required merely to inspect source |
| Auth/DB/service/bus/work/telemetry modules | Graph-neutral domain kernels and optional graph installation/projection | Mandatory graph adoption for plain library callers |
reaktor-flow | Reaktor scene adaptation, measurement, layout, maps and editor adapters | Product shell chrome |
compose-flow | Generic canvas, camera, rendering, generic edges and hit testing | Reaktor semantics |
| BestBuds engine / desktop / MCP | Product workflows, adapters, tools, inspector, context and orchestration | Duplicated graph semantics or authority rules |
These are target responsibilities, not an instruction to create all these packages at once. The first migration can place the pure kernel behind existing APIs and extract a module once dependency tests demonstrate the boundary.
The complete module and desktop integration matrix expands this HLD: every subsystem contributes definitions, operations, observations, maps, runtime hooks or presentation adapters through an explicit contract. Graph-neutral APIs remain usable independently, while Reaktor hosts install the shared projection and execution bindings.
5. Semantic model
Graph, node, port and edge
At a revision, a graph contains finite sets of nodes N, ports P and edges E, a port-owner function owner: P → N, typed capability relations, and a schema catalog. Every edge names exact source and destination ports. A node can have zero ports and zero capabilities. A graph partition has a stable identity and a declared owner/authority; publication produces a new revision.
A basic node is an identity plus data. A basic port is an identity, owner, consumer/provider role, contract reference and cardinality declaration. A basic edge is an identity, two endpoint references and a relation/interface reference. Constructors do not connect, invoke, emit events or allocate runtime resources.
A port contract and an edge contract answer different questions. A port contract defines the interface a node requires or offers: operations, typed values or a structural relation. An edge contract defines a legal relationship between endpoints, including allowed endpoint shapes, direction, multiplicity and composition rules. An invocation edge additionally records the negotiated service contract and binding profile. Matching string names is never sufficient.
Default callable binding is consumer → provider, preserving current Reaktor semantics. A consumer requiring Messaging.send binds to a provider offering that operation. A response returns in the other direction. For a stream, values can also flow provider → consumer. For navigation, the originating route's consumer references the destination's navigation provider. UI arrows must distinguish “requires/invokes,” “delivers values,” and “next control step.”
Edges for structural relations also attach to ports. Modules can generate compact implicit ports such as Ownership.child and Ownership.parent; these implement relation contracts and are not callable services. The normal inspector hides these ports until structural detail is requested. A relation with unusual role rules must declare them in its schema; it cannot bypass endpoint validation.
Multiple edges between the same nodes are valid. A consumer's cardinality may be one, optional, many or a module-defined constrained multiplicity. A single consumer with two candidates is an ambiguity error unless an explicit resolver/aggregate capability defines selection. Requiredness can depend on an activation profile, but the condition must be a typed predicate rather than an arbitrary callback evaluated secretly during wiring.
Capabilities
A capability is a versioned typed data facet on a node, port or edge. Examples include Screen, Container, Route, Actor, Weighted, AuthRequirement, DeliveryPolicy, StateSchema, SourceLocation, TelemetryLink and TestDefinition. Empty marker capabilities can be stored as membership bitsets.
A module registers the facet's schema, valid entity kinds, dependencies/exclusions, invariants, available operations, inspector metadata and optional compiler/runtime handlers. Capability values describe behavior requirements; the implementation registry supplies executable code. Installed handlers are identified by schema/ABI and artifact digest, never serialized as lambdas inside graph data.
Four concepts stay distinct:
| Concept | Question |
|---|---|
| Data capability | What does this entity describe or support? |
| Runtime implementation | Which installed code fulfills the declared behavior? |
| Authority | Who may read or act on which resources under which conditions? |
| Effect | What external state or sensitive information can this operation touch? |
Unknown capabilities can round-trip losslessly and render generically if their encoding is understood. A runtime cannot activate an unknown required behavior or effect. An optional presentation facet may be ignored. This is an explicit compatibility classification, not ignoreUnknownKeys applied indiscriminately to executable contracts.
Fractal composition
A graph can be packaged as a component and instantiated within another graph through boundary ports. Containment is an acyclic ownership relation; dependency, navigation and message relations may contain cycles. Internal entities retain identity under visual expansion/collapse. An exported boundary port forwards to an internal endpoint through an explicit binding, preserving source and runtime provenance.
A definition is reusable. Two feature instances do not share runtime state merely because they use the same definition. Instance identity, ownership and configuration distinguish GymBuddy's current workout from its calendar workout, and one user's chat actor from another's. Detaching a visual scope never destroys those runtime instances; an explicit lifecycle operation does.
Identity, revision and time
| Identity | Meaning |
|---|---|
| Graph/partition ID | Stable namespace and ownership boundary |
| Entity ID | Stable semantic identity of a node, port or edge within that namespace |
| Definition revision | Content-addressed normalized definition, schema lock and program/artifact references |
| Instance ID | A particular realization of a reusable definition in an owned runtime |
| Activation epoch | Fencing generation for a runtime activation/cutover |
| Operation/run/event ID | One command, workflow run, test run, invocation or observation |
| Local handle | Dense slot plus generation, valid only under the relevant store/lease |
Use explicit or generated persisted IDs for authored entities. Source rename/move preserves identity through compiler metadata and migration aliases. Paths are locators. Instance identity is not definition identity. Dense slots never escape over FFI, persistence, deep links or federation.
Revision hashing needs a specified canonical order, stable schema IDs, canonical scalar encoding, explicit defaults and deterministic unknown-field retention. Signatures bind the resulting artifact digest plus target/profile constraints. Floating-point edge cases, map ordering and Unicode normalization require conformance vectors; “hash the JSON” is not a protocol specification.
6. Data-oriented storage with a pleasant API
The public model is typed records and views. The hot representation is not a heap containing one polymorphic object with several maps per entity.
| Data | Proposed representation | Why |
|---|---|---|
| Entity identity/kind and port ownership | Dense primitive columns plus stable-ID-to-slot index | Fast scans and compact references; stable external identity remains available. |
| Edge endpoints and relation kinds | Parallel endpoint/relation columns | Batch filtering and adjacency construction without following object pointers. |
| Adjacency | Compact base ranges plus indexed versioned deltas; periodic compaction | Efficient reads without rebuilding a whole CSR-like structure on each edit. |
| Capability membership | Bitsets or sparse sets per facet | Efficient intersections; avoid an archetype for every overlay combination. |
| Capability payloads | Typed columns for hot facets; schema-coded blocks for cold/variable data | Keep runtime queries cache-friendly without making heterogeneous data inexpressible. |
| Labels, source locations and schemas | Interned tables and cold blocks | Keep strings and reflection out of repeated traversal. |
| Mutable runtime state | Activation-owned state stores and resource handles | No jobs, closures or sockets in immutable definition storage. |
| Telemetry, payloads and test artifacts | External event/time-series/blob stores with graph references | Observation volume does not multiply the resident definition graph. |
Use chunked copy-on-write publication or an equivalent immutable segment scheme. Readers pin snapshots; writers validate a patch against its base and atomically publish a new root. Platform-specific reclamation must prove that a retired segment is not reclaimed while readers or FFI borrows still use it. Do not assume a JVM technique automatically works on Kotlin/Native, JS or Wasm.
For small graphs, a flat compact implementation may be cheaper than elaborate indexing. Build indexes lazily or when declared workloads justify them. Specialized dense capability tables are an optimization behind one logical API, not a second semantic model. Use generics/reified helpers and generated typed facades for DX; use primitive cursors or batches for hot loops to avoid per-element wrappers and boxing.
Published collections must be truly immutable by ownership or persistent storage. Kotlin's read-only List/Map interfaces alone do not prevent the caller from retaining a mutable backing collection. The reference Kotlin types later in this document describe values, not permission to retain mutable input arrays.
Incrementality and scheduling
Each map, validator and compiled plan records its schema/entity/relation dependencies. A patch invalidates the affected dependency closure. Unknown dependencies trigger a conservative wider revalidation. Worker threads compile layouts, indexes and plans; publication uses revision checks so a stale background result cannot replace a newer one.
The local runtime compiles bindings into direct dispatch tables. Calling a hot provider should not scan the graph, allocate a traversal or serialize a payload merely because a remote implementation is also possible. Required authorization/effect checks remain at the generated dispatch boundary and may use safely scoped caches. Revocation and policy changes invalidate those caches.
High-volume telemetry uses sampling/aggregation and bounded queues. Structural deltas, policy changes and observations have separate revision streams. No actor state update or trace span should force full graph re-layout.
Performance acceptance, not invented speedups
The following are initial engineering budgets to validate, not measured results or unconditional promises. Record hardware, OS, target, build mode, graph distribution, schema/capability density, warm/cold status and profiler artifacts in reaktor-performance.
| Workload | First qualification target |
|---|---|
| Current BestBuds/GymBuddy graphs | No material startup or interaction regression against the current baseline; compare p50/p95, allocations and retained memory. |
| 10k nodes, 50k ports, 100k edges, mixed capabilities | Warm indexed one-hop query p95 below 5 ms; a bounded local map update below 50 ms, excluding provider/network latency. |
| 1k changed entities in that graph | Incremental normalization/validation/publication p95 below 50 ms, with full validation correctness cross-checks. |
| Large offline inventory: 1m nodes / 5m edges | Bounded paged inspection within a declared memory budget; initial target below 1 GiB for base topology/indexes, excluding retained payloads and historical snapshots. Measure actual capability density separately. |
| Main MacBook and Dell U4025QW, normal/wide/ultrawide and portrait canvas | Visible interaction meets a 16.7 ms frame budget at 60 Hz; qualify higher-refresh targets separately. Expanded scene work must be culled and asynchronous. |
| Hot local typed service call | No graph traversal or payload codec on the steady-state direct path; compare checked dispatch overhead and allocation count with today's typed port call. |
| Repeated snapshot/expand/close and remote detach cycles | Bounded retained memory after reclamation; no growing listener/job/handle count. |
Use chain, star, balanced tree, high-degree hub, dense SCC, sparse overlays and churn-heavy graphs. A benchmark containing only a tidy tree cannot qualify the graph. Compare the simple reference model with the optimized store and preserve identical results. Performance and DX are both release gates; neither compensates for failure of the other.
7. Maps: a common skeleton with typed overlays
A map is a versioned selection/derivation over a graph context. It includes selected nodes, ports and edges, chosen capability views, derived claims, coverage and provenance. The complete graph is the identity map over the declared scope and schema catalog. “Complete” never silently means every remote entity is loaded or every principal can see everything.
There are three related artifacts:
- Map definition: a typed query plan and declared dependencies. For example, select route-capable nodes, navigation edges and authorization requirements.
- Map result: a snapshot-scoped subgraph plus typed derived facts and a coverage/frontier report.
- Presentation profile: styling, layout, visible labels, thresholds and semantic zoom rules for that result.
A fourth use, an executable policy/selection artifact, is deliberately explicit: a compiled route table, rollout selection or authorization policy may be derived from a map, but changing the displayed overlay does not activate it. Activation follows the modification protocol.
Map algebra
Provide typed select, projectCapabilities, union, intersect, difference, joinFacts, derive, reachable, group and aggregate. Set operators preserve entity identity; they do not clone nodes. A map's edge set is endpoint-closed: include its endpoint ports/owners or include explicit boundary references explaining why details are unavailable.
Derived relations carry a producer ID, producer version, input revision/fact-cut digest and witness references. Their stable identity derives from the producer and semantic input keys, not from canvas positions. They cannot masquerade as declared canonical edges. A derived entity can be inspected through the same APIs, but mutation redirects to its authoritative source or is rejected with a reason.
Set union can be commutative; transformations, policy composition and rollout precedence often are not. Publish the algebra for each operator. Conflicting facts remain a conflict or resolve through an explicit policy with retained alternatives. Never make overlay order silently override authorization or executable configuration.
Cache keys include the definition revision vector, schemas, map version, environment, tenant/principal/visibility policy, query parameters, time/fact cut and relevant run/activation. A cached result for one principal must not leak into another's view.
Useful maps, with actual questions
| Map | Example question | Required input / result |
|---|---|---|
| Navigation | Which screens can this role reach from this deep link under these flags? | Route contracts, roots, conditions, policy context; witnessed routes and unresolved conditions. |
| Auth | Why was this operation denied, and which grants could permit it? | Principal/session/token metadata, policies, resource/tenant context and recorded decisions; explanations tied to policy revision. |
| Runtime | Which implementation is serving this logical provider now? | Definition-to-instance bindings, placement, deployment digest and fresh activation observations. |
| Telemetry | Where did this request spend time across phone, Worker, server and DB? | Correlated spans/events and boundary links; sampled/missing segments visible. |
| Analytics | Which eligible user journeys stop after opening chat? | Versioned event taxonomy, cohort/consent context and aggregates; observation gaps remain distinct from unreachable routes. |
| Data | Which tables/collections/graph labels does this operation read or mutate? | Declared effects, schema adapters and observed query evidence, with engine-specific details. |
| IDE | What source change affects this route, contract or native export? | Symbol/source maps, generated artifact provenance, dependency edges and build target. |
| Delivery | Which activations use this revision and which are waiting for cutover? | Release plan, artifact digest, target profiles, epochs and receipts. |
| Test / assurance | What proves this patch, and what has not been tested? | Test definitions, affected closure, run artifacts, budgets, assumptions and stale evidence. |
Flow selection differs from map selection
A map selects a subgraph. A flow selection identifies a declared program path, a candidate route, or an observed causal execution through that subgraph. It can include repeated visits, branches, fan-out/fan-in and concurrent partial order. Store its ordered/causal steps and exact port/edge references. A highlighted simple path is not enough to represent a distributed workflow.
Selection carries graph revision, map, entity/port, source, activation/run and time context across IDE, database, auth, devices and MCP. Overlay switching preserves that semantic selection even if the entity becomes hidden; show why and offer reveal. It does not silently choose a different node.
8. Traversals and visitors
A traversal is a strategy over a pinned map result from explicit starting references. Its request declares relation types, direction, deterministic ordering, cycle policy, maximum visits/edges/depth, deadline/cancellation, remote boundary policy and result budget. DFS uses an explicit stack. BFS uses a queue. Topological traversal rejects cycles or returns SCCs; weighted algorithms validate weight assumptions. These are different contracts rather than one callback with surprising behavior.
The basic visitor is a pure fold over discovery events: it receives a view and accumulator and returns the next accumulator plus Continue, Prune or Stop. Its result can contain diagnostics, route-table entries, test selections or typed patch proposals. A separate structured DFS event stream supplies enter/leave guarantees for scope-sensitive passes. BFS never pretends to supply a nesting stack. Pruning, duplicate visits and cancellation behavior are specified and tested for each strategy.
Results include visited counts, termination reason, unresolved frontier, coverage, and witness paths when requested. “No denied path found in this bounded result” is not “all users are authorized.” A remote boundary may be opaque, use a pinned cached export, or be expanded by an authorized async query before a new local pass. Pure traversal itself does not secretly call the network.
Visitors still do useful tasks:
| Task | Visitor output | Effectful consumer |
|---|---|---|
| Navigation setup | Validated route/binding table | Runtime installs table for an activation. |
| Wiring | Deterministic binding proposal with ambiguity diagnostics | Kernel validates and publishes atomic patch. |
| Auth analysis | Policy obligations, decisions under explicit inputs and witnesses | Runtime enforces at invocation; tools display explanations. |
| Agent refactoring | Findings, typed patch and affected-test selection | Shared change planner executes authorized plan. |
| Telemetry installation | Instrumentation plan and required event hooks | Runtime attaches bounded observers. |
| Dead-screen finder | Reachability classification and evidence | Workbench opens source/tests or offers a proposed removal. |
Kotlin interfaces alone cannot enforce purity: a trusted Kotlin plugin can still read a global or perform I/O. Untrusted/portable visitors must execute in the restricted program runtime with only declared read imports and budgets. Trusted native passes require review, dependency constraints and conformance tests; their assurance label reflects that distinction.
Dead-screen analysis must be honest
Roots include normal launch, deep links, notification actions, platform entry points, role/tenant variants, experiments and dynamic configuration. Classify screens as reachable with a witness, unreachable within a stated closed model, unobserved in a time/cohort window, or unknown because inputs/edges are missing. Conditional reachability may require a solver or bounded scenario enumeration. Lack of telemetry is never sufficient proof of dead code.
9. Services and FFI
A service is an interface-bearing capability whose operations can cross a machine, process or language boundary. Keep existing graph-neutral Service callers working. Generated Kotlin, C++ and TypeScript bindings share stable operation IDs, request/response/error schemas, version negotiation and source maps.
Each bound operation declares:
- Interaction shape: unary call, stream, publish/accept, subscription or durable job handle.
- Effects, principal propagation, resource/tenant scope and authority requirements.
- Locality and placement: direct, thread/process, native ABI or remote transport.
- Completion: returned value, accepted message, committed mutation or completed workflow.
- Deadline, cancellation propagation, retry eligibility and idempotency scope.
- Buffer/resource ownership, maximum sizes and serialization/ABI profile.
Local and remote calls can have the same typed interface while exposing different failure capabilities. A timeout after sending a mutation may have unknown outcome; it must not be converted to “nothing happened.” Retry only under an operation contract that makes it valid. Cancellation acknowledgement is distinct from requesting cancellation, and neither necessarily reverses committed effects.
FFI invocation uses validated envelopes containing operation/contract IDs, request/run context, buffer bounds and ownership mode. Generated direct fast paths can elide serialization when safe. A borrowed buffer has a lease; a returned owned handle has explicit release and generation checks. Async calls retain needed buffers until completion/cancel acknowledgement and specify callback thread/dispatcher and reentrancy. A raw Long is not a portable lifetime protocol. WIT's separation of contracts, values and owned/borrowed resources is a useful reference, not a requirement to rewrite the existing codec. WIT reference.
Interface compatibility checks include operation availability, required/optional fields, wire representation, nullability, error variants, size limits, streaming semantics and effects. An additive field with a default may be compatible; removing an operation or adding a newly required effect is not automatically compatible. Kotlin generic type safety at one call site does not establish cross-version or cross-language compatibility.
10. Async: channels, subscriptions and durable work
Adopt channels as the organizing concept. A channel is a node with publish/consume/inspect capabilities and a message schema. A topic is a channel with fan-out subscriptions. A queue is a channel with a competing-consumer delivery policy. A subscription is an ordinary node with its own filter, delivery policy, progress and destination. An actor mailbox can expose the same protocol family with an explicitly in-memory, activation-scoped profile.
No new kernel entity kind is required. The async module introduces vocabulary and execution contracts. This is seamless composition at the type level while keeping delivery behavior inspectable.
Canonical bindings still point consumer → provider. A producer requires a channel's publish service. A delivery adapter requires a handler's consume service. A subscription links its source channel through a structural/source contract. The delivery map renders message movement producer → channel → subscription → handler and identifies that as value flow, not the raw orientation of every binding edge.
Delivery policy must be data
| Dimension | Required semantics |
|---|---|
| Durability | Volatile, persisted before acceptance, or transactionally enqueued with a named store boundary. |
| Routing | Fan-out per subscription, competing consumers per group, partition/key affinity and explicit filters. |
| Ordering | None, per key, per partition or a provider-qualified stronger order; retries/replays state their effect on order. |
| Acknowledgement | Accepted, delivered, handler-completed or transaction-committed; broker ack point is explicit. |
| Retry | Eligible errors, delay/backoff/jitter, maximum attempts/age, and retry authority. |
| Deduplication | Key, scope, storage, retention and the transaction covering the business effect. |
| Backpressure | Message/byte capacity, in-flight limit, producer wait/reject/drop policy and fairness. |
| Failure | Dead-letter target, poison-message reason, redrive policy, cancellation and expired leases. |
| Visibility | Lag, attempts, handler duration, last progress, oldest age and coverage/freshness of observations. |
Provider adapters publish a guarantee profile. Validation rejects an unsupported requested policy rather than silently weakening it. For example, Cloudflare Queues documents at-least-once delivery; consumers must handle possible duplicates. A Reaktor wrapper cannot upgrade that to general end-to-end exactly-once processing by renaming an enum. Cloudflare delivery guarantees.
For a database mutation that emits an event, use a transactional outbox where the provider supports that boundary: commit the business row and outbox record together; publish later; deduplicate at the consuming effect boundary. The publisher can crash after sending but before marking the record sent, so replay can publish twice. A broker-specific exactly-once acknowledgement feature does not make arbitrary downstream effects exactly once.
A durable workflow is a stateful program capability with an input schema, pinned program revision, durable history/checkpoint policy, timers, child runs, effect IDs and compensation rules. Deterministic decision logic is separated from external activities. Replaying history reuses recorded results; it must not repeat a payment, notification or database mutation merely because code was re-executed. Workflow upgrades pin old runs, use explicit version branches or apply a tested state/history migration. Temporal replay model.
11. Distributed stitching and runtime ownership
Federation joins exports from owned partitions using stable endpoint and contract IDs. A runtime export identifies its source revision, instance/epoch, schema catalog, offered endpoints, placement and observation cursor. Authentication of the exporter and authorization of the reader are separate from matching an ID.
The global query result contains a revision vector and coverage, not an invented single instantaneous snapshot. Each owner can provide a consistent local cut. A causally consistent cross-owner cut requires an explicit supported protocol; otherwise the result is a declared combination of observations from different times. Partial, stale, unavailable and inaccessible boundaries remain visible without leaking unauthorized details or counts.
Definition state has an authoritative writer or explicit multi-writer protocol per partition. Initial implementation should use optimistic concurrency against a base revision, not silently merge every edit with a CRDT. Concurrent nonoverlapping edits may be merged only after normalization and invariant checks. Concurrent edits to ownership, required bindings, schemas or policy often require a conflict decision.
Runtime placement is a map over instances: Android/iOS processes, browser tabs, desktop JVMs, Workers, Durable Objects, servers, Kubernetes workloads and native modules. Logical service identity survives a pod replacement; activation epoch and artifact digest expose that replacement. Device-offline state does not delete the corresponding definition. Expired discovery records do not prove a service was intentionally removed.
Distributed invocation carries causal/run context through service, queue and FFI boundaries, with appropriate attenuation of authority. Trace context is correlation metadata, never a credential. Telemetry links reference recorded causality; they cannot infer that two events with similar timestamps are definitely the same operation.
For BestBuds, D1, Postgres, ClickHouse, Memgraph, SQLite, Durable Object storage and object stores remain physical systems of record. The semantic graph catalogs schemas, ownership, operations, deployments and selected records through adapters. It is not automatically a replacement storage engine for all product data, nor should millions of messages become eagerly resident workbench nodes. Query result graphs are bounded maps with their own result identity and provenance.
12. Kotlin authoring, portable logic and Turing completeness
Two stages in one language experience
Stage A — authoring. An ordinary Kotlin builder produces graph/program IR. It may use functions, loops and reusable components to generate definitions. Its output is normalized, schema-checked and reproducible under declared inputs. The builder's Kotlin execution happens during build/authoring; its arbitrary closures are not the artifact sent to clients.
Stage B — portable execution. A typed logic DSL constructs explicit expressions, branches, state transitions, loops and calls to declared effects. A compiler plugin can later lower a supported Kotlin subset into the same program IR. Unsupported constructs fail with source diagnostics; they never fall back silently to unrestricted runtime evaluation. KSP can generate declarations and registries, but does not supply arbitrary expression/body analysis. Kotlin builders, KSP scope.
The compact program representation may use typed registers/blocks rather than reifying every arithmetic operation as a globally indexed entity. The graph contains the program definition and imports; an on-demand code map expands its internal IR using stable instruction/source references. Native Kotlin/C++ algorithms remain ordinary code behind declared contracts. Blueprint authoring composes these primitives and can edit supported portable logic with source round trips.
What Turing completeness does and does not mean
A static port graph is a data structure. Cycles alone do not make it a universal programming language. Turing completeness belongs to an execution semantics capable of expressing general computation, with unbounded resources in the mathematical model. The target portable language can include conditional branching, general loops/recursion and suitable memory; a machine-simulation/conformance example should establish the claim instead of using the phrase as marketing.
General computation means there is no algorithm that decides termination for every possible program. Purity does not imply termination. Therefore Reaktor cannot promise arbitrary Turing-complete logic, automatic proof of every behavior and guaranteed unbounded execution all at once. It can offer a total/bounded subset for policies and queries, a general portable subset with explicit resource limits, and trusted native implementations with declared assurance. The underlying computability limit is grounded in Turing's original paper.
Practical execution uses fuel/instruction budgets, memory limits, deadlines, cancellation, bounded output and effect quotas. Exhaustion is a typed result, not a hung UI or implicit success. For durable work, a budgeted slice checkpoints or yields according to its profile. Determinism requires explicit inputs for time, randomness, environment and effect outcomes. Numeric overflow, floating-point behavior, map iteration, exceptions and concurrency ordering must be specified across targets.
Code push classification
| Proposed change | Eligible mechanism | Required evidence |
|---|---|---|
| Presentation map or saved view | Versioned user/workspace data | Schema compatibility and rendering tests; does not change executable policy. |
| Dynamic config or flow/overlay selection affecting behavior | Signed configuration revision with typed conditions | Target compatibility, policy checks, scenario tests, rollout/cutover receipt. |
| Rewiring installed compatible providers | Semantic graph patch plus compiled plan activation | Contract/effect/lifecycle validation, impacted tests, state/resource transition plan. |
| Portable program change within installed imports | Signed program artifact | IR validation, supported target profile, budgets, effect authority, migration and replay evidence. |
| New native implementation, ABI or unavailable import | Build and distribute a new host artifact | Platform build, conformance and deployment qualification. |
| Persistent state/schema change | Explicit migration plan | Compatibility window, backup/recovery where applicable, data checks and reconciliation. |
An artifact is code-pushable only relative to a target's installed runtime, allowed imports, policy and distribution constraints. Kotlin purity or a data encoding is not a universal mobile distribution exemption. Apple's current guideline 2.5.2 restricts downloaded code that changes app functionality, with specified exceptions; target release profiles need review against the applicable distribution rules. Apple App Review Guidelines. Default to the ordinary release path where eligibility has not been established.
Runtime replacement protocol
Prepare and verify artifact → stage under new epoch → check state compatibility → drain/fence or migrate affected instances → publish activation binding → observe/reconcile → retain receipt. Definition publication can succeed while activation fails; report both. An old writer fenced by a new epoch cannot continue mutating the new state. A rollback may need a reverse migration or compensation; switching a pointer back is insufficient after irreversible external effects.
13. Important Kotlin interfaces
These are proposed, compilable contract declarations, not shipped APIs. The complete Kotlin specimen is kept outside runtime source sets. The declarations express the main boundaries; codecs, constructors with validation, wire formats, platform storage and runtime implementations remain implementation work. Published values require immutable backing storage. All external input is validated against the schema catalog.
Identity, pure graph data and authoring
The builder is an authoring interface. Its output is data; registering a provider here declares a contract, not a live implementation. Generated module helpers return named port bundles so ordinary product code rarely handles schema digests directly.
data class GraphId(val value: String)
data class EntityId(val graph: GraphId, val value: String)
data class Digest(val value: String)
data class SchemaRef(val id: String, val version: Int, val digest: Digest)
data class BlobRef(val schema: SchemaRef, val digest: Digest, val byteLength: Long)
data class Revision(val graph: GraphId, val digest: Digest)
data class RevisionSet(val entries: List<Revision>, val digest: Digest)
data class SnapshotRef(val definitions: RevisionSet, val factCut: Digest)
data class ActivationRef(
val instance: String,
val epoch: Long,
val definitions: RevisionSet,
)
data class LocalHandle(val slot: Int, val generation: Int)
enum class EntityKind { Node, Port, Edge }
enum class PortRole { Consumer, Provider }
data class Cardinality(val minimum: Int, val maximum: Int?)
data class ContractRef(val schema: SchemaRef)
data class CapabilityKey<T : Any>(val schema: SchemaRef)
data class CapabilityValue(val entity: EntityId, val value: BlobRef)
data class NodeRecord(val id: EntityId)
data class PortRecord(
val id: EntityId,
val owner: EntityId,
val role: PortRole,
val contract: ContractRef,
val cardinality: Cardinality,
)
data class EdgeRecord(
val id: EntityId,
val from: EntityId,
val to: EntityId,
val relation: SchemaRef,
val bindingContract: ContractRef?,
)
data class GraphDefinition(
val revision: Revision,
val nodes: List<NodeRecord>,
val ports: List<PortRecord>,
val edges: List<EdgeRecord>,
val capabilities: List<CapabilityValue>,
)
interface Graph {
val snapshot: SnapshotRef
fun node(id: EntityId): NodeRecord?
fun port(id: EntityId): PortRecord?
fun edge(id: EntityId): EdgeRecord?
fun <T : Any> capability(id: EntityId, key: CapabilityKey<T>): T?
}
interface SnapshotLease : AutoCloseable {
val graph: Graph
override fun close()
}
interface GraphStore {
fun acquire(revisions: RevisionSet): SnapshotLease
fun validate(patch: GraphPatch): ValidationReport
fun commit(patch: GraphPatch): CommitResult
}
data class Contract<C : Any>(val ref: ContractRef)
data class Consumer<C : Any>(val id: EntityId, val contract: Contract<C>)
data class Provider<C : Any>(val id: EntityId, val contract: Contract<C>)
data class NodeRef<P>(val id: EntityId, val ports: P)
@DslMarker
annotation class GraphDsl
@GraphDsl
interface NodeBuilder {
val id: EntityId
fun <T : Any> capability(key: CapabilityKey<T>, value: T)
fun <C : Any> consumes(key: String, contract: Contract<C>): Consumer<C>
fun <C : Any> provides(key: String, contract: Contract<C>): Provider<C>
}
@GraphDsl
interface GraphBuilder {
fun <P> node(key: String, configure: NodeBuilder.() -> P): NodeRef<P>
fun <C : Any> connect(
key: String,
consumer: Consumer<C>,
provider: Provider<C>,
relation: SchemaRef,
): EntityId
fun build(): GraphDefinition
}
Maps, traversal and visitors
This is the minimal query algebra and discovery-visitor contract. Typed joins, predicates, weighted algorithms, structured DFS events, pagination and remote export sessions extend these contracts through versioned modules. They must preserve the coverage and budget laws described above.
sealed interface Selection {
data object All : Selection
data class Ids(val ids: List<EntityId>) : Selection
data class HasCapability(val schema: SchemaRef) : Selection
data class Union(val inputs: List<Selection>) : Selection
data class Intersection(val inputs: List<Selection>) : Selection
data class Difference(val left: Selection, val right: Selection) : Selection
}
data class ReadContext(
val workspace: String,
val environment: String,
val principalRef: String,
val tenantRef: String?,
val visibilityPolicy: Digest,
val snapshot: SnapshotRef,
)
data class MapDefinition(
val id: EntityId,
val version: Digest,
val selection: Selection,
val projectedCapabilities: List<SchemaRef>,
val derivations: List<ProgramRef>,
)
enum class BoundaryReason { Unloaded, Inaccessible, Unavailable, Unknown }
data class Frontier(val ref: EntityId?, val reason: BoundaryReason)
data class Coverage(
val completeWithinDeclaredScope: Boolean,
val frontier: List<Frontier>,
val staleEvidence: List<Digest>,
)
data class MapResult(
val definition: MapDefinition,
val context: ReadContext,
val graph: Graph,
val coverage: Coverage,
val lineage: List<Digest>,
)
interface MapEngine {
suspend fun evaluate(definition: MapDefinition, context: ReadContext): MapResult
}
enum class Direction { Outgoing, Incoming, Both }
enum class TraversalOrder { BreadthFirst, DepthFirst, Topological, StrongComponents }
data class TraversalBudget(val maxEntities: Int, val maxEdges: Int, val maxDepth: Int)
data class TraversalSpec(
val starts: List<EntityId>,
val relations: List<SchemaRef>,
val direction: Direction,
val order: TraversalOrder,
val budget: TraversalBudget,
)
interface Cancellation {
fun isRequested(): Boolean
}
enum class VisitAction { Continue, Prune, Stop }
data class Visit(val entity: EntityId, val viaEdge: EntityId?, val depth: Int)
data class VisitStep<A>(val accumulator: A, val action: VisitAction)
fun interface Visitor<A> {
fun visit(graph: Graph, at: Visit, accumulator: A): VisitStep<A>
}
enum class StopReason { Exhausted, VisitorStopped, BudgetExceeded, Cancelled, InvalidStrategy }
data class TraversalResult<A>(
val value: A,
val reason: StopReason,
val coverage: Coverage,
val visitedEntities: Int,
val examinedEdges: Int,
)
interface Traversal {
fun <A> run(
map: MapResult,
spec: TraversalSpec,
initial: A,
cancellation: Cancellation,
visitor: Visitor<A>,
): TraversalResult<A>
}
Services and async capabilities
The call facade illustrates unary invocation; interaction-shape validation rejects using it as an implicit stream or durable queue. Streaming adapters expose separate typed sessions with explicit demand, close and cancellation. Authority references are broker-validated references, never self-authorizing strings. Delivery profiles require provider conformance.
data class EffectRequirement(val operation: SchemaRef, val resourceSelector: BlobRef)
enum class Interaction { Unary, Stream, Publish, Subscribe, DurableJob }
data class Operation<C : Any, I : Any, O : Any>(
val id: String,
val contract: Contract<C>,
val input: SchemaRef,
val output: SchemaRef,
val errors: SchemaRef,
val interaction: Interaction,
val effects: List<EffectRequirement>,
)
data class InvocationContext(
val operationId: String,
val activation: ActivationRef,
val authorityRef: String,
val remainingBudgetMillis: Long,
val idempotencyKey: String?,
val causationRef: String?,
)
enum class EffectOutcome { NotStarted, Applied, PartiallyApplied, Unknown }
data class CallFailure(val code: String, val outcome: EffectOutcome, val evidence: Digest?)
sealed interface CallResult<out T> {
data class Success<T>(val value: T, val receipt: Digest) : CallResult<T>
data class Failure(val failure: CallFailure) : CallResult<Nothing>
}
interface BoundService<C : Any> {
suspend fun <I : Any, O : Any> call(
operation: Operation<C, I, O>,
input: I,
context: InvocationContext,
): CallResult<O>
}
interface RuntimeIsland {
val activation: ActivationRef
fun <C : Any> bind(consumer: Consumer<C>): BoundService<C>
}
enum class Durability { Volatile, PersistedBeforeAcceptance, TransactionalOutbox }
enum class Routing { FanOut, CompetingConsumers, KeyAffinity }
enum class Ordering { Unordered, PerKey, PerPartition }
enum class Overflow { Wait, Reject, DropOldest, DropNewest }
enum class AckPoint { Accepted, HandlerCompleted, TransactionCommitted }
data class DeliveryPolicy(
val durability: Durability,
val routing: Routing,
val ordering: Ordering,
val ackPoint: AckPoint,
val maxInFlight: Int,
val maxBufferedBytes: Long,
val overflow: Overflow,
val retryProfile: BlobRef,
val deduplicationProfile: BlobRef?,
val deadLetter: EntityId?,
)
data class ChannelDefinition(val entity: EntityId, val message: SchemaRef)
data class SubscriptionDefinition(
val entity: EntityId,
val channel: EntityId,
val handlerPort: EntityId,
val filter: ProgramRef?,
val delivery: DeliveryPolicy,
)
data class PublishReceipt(val messageId: String, val durability: Durability, val evidence: Digest)
interface Publisher<T : Any> {
suspend fun publish(message: T, context: InvocationContext): CallResult<PublishReceipt>
}
Portable program shape
This compact register/block representation illustrates the separation from graph storage. The profile defines register assignment/initialization, intrinsic semantics, typed failures, loop semantics, memory and yielding. The initial implementation must reject profiles or instructions it cannot validate. This specimen is not a finished VM specification or a proof of Turing completeness.
data class ProgramRef(val digest: Digest, val profile: SchemaRef)
data class Register(val index: Int, val schema: SchemaRef)
data class BlockId(val index: Int)
sealed interface Instruction {
data class Constant(val target: Register, val value: BlobRef) : Instruction
data class Compute(
val target: Register,
val intrinsic: SchemaRef,
val arguments: List<Register>,
) : Instruction
data class Invoke(
val target: Register,
val operation: SchemaRef,
val input: Register,
) : Instruction
}
sealed interface Terminator {
data class Branch(val condition: Register, val yes: BlockId, val no: BlockId) : Terminator
data class Jump(val target: BlockId) : Terminator
data class Return(val value: Register) : Terminator
}
data class ProgramBlock(val id: BlockId, val instructions: List<Instruction>, val end: Terminator)
data class ProgramDefinition(
val ref: ProgramRef,
val entry: BlockId,
val input: Register,
val result: SchemaRef,
val blocks: List<ProgramBlock>,
val imports: List<SchemaRef>,
val effects: List<EffectRequirement>,
val sourceMap: BlobRef,
)
data class ExecutionBudget(val fuel: Long, val memoryBytes: Long, val effectCalls: Int)
Patches and execution plans
A GraphPatch is limited to one owning partition. Cross-partition changes become a Plan containing locally atomic steps. expectedDigest = null means the entity must be absent. Explicit removal operations must account for dependent edges and facets. commit rechecks validation and concurrency; a prior accepted report is not a bypass token.
data class EntityPrecondition(val entity: EntityId, val expectedDigest: Digest?)
sealed interface PatchOp {
data class PutNode(val value: NodeRecord) : PatchOp
data class PutPort(val value: PortRecord) : PatchOp
data class PutEdge(val value: EdgeRecord) : PatchOp
data class PutCapability(val value: CapabilityValue) : PatchOp
data class RemoveCapability(val entity: EntityId, val schema: SchemaRef) : PatchOp
data class RemoveEntity(val entity: EntityId) : PatchOp
}
data class GraphPatch(
val id: String,
val base: Revision,
val preconditions: List<EntityPrecondition>,
val operations: List<PatchOp>,
val sourceAuthorityRef: String,
)
data class Finding(val rule: String, val subjects: List<EntityId>, val evidence: Digest?)
data class ValidationReport(val patchDigest: Digest, val accepted: Boolean, val findings: List<Finding>)
sealed interface CommitResult {
data class Committed(val revision: Revision, val receipt: Digest) : CommitResult
data class Rejected(val report: ValidationReport) : CommitResult
data class Conflict(val current: Revision) : CommitResult
}
data class CommandRequest(val operation: SchemaRef, val input: BlobRef, val context: ReadContext)
data class PlanRef(val digest: Digest)
data class Plan(
val ref: PlanRef,
val inputs: SnapshotRef,
val patches: List<GraphPatch>,
val commands: List<CommandRequest>,
val requiredEffects: List<EffectRequirement>,
val requiredEvidence: List<EntityId>,
val expiresAtEpochMillis: Long,
)
data class ExecutionReceipt(val plan: PlanRef, val outcome: EffectOutcome, val evidence: List<Digest>)
interface ChangeProtocol {
suspend fun prepare(patches: List<GraphPatch>, commands: List<CommandRequest>): Plan
suspend fun execute(plan: PlanRef, authorityRef: String): ExecutionReceipt
suspend fun reconcile(plan: PlanRef, authorityRef: String): ExecutionReceipt
}
Tests and assurance evidence
Definitions, executions and evidence have separate identities. The target profile names runtime/compiler/hardware and provider conditions. Existing Reaktor truth/provenance types should back the implementation; these fields describe the minimum evidence boundary, not a replacement truth taxonomy.
enum class TestKind { Unit, Contract, Property, Integration, Scenario, Performance, Memory, Model }
data class TestDefinition(
val entity: EntityId,
val kind: TestKind,
val subject: Selection,
val program: ProgramRef,
val fixture: BlobRef,
val requiredEffects: List<EffectRequirement>,
val acceptance: BlobRef,
)
enum class Assurance { Observed, Tested, BoundedChecked, ProvenUnderAssumptions }
data class EvidenceRecord(
val test: EntityId,
val testRevision: Digest,
val runId: String,
val inputs: SnapshotRef,
val artifacts: List<Digest>,
val targetProfile: BlobRef,
val seed: Long?,
val assumptions: BlobRef,
val assurance: Assurance,
val result: BlobRef,
)
interface GraphVerifier {
fun selectTests(patch: GraphPatch, graph: Graph): List<EntityId>
suspend fun verify(plan: PlanRef, authorityRef: String): List<EvidenceRecord>
}
14. Modification protocol for developers and agents
The graph should help an agent answer four questions before editing: what owns this behavior, what else depends on it, which changes are permitted here, and what evidence would establish the result? Expose those answers as typed queries and findings, with source/target links. Do not require an agent to reconstruct them from a screenshot or infer authority from chat text.
The shared protocol is:
| Step | Concrete artifact / invariant |
|---|---|
| Read | Authorized snapshot and source/observation context, with coverage and a revision vector. |
| Propose | Intent, typed graph patch and/or operational command; stable target IDs; declared expected outcome. |
| Normalize | Canonical ordered operations, explicit removals/rebindings, resolved schema and source ownership. No side effects. |
| Validate | Structural/type/capability invariants, base revision, policy/effects, target compatibility and source round-trip consistency. |
| Plan | Fingerprint of exact inputs, artifacts, commands, target instances, preconditions, policy, required tests, budgets and recovery steps. |
| Establish authority | Broker-issued scoped authority or policy-required approval bound to that plan and expiry. Sensitive reads are included. |
| Execute | Revalidate authority, expiry and preconditions at each effect boundary; publish local patches atomically; execute target-specific operations with idempotency keys. |
| Reconcile | Compare desired result with authoritative observed state; expose partial, failed and unknown outcomes. |
| Retain receipt | Exact plan, artifacts, affected revisions/epochs, results, evidence, omissions and any outstanding recovery. |
This is not a mandatory human click for every action. Policy can authorize low-impact work automatically. The essential requirement is explicit scope and a reproducible plan; neither a UI button nor an agent identity grants ambient production access.
Atomic patches and source ownership
Validate the complete candidate revision before publication. Required bindings, endpoint existence, containment, schemas and capability compatibility must hold at the new root. Readers see the old or new revision, never the first half of a bulk connection. A failed patch publishes nothing and emits a rejection finding rather than a misleading successful port event.
Source-derived definitions remain owned by source. A visual semantic edit produces a supported source change, re-extracts and compares the normalized result. Reject edits that cannot round-trip without losing comments, identity or unsupported constructs; offer a source edit with diagnostics. Graph-native documents can be directly authoritative within their declared scope. Provider-observed facts cannot be edited as if they were desired configuration.
Control-plane writes go through this protocol. Routine application effects, such as sending a message, use the already validated runtime plan and checked operation boundary; they do not need a new human change plan for every call. Those calls still retain operation identity, effect scope and outcome semantics. This separation keeps governance off unnecessary hot paths.
Distributed changes
A plan spanning two owners is a coordinated transition with explicit intermediate states. Use prepared artifacts, compatibility windows, fencing and ordered activation where supported. Otherwise use a saga with reconciliation and compensation. Do not expose a global commit() that implies atomic rollback of HTTP calls, databases and devices.
Revocation or policy changes after planning require execution-time reauthorization. A changed schema, instance epoch, source revision or migration fingerprint invalidates relevant preconditions. An inverse graph patch is a new validated change; it is not proof that an external effect can be undone.
Agent and MCP interface
Expose query, explain, resolveSource, compare, propose, validate, plan, execute, cancel, reconcile and readEvidence as typed operations over the same model. A tool response includes stable references, coverage, pagination and a bounded result. Tool availability is filtered by authority; the execution broker checks authority again. User-supplied source/doc/telemetry text remains data, not instructions to the agent or executor.
15. Tests as graph entities
Tests should be discoverable and composable in the same graph without running merely because the graph was opened. A test definition declares its subject map, fixtures, generator/seed, runner, effects, platform/provider profile and assertions or performance budget. A test run is an activation/execution with a distinct ID. Evidence is immutable and tied to the exact test, code, schema, graph, policy and environment revisions.
| Test family | First-class capability / result |
|---|---|
| Unit and contract | Pure logic assertions, port/schema compatibility, generated local/remote/FFI contract vectors. |
| Property and model-based | Graph/patch generators, reference-model equivalence, shrinking and a replayable counterexample. |
| Integration | Real provider fixture, declared credentials/effects, setup/teardown, result and cleanup receipt. |
| Application scenario | Route/role/flag/device starting context, actions, expected UI and downstream effects. |
| Performance and memory | Workload distribution, warm-up, sample policy, p50/p95/p99, allocations, peak/retained bytes and profiling artifacts. |
| Concurrency and failure | Interleavings, cancellation, retry, restart, disconnect, lease expiry and partition schedules. |
| Formal check | Model artifact, property, bounds/assumptions, solver/tool version and counterexample/proof reference. |
Affected-test selection walks declared dependency and effect relationships, including source imports, schema consumers and runtime adapters. Dynamic or unmodeled boundaries broaden the selection and lower confidence; they never justify skipping tests silently. A cached result is reusable only when the relevant input closure and acceptance profile match.
An agent can propose a patch and receive the smallest justified test plan plus the reason each test was selected. Failed evidence becomes a source-linked finding or a replayable scenario. A UI test cannot replace an authorization test, and a successful model check cannot replace provider qualification. Keep all these evidence classes visible.
The initial acceptance harness must include real BestBuds and GymBuddy source/build scenarios, plus synthetic scale/failure fixtures. Tests that merely serialize the new data classes do not establish the redesign's value.
16. Formal methods with useful, limited claims
Start with invariants that prevent actual failures in the current architecture. The formal-methods design gives the broader program; this proposal selects the first kernel obligations.
| Law | Executable check / verification approach |
|---|---|
| Every port has one existing owner; every edge has valid endpoints | Deterministic validation plus generated malformed graphs. |
| Endpoint roles, contracts and cardinality satisfy the edge relation | Type/schema checker, compatibility vectors, Alloy relation models. |
| Ownership is acyclic; explicit dependency cycles remain legal | Incremental ownership check cross-checked with a simple full traversal. |
| Rejected patches do not change the published revision or emit success effects | Reference-model property tests; model publication as a state transition. |
| Concurrent publication respects base revisions | Linearizability/interleaving tests and a small TLA+ state model. |
| A local handle cannot refer to a different entity after slot reuse | Generation checks, stale-handle tests and FFI lifetime tests. |
| A map cannot elevate visibility or invent missing coverage | Policy model tests, cross-principal cache tests and noninterference checks within a stated model. |
| Effect execution requires current authority for the target and operation | Broker contract tests, revocation/TOCTOU schedules and runtime monitors. |
| An activation's stale epoch cannot write after cutover | Fencing model plus crash/restart/partition integration tests. |
| Replay does not reissue a committed effect as a new effect | Durable-run state model, history conformance and duplicate-delivery fault tests. |
| Optimized storage/query results equal the simple model | Property-based differential tests after randomized patches and compaction. |
| Portable instructions obey their type/effect/resource profile | IR verifier, interpreter/native lowering conformance and adversarial artifact tests. |
For a single owner, let S be the current immutable definition and p a patch. The initial transition law is:
candidate = applyToPrivateCandidate(S, p)
eligible = p.base == revision(S)
AND sourceAuthorityAllows(p)
AND wellFormed(candidate)
AND preservesRequiredContracts(S, candidate)
if eligible AND compareAndPublish(revision(S), candidate):
published' = candidate
receipt' = committed(p.digest, revision(candidate))
else:
this transition publishes no graph change
receipt' = conflict-or-rejection(p.digest, reasons)
Other writers may publish concurrently; “no graph change” means this rejected transition made none, not that the whole world froze. External effects are absent from applyToPrivateCandidate. Runtime activation is a subsequent protocol. This is a specification sketch, not a model-checking result.
Use Alloy for bounded structural/relational exploration and relevant temporal models, TLA+ for publication/leases/retries/cutover, and SMT-backed checks for a restricted predicate language. A small proof-oriented kernel can later use Lean or another proof assistant where the maintenance cost is justified. Avoid coupling initial adoption to proving all application code. Alloy language specification, TLA+ overview.
Every assurance statement records the model, property, bounds, assumptions, tool/version, target and artifact digest. “No counterexample within these scopes” is distinct from a proof under assumptions. Liveness claims require fairness and failure assumptions. Native adapters, compiler lowering and external providers are part of the trusted boundary until checked; modeling them as perfect functions would erase the failures we need to study.
17. BestBuds worked example: send a message and diagnose failure
This is the target connected flow, grounded in existing chat actors, service operations, pubsub and notification code. The complete join, transactional guarantees and distributed debugger are not established as implemented by this document.
| Step | Graph representation | Developer/agent value |
|---|---|---|
| Open a chat from a normal route or notification | Screen/route capability with typed payload, entry-point relation and active flag/policy context | See exactly which route and role led to the screen. |
| User sends a message | Chat actor instance, consumed messaging operation and operation/run ID | Inspect actor state/mailbox and jump to the ordinary Kotlin method. |
| Client invokes messaging | Logical service contract bound to a concrete client/server transport and active deployment | Follow the exact request schema and endpoint across the boundary. |
| Server authorizes and moderates | Auth decision and moderation operations joined to policy revision, tenant/resource and trace | Explain denial or moderation failure without guessing from a red edge. |
| Store the message and schedule downstream work | Declared Postgres mutation and outbox transaction, if implemented for this operation | Inspect the actual schema/query/transaction evidence and pending event. |
| Deliver downstream events | Channel, subscriptions, adapter placement, attempts and deduplication scope | Identify lag, duplicate handling, dead letters and which consumer group owns progress. |
| Update connected clients / notifications | Socket or notification delivery operations, including Durable Object placement where used | Distinguish accepted notification from confirmed device delivery. |
| Render updated state | Client actor/state update, device activation and screen observation | Link the visible problem to the producing operation and target build. |
Suppose the operator sees “message pending” on iOS. The workbench should retain the selected client activation and message operation while moving through actor → service → auth → storage → delivery → device. It can explain one of several materially different outcomes: request not sent; authorization denied; server outcome unknown after timeout; message committed but outbox pending; event delivered twice but deduplicated; handler failed; device offline; client update received but view state stale. Each explanation needs evidence and an unresolved frontier where evidence stops.
The agent then proposes a specific change, such as a retry-policy correction or a missing consumer binding. The plan shows whether that is config, a graph patch, portable logic or a native release; the authority and schema requirements; affected clients/servers; contract/scenario tests; and recovery. Execution produces a retained receipt and observed reconciliation. This closes a developer workflow instead of adding another graph decoration.
Preserve the Kotlin DX
At the kernel-facing level, wiring can remain this small. The following function uses the proposed contract declarations and is included in the downloadable specimen. Domain helpers add actor/service capabilities and return named port bundles; product developers should not need to manually build schema records for each use.
fun <C : Any> messagingBindings(
graph: GraphBuilder,
messaging: Contract<C>,
bindingRelation: SchemaRef,
): GraphDefinition = with(graph) {
val chat = node("chat") { consumes("messaging", messaging) }
val endpoint = node("messaging") { provides("api", messaging) }
connect("chat.messaging", chat.ports, endpoint.ports, bindingRelation)
build()
}
These nodes are pure definitions. A separate runtime registry binds the service implementation and actor factory using their declared capability/contract IDs. Existing ChatActor.open, sendMessage, retry and reaction methods remain ordinary typed methods; the redesign does not require drawing every list transform or repository algorithm. State ownership, required ports, effects and source locations become inspectable contracts around that code.
Auth and database detail must remain useful
The auth map must link principals, organizations/tenants, tiered roles, memberships, grants, resources, sessions and token metadata. Access, refresh, service and PAT credentials differ in purpose, audience, scope, expiry, issuer, subject and revocation lifecycle. Show who issued/uses a credential and recorded enforcement decisions. Raw secrets are not canonical graph properties or ordinary telemetry; a narrowly authorized credential operation may issue or reveal a permitted value through a dedicated sensitive result path. Do not claim every access token can be enumerated if the identity provider does not maintain such a registry.
The data map must retain engine-specific capabilities: Postgres tables/indexes/plans, ClickHouse statistics and query behavior, Memgraph labels/relationships/Cypher, D1/SQLite schema and results, Durable Object instance/storage context, and device object-store schemas/files. A generic graph representation joins them to operations and owners; specialized query and editing interfaces retain the details developers need. Query permissions, schema modification and record mutation are separate effect contracts.
18. Workbench and design implications
The graph redesign supplies the semantics behind the Pencil design. It does not replace reaktor.pen, and this documentation change does not edit its authored boards or claim new runtime screens. Update the atlas/Pencil implementation handoff when an accepted kernel contract changes the user flow.
| Surface | Required behavior from this substrate |
|---|---|
| Graph canvas | Same selected entity and exact ports across map switches, semantic zoom, expansion and partial loading. Geometry never changes graph identity. |
| Adaptive expansion | Use measured canvas dimensions after docks/toolbars: expand right in landscape/square and below in portrait. Preserve anchors and camera intent; maintain stable layout where possible. |
| Collapsed groups | Show boundary portals and accurate edge bundles; selection can reveal the exact internal endpoint without inventing a connection. |
| Large graph | Indexed neighborhood queries, viewport culling, level of detail, bounded expansion, cancellable background layout and incremental scene publication. |
| Inspector | Typed node/port/edge/capability details, source authority, revision/activation, connected endpoints, map derivation and evidence. |
| Compute | Logical worker/server topology joined to observed routes, Kubernetes workloads, bindings, database connections, versions, health and deployment receipts. |
| Database | Real schema/result/statistics/plan adapters and reviewed data/schema operations, with a stable link to the owning service and environment. |
| Auth | Principal/session/credential metadata and policy decisions joined to actual operation boundaries; issuance/revocation are governed operations. |
| DevTools | Device/app/view identity joined to graph activation, route and source; adb/idb operations, deployment, file/data inspection and performance evidence use explicit targets. |
| IDE / MCP | Same query/selection/diagnostic/plan contracts with source navigation and bounded authoritative operations. |
The adaptive layout work already recorded in the UI/UX audit is an implementation input. This redesign adds requirements for identity, incremental invalidation and large-scale queries; it does not retroactively qualify million-node rendering or all physical devices.
19. Migration: preserve the graph, replace its load-bearing internals
Use one vertical slice and explicit compatibility adapters. Avoid a fleet-wide rewrite before the new kernel proves better behavior and acceptable performance.
| Phase | Concrete deliverable | Exit gate |
|---|---|---|
| G0 — laws and baselines | Stable schema/identity proposal, simple immutable reference model, canonical encoding vectors; current graph/DX/performance baselines | Reproduce current BestBuds and GymBuddy wiring/navigation semantics; record existing differences and scale costs. |
| G1 — pure definitions and atomic patches | Data records, snapshot store, contract registry, validation and all-or-nothing local publication | Randomized patch/reference equivalence; failed bulk wiring leaves no partial edges; concurrent readers observe stable snapshots. |
| G2 — adapters and typed DX | Existing node/port DSL adapter, source IDs, generated contract keys; GraphDocument semantic-reference adapter | Current apps and editor documents still load; identity survives rename/round trip; graph inspection no longer requires unrelated effects. |
| G3 — maps and traversal | Typed maps, coverage, bounded iterative traversal, pure visitors and incremental indexes | Auth/navigation/source maps agree on entity IDs; BFS/DFS semantics and cycle/budget tests pass; scale and memory budgets measured. |
| G4 — runtime capability separation | Installed behavior registry, activation-owned resources, compiled dispatch and route/actor integration | BestBuds chat and GymBuddy route instances retain behavior; cancellation/close/rebind tests pass; local call performance meets baseline. |
| G5 — one distributed BestBuds flow | Messaging service contract, auth enforcement, store effects, one channel/subscription adapter, runtime exports and trace joins | Diagnose and recover one real client-to-server-to-delivery failure with exact revisions, outcomes and coverage. |
| G6 — safe modification and tests | Shared planner/broker/receipts, affected-test selection, source edit round trip and provider-qualified operations | A developer and agent independently complete the same change → test → execute → reconcile workflow. |
| G7 — portable logic and formal expansion | Restricted typed interpreter, signed artifacts, budgets, target conformance; then compiler lowering and deeper models | One eligible config/logic update activates safely on supported targets; incompatible or unauthorized artifacts fail with useful diagnostics. |
G5 does not wait for every possible VM target or proof assistant. Real provider flows are required early enough to shape the abstractions. G7's restrictions can be introduced during G1–G4 for predicates/queries; general portable behavior follows a stable kernel and effect model.
Compatibility rules
- Preserve consumer/provider direction, route payload semantics and the existing graph-neutral module APIs.
- Keep a legacy object-graph projection while moving definitions and runtime state apart. Label legacy-only identity and coverage limits; do not hash unstable runtime UUIDs into fake durable source identity.
- Preserve the additive
GraphDocumentwire contract. Add semantic references and sidecar projection state through an explicit adapter/version path; do not rename existing fields or use scope paths as new kernel IDs. - Maintain old and new readers for a declared compatibility window, with export/import vectors and unknown-field retention tests.
- Migrate one ownership scope at a time. Never let both old and new runtimes own the same actor/mailbox/effect without an explicit bridge and fencing.
- Retire old paths only after product behavior, source round trips, runtime lifecycle and performance evidence pass. Keep the simple reference store for differential verification even after optimized storage ships.
20. Requirement-to-acceptance matrix
Each requested ecosystem concern has a home and an observable exit condition. These are design coverage entries, not a completion checklist marked done.
| Requirement | Core mechanism | Acceptance evidence |
|---|---|---|
| Heterogeneous graph and capability composition | Typed records, relation contracts, facet registry | New module composes without editing a central node-kind enum or adding runtime cost to bare nodes. |
| Navigation and fractal architecture | Route/state capabilities, ownership, boundary ports, typed roots | Nested routes, repeated instances, deep links and back navigation preserve state/identity across targets. |
| Workflows and flow selection | Program definitions, causal selections, runs/history | Branches, loops, fan-out, cancellation and replay remain inspectable with exact step identity. |
| Maps and overlay selection | Query/derivation algebra plus presentation profile | Auth + telemetry + source compose with stable selection, lineage and correct policy/time-scoped caches. |
| Auth and tiered RBAC | Requirements, operation effects, authority broker and decision facts | Connect, invoke, token expiry/revocation and cross-tenant denial tested at real execution boundaries. |
| Telemetry and analytics | Stable definition/activation/run links and external observations | Trace and aggregate joins identify source/revision; missing samples and cohort limits remain explicit. |
| Dead-screen finder | Conditional reachability plus observation map | Deep-link/notification/flag roots included; unreachable and unobserved produce distinct evidence. |
| Services and FFI invocation | Schema/operation registry, generated stubs, boundary profiles | Kotlin/C++/TS contract vectors, buffer lifetime/cancellation tests and remote unknown-outcome handling. |
| Pubsub, queues and actors | Channels, subscriptions, delivery profiles and activation ownership | Duplicate, retry, pressure, crash, dead-letter and ordering behavior matches the selected adapter. |
| Distributed system graph | Export contracts, ownership, revision vectors and federation coverage | Phone/Worker/server/device fragments stitch by contract identity without a central per-call dependency. |
| Versioning and code push | Canonical revisions, program artifacts, activation epochs and target eligibility | Compatible update can stage/activate/reconcile; incompatible state/import/platform changes fail before activation. |
| Tests and automation | Test definitions, effect-scoped runners, immutable run evidence | Agent-selected tests explain impact and return reproducible failures; performance/memory regressions block release. |
| Formal methods | Kernel laws, models, bounded checks, proof/evidence metadata | Counterexamples map to source/patch; claims accurately state scope, assumptions and trusted adapters. |
| IDEs and MCP | Shared queries, diagnostics, source maps and change protocol | Same entity/operation opens the correct source and retains authority/context across tools. |
| Compute and databases | Runtime placement and provider-specific schema/operation projections | Real worker/Kubernetes/storage queries and reviewed modifications retain target, result and reconciliation. |
| DevTools and adaptive UX | Device/activation/view links plus scalable map scene | Real adb/idb workflows and graph navigation work across qualified viewports without losing exact selection. |
| Performance and excellent DX | Compiled typed facade over compact indexed storage | Product code stays concise; measured latency/memory/frame budgets pass on declared workloads and targets. |
21. Decisions still requiring experiments
The semantic direction above is concrete enough to implement. These implementation choices remain open because evidence should decide them:
| Choice | Recommended first experiment | Decision criterion |
|---|---|---|
| Storage layout | Simple immutable reference store plus one columnar/chunked candidate | Same results under randomized patches; better measured scans/memory without unacceptable small-graph or edit cost. |
| Schema encoding | Reuse existing schema/codec work where conformance permits; define canonical hashing separately | Cross-language evolution and malformed-input vectors pass; no accidental dependence on runtime class names. |
| Source identity | Explicit persisted IDs plus generated symbol metadata and rename support | Stable identity through source moves, repeated instances and visual/source round trips. |
| Portable execution target | A small typed reference interpreter first; compare native lowering and Wasm for qualified profiles | Debuggability, budgets, conformance, size/startup and target distribution eligibility. |
| Federated cut semantics | Owner-consistent snapshots with explicit revision vector and partial coverage | Useful queries under disconnect/restart without pretending to supply unsupported global consistency. |
| Channel provider | One existing BestBuds pubsub/queue path and an in-memory test adapter | Measurable duplicate/failure/pressure behavior and a real developer debugging journey. |
| Formal tooling | Structural model plus publication/fencing transition model | Counterexamples reproduce in executable tests; models remain small enough to maintain. |
Do not postpone the kernel laws while debating tools. Conversely, do not lock in a storage engine or universal VM based on a diagram. The first deliverable after this proposal is G0/G1 plus a preserved BestBuds slice, not a new collection of empty modules.
22. Complete framework and desktop integration
The graph is the composition, inspection and modification substrate of the entire Reaktor ecosystem. Integration is not restricted to modules that happen to inherit Node today. Every framework module and desktop feature must declare its graph-facing contracts, relevant effects, evidence and ownership. Almost everything contributes a map, provides runtime behavior, emits observations, exposes operations or consumes those facilities. A subsystem can play several of these roles.
The semantic kernel stays small by moving vocabulary and handlers into module registrations. A camera frame, database row, compiler instruction, UI pixel or telemetry sample need not become an eagerly resident canonical node. Its stream/schema/resource/operation and relevant provenance must be addressable, with bounded detail maps when useful. This is how the design combines complete integration with data-oriented performance.
22.1 Expanded review scope and current seams
The follow-up audit enumerated 34 framework module/build directories and 658 non-test source files under their src trees: 31 included root Gradle modules, the included dependeasy build, the standalone reaktor-cli build and the paused reaktor-react module. It extracted declarations across those trees and inspected selected domain interfaces, adapters and implementation boundaries. Native wrappers, CMake/build entry points and generated bridges were inventoried separately by path/surface; vendored C++ and generated distribution bundles were not treated as hundreds of separate Reaktor integration modules. reaktor-tactile has no source in this census. A source file count is not a working-provider count.
Desktop coverage comes from WorkbenchModes.kt, WorkbenchPaneCatalog.kt, WorkbenchModePanes.kt, the common WorkbenchGraph/pane subgraphs, operational models/control plane, the architecture overlay, source/device/database adapters, StudioDesignCatalog.kt, and the desktop MCP entry point. The mode enum has 13 values; visibleReaktorModes() lists 12, with App/UI preview mounted separately in the native rail. The authored catalog has 9 families and 74 subpanes; additional graph, auth-directory, compute, database and device controls are covered below rather than discarded because they are outside that catalog.
The running native application was inspected through its accessibility surface at the verification snapshot. It showed the BestBuds graph, relation-layer filters, exact port inspectors, source/runtime/evidence context, all mode labels and the Runs/Logs/Traces/Network/Tests/Build/Diagnostics drawer. This establishes the current surface and context seams; it is not a fresh qualification of every button, provider or authored board. The UI/UX audit retains behavioral qualification and remaining gaps.
The machine-readable integration inventory records module source paths, declaration names, revisions, mode values and exact authored tab labels. It is a dated review artifact. New modules or surfaces must extend the matrix and conformance contract rather than being assumed covered by the word “everything.”
| Current seam found in code | Required redesign integration |
|---|---|
Feature / CreateSlot and platform Adapter registrations | Export owned provider identities, required contracts and availability through a host adapter. Preserve plain-library callers; progressively replace ambient cross-module calls with explicit runtime bindings. A legacy opaque call remains a declared coverage gap. |
Common WorkbenchShellGraph and pane graphs already contain actors, routes and interactors | Preserve them as real host-runtime composition. Connect their document, selection and operation references to the inspected graph through typed relations. The desktop is itself a Reaktor application. |
ToolingCatalog, CloudResource/CloudRun, OperationalSnapshot and editor GraphDocument have distinct models | Adapt them to shared entity/run references and typed contracts. Keep provider-specific detail and existing wire compatibility. Do not create another unconnected catalog with another set of IDs. |
OperationalArchitectureOverlay already projects providers, targets, resources, tasks and runs | Evolve this projection into a registered map with source-owned identities and typed relation endpoints. Preserve provenance while replacing open attribute bags in semantic hot paths. |
| Cloud inventory can recover a provider failure as an empty list | Carry a source availability/coverage record alongside results. A failed provider must not look like a successfully observed empty estate. |
OperationalControlPlane already fingerprints plans, tracks runs and delegates to tooling | Reuse and extend this seam for shared graph/command plans and receipts. Keep existing effect/sensitive-output protections during migration. |
| Desktop MCP installs the active graph and exposes graph, architecture and control-plane reads | Preserve active-session identity and the current consistency qualifier. Evolve through the same query/operation registry as the UI and CLI; do not bypass authority by exposing a raw graph mutator. |
Conductor owns protocols, agent sessions and a causal thread document | Project thread/protocol/run identities, context inputs and tool effects. Preserve the independent Conductor API and distinguish an agent's proposal from an executed system change. |
| The UI/AI modes have distinct state and do not all map into an operational domain today | Register their maps, actions, selection context and execution ownership explicitly. A pane label or capability declaration is insufficient integration evidence. |
22.2 Six ways a module connects to the substrate
| Contribution | What is registered | Ownership and execution rule |
|---|---|---|
| Definition vocabulary | Node/port/edge capabilities, contracts, schemas, relations, source extractors | Pure versioned data; source or graph-document owner controls changes. |
| Runtime behavior and hooks | Implementations, lifecycle/resource bindings, invocation guards/transforms and delivery handlers | Installed code owned by a runtime activation; contracts and effect checks apply at the boundary. |
| Observation source | Runtime state, provider inventory, measurements, traces, artifacts and cursor-based updates | Source owns truth and freshness; readers receive scoped coverage and lineage. |
| Map and analysis | Queries, joins, derived relations, traversals, visitors and invariants | Pure/bounded computation over declared inputs; derived facts retain input revision and witness references. |
| Operation | Typed reads, writes, build/test/device/cloud actions, cancellation and reconciliation | Shared planner/executor/authority path; provider-specific outcomes and limits remain explicit. |
| Presentation | Inspector sections, editors, graph styles, diagnostics, commands and source links | Reads the same maps and action descriptors; UI state does not silently mutate application behavior. |
An integration manifest describes these contributions. It contains data and implementation references, not serialized Kotlin closures. Runtime installation binds those references to trusted native handlers or supported portable programs. Plugins cannot register handlers for another owner's namespace or replace security-critical hooks merely because their manifest loads.
Default developer experience: install the module normally; a Reaktor host discovers its opt-in graph integration and installs it once for the relevant scope. Generated typed helpers hide registry boilerplate. The plain-library API continues to work without graph construction. Explicit registry/batch APIs remain available for unusual use cases and performance-sensitive code.
22.3 Every framework module and build
The following table names every module in the census. The “contribution” column is required target behavior, not a claim that the module already has that integration. Availability must be qualified per platform and adapter.
| Module / current source seam | Graph contribution and useful maps | Owned execution / integration acceptance |
|---|---|---|
reaktor-core — Feature, Adapter, Component, permissions, Fact | Module/provider identity, host/platform capabilities, component lifecycle, availability and provenance. | Platform lifecycle/permission adapters retain ownership; graph inspection does not allocate every feature. Plain use and graph use agree on availability. |
reaktor-graph-port — port graph, bindings, selectors | Canonical typed endpoint/relation facade, contract compatibility and efficient neighborhood access. | Atomic validated wiring, stable IDs and bounded traversal replace incidental object mutation. |
reaktor-graph — routes, containers, actors, ServiceNode | Application structure, route/payload contracts, actor state/mailbox definitions, service bindings and ownership maps. | Runtime capabilities own jobs/resources/state; typed route and actor APIs retain current DX. |
reaktor-flow — graph document/session, architecture overlays, layout | Graph/editor adapters, selected maps, scene detail, source links, exact ports and projection lineage. | Layout/camera/pins stay presentation state; edits to semantics produce source-aware patches. |
compose-flow — viewport, generic nodes/edges/handles | Generic rendering/hit-testing contract consumed through reaktor-flow. Performance evidence can reference the graph scene. | Remains graph-neutral and does not import Reaktor semantics; viewport work is bounded and culled. |
reaktor-ui — component specs, design tokens, Machine Signal, adaptive layouts | Component/design-system definitions, variants, renderer links, accessibility/preview/test maps and token provenance. | Tokens retain one owner. Composition/recomposition and geometry use UI runtime state; no canonical patch per pixel/frame. |
reaktor-react — paused module; JSI, Promise, FlowHandle, module invokers | Reserved integration boundary for JS/native module and operation contracts, renderer/host attachment and handle/stream ownership. | It is excluded from the root build; this proposal does not reactivate it. Any future revival must qualify cancellation, lifetime and error propagation with graph-neutral APIs. |
reaktor-web — platform WebView seams | WebView instance, document/origin, navigation and bridge contracts; browser/debug attachment maps where supported. | Host owns WebView/security/lifecycle. Do not advertise unsupported browser/network inspection based on a wrapper class. |
reaktor-io — files, share/compression, HTTP/WebSocket/PartySocket | File/resource schemas, network endpoints, connection/reconnect state, stream and transfer operations. | Files/sockets stay provider resources; byte streams use bounded buffers and explicit read/write authority. |
reaktor-media — camera/gallery, caches, media services/uploader, speech | Capture/pick/transform/upload pipeline, media artifact/codec/cache references, speech operation contracts and progress. | Camera/microphone sessions, frames and large blobs stay outside the resident graph. Permission, cancellation and supported-platform evidence are required. |
reaktor-location — location and map adapters | Location-source capability, coordinate system, accuracy/time metadata and geography overlay links. | Device owns permission and acquisition. Software topology layout is independent of physical geography; precise locations are scoped sensitive observations. |
reaktor-sensors — step counter, baseline/rebasing | Sensor/device/session capability, measurement schema, time/reset/baseline provenance and availability. | High-rate data is streamed/aggregated. Unsupported or denied readings never become zero-valued healthy measurements. |
reaktor-health — health availability, permissions, steps and sessions | Health-store/read/write contracts, consent scope, session/aggregate result maps and provenance. | HealthKit/Health Connect adapters retain platform constraints. Register graph-neutral APIs and explicitly scoped sensitive reads/writes. |
reaktor-notification — client, node, scheduler, events and dev harness | Categories/actions, permission, endpoint metadata, schedule/delivery/tap flow, route targets and test harness. | Join scheduled → accepted → received → response with evidence; device delivery and user action are distinct. Listener/scheduler cleanup belongs to the host. |
reaktor-auth — auth kernel, providers, graph ports and directories | Principal/tenant/role/grant/session/credential metadata, requirements, enforcement points and decision/simulation maps. | Invocation-time authority remains enforced when an auth overlay is hidden. Issuance/revocation and sensitive reads use governed operations. |
reaktor-security — device credentials, MLS conversations/envelopes, secret box | Crypto-device/group identity, membership, protocol/key epoch metadata, native implementation and security evidence. | Private keys, decrypted content and sealed state stay in authorized crypto/storage boundaries. MLS epoch is a separate typed domain from graph activation epoch. |
reaktor-secrets — secret refs/versions/store adapters | Secret reference/version metadata, consumers, rotation dependencies and access/audit operations. | Values travel only through scoped secret capabilities; no raw secrets in snapshots, maps, logs or general agent context. |
reaktor-db — SQL/object-store/cache/sync and Memgraph inspection | Engine/schema/table/collection/relationship catalogs, object ownership, query/result/plan, cache/sync and migration maps. | Data stays with stores; results are bounded maps. Read, mutation, schema migration, sync and retention have separate contracts. |
reaktor-service — typed handlers, chain/interceptors, endpoint transport | Service/operation schemas, routes, bindings, effects, guards and cross-language/source mappings. | Compile required interceptors into dispatch. Same contract can use qualified transports without erasing their failure/completion semantics. |
reaktor-google — PubSub topic/subscription/message/ack APIs | Topic/subscription/channel bindings, messages/delivery summaries, ack/retry/lag and credential-provider metadata. | Provider guarantee profiles qualify publish/pull/push/ack behavior; broker delivery and business completion are separate. |
reaktor-cloudflare — Worker/DO context, bindings, storage, AI | Worker/DO instance/namespace contracts, service routes, D1/R2/KV/Hyperdrive/vector/AI bindings and placement/effect maps. | Worker/DO runtime owns invocation and storage. Bindings describe deployment facts; observed versions and requests need independent evidence. |
reaktor-cloud — inventory/tool providers, Kubernetes, Wrangler, Dagger/Pulumi adapters | Provider/resource/operation/deployment topology, observed health/drift, logs and cost dimensions. | Use existing provider/planning interfaces; preserve failures and partial coverage. Mutations bind exact target, input, authority and receipt. |
reaktor-work — task manager and background workers | Schedule/task definitions, constraints, payload schemas, run/status, retry/reschedule and cancellation maps. | The platform scheduler owns actual background execution. OS-deferred work is distinct from a graph-runner failure or immediate execution promise. |
reaktor-telemetry — graph instrumentation, analytics sinks, crash adapters | Instrumentation schema, trace/event/metric/crash sources and definition/activation/run correlation. | Observers attach/detach incrementally. Payloads remain in telemetry stores; sampling, redaction, freshness and missing coverage are visible. |
reaktor-performance — collectors, harnesses, budgets, reports | Performance/memory/build-size budgets, benchmark workloads, profiles and regression evidence. | Measurements carry target/build/workload identity; instrumentation overhead is measured and bounded. |
reaktor-flexbuffer — codecs, views, pools, schema tooling, native bridge | Wire/schema/codec profile, artifact compatibility, ownership and codec performance/conformance evidence. | Compact storage may reuse the codec after validation; buffers are not entities per byte. Canonical hashing remains separately specified. |
reaktor-ffi — Switch, Invokable and native transports | Exported operation registry, ABI/contract profile, target/handle/lifetime and FFI invocation evidence. | Generated typed dispatch validates buffers, leases, errors and cancellation; opaque native operations are labeled as such. |
reaktor-compiler — processors and generators | Symbol/schema/source maps, portable-program lowering, generated artifact provenance and diagnostics. | Build-time transformations produce deterministic artifacts and reject unsupported semantics; they are not runtime node constructors. |
dependeasy — Gradle plugins, platform/native/bootstrap configuration | Module/dependency/target/toolchain graph, native inputs, build tasks and artifact lineage. | Gradle/CMake own builds; extracted definitions preserve source authority. Dependency changes drive impact/test/build selection. |
reaktor-tooling — discovery, catalog, planner, executor, devices/source index | Workspace/target/resource/task/run/artifact identities, source symbols, device operations and run ledger. | Reuse its planning/execution ports and process supervision; unify references with cloud/desktop/MCP rather than duplicate authority logic. |
reaktor-cli — command tree and discovered script families | Terminal projection of registered queries, task/operation descriptors, diagnostics and plans. | A command and its desktop/MCP equivalent resolve to the same operation and target; raw scripts remain explicit opaque actions until qualified. |
reaktor-mcp — read server/client and protocol descriptors | Tools/resources/session attachment, schemas, authority-filtered discovery and query provenance. | Current read surfaces remain qualified as reads; future execution delegates to the shared broker. Tool descriptions are not executable authority. |
reaktor-conductor — agents, protocols, context compiler and thread events | Agent/thread/protocol/task DAG, context lineage, model/session/budget, proposed patch and run/evaluation maps. | Agent harnesses execute within declared tool/effect budgets. Store conversation/artifacts appropriately and link them; private context does not become ambient graph visibility. |
reaktor-tactile — build/README placeholder, no source | Reserved future haptic/tactile capability vocabulary only when real APIs are designed. | Keep status unavailable; no claim of an installed handler, working haptic operation or completed graph integration. |
Non-Gradle surfaces are also part of the system: CMake/cinterop and native vendor dependencies contribute build/ABI/artifact facts through tooling; experiments contributes explicitly experimental evidence; framework docs/website and product ReaktorWeb contribute source/docs/knowledge-map artifacts. Standalone design-system files, generated TypeScript/native outputs and bootstrap tools link back to their owning module/build inputs. A directory or vendored library does not become a second authority for runtime semantics.
22.4 Every desktop mode and authored family
The kernel does not own a Pane enum. The workbench registers mode, editor, inspector and action contributions against the shared semantic/context contracts. Specialized tools retain their own UI; switching mode changes the projection and available operations while preserving the selected system identity.
| Desktop mode / surface | Complete authored family or additional controls | Graph integration requirement |
|---|---|---|
| Graph | Application explorer; relation layers; System/Container/Component/Code detail; exact ports; Inspect/Ports/Runtime/Source/Telemetry/A11y; source/diff/preview links | One map/selection model with coverage, source authority, runtime binding and evidence. Expansion/layout changes presentation; edits produce explicit semantic/source proposals. |
| App / UI preview | Separate preview mode and native rail entry; mobile/tablet/desktop targets, theme/network context and element inspection | Preview session and view-tree instance link to definition, activation, build, route and source. Simulated device/network state is labeled and cannot masquerade as observed hardware. |
| DevTools | Preview, Devices, Testing, Pipeline, Releases, Recorder, Traces, Logs, Source; additional Mobile/Workers/Servers/Workspace domain tabs | Device/app/process/view/recording/run/source references join to the application graph. adb/idb, install/delete, file/database inspection, breakpoints and replay are typed target-scoped operations. |
| UI | Canvas, Workbench, Design System, Flow, Responsive, A11y, Visual Tests, Source Diff | Design/component/token/variant identities connect to implementation, viewports, navigation and visual/accessibility evidence. References and authored examples remain distinct from active application instances. |
| Database | Query, Schema, Data, Relationships, Query Plan, History, Migrations; connection/catalog/statistics and engine-specific graph/object inspection | Query session, engine schema, parameters, result page, execution plan and migration plan retain environment, authority, source and affected-service links. Data grids remain specialized projections, not screenshots of the graph. |
| Auth | Providers, Roles & Permissions, Sessions, Audit, Security, Simulator; principals, memberships, refresh tokens, PATs, service accounts, grants, issuance and signing-key lifecycle | Join selected identity/resource to requirements and actual enforcement points. Simulated policy decisions and observed decisions are separate evidence. Session/token lifecycle operations share the broker. |
| Cloud | Resources, Operations, Deploy, Pipeline, Runs, Cost; Worker/server routes, Kubernetes objects, bindings, database connections and drift | Logical service → deployable artifact → placement → observed instance → operation/run. Provider/source coverage is retained across topology, tables, logs and cost views. |
| Deploy | Target/environment selection, build/package/release, promotions, distribution, rollout and recovery | Shared artifact/plan/approval/activation/receipt graph. Releasing mobile, desktop, web, Workers and servers uses qualified target adapters and explicit compatibility/cutover windows. |
| Testing | Unit/contract/property/integration/model/performance/memory plus Maestro, Playwright and desktop/device harnesses | Test definition → affected map → fixture/profile → run → results/artifacts/counterexample. A declared harness is distinct from an executed qualifying test. |
| Insights / Telemetry | Spans, Metrics, Logs, Profiles, eBPF, Crashes, Pipelines, Alerts, Sources | Source/collector configuration, signal schema, resource/activation/run context, sample windows and event lineage. eBPF and crash panes require actual qualified collectors; presence in the catalog is not evidence of attachment. |
| Analytics | Performance, Errors, Funnels, Cohorts, Retention, Experiments, Costs, Reports | Versioned event taxonomy, consent/cohort/time scope, experiment assignment and user journey join to routes/programs/releases. Business outcomes and runtime metrics retain their distinct units and evidence. |
| Agent | Chat, Kanban, Tasks DAG, Agents, Pipeline, MCP, Memory, Runbooks, Audit | Conductor thread/protocol/task/run/context lineage with typed findings/proposals/patches. Kanban status alone cannot establish that an operation ran; audit/receipt references do. |
| AI | Playground, Notebooks, Models, Chain Builder, Prompts, RAG, Tools, Evals, Guardrails, Routing & Cost, AI Traces, Releases | Model/provider/prompt/program/dataset/index/tool contracts; chain execution, retrieval lineage, eval evidence, routing/budget policy and artifact releases. Inputs/outputs may be sensitive; caches and datasets are separately owned. |
The exact 74 authored subpane labels are retained in the inventory. The table also covers top-level Graph, App, Testing and Deploy surfaces outside those nine families. Additional mounted controls must be registered rather than silently dropped to match an older design catalog.
Cross-cutting desktop facilities have the same requirement:
| Facility | Semantic hook and ownership |
|---|---|
| File/Edit/View/Navigate/Code/Graph/Run/Tools/Window/Help menus and command palette | Commands resolve through action descriptors with current target/context and availability reasons. Menus, shortcuts and agent tools invoke the same domain operation. |
| Explorer, search, bookmarks, favorites, history and source/definition navigation | Stable entity/symbol/document references plus user-owned workspace state; missing or renamed targets resolve through identity/alias rules. |
| Open documents, source diff, editor undo, graph documents and saved maps | Document owner and revision are explicit. Undoing a camera move is local presentation undo; undoing a committed semantic change is a new validated patch. |
| Runs, Logs, Traces, Network, Tests, Build and Diagnostics drawer | One run/artifact/evidence index joins to operations and selected entities. Counts state their scope and coverage; a network inventory count is not automatically a captured request count. |
| Status bar, environment/target selection, run/debug/stop and pending plans | Display the exact selected context and actual execution target. Changing a filter does not retarget a prepared operation; stale plan preconditions invalidate it. |
| Browser, terminals, JVM/native/device debugger and detached preview windows | Attachment capability with session/host identity, source map, authority, availability and disposal. An opaque external tool retains an explicit boundary and deep link. |
| Design studio, authored board chooser, Pencil references and component previews | Design/source reference map linked to target semantics and qualification evidence. The authored design remains a specification, never the runtime body of an operational pane. |
| Split panes, tabs, docks, cameras, selection and adaptive viewports | Local/persisted workspace state keyed by graph/map identity. Geometry and hover changes are not replicated as application definition revisions. |
| Workspace opening, discovery, indexing, caches and background refresh | Source/attachment tasks with progress, diagnostics, cancellation and coverage. A slow provider cannot indefinitely block unrelated local graph work. |
22.5 One graph also describes Reaktor itself
There are several namespaces/ownership scopes in one semantic model: framework definitions, product definitions, deployed/runtime instances, workspace/authoring artifacts, operations/evidence and external provider resources. These are not competing graph kernels. A Workbench actor can own a preview session that inspects a BestBuds activation, renders a selected map and invokes a tooling operation through typed boundary relations.
Keep the inspected application's authority and lifetime separate from the inspector's. Closing the preview releases its view/resource attachment; it does not delete the application definition or revoke a user's session. Installing an inspector cannot grant access to its target. The graph must also support a self-inspection boundary: operational telemetry from inspecting the graph does not recursively trigger infinite inspection events or unbounded graph growth.
The shared Workbench context includes workspace, revision/fact cut, environment, principal/tenant/visibility policy, selected map(s), exact entity/port, activation, selected causal flow, mission and run. A live-follow mode must explicitly move the pinned context to newer observations; a saved historical result remains historical. Agents and UI receive appropriately scoped projections of this same context.
22.6 Hooks are contracted boundaries, not arbitrary callbacks everywhere
A module registers a versioned hook boundary and declares transform, enforce or observe purpose, input/output schema, handler reference, effect requirements, dependencies/order, failure policy and resource budget. Runtime implementations are bound separately. The first implementation should support a small set of useful boundaries and extend them through schema-qualified modules.
| Boundary family | Examples and required semantics |
|---|---|
| Author/extract/validate/compile | Source extraction, schema registration, invariant checking, route/dispatch compilation and source maps. Pure passes return outputs/findings; they do not perform runtime effects. |
| Activate/deactivate/dispose | Resolve providers, allocate actor/camera/socket resources, restore supported state, attach observers, drain and close. Every registration has an owner and removal path. |
| Bind/invoke/return/fail/cancel | Contract negotiation, auth/tenant checks, input transformation, telemetry, retry eligibility and cancellation propagation. Auth cannot be disabled by hiding a map or bypassing an inspector. |
| Enqueue/deliver/ack/checkpoint | Admission/backpressure, subscription filtering, message identity, effect deduplication, retry/dead-letter and durable history. Completion and replay rules stay provider-qualified. |
| Commit/change/reconcile | Validate an immutable candidate, publish, invalidate queries, compile/activate and record receipts. Observers see committed changes; they cannot mutate the collection currently being traversed. |
| Observe/project/render | Source cursors, stale/partial availability, map invalidation, bounded aggregation, source-to-view correlation and scene update. Presentation does not become an effectful policy hook. |
Order is a validated dependency DAG with deterministic tie-breaking. Cyclic or ambiguous security-sensitive ordering fails registration. Enforcement failures/timeouts fail the protected operation closed. Optional telemetry failure normally reports lost observation without changing business outcome, subject to the declared policy. A transformation cannot remove required authorization or enlarge authority. Hook reentrancy, cancellation, asynchronous completion and which thread/runtime owns the callback must be defined by its boundary contract.
Compile hook chains at activation/revision change and cache checked dispatch plans. Avoid reflective registry scans, string-map lookups, arbitrary async suspension or graph traversal on every frame, sensor sample or local call. Batch high-rate observations and retain loss/drop counts. A hook descriptor is not permission to put a global event bus into the pure kernel.
22.7 Observation and projection protocol
Every source—device inventory, Kubernetes, database schema, auth directory, trace collector, source index, model provider or test runner—needs the same outer protocol while keeping its own typed payload and guarantees:
- Identify source/owner, schema, target, authority, source revision or activation generation, and collection scope.
- Read an initial bounded snapshot/page with coverage, capture/freshness metadata and a resumable cursor where supported.
- Apply ordered deltas only within that source/generation. Duplicate pages are idempotent; gaps or generation changes request resynchronization. There is no assumed global total order.
- Distinguish entity deletion/tombstone from temporary absence, permission loss, stale cache, unsupported capability and provider failure.
- Track dependency invalidation and observation cut separately from definition revisions. Maps carry lineage and explicit partial results while updates are pending.
- Enforce byte/entity/time quotas, cancellation, retention/redaction and attachment cleanup. Large rows/blobs/events stay behind bounded result handles or external references.
Use the existing Fact/truth/provenance semantics for observation envelopes. Do not collapse assurance, source, freshness and availability into one Live boolean. Sensitive data may be visible only through a purpose-specific session/result capability; graph visibility does not imply permission to export it to a model, file or remote peer.
22.8 Kotlin integration contracts
The following declarations extend the same compiled proposal specimen. They specify data boundaries; the registry, source adapters and handler implementations are still proposed. A BlobRef below names a schema-validated batch of definition candidates or provenance-bearing observation records, including tombstones where appropriate. It is not an untyped permission to overwrite arbitrary graph state. The host validates schema, namespace, source authority and cursor generation before materialization.
data class CapabilityDescriptor(
val schema: SchemaRef,
val validOn: Set<EntityKind>,
val requires: List<SchemaRef>,
val excludes: List<SchemaRef>,
val requiredBehavior: SchemaRef?,
)
enum class HookPurpose { Transform, Enforce, Observe }
data class HookDescriptor(
val id: SchemaRef,
val boundary: SchemaRef,
val input: SchemaRef,
val output: SchemaRef,
val purpose: HookPurpose,
val handler: SchemaRef,
val before: List<SchemaRef>,
val after: List<SchemaRef>,
val effects: List<EffectRequirement>,
val budget: ExecutionBudget,
val failurePolicy: SchemaRef,
)
data class QueryDependency(
val entities: Selection,
val readsSchemas: List<SchemaRef>,
)
data class ProjectionDescriptor(
val id: EntityId,
val sourceContract: SchemaRef,
val outputSchemas: List<SchemaRef>,
val dependencies: List<QueryDependency>,
val effects: List<EffectRequirement>,
val retentionProfile: SchemaRef,
)
data class InspectorDescriptor(
val id: SchemaRef,
val subjects: Selection,
val maps: List<EntityId>,
val actions: List<SchemaRef>,
val rendererContract: SchemaRef,
)
data class GraphIntegrationManifest(
val module: SchemaRef,
val requiresModules: List<SchemaRef>,
val capabilities: List<CapabilityDescriptor>,
val contracts: List<ContractRef>,
val projections: List<ProjectionDescriptor>,
val maps: List<MapDefinition>,
val operations: List<SchemaRef>,
val hooks: List<HookDescriptor>,
val inspectors: List<InspectorDescriptor>,
val conformanceTests: List<EntityId>,
)
data class ProjectionCursor(val source: EntityId, val generation: String, val position: String)
data class ProjectionBudget(val maxEntities: Int, val maxBytes: Long, val remainingMillis: Long)
data class ProjectionRequest(
val projection: EntityId,
val context: ReadContext,
val authorityRef: String,
val after: ProjectionCursor?,
val budget: ProjectionBudget,
)
enum class SourceAvailability { Available, Unavailable, Unsupported, Unknown }
data class ProjectionPage(
val source: EntityId,
val sourceRevision: Digest?,
val records: BlobRef,
val next: ProjectionCursor?,
val resetRequired: Boolean,
val availability: SourceAvailability,
val coverage: Coverage,
)
interface GraphProjectionSource {
suspend fun read(request: ProjectionRequest): ProjectionPage
}
interface InstalledGraphIntegration : AutoCloseable {
val manifest: GraphIntegrationManifest
fun source(id: EntityId): GraphProjectionSource?
override fun close()
}
data class SemanticFocus(
val entity: EntityId,
val map: EntityId?,
val activation: ActivationRef?,
val evidence: Digest?,
)
data class FlowStep(
val id: String,
val focus: SemanticFocus,
val viaEdge: EntityId?,
val causedBy: List<String>,
)
data class FlowSelection(val id: String, val steps: List<FlowStep>, val lineage: List<Digest>)
data class WorkbenchContext(
val read: ReadContext,
val maps: List<EntityId>,
val focus: SemanticFocus?,
val flow: FlowSelection?,
val missionId: String?,
val runId: String?,
)
Installed integrations resolve native/portable implementation references through the host's trusted registry. Discovery of a manifest does not load untrusted code automatically. The binding/authority contract applies equally to built-in modules and third-party plugins. Manifest uninstall/upgrade drains owned work, releases attachments and invalidates contributions without deleting another source's entities.
22.9 Integration release gates
“Hooks into the graph” is accepted only when the following are demonstrated for the exact module/provider/target:
- Coverage: every module, pane, operation and source appears in the integration catalog with an owner, status and implementation/evidence reference. Unsupported and opaque boundaries are explicit.
- Identity: source → definition → activation → operation → observation/test/artifact joins work across UI, CLI and MCP. Rename, reconnect, restart and repeated instances do not silently change identity.
- Dual surface: equivalent plain-library and graph-bound calls produce equivalent domain behavior; graph-disabled use does not initialize the whole Workbench or require a graph store.
- Authority: hidden overlays, cached sessions, agent tools and local fast paths cannot bypass enforcement. OS permissions, tenant authority and secret/crypto ownership retain their distinct checks.
- Lifecycle: install/refresh/reconnect/upgrade/uninstall cycles do not leak jobs, listeners, buffers, handles or stale cache entries. Pending cancellation and unknown outcomes remain inspectable.
- Projection: cursor gaps, duplicate updates, stale/missing sources and revoked visibility produce truthful coverage and invalidate affected maps without recreating the entire graph.
- Performance: the same workload passes with observers disabled and enabled under an explicit overhead budget; high-rate producers do not generate unbounded graph mutations or layout work.
- Developer workflow: a real task starts from any relevant pane, reaches source and runtime/data evidence, makes a supported change, tests it, executes/reconciles it and returns a retained result with the original context intact.
Add these gates to G0–G6 incrementally, beginning with source/tooling/workspace integration, then the existing BestBuds chat/auth/data/compute/device slice. Also qualify one peripheral path early—such as permission → camera/media upload → background task → notification → route—to ensure the core was not accidentally designed only for server requests and navigation. Health/sensors/location and secure-device/secret lifecycles need their own target-specific evidence before being called fully integrated.
Validation of this document
This change supplies the architecture proposal, two HLD/topology diagrams, the Kotlin contract specimen, the complete framework/desktop integration matrix and links from the living implementation/design documents. The complete specimen, including the wiring example and integration contracts, compiled successfully with Kotlin 2.3.0; all eight Kotlin blocks in this document match that specimen. That checks declaration/type consistency, not a runtime implementation. The module and authored-subpane coverage was checked against the inventory. The diagrams were rendered for visual inspection. Documentation navigation, site build and published-route checks are recorded with the delivery of this revision. No performance measurements, provider qualification, formal proofs or new runtime feature completion are claimed by publishing it.
23. Independent review (Claude)
Independent review · Claude (Opus 5) · 9 September 2026 · advisory; not an accepted change to the proposal above. This section reviews §1–§22 against the source they cite. It was written after reading the full proposal, the complete Kotlin specimen, and targeted reads of the implementations named in §2. It decides nothing and supersedes nothing. It records defects, internal contradictions and one scope risk that should be resolved before G1 opens. Findings are ordered by the cost of leaving them unfixed.
23.1 Summary judgment
The diagnosis is accurate. Every claim in §2 that could be checked against source was checked and holds (§23.6). The direction — pure definition data, typed capability facets, runtime resources owned by activations, maps over one skeleton, coverage as a first-class result rather than an afterthought — is right and should proceed.
Two things are not yet true of the artifact as delivered.
The specimen delivers neither half of its title. It is not data-oriented: there is no cursor, batch or column API anywhere in its 483 lines, and the only read path allocates per entity. It is not typed where typing carries weight: capability and contract type parameters are phantoms, cross-cutting identity is String, and the payload of nearly every record is a BlobRef that nothing in the file can resolve.
§19 and §22 pull in opposite directions. §19 correctly prescribes one vertical slice with adapters. §22 declares a 34-module, 74-subpane adoption contract with eight per-module release gates, in the same normative voice. Against the project's actual capacity the second will either be ignored or stall the first.
Neither is fatal. The first is a specimen revision measured in a few hundred lines. The second is an editorial decision about what §22 is.
23.2 Defects in the contract specimen
| # | Defect | Class | Blocks |
|---|---|---|---|
| C1 | No blob resolution path; BlobRef carries the payload of most records and nothing can open it | Incomplete contract | G1 |
| C2 | CapabilityKey and Contract type parameters are phantoms; equal keys, different static types | Unsound typing | G1 |
| C3 | Interaction names Stream/Subscribe/DurableJob with no interface — the defect §2 charges to ServiceTransport | Contradiction | G4 |
| C4 | Coverage.completeWithinDeclaredScope: Boolean collapses what §22.7 forbids collapsing | Contradiction | G3 |
| C5 | Coverage.frontier enumerates inaccessible boundaries, leaking counts §11 forbids leaking | Correctness / policy | G3 |
| C6 | Authority, principal, tenant, run and cursor identity are bare String, against decision #2 and §13's own prose | Unsound typing | G1 |
| C7 | EntityId carries no kind, so §16's first two laws cannot be expressed in types | Weak typing | G1 |
| C8 | GraphPatch.base is one Revision while reads are a RevisionSet; cross-partition read-set is unfenced | Correctness | G1 |
| C9 | No cursor, batch or column read API; the data-oriented half has no contract | Missing contract | G1 |
| C10 | Traversal.run consumes a MapResult whose coverage must therefore precede discovery | Design inversion | G3 |
| C11 | The structured DFS enter/leave stream is promised in §8 and absent from the specimen, while G3 gates on it | Missing contract | G3 |
| C12 | Redaction boundary between principal-scoped MapResult and unscoped Graph is unspecified | Correctness / policy | G3 |
C1 — the specimen has no data plane. BlobRef is (schema, digest, byteLength): a reference, not bytes. It then carries nearly all real payload — CapabilityValue.value, ProjectionPage.records, EffectRequirement.resourceSelector, CommandRequest.input, TestDefinition.fixture and acceptance, EvidenceRecord.assumptions, result and targetProfile. There is no blob store, no resolve, and no codec interface in the file; CapabilityDescriptor does not carry one either. Consequently Graph.capability(id, key): T? cannot be implemented from the declarations given — nothing maps a SchemaRef to a decoder. A second consequence lands on the hot path: because EffectRequirement.resourceSelector is a blob, no authority check can name its target resource without decoding, yet §6 requires that check to sit in generated dispatch. Fix: add the schema/codec registry and a blob-resolution capability to the specimen, and make EffectRequirement name its resource in typed fields.
C2 — phantom type parameters. data class CapabilityKey<T : Any>(val schema: SchemaRef) binds T to no constructor parameter and carries no witness, so capability() can only cast. Because the key is a data class over schema alone, CapabilityKey instances for two different T with the same schema compare equal; a registry keyed on them resolves the wrong type silently. Contract<C> has the identical shape, which makes RuntimeIsland.bind(consumer: Consumer<C>): BoundService<C> an unchecked cast as well. Fix: give the key a decoder (CapabilityKey<T>(schema, Codec<T>)), or drop the parameter and return the encoded value honestly.
C3 — the interaction enum repeats the diagnosed defect. §2 charges ServiceTransport with naming PUBSUB, QUEUE and WORKFLOW without implementing their semantics; the charge is correct. The specimen then ships Interaction { Unary, Stream, Publish, Subscribe, DurableJob } while defining only BoundService.call and Publisher.publish. Stream, Subscribe and DurableJob have no session type, no demand signal, no close and no cancellation. §13's prose acknowledges this and defers the sessions, which is the right call — but then the enum should not name them yet. An enum value is a promise the type system will be read as having kept. Fix: reduce Interaction to the shapes that have interfaces, and reintroduce values alongside their sessions.
C4 — coverage collapses availability. §22.7 says, correctly, not to collapse assurance, source, freshness and availability into one Live boolean. ProjectionPage honours this with SourceAvailability. Coverage — the kernel's own type, and the one every map and traversal returns — reduces the same question to completeWithinDeclaredScope: Boolean. The rule should apply first to the kernel that states it. Fix: give Coverage per-frontier availability and freshness, and drop the boolean or derive it.
C5 — the frontier leaks counts. §11 requires partial, stale, unavailable and inaccessible boundaries to remain visible "without leaking unauthorized details or counts", and §16 carries the law that a map cannot elevate visibility. Coverage.frontier: List<Frontier> is a count, and Frontier.ref: EntityId? may name the entities. Unloaded and Unavailable are safe to enumerate; Inaccessible is not, and the type does not distinguish them. Fix: aggregate the inaccessible case into a single redacted marker, and keep enumeration for the other reasons.
C6 — identity is stringly typed. InvocationContext.authorityRef, ReadContext.principalRef and tenantRef, WorkbenchContext.missionId and runId, InvocationContext.causationRef and idempotencyKey, ActivationRef.instance, ProjectionCursor.generation and position are all String, as are the authorityRef parameters of ChangeProtocol.execute, GraphVerifier.verify and ProjectionRequest. §13's own preamble says authority references are "broker-validated references, never self-authorizing strings", and decision #2 rules that labels and class names are never durable identity. §2 then charges the current Port.Type with exactly this. The charge is if anything understated — Port.kt falls back to anonymous_${counter} for anonymous classes, so present identity is not even stable within a run. Value classes cost nothing at runtime and prevent the whole class of mix-ups. Fix: one value class per identity kind in the kernel, before any of them reaches a wire format.
C7 — EntityId carries no kind. EdgeRecord.from and to are EntityId, though §5 requires edges to name exact ports; nothing prevents a node id. PortRecord.owner could name an edge. §16's first law — every port has one existing owner, every edge has valid endpoints — is therefore a runtime check in a design whose stated pitch is typed records. NodeId, PortId and EdgeId make both violations unrepresentable and cost one line each. This pairs naturally with C6.
C8 — the patch fences only what it writes. Reads return SnapshotRef(definitions: RevisionSet, …); GraphPatch.base is a single Revision. A patch on partition B that was decided by reading partition A cannot express that read, so a concurrent publication to A permits a stale-derived patch to commit to B. This is write-skew, and §16's law "concurrent publication respects base revisions" is stated over the write set only, so the law as written does not catch it. Fix: carry the read-set (RevisionSet plus cross-partition entity preconditions) in the patch, and restate the law over the read-set.
C9 — nothing in the specimen is data-oriented. §6 mandates dense primitive columns, interned tables, primitive cursors and batches "to avoid per-element wrappers and boxing", and makes allocation count a release gate. The specimen's only read API is Graph.node(id): NodeRecord?, which allocates a record per lookup and hashes an EntityId holding a GraphId holding a String. There is no cursor, no batch, no column view, and LocalHandle(slot, generation) is declared and then referenced by no interface in the file. So the storage half of the title has no contract, and G1's exit gate exercises only the reference model. Experience says the pleasant API ships and the compact one does not, unless both are specified together. Fix: put the cursor/batch surface in the specimen before G1, and make G1's differential test run over both.
C10 — traversal inverts the large-graph case. Traversal.run(map: MapResult, …) consumes an evaluated map, and coverage is a field of MapResult, so the frontier must be known before traversal starts. In the 1m-node paged-inspection workload of §6 the frontier is discovered by the traversal. The two requirements cannot both hold as typed. Fix: make coverage a traversal output as well as a map field, or give bounded inspection its own entry point that does not require a materialised map.
C11 — the enter/leave contract is diagnosed but never written. §2's claim is exactly right and was verified: DepthFirstTraverser invokes the returned ExitScope, BreadthFirstTraverser discards it, and HierarchyVisitor's mapStack push/pop is therefore unsound under BFS today. §8 promises "a separate structured DFS event stream" with enter/leave guarantees. It is not in the specimen, while G3's exit gate is "BFS/DFS semantics and cycle/budget tests pass". A contract that is not written cannot be tested. This is roughly twenty lines and it is the one place the redesign fixes a bug that exists now.
C12 — the redaction boundary is unstated. MapResult is principal-scoped because it embeds ReadContext, but Traversal.run operates on map.graph: Graph, and Graph has no principal. If that is the raw snapshot view, a traversal reads unfiltered data and §16's noninterference law fails at the type level rather than at runtime. Fix: state whether filtering is materialised at map evaluation or applied at Graph access, and make the type say which.
23.3 Programme risk: §19 against §22
§19 is the right plan. One vertical slice, explicit compatibility adapters, retire nothing until evidence passes.
§22 then declares itself "the required adoption contract for the complete framework and desktop", and §22.9 requires, per module and provider and target, evidence across coverage, identity, dual surface, authority, lifecycle, projection, performance and developer workflow. Multiplied across 34 module/build directories and 74 subpanes, that is not an adoption contract; it is a second programme an order of magnitude larger than G0–G7, written in the same imperative voice and with no owner, sequence or budget attached.
Set against what exists — no continuous integration, a large majority of modules without a test harness, roughly 30 of 74 panes actually wired, and BestBuds as the only real consumer — the predictable outcome is that §22 is read as aspirational and then ignored, which costs the document its credibility, or read as binding and then blocks G1.
The content of §22 is worth keeping; it is the most complete map of the system anyone has written. The framing is the problem. Recommendation: demote §22 from contract to a target-state register — a per-module row with owner, status and evidence link, explicitly not a gate. Keep exactly one integration gate, G5's BestBuds slice. Let a module earn its row by adopting, rather than being pre-assigned a debt it has no plan to pay.
23.4 The missing artifact: a kernel v0
The document runs to roughly 1,300 lines and states on the order of 150 normative requirements. It does not contain a section that says: these are the types, laws and tests G1 ships, and this is what G1 explicitly does not do. §19's G1 row is one sentence, and §21 correctly refuses to pre-decide storage — but between them there is no buildable unit.
For a proposal intended to be implemented by agents as well as people, that is the highest-leverage omission. Forty lines would close it: the G1 type list, the four invariants it enforces, the differential test against the reference store, the acceptance numbers already given in §6, and the non-goals. Everything needed is present in the document; it has not been gathered.
23.5 What should survive unchanged
The honesty calibration is better than most production architecture writing and is the document's most transferable property. Specifically: the Apple 2.5.2 constraint on code push, the Cloudflare at-least-once note and the refusal to launder it into exactly-once, "hash the JSON is not a protocol specification", "a suspend function alone does not supply durability", the §6 performance table labelled as budgets to validate rather than results, the treatment of a timeout as an unknown outcome rather than a failure, and the "Validation of this document" paragraph that states precisely what was and was not checked. Also worth preserving: the consumer→provider preservation rule, the map/flow-selection distinction, and the four-way separation of data capability, runtime implementation, authority and effect.
Whatever survives redrafting, these should survive verbatim.
23.6 Verification log
Claims in §2, §21 and §22.1 that could be checked against source on 9 September 2026, at the working-tree state of the sibling workspace:
| Claim | Result |
|---|---|
| DFS is recursive; BFS ignores the exit closure DFS invokes | Confirmed. DepthFirstTraverser calls onExit(); BreadthFirstTraverser discards the returned ExitScope. HierarchyVisitor is unsound under BFS as described. |
Type identity involves strings/KClass | Confirmed, and stronger than stated: KClass.name() falls back to anonymous_${sequence}, so identity is unstable within a single run. |
ServiceTransport names PUBSUB/QUEUE/WORKFLOW without their semantics | Confirmed; ServiceEndpoint.portType also formats transport identity as a string. |
ReaktorProcessor.process() returns immediately | Confirmed; the body is guarded by an unconditional early return. |
13 mode values; visibleReaktorModes() lists 12; App mounted separately | Confirmed exactly. |
reaktor-tactile has no source in this census | Confirmed; the src tree exists and is empty. |
34 framework module/build directories = 31 included root modules + dependeasy + standalone reaktor-cli + paused reaktor-react | Confirmed. settings.gradle.kts has 31 include( lines, includeBuild("dependeasy"), and //include(":reaktor-react") // will fix later. reaktor-cli carries its own settings file. This breakdown is precise; an earlier reviewer count of 33 was wrong. |
| All eight Kotlin blocks in this document match the specimen | Confirmed by extraction and comparison: 8 fenced blocks, 433 non-blank lines, zero divergence in either direction. |
| Diagrams, inventory JSON and specimen exist and are reachable; document is registered in the nav manifest | Confirmed. |
| Specimen compiles under Kotlin 2.3.0 | Not re-verified in this review. No finding above depends on it; unused type parameters (C2) compile without error. |
Not checked: performance claims of any kind, provider behaviour, the accessibility-surface inspection reported in §22.1, and the 101-document/3,455-file corpus counts in §2.