State Model¶
Tidemark's runtime has to keep browser-side worker state and kernel-visible guest state coherent. The state model defines what is owned by the kernel, what is mirrored or transported by the runtime, and what is only application or SDK policy.
State Owners¶
flowchart TB
SDK["SDK<br/>provider and application policy"]
Runtime["Runtime API<br/>public process and filesystem methods"]
KernelWorker["kernel worker<br/>canonical runtime-facing FS and lifecycle state"]
ProcessOwner["process owner<br/>host execution and state transport"]
ThreadWorker["thread worker<br/>execution status and local continuation"]
Kernel["kernel wasm<br/>guest-visible semantics and supervisor"]
SDK --> Runtime
Runtime --> KernelWorker
Runtime --> ProcessOwner
ProcessOwner <--> KernelWorker
ProcessOwner <--> ThreadWorker
ThreadWorker <--> Kernel
KernelWorker <--> Kernel
The kernel defines guest-visible semantics and owns Linux-shaped decisions through the supervisor. The runtime moves state and executes host effects so those decisions can survive browser worker boundaries and async host events.
Shared Memory And Page Cache¶
The runtime allocates a SharedArrayBuffer-backed page cache during
Runtime.create and passes it to kernel worker and process creation paths. The
kernel environment receives that page cache when WebAssembly instances are
created.
The current runtime creates the page cache during runtime initialization, passes it into kernel-worker and process creation paths, and exposes snapshot and diagnostic operations around it. The supervisor and kernel-owned publication rules remain authoritative for page identity, dirty state, fills, flushes, and control-plane transitions.
The page cache is not an application-visible storage API. It is part of the runtime and kernel substrate used to make filesystem and process state visible across workers.
Filesystem Layers And Snapshots¶
The runtime exposes filesystem operations such as write, bulk write, symlink, read, readlink, mkdir, stat, readdir, snapshot loading, and file layer application. The SDK builds on that with resolver, cache, and provider flows.
sequenceDiagram
participant App as Application
participant SDK as SDK provider layer
participant Resolver as resolver/cache
participant Runtime as Runtime.fs
participant KW as kernel worker
participant Kernel as kernel memfs exports
App->>SDK: install provider-backed file layer
SDK->>Resolver: resolve manifest and blobs
Resolver-->>SDK: manifest + blob URLs or Requests
SDK->>SDK: fetch, cache, validate entries
SDK->>Runtime: applyFileLayer(entries)
Runtime->>KW: apply-file-layer(entries)
KW->>Kernel: update memfs/page-cache state
Kernel-->>KW: updated state
KW-->>Runtime: file-layer-applied
Runtime->>Runtime: refresh runtime FS snapshot
The SDK provider interfaces let applications choose where file layer data comes from. The runtime receives concrete entries; it does not need to know which package manager, registry, or upstream system produced them.
Runtime Filesystem Read Path¶
Runtime reads first use the most recent published runtime filesystem snapshot
when possible. If the entry is unavailable or stale, the runtime asks the kernel
worker through read-file.
flowchart TB
Read["Runtime.readFile(path)"]
Snapshot["runtime FS snapshot"]
Hit{"file data present?"}
ReturnSnapshot["return snapshot bytes"]
RPC["kernel-worker read-file"]
ReturnRPC["return kernel-worker bytes"]
Read --> Snapshot
Snapshot --> Hit
Hit -- yes --> ReturnSnapshot
Hit -- no --> RPC
RPC --> ReturnRPC
This read path exists alongside explicit mutation paths that refresh the runtime snapshot after writes, symlinks, directory creation, and layer application.
Kernel-Worker RPC¶
The runtime uses request ids for kernel-worker RPCs so host effects and state transport can be pipelined safely. The current request set includes:
- kernel initialization,
- single and bulk file writes,
- file layer application,
- symlink creation,
- read-file and readlink,
- mkdir, stat, and readdir,
- filesystem snapshot load and snapshot export,
- process registration and supervisor-requested lifecycle host operations,
- supervisor-selected blocked syscall resume execution,
- process and page-cache diagnostic operations.
flowchart LR
Runtime["Runtime API call"]
Request["KernelWorkerRequest<br/>requestId + typed payload"]
Handler["kernel-worker handler"]
Action["fs, lifecycle, sync, debug operation"]
Response["KernelWorkerOutbound<br/>requestId + typed result"]
Runtime --> Request
Request --> Handler
Handler --> Action
Action --> Response
Response --> Runtime
This is a host-execution contract, not a second source of Linux policy hidden behind a single mutable global object.
Snapshot Categories¶
The runtime message types show which state must cross worker boundaries:
| Snapshot or state | Purpose |
|---|---|
KernelRuntimeState |
Kernel-visible runtime state passed between kernel and workers. |
| fd entry snapshots | Transport or mirror of supervisor/kernel-owned descriptor state. |
| OFD slot snapshots | Open-file-description state transported across host boundaries. |
| pipe slot snapshots | Supervisor-controlled metadata plus direct data-plane coordination. |
| socket state snapshots | Supervisor-controlled socket state plus host network buffer transport. |
| guest memory write snapshots | Guest memory changes that must be replayed or synchronized. |
| kernel memory write snapshots | Kernel-side memory changes surfaced from execution. |
| child-exit records | Transport for supervisor-owned child publication and wait ordering. |
| fork stack snapshots | Stack state needed across fork-style transitions. |
These categories explain why explicit state transport is a central runtime responsibility. They do not transfer scheduling, lifecycle, fd/OFD, pipe, socket, or filesystem control authority from the supervisor to TypeScript.
FD, OFD, Pipe, And Socket Synchronization¶
The implementation treats file descriptor and kernel-object state as structured state, not as loose JavaScript side data.
flowchart TB
Thread["thread worker status"]
Owner["process owner host executor"]
FD["fd entry snapshots"]
OFD["OFD slot snapshots"]
Pipe["pipe slot snapshots"]
Socket["socket state snapshots"]
KernelWorker["kernel-worker sync"]
Kernel["kernel wasm / supervisor state"]
Thread --> FD
Thread --> OFD
Thread --> Pipe
Thread --> Socket
FD --> Owner
OFD --> Owner
Pipe --> Owner
Socket --> Owner
Owner --> KernelWorker
KernelWorker --> Kernel
The current implementation exposes fd/OFD, pipe, socket, memory, and synchronization records through the kernel ABI. Runtime adapters transport those records and execute supervisor decisions; they do not recompute guest-visible lifetime or readiness policy. Tests should cover both the kernel decision and the observable result of the retained host effect.
This structure is what lets thread execution, supervisor-owned process state, and kernel-worker state converge after a blocking syscall, fork-style transition, network operation, or file mutation.