9.7 KiB
Browser Verse Transport Boundary
Date: 2026-08-17
Status
This is the implementation map for the browser Verse boundary.
samples/eve-two-runtime remains the clean package-consumer/jsdom checkpoint.
samples/eve-browser-network runs a durable C# provider, a real Chromium Eve
lowerer, an independent C# headless observer, and a separate local Odin fixture
over binary loopback CultNet WebSocket routes under an explicit
local-development trust policy. It proves one canonical
command effect, idempotent retry, shared observation, provider restart on a new
physical route, browser rediscovery, retained lease resubscription, and a second
canonical command after reconnection.
The current substrate has a browser client boundary and local live proof, but not a complete public Verse proof:
cultmesh-tsis a Node package and importsnode:dgramat its root;cultnet-ts/contractsis the browser-safe contract entrypoint; the package root still includes Node transport, filesystem, crypto, stream, and UDP modules and must not enter browser bundles;- C# and TypeScript now share
cultnet.database_subscribe.v0,cultnet.database_unsubscribe.v0, andcultnet.database_change_raw.v0;cultmesh-browserconsumes those messages as explicit document leases; cultmesh-browserowns stable identity, route refresh, resubscription, and typed operation correlation without exposing direct document writes;CultMeshBrowserOdinRendezvousresolves stable Verse/provider identity withcultmesh.verse_catalog_request.v0andcultmesh.verse_catalog_response.v0; application callbacks no longer need to smuggle provider URLs into the browser client;CultMeshBrowserClientowns the final authority gate: remote use requires a consumer-pinned Odin P-256 root, an Odin-signed route certificate,wss://, and provider possession proof over a fresh nonce. A catalog source cannot bypass that gate by returning a route-shaped object;- Kotlin has a channel-aware WebSocket transport adapter, TypeScript has the
browser client, and
GameCult.Networking.WebSocketsprovides the bounded C# schema server host adapter; - Hermodr can lower Odin state into a browser, but it is an infrastructure runtime, not the clean-consumer game API;
- the sample's separate local Odin fixture serves the production Verse-catalog contract and is restarted with a changed provider route; the same Chromium client automatically rediscovers that route.
- the sample validates its surface against Eve's canonical TypeScript contract, but its provider still carries a minimal local C# DTO mirror. The released-artifact gate requires the renderer-neutral C# Eve surface contract as an independently consumable Eve artifact; Unity must not be that contract's package owner.
Authority Map
Owner:
- CultNet owns binary WebSocket framing and schema-v0 message validation.
- CultMesh owns stable Verse/provider identity, document leases, subscriptions, route replacement, and command/receipt correlation.
- Odin owns discovery of the current
wss://candidate for a stable Verse and provider identity. - The provider daemon owns application state, operations, receipts, and the Eve surface.
- Eve owns surface and command contracts; the browser lowerer owns DOM only.
Inputs:
- an Odin-discovered route certificate and consumer-configured Odin root;
- stable Verse and provider identities;
- provider key possession over a fresh client nonce;
- requested schema ids and record keys;
- typed operation invocations and idempotency keys;
- canonical CultNet schema-v0 MessagePack messages.
Outputs:
- leased typed document snapshots and live changes;
- typed operation receipts;
- explicit connection/session diagnostics;
- deterministic unsubscribe and disposal;
- route replacement without changing provider or document identity.
Derived state:
- browser caches, DOM trees, loading/error presentation, and optimistic visual affordances are projections only;
- a socket URL is a disposable discovery candidate, never provider identity;
- reconnect status is observable session state, not application truth.
Forbidden writers:
- browser lowerers cannot mutate provider documents directly;
- Hermodr, service workers, renderer caches, and app-specific HTTP endpoints cannot become alternate gameplay authorities;
- no JSON polling API may mirror the database as a second state system;
node:dgram, Node streams, filesystem stores, and Node crypto cannot enter a browser bundle;- a late socket, stale subscription generation, or reconnect replay cannot overwrite a newer session;
- application code cannot own reconnect sleeps, endpoint ranking, or resubscription loops.
Shared paths:
- initial load, live update, reconnect, tab background/resume, command retry, and provider route rotation all use one CultMesh document-lease/session path;
- browser, Unity, headless C#, and future native clients consume the same provider-owned documents and receipts;
- every command crosses the same typed operation boundary regardless of which Eve lowerer emitted it.
Deletion line:
- the jsdom checkpoint remains labeled as a Node-hosted DOM proof;
- browser applications import
cultmesh-browserandcultnet-ts/contracts, never the Node-only package roots; - subscription messages remain one shared schema contract across the C# and TypeScript catalogs;
- the real provider adapter must consume the canonical WebSocket message lane; no sample-only WebSocket protocol is permitted.
Required Runtime Shape
The browser-facing package must be importable by a standards-mode browser or a normal bundler without Node polyfills. It exposes a narrow API shaped like:
const mesh = await CultMeshBrowserClient.connect({
rendezvous: odin,
verseId: "sample.counter",
providerId: "sample.counter-provider",
runtimeId: "sample.browser",
});
using surface = await mesh.leaseRawDocument({
schemaId: "gamecult.eve.surface.v1",
recordKey: "eve:surface:counter",
});
surface.watch(record => render(decodeCultNetPayload(record)));
const receipt = await mesh.invoke({
serviceId: "sample.counter",
operation: "increment",
payloadSchema: "sample.increment.v1",
payload: {},
idempotencyKey: crypto.randomUUID(),
});
The names are illustrative. The ownership is not: application code supplies identity and intent; CultMesh owns route/session continuity; the provider owns the result.
Wire Contract
WebSocket carries binary MessagePack CultNet schema-v0 messages. The first implementation must support:
cultnet.hello.v0;- authentication/session verification;
cultnet.snapshot_request.v0andcultnet.snapshot_response_raw.v0;cultnet.database_subscribe.v0,cultnet.database_unsubscribe.v0, andcultnet.database_change_raw.v0;cultnet.operation_request.v0andcultnet.operation_response.v0;cultmesh.verse_catalog_request.v0andcultmesh.verse_catalog_response.v0on the Odin route;cultnet.error.v0.
The WebSocket frame is a transport body, not a second message schema. Payload size, queue depth, subscription count, and command rate are bounded. Schema, identity, authority, and idempotency validation happen before provider code.
Acceptance Gate
Current executable coverage from scripts/verify-eve-browser-network.mjs:
- authenticated binary C# WebSocket provider;
- separate local Odin fixture using the canonical Verse-catalog messages;
- real Chromium and retained C# headless consumers, both discovered through the same Odin identity;
- shared surface and counter document leases;
- Eve button to typed operation to provider receipt to shared state;
- duplicate idempotency key produces one effect;
- provider restart on a different physical port rehydrates the
.ccstate; - the retained browser lease rediscovers through Odin and resubscribes;
- the retained C# client independently rediscovers, resubscribes, invokes the
second command through
CultMeshClient.InvokeAsync, and receives the provider-authored receipt without application transport or reconnect code; - Chromium observes the C# command's canonical state and receipt chronology;
- 10,000 typed no-op operations traverse the retained C# WebSocket session; the gate records throughput, p99, post-GC managed growth, and private-memory movement without growing provider state;
- generated browser bundle contains no
node:builtin import.
The full public Verse gate still requires the deployed Odin daemon rather than the local contract fixture and released-artifact-only .NET consumption. The source-contract gate runs on Windows and Linux CI.
From an empty temporary consumer using packed/released artifacts only:
- start a provider daemon with one durable counter document and one validated Eve surface;
- advertise it by stable identity through a local Odin fixture or real Odin;
- connect one real Chromium page and one C# headless client;
- lease the same surface and counter document in both runtimes;
- click the browser button and require one provider-authored canonical receipt;
- observe the same state version and receipt id in both clients;
- disconnect or rotate the physical WebSocket endpoint, then require both leases to resume without application reconnect code;
- invoke from C# after route replacement and require Chromium to observe the same provider-authored state and receipt;
- restart the provider and prove state plus receipt persistence;
- run a non-persistent operation workload long enough to falsify retained callback or managed-heap growth;
- reject malformed schemas, direct document writes, duplicate command effects, stale subscription generations, and unsupported authority;
- inspect the browser bundle and fail if it contains Node builtin imports.
The gate runs on Windows and Linux. A screenshot is useful presentation evidence, but the receipt/state chronology is the authority proof.