Build, compilation and resource budgets
Technical preprint, 16 September 2026 — web reading edition. This preserves the supplied paper’s content and its historical evidence boundary. Proposed interfaces, conditional propositions and constructed studies are not released APIs or deployment proof. Aligned equations, tables and listings retain their source layout. Source figure pages retain the original vector artwork. The accompanying finite model and coverage-map source package were not supplied; their reported results have not been independently reproduced here.
Current guides: reaktor-build-tools · reaktor-cloud-pane · performance-observability.
The engine and feature composition · Graph model, protocols and computation · Platforms, identity and polyglot execution · Data authority, contracts and federation · Build, compilation and resource budgets · LiveUpdate, coordinator and human-agent authoring · Assurance and adoption studies · Precedents, evaluation and implementation sequence · References, notation, exercises and source lineage
23. Build, cloud, observation, and reproducible development
23.1 Dependeasy publishes build facts; tools execute them
Dependeasy’s existing role includes KMP conventions, Android/iOS native integration, dependency and toolchain policy, cinterop generation, and JavaScript package outputs. The build-tools design extends it into a producer of versioned target, source-set, artifact, test, and tool requirements for the CLI, desktop, agents, and CI [5, 19]. A provider should consume authoritative build-model facts rather than repeatedly guessing them from filenames when those facts are available. A proposed build-target descriptor identifies source inputs, dependencies, toolchain, outputs, host requirements, tests, budgets, and supported operations. Gradle remains the Kotlin build system; CMake and platform toolchains remain native executors. Vite/Metro/Wrangler, Xcode/Fastlane, and test tools retain their own appropriate responsibilities. The engine supplies a coherent discovery and operation model, not a replacement compiler for every target. The Reaktor CLI is the terminal projection of that catalog. Its source-reported implementation discovers and runs tasks from existing project files; the complete manifest-backed convergence and authorization pipeline remain proposed [20]. The same task identity should eventually resolve from a terminal command, desktop button, or agent invocation. A successful process exit, produced artifact, and deployed healthy instance remain distinct outcomes.
23.2 A release is a dependency-aware operation plan
Dagger provides programmable container-based pipeline execution, and Pulumi’s Automation API provides programmatic control of infrastructure plans and updates [94, 95]. Reaktor’s reference design composes such tools with Worker and mobile release executors [6]. A pipeline that calls a host-only signing tool still needs an appropriate host runner; reproducibility does not erase platform requirements. A release selects compatible code, schemas, policies, resource configuration, and dynamic-update artifacts. Its plan orders operations and records approval, expected base revisions, and recovery conditions. Expand–migrate–contract changes preserve mixed-version compatibility where required. The plan reports partial completion rather than pretending a fleet rollout was one atomic graph mutation.
23.3 GCP cells and attached customer environments
The reference cloud design chooses regional k3s cells on GCP, with Reaktor-managed and customer-owned deployment options. A cell is an execution and authority boundary, not one node in a geographically stretched cluster. An outbound cell agent reports inventory and applies signed scoped operation plans; the general registry and managed-cell control loop are design targets [96].
data class CellBinding(
val cell: CellId,
val ownership: OwnershipRef,
val region: RegionId,
val authority: DelegatedAuthorityRef,
val permittedOperations: OperationPolicyRef,
val observedRevision: ObservationWatermark,
)
The control plane owns intent, policy, and operation history. The cell retains enforcement over its permitted resources. A disconnected agent cannot assume unlimited offline authority; its plan validity, expiry, idempotency, and replay handling are explicit. Local workloads should continue within their existing contracts when the management plane is unavailable. This is a control-plane design obligation rather than a claim of automatic outage independence. Cloudflare Workers and associated resources remain a separate execution plane connected by service, bus, and data contracts. Supabase and other providers retain their own authority and operations. A configuration importer proves what a file declares; only an appropriate provider observation can confirm existence or health. The graph records both and exposes drift.
23.4 Signals belong to contracts, not only dashboards
The analytics/telemetry design distinguishes app-owned product events, framework telemetry, performance measurements, and operational audit. Each has a schema, producer, privacy policy, and purpose [97]. A product event catalog can reject forbidden payload fields before emission. A release identifier and logical operation identity connect a signal to the system without requiring every invocation ID to become an unbounded metric label. The performance design supplies collectors, budgets, report models, and upstream profiler/test integrations. Its target path connects platform reports and runtime signals to OTel and the selected observation backends, including the Grafana family and analytical stores where appropriate [98, 71]. Existing profilers remain authoritative for their measurements. Reaktor normalizes references, context, and findings; it does not claim to replace Instruments, Perfetto, JFR, or browser profiling. A journey SLO links user-visible success to participating components. The notification example distinguishes accepted intent, provider acceptance, known delivery, and tap. An ingestion pipeline also observes itself: queue age, rejected events, dropped telemetry, exporter state, and source watermarks. A silent dashboard is not evidence of a healthy system. The workbench should connect missing observations to the corresponding producer and pipeline dependencies.
23.5 Development profiles before production mirroring
The Shadow Dev design begins with isolated development application IDs, auth scope, Worker bindings, and data stores, then grows toward captured traffic, moving baselines, and disposable overlays [18]. This order is important. Replay infrastructure built over production credentials is not a safe development environment. A capsule identifies a reproducible incident or test input: source/artifact revisions, selected observations, permitted state references, nondeterministic inputs, and comparison policy. Materialization obtains a bounded dependency closure, redacts according to policy, and creates an immutable base with writable overlays. External effects are blocked or substituted by default. The selected seed or capture does not establish full determinism if unrecorded clocks, remote responses, or scheduling decisions still matter. The same capsule can serve a human diagnosis session, an agent task, a regression test, and a release gate. Its evidence record distinguishes a matching output from a matching sequence of effects or a
performance comparison. Long-lived incident fixtures need explicit retention and privacy review; “pinned” cannot silently mean legally or operationally permanent.
23.6 Operate existing systems without claiming complete ownership
A foreign service can enter through an interface specification, source scanner, trace, or resource importer. Its declared knowledge tier determines which transformations the graph can justify, while an independent operation provider and authority determine which actions are allowed [99]. A source-scanned service can remain read-only in the authoring graph while an authorized infrastructure provider exposes a carefully scoped restart. Knowledge and operational permission are distinct dimensions. This supports incremental adoption: inspect first, attach typed boundaries, integrate tests and operations, and replace implementation only where useful. The enterprise need not rewrite its estate into Kotlin to obtain a connected service/resource view. It does need to pay for adapter maintenance, source mappings, schema evolution, and the reconciliation of conflicting evidence.
Original page layout, starting at page 57
24. Compilation and data-oriented implementation
24.1 Representations for different workloads
The architecture has an authoring representation, a semantic snapshot, and an execution representation. Authoring favors typed classes, delegates, and navigable member references. The semantic snapshot favors deterministic records, indexing, and revisioned queries. The execution representation favors direct bindings, compact dispatch, buffers, and schedulers. The snapshot is canonical for analysis of its revision, while the relevant source remains authoritative for authored declarations. Generated files carry source mappings and fingerprints. Supported visual edits produce source and semantic patches; re-elaboration confirms that the actual semantic change matches the intended proposal. Arbitrary implementation code is not forced into a graphical syntax.
24.2 Record layout and indexing
A compact layout stores nodes, ports, edges, and incidences in separate typed tables. Hot port columns include owner index, endpoint-type index, and flags. Binary edges can store two inline endpoint references. N-ary edges use offsets into incidence storage. Reverse incidence indexes support port-to-edge traversal without scanning every edge. Stable IDs remain external identities. Dense indices are local to a storage revision or protected handle generation. Reordering or compacting a table must not silently change a persistent reference. Names, schemas, profile descriptors, and repeated policy sets can be interned. Documentation, source locations, visualization coordinates, and evidence are cold side data. Not all fields should be forced into one structure-of-arrays layout. A small binary-edge record consumed as a unit may benefit from an array of structs; bulk owner or type scans may benefit from columns. Sparse typed side stores support aspects that apply to a minority of entities. Creating a distinct archetype for every combination of metadata would introduce unnecessary fragmentation. MassEntity separates data fragments from processing [100]. Unreal’s Render Dependency Graph records dependencies before compilation and execution [101]. The relevant design principle is workload-specific representation with explicit dependencies, not adoption of an entire game-engine object or scheduling model.
24.3 Snapshots and mutation cost
Semantic immutability does not require copying the whole graph. Chunked copy-on-write tables, persistent indexes, or a compact base plus deltas can publish revisions while sharing unchanged data. Frozen analysis snapshots can use compressed adjacency ranges. Highly mutable editor state can use a different representation with the same abstraction function. A storage implementation has an abstraction function 𝛼 mapping physical records to the semantic model. The key refinement obligation is
𝛼(applyStore(𝑆, Δ)) = applyModel(𝛼(𝑆), Δ), (19)
for admitted patches, together with preservation of published-revision isolation. Temporary allocation strategy is irrelevant to port ownership provided Equation 6 and the decoding relation remain true.
24.4 Compiled dispatch
Binding produces an invocation plan for a caller or participating endpoint. The plan selects a direct handler, a codec/transport path, a recipient-selection structure, or an FFI entry. Applicable authorization and instrumentation are compiled into the plan or invoked at explicit enforcement points. An ordinary call should not rediscover its provider through a graph traversal. The existing consumer implementation already caches a local target [9]; the richer model must preserve an equivalent direct path. Where fixed bindings and proof obligations allow it, code generation can specialize or inline the dispatch. Dynamic update boundaries retain an indirection deliberately, because that indirection is part of their lifecycle semantics. Kotlin wrappers can expose typed handles, but value classes do not by themselves establish zero allocation across generic or foreign-function boundaries. Runtime-specific benchmarks determine representation choices. Readable interfaces and data-oriented storage are compatible; neither requires exposing raw arrays to application authors.
24.5 Lifetime, concurrency, and payload ownership
Published graph and execution bindings must form a compatible revision. Readers pin the relevant revision or use a documented consistency mode. Retired handlers, buffers, and native resources are reclaimed only after all protected users have released them. Acquire-and-pin must be safe against concurrent retirement; a plain pointer load followed by an unprotected reference increment is insufficient. Payload contracts distinguish immutable shared values, transferred ownership, and borrowed views. A borrowed buffer cannot be retained across an asynchronous boundary beyond its lifetime. Broadcasting a mutable reference to several receivers changes aliasing semantics unless the contract permits it. Zero-copy paths are valid only when representation, synchronization, and ownership requirements hold. Concurrency can be partitioned by project, module, or actor ownership. A global lock on every operation would defeat the execution/control separation. Conversely, uncontrolled lock-free mutation is not an architectural goal: synchronization is chosen to preserve the explicit revision and lifetime contracts.
24.6 Performance claims and measurements
Performance is an empirical obligation. The evaluation compares current direct ports, the proposed compiled bindings, and representative adapter paths on each supported runtime. Measurements include allocations, retained memory, direct-call overhead, serialization cost, graph traversal, patch validation, snapshot publication, high-degree membership updates, and workbench query latency. Memory and latency under skewed degree distributions matter more than uniform synthetic graphs alone. Large actor groups and subscriptions require tests of lazy membership, incremental indexes, and
partition-local queries. Sparse incidence representations leave open the use of bulk graph-processing backends, but no GPU or sparse-linear-algebra dependency is required for ordinary execution.
24.7 Measured realization rather than representation fashion
The reference implementation’s generated FlexBuffer coders, broad serializer fallback, and caller-owned buffer paths illustrate why one representation need not serve every workload. The source performance guide distinguishes jointly deployed exact-layout payloads from independently evolving wire or storage contracts [89]. Its reported measurements are not reproduced here. A graph compiler can select a qualified codec profile, but only after compatibility requirements and buffer lifetime permit it. The same principle applies to graph storage. Binary edges can use two inline endpoint slots; n-ary edges can use ranges in incidence storage. A typed incidence view presents both uniformly to algorithms. Sparse facets do not require a separate object map on every node. None of these choices changes node ownership or makes a rendered scene the canonical graph. Encoding and patch application must preserve the semantic abstraction, and benchmarks must include incremental edits, skewed fanout, and retained revisions rather than only sequential scans.
Original page layout, starting at page 59
25. Hardware, resource budgets, and performance semantics
The semantic graph describes a system independently of its memory layout, but its implementation runs on finite machines. CPU caches, memory bandwidth, scheduling, allocation, serialization, and network propagation constrain attainable performance. Data-oriented design is valuable when it aligns representation with actual access patterns; it is not a rule that every object must become a column.
25.1 The cost of following a relationship
An object-oriented graph often stores references from node to port to edge to another port. This is convenient for mutation and direct binding, but a large analytical traversal can touch many separately allocated objects. An indexed representation can place owner, endpoint-type, and incidence records in compact arrays. A query scanning only owners and roles then avoids loading labels, source locations, serializer objects, and UI metadata. The benefit depends on workload. A binary call that already holds its implementation reference may become slower if it is forced through several array lookups. A small adjacency record whose fields are always used together may favor an array-of-structs layout. A bulk type-checking pass may favor separate columns. The semantic model should admit both representations and require correctness of their mappings rather than prescribe a single universal layout [102].
25.2 Bandwidth and operational intensity
For an appropriate computational kernel, the Roofline model bounds attainable throughput by compute capacity and memory bandwidth multiplied by operational intensity [103]:
𝑃 ≤ min(𝑃 𝑝𝑒𝑎𝑘 , 𝐵𝑚𝑒𝑚 𝐼), (20)
where 𝐼 measures useful operations per byte transferred. Graph analyses are often constrained by memory access rather than arithmetic. Their irregular access patterns mean that a simple floating-point Roofline is not a complete predictive model, but the underlying question remains useful: how much data must move per useful result? Suppose an illustrative analysis examines ten million records and reads 16 relevant bytes per record. The minimum useful traffic is 160 MB. At a sustained 20 GB/s, reading those bytes alone takes at least 8 ms. This is a hypothetical lower-bound calculation, not a Reaktor benchmark. Random access, indexes,
synchronization, decoding, and output construction add costs. If the representation forces another 80 bytes of unrelated data through memory per record, no faster arithmetic instruction can recover the wasted traffic. This motivates compact indexes, hot/cold separation, interned contracts, and bounded result material-ization. It does not imply that every analysis should be vectorized or sent to a GPU. Transfer and launch overhead can dominate a small query.
25.3 Parallelism has a serial boundary
If fraction 𝑠 of a workload remains serial and the rest parallelizes perfectly across 𝑝 workers, the idealized
speedup is
𝑆 𝑝𝑒𝑒𝑑𝑢 𝑝( 𝑝) ≤ . (21)
𝑠 + (1 − 𝑠)/𝑝
This is Amdahl’s familiar bound under fixed-work assumptions [104]. For graph validation, an exclusive
commit step, a shared allocator, or a final global policy check can limit speedup even when local checks
run in parallel.
The architecture should separate parallel candidate analysis from short authoritative publication. It
should also avoid placing unrelated runtime data-plane operations behind the graph editor’s mutation
lock. A design with more threads is not necessarily a design with more throughput. NUMA placement,
cache-line contention, and redundant scans can consume the additional capacity.
25.4 Batching exchanges overhead for latency
A bridge call has fixed overhead and payload-dependent work. If fixed overhead is ℎ and 𝑏 records share a batch, its amortized contribution is ℎ/𝑏 per record. However, waiting to collect the batch adds delay and can increase retained memory. A scheduler can flush on a maximum size, deadline, frame boundary, or explicit transaction boundary. A UI tree-update batch should remain a coherent commit for one boundary generation. A sensor stream may prefer bounded freshness over large batches. A durable ingestion path can tolerate more delay in exchange for throughput. These choices belong in profile and execution-plan parameters, not a hard-coded global batch size. Large blobs should normally cross the FFI through controlled handles or suitable shared views rather than repeated encoding through a JavaScript object graph.
25.5 Queueing identities are not latency guarantees
Little’s law relates long-run average population 𝐿, effective arrival rate 𝜆, and time in a stable system 𝑊 under the appropriate assumptions: 𝐿 = 𝜆𝑊 [105]. If an illustrative stage sustains 200 admitted jobs/s and the mean time spent in that stage is 0.05 s, it has 10 jobs in the stage on average. This does not establish that ten threads are required, that ten buffer slots are sufficient, or that a tail-latency bound is satisfied. Resource planning must distinguish concurrency, queued work, active service, and external waiting. Asynchronous execution can have many waiting requests and few active CPU tasks. A time-window measurement must account for work that began before the window or finishes afterward. A queue growing without bound does not satisfy the stable operating assumptions used for the simple calculation. The system graph should connect admission, measured backlog, service time, and capacity assump-tions. An alert can then report whether delay is associated with saturation, failed consumers, missing acknowledgements, or upstream retries. A topology picture alone cannot make this diagnosis.
25.6 Memory ownership and reclamation
A snapshot is immutable to readers, but its buffers and bound resources still have lifetimes. Publishing a new snapshot and reclaiming the previous one are different events. Read-copy-update (RCU) explicitly separates removal from reclamation and waits for protected readers before freeing retired data [106]. Reaktor can use an appropriate target-specific mechanism with the same obligation, without assuming Linux kernel primitives apply unchanged to Kotlin coroutines or Hermes callbacks. A reader that loads a pointer and only then increments a reference count may race with reclamation between those operations. Acquire-and-pin must be one properly synchronized protocol. Long-lived calls or sessions need ownership that remains valid across suspension. Deferred callbacks, queued events, and borrowed native buffers must participate in the same lifetime accounting or be invalidated safely by generation checks. Garbage collection can preserve a managed object’s memory without preserving an external native resource it references. Conversely, retaining an old generation indefinitely can prevent memory from being reclaimed even when it is no longer reachable from new calls. The execution runtime needs accounting for both kinds of lifetime.
25.7 A concrete snapshot layout budget
A deployment-local implementation can use 32-bit indexes when its admitted graph size fits that range, while stable external IDs remain larger opaque identifiers. The choice is a capacity contract. A compiler must reject an oversized snapshot or select a wider representation; truncating IDs is not an optimization. A candidate layout for a binary edge stores two port indexes, a profile index, and a flags word. A n-ary edge stores an incidence range plus its profile. The inverse port-to-incidence index is a separate derived structure. Sparse side stores hold policy, provenance, and documentation fields. No performance claim follows from this sketch until allocation, traversal, mutation, and retention are measured on the intended targets. Updates need peak-memory planning. If the active generation uses 𝑀𝑎 , the prepared candidate 𝑀𝑐 , the transferable state 𝑀𝑠 , and staging buffers 𝑀𝑏 , a coexistence plan may require approximately their sum before reclamation. A boundary restart can be preferable when simultaneous generations exceed the device’s budget. Update mode is therefore partly a resource decision, not only a semantic one.
25.8 Physical delay and placement
Information propagation has a physical lower bound. Ignoring routing and processing, a signal traversing distance 𝑑 cannot arrive sooner than 𝑑/𝑐, where 𝑐 = 299 792 458 m/s in vacuum [107]. Real communica-tion media and networks add propagation and queueing delay. A synchronous control loop cannot be made arbitrarily responsive by a location-transparent API when its critical path crosses a distant network. This observation favors placing latency-critical work near its state or physical process, while leaving planning, analysis, and fleet coordination elsewhere. It does not dictate that every service must be co-located: fault isolation, capacity, jurisdiction, and operational ownership can justify separation. The graph’s purpose is to make these competing constraints inspectable and analyzable.