2026-06-16 01:07:17 +01:00
# Runtime Parity Scope
This is the claim CultLib can make without turning evidence into incense.
Parity means the targeted runtimes speak the same wire language and expose
similar developer-facing entrypoints for the roles they own. It does not mean
every runtime clones the C# production server, LiteNetLib history, or hot-loop
memory layout.
## Objective
Cross-runtime parity has three layers:
- Wire parity: shared CultCache file/state contracts, schema-v0 MessagePack
documents, transport profiles, and RUDP packets must cross runtime boundaries
without translation folklore.
- Feature parity: each runtime must expose the CultCache/CultNet/CultMesh
surfaces needed for its intended role, with unsupported production-server
ownership called out plainly.
- Ergonomic parity: callers should find a branded `CultMesh` entrypoint,
typed catalogs, discovery helpers, authority checks, stream surfaces, and
transport helpers instead of assembling raw maps and channel strings.
SoA performance parity is deliberately not a cross-runtime requirement. C#
2026-09-13 16:21:25 +02:00
owns the shared-memory streaming body path. The C# CultCache SoA table (ECS-style
structure-of-arrays columns over cached documents) is parked at the tag
`parked/cultcache-soa` : it was built for hot-loop performance, had no consumer
outside tests, and is restorable from that tag (`docs/parked-features.md` ).
It is not a supported surface in the current tree. Other runtimes may add native hot paths when their
2026-09-13 16:01:32 +02:00
runtime role earns them, but they do not need to mimic Unity/C# memory layout
to speak CultNet or participate in CultMesh.
2026-06-16 01:07:17 +01:00
## Current Targeted Runtimes
| Runtime | Role | Claimed parity | Not claimed |
| --- | --- | --- | --- |
2026-09-13 16:01:32 +02:00
| C# | Reference implementation and production game/server substrate | CultCache typed documents, CultNet schema-v0, LiteNetLib production path with adapter profile, shared transport profiles, shared RUDP socket transport, C# multi-peer RUDP listener and schema service host, C# interop RUDP serve/dial path, connected RUDP CultMesh client helpers, RUDP-backed schema-client selection for `rudp://` service endpoints, RUDP reconnect policy/controller and reconnect-loop helper, LiteNetLib client reconnect-controller adoption, schema-client transport port for service request/response clients, CultMesh node/session/catalog/stream/simulation/RUDP surfaces, authorized peer lookup | No need to abandon LiteNetLib before the CultNet adapter fully owns production service adoption |
2026-06-17 08:05:41 +01:00
| Python | Package runtime, local daemon endpoint, raw interop peer, typed state participant | CultCache/CultNet/CultMesh package surface, branded CultMesh node/schema/shard/Verse/peer/authority/stream/RUDP ergonomics, authorized peer lookup, shard catalogs/logs, schema-transport factory for raw client request/subscription flows, local TCP and RUDP CultMesh server listeners, Python interop RUDP serve/dial path, session/prediction/simulation fact helpers, RUDP codec/session/socket transport, RUDP reconnect policy/controller and reconnect-loop helper, schema-v0 MessagePack over RUDP evidence, benchmark evidence against C# cache paths | Universal C# throughput, full C# daemon/server stack, and RUDP as the only public service pipe |
2026-06-17 07:28:47 +01:00
| TypeScript | Node/browser-adjacent projection and interop runtime | CultCache parity tests, CultNet schema-v0 peer, advertised schema/shard catalog wire contracts plus request/sync helpers, transport profiles, TCP-framed transport port and peer helper, shared RUDP socket transport, RUDP interop serve/dial path, RUDP reconnect policy/controller, RUDP reconnect-loop helper, branded CultMesh node/schema/shard/Verse/peer/authority/stream/RUDP ergonomics, authorized peer lookup | Full C# game session/server stack |
Give the Rust CultMesh runtime a home
The only Rust CultMesh implementation in existence was 1,363 lines inside
Ghostlight's vendor directory. It was in no library repo and no standalone
repo, so it had never been checked against the browser, Kotlin, and
TypeScript CultMesh bodies it must interoperate with.
It is not a duplicate of the facade in cultnet-rs. That one is the small
surface the parity table claims for Rust: peer cards, authority leases,
endpoint parsing. This is the stream and session layer -- node, document
sets, RUDP document publication, stream descriptors, negotiation, stream
catalog, and shared-memory frame rings -- which the same table lists under
Rust's "Not claimed". A consumer grew the unclaimed surface because there was
nowhere else to put it.
Its path dependencies already matched this layout and it builds against
CultLib's cultnet-rs unchanged, so it does not depend on the forked RUDP
extras. Seven runtime-local tests pass, and CI now runs them.
The parity table gains no claim from this. The Rust row says plainly that no
interop lane exercises the stream surface, and expansion work records that
runtime-local tests are not a parity claim. Landing code is not evidence.
packages/cultmesh-rs needed an explicit .gitignore re-include; the NuGet
packages rule hides every language package until one is added by name.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 23:09:45 +02:00
| Rust | Low-level cache/transport/runtime substrate | CultCache/CultNet interop lane, schema and shard catalog helpers, typed same-schema alias hydration from raw snapshots, transport profiles, TCP-framed port, shared RUDP codec/session/socket transport, Rust interop RUDP serve/dial path, connected RUDP CultMesh client helpers, RUDP reconnect policy/controller and reconnect-loop helper, schema-v0 MessagePack over RUDP evidence, small CultMesh facade for schema registry, shard catalog, peer cards, authority leases, authorized peer lookup, RUDP endpoint parsing, and peer-card/authorized-peer RUDP client construction | Full CultMesh game-session/server facade or production game-session server. `packages/cultmesh-rs` now holds a Rust stream and session surface -- node, document sets, RUDP document publication, stream descriptors, negotiation, stream catalog, and shared-memory frame rings -- but no interop lane exercises it, so it carries no cross-runtime parity claim |
2026-09-13 16:21:25 +02:00
| Kotlin | JVM/Android client substrate | Typed MessagePack cache, one-call typed snapshot document sync through local same-schema aliases, built-in schema catalog advertisement, schema/shard catalogs with shared schema-message transport fetch/sync helpers, authority leases, authorized peer lookup, stream catalog, branded `CultMesh` facade, WebSocket transport profile/connection helper, RUDP client/server sugar, connected RUDP CultMesh client helpers, Kotlin interop RUDP serve/dial path, RUDP reconnect policy/controller and reconnect-loop helper, schema-v0 MessagePack over RUDP evidence | C# SoA store (parked at `parked/cultcache-soa` ), full C# server daemon, or Unity hot-loop memory layout |
2026-06-16 01:07:17 +01:00
## Evidence Gates
2026-06-16 19:02:25 +01:00
- `.github/workflows/cultnet-interop.yml` is the hosted CI witness for the
cross-runtime wire claim. It builds the TypeScript workspace, Kotlin interop
peer, Rust/C# interop peers through the TypeScript harness, installs the
Python package dependencies, then runs named RUDP lanes for Python, Rust, C#,
and Kotlin, the RUDP impairment matrix, and the schema-v0 discovery lane.
2026-06-16 01:07:17 +01:00
- `packages/cultnet-ts/test/interop/cultnet-interop.test.ts` is the main live
wire harness. It covers schema-v0 interop and RUDP exchange across C#,
TypeScript, Rust, Python, and Kotlin, including loss, reordering,
fragmentation, disconnect reason propagation, ping/pong, and schema-v0
2026-06-16 02:23:02 +01:00
MessagePack over RUDP for C#, Rust, Python, and Kotlin peers against
2026-06-16 04:22:19 +01:00
TypeScript. Those RUDP schema-message tests also assert the advertised
`reconnectPolicy` profile field from C#, Rust, Python, and Kotlin peers.
2026-06-16 05:29:45 +01:00
Runtime-local tests cover the deterministic delay helper and reconnect
controller in C#, TypeScript, Rust, Python, and Kotlin.
Split the Python runtime into cultcache-py, cultnet-py, cultmesh-py
One distribution named cultcache-py carried three libraries. Rust and
TypeScript layer them as cultcache < cultnet < cultmesh; Python now does
the same, one package per layer, module names unchanged so every
`from cultmesh_py import ...` keeps working.
Two imports ran against that layering and are resolved by moving code to
where the dependency direction says it lives, not by adding a shim:
- cultnet_py.interop_peer imported the Verse/peer catalog, authority
lease, stream, and simulation-fact contracts from cultmesh_py. They are
wire contracts a bare peer has to speak without owning a node, which is
why cultnet-rs and cultnet-ts keep them in the net layer. They now live
in cultnet_py.cultmesh_contracts; cultmesh_py re-exports them.
- cultcache_py.benchmark imported cultnet_py. It measures framed CultNet
parse beside cache paths, so it and compare_csharp move to cultnet_py.
verify checks all three packages and moves to cultmesh_py.
The single 6,693-line test module is split by what each test touches: a
test using any cultmesh_py name lands in cultmesh-py, else cultnet_py in
cultnet-py, else cultcache-py. Each suite runs with only its layer and the
layers below on the path, so a test that reaches up fails to import
rather than quietly binding the packages back together. 11 / 53 / 78 =
the same 142.
Workflows install all three; the publish job is one matrix over the
three packages keyed by tag prefix. The TS test harnesses put all three
src directories on PYTHONPATH. cultcache-py bumps to 0.2.0 because it no
longer contains cultnet_py or cultmesh_py; the new packages start at
0.1.0. Nothing was ever published, so no PyPI consumer moves.
cultcache-py 11 tests, path: cultcache-py/src
cultnet-py 53 tests, path: + cultnet-py/src
cultmesh-py 78 tests, path: + cultmesh-py/src
python -m cultmesh_py.verify -> ok, all five checks
cultnet_py.interop_peer imports with cultmesh_py absent
Not run here: the cultnet-ts interop ring and cultcache-ts store matrix
need dotnet/kotlin peers; their PYTHONPATH change is four lines.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 13:10:47 +02:00
- `docs/python-runtime-parity.md` is the Python-specific audit ledger. Its
2026-06-16 01:07:17 +01:00
"Still Not Claimed" section is part of the contract, not an apology.
- `docs/cultnet-transport-parity.md` is the transport ownership map. It tracks
2026-06-16 10:33:55 +01:00
the remaining work to lower older LiteNetLib/WebSocket bodies behind the
2026-06-16 01:07:17 +01:00
shared transport port and expand RUDP adoption beyond the core proof.
- `packages/cultmesh-kotlin/README.md` records Kotlin's runtime role and
ergonomic surface, including the explicit non-claim around C# SoA storage.
2026-06-16 19:02:25 +01:00
## Expansion Work Outside The Current Parity Claim
The current claim is role-scoped feature, wire, and ergonomic parity across the
targeted runtimes. The stronger claim that every production daemon/service body
has already moved to native RUDP, or that every runtime clones the C# production
server body, is deliberately not made.
2026-06-16 01:07:17 +01:00
2026-06-16 12:15:23 +01:00
- Broaden production service adoption so remaining daemon paths use the shared
transport port consistently. The C# built-in LiteNetLib service wrappers now
2026-06-16 16:07:56 +01:00
register transport-aware `CultNetServerPeer` listeners instead of requiring
`NetPeer` callbacks, and TypeScript TCP peer creation has a transport-first
helper. C# Verse discovery, peer exchange, shard-log fetch, shard-snapshot
fetch, and shard write forwarding clients now consume a schema-client
2026-06-17 14:09:52 +01:00
transport port and select the C# RUDP schema client for `rudp://` endpoints
while keeping LiteNetLib for `cultnet://` endpoints. Broader daemon adoption
remains the unclaimed layer.
2026-06-16 10:33:55 +01:00
- Extend RUDP adoption through daemon/socket reconnect loops. RUDP profiles now
advertise the portable reconnect policy, runtime-local tests prove the shared
controller across the targeted runtimes, and the C# LiteNetLib client plus
C#/TypeScript/Rust/Python/Kotlin RUDP reconnect loops use that controller;
broader service adoption remains a separate claim.
2026-06-16 01:07:17 +01:00
- Keep Kotlin ergonomic parity moving with Android/JVM-shaped APIs instead of
2026-06-16 14:42:57 +01:00
backfilling C# server responsibilities it should not own. Kotlin WebSocket
and RUDP adapters now share one `CultNetSchemaMessageTransport` helper shape
for schema/shard catalog request and sync flows.
Give the Rust CultMesh runtime a home
The only Rust CultMesh implementation in existence was 1,363 lines inside
Ghostlight's vendor directory. It was in no library repo and no standalone
repo, so it had never been checked against the browser, Kotlin, and
TypeScript CultMesh bodies it must interoperate with.
It is not a duplicate of the facade in cultnet-rs. That one is the small
surface the parity table claims for Rust: peer cards, authority leases,
endpoint parsing. This is the stream and session layer -- node, document
sets, RUDP document publication, stream descriptors, negotiation, stream
catalog, and shared-memory frame rings -- which the same table lists under
Rust's "Not claimed". A consumer grew the unclaimed surface because there was
nowhere else to put it.
Its path dependencies already matched this layout and it builds against
CultLib's cultnet-rs unchanged, so it does not depend on the forked RUDP
extras. Seven runtime-local tests pass, and CI now runs them.
The parity table gains no claim from this. The Rust row says plainly that no
interop lane exercises the stream surface, and expansion work records that
runtime-local tests are not a parity claim. Landing code is not evidence.
packages/cultmesh-rs needed an explicit .gitignore re-include; the NuGet
packages rule hides every language package until one is added by name.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 23:09:45 +02:00
- Bring `packages/cultmesh-rs` under the wire claim. It arrived from a consumer repo where it grew
outside any conformance harness, and its stream, negotiation, and shared-memory frame-ring
surfaces have never been checked against the browser, Kotlin, and TypeScript CultMesh bodies
they must interoperate with. Runtime-local tests pass; that is not a parity claim.
Bound the RUDP receive path and refuse hostile sequences
Clears the cultnet half of the retained debt. The two unported commits from the
retiring GameCult/cultnet-rs lineage were not portable as patches: this lineage
had reworked the same receive path with sequence domains and ACK horizons, and
applying them raised nine conflicts that would have reverted that work. Most of
what they added already existed here by another route -- received-sequence
history, fragment-set count and reassembly bytes are all bounded already. So
the gaps were taken rather than the patches.
Three were real. The per-channel maps grew without limit, and a peer picks its
own channel ids, so ordered and sequenced channel tracking is now capped at 64
each. The out-of-order hold buffer grew without limit, and a peer picks its own
send order, so it is capped at 1024 frames and 4 MB; sizes are computed from the
buffer rather than tracked in counters, which cannot drift.
The fourth was the sharpest. remember_received ran before the duplicate
early-return, so a single forged packet far past the current highest advanced
the receive state beyond every sequence still in flight and starved the
session. Such a packet is now refused without being remembered.
Reliable sequence exhaustion aborted the process through expect(). The capacity
gate that already guards the send window now also refuses when the sequence
space cannot cover the request, and allocation saturates rather than panicking
so no future path can reintroduce the abort.
Five tests cover the bounds and both refusals. cultnet-rs passes 103,
cultcache-rs 48, cultmesh-rs 7, and the TypeScript-Rust RUDP interop lanes pass
5 of 5 with the hardened peer, so legitimate traffic is unchanged.
The parity ledger now records what this actually leaves owed: these are
refusals, not wire-format changes, so the interop lanes stay green whether or
not the other four runtimes match. The gap will not announce itself.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 00:57:07 +02:00
- Carry the RUDP receive-path bounds to the other runtimes. Rust now caps tracked ordered
and sequenced channels, caps the out-of-order hold buffer by frames and bytes, refuses a
packet far ahead of the highest received so a forged sequence cannot starve a session, and
reports reliable sequence exhaustion instead of aborting. C#, TypeScript, Python and Kotlin
still accept all of it. These are refusals rather than wire-format changes, so the interop
lanes stay green either way -- which is exactly why the gap will not announce itself.
2026-06-16 01:07:17 +01:00
- Keep performance claims evidence-bound: C# owns SoA; Python has benchmark
comparison gates; other runtimes should advertise measured native hot paths
only when those paths exist.