Add Rust CultMesh catalog factories

This commit is contained in:
Meta Vens 2026-06-16 16:26:04 +01:00
commit 0308167c3e
5 changed files with 98 additions and 13 deletions

View file

@ -362,11 +362,12 @@ Current progress:
Android clients can react to lease changes without treating peer-card contact
hints as trust.
- Rust now has a small `CultMesh` facade for its substrate role: peer cards,
sorted peer catalogs, authority lease catalogs, `rudp://host:port` endpoint
parsing, and RUDP client/server construction from endpoint or peer-card
contact hints. The facade delegates to the existing Rust RUDP socket
transport; discovery contact remains separate from trust, which is still
gated by the authority lease catalog.
sorted peer catalogs, authority lease catalogs, schema registry factories,
shard catalog factories, `rudp://host:port` endpoint parsing, and RUDP
client/server construction from endpoint or peer-card contact hints. The
facade delegates to the existing Rust schema registry, shard catalog, and RUDP
socket transport owners; discovery contact remains separate from trust, which
is still gated by the authority lease catalog.
- Rust now also has substrate-shaped shard catalog helpers:
`CultNetShardDescriptor`, `CultNetShardCatalog`, request filtering by schema
id and record key, response creation, response application, and built-in

View file

@ -33,7 +33,7 @@ CultMesh.
| C# | Reference implementation and production game/server substrate | CultCache typed documents and SoA, CultNet schema-v0, LiteNetLib production path with adapter profile, shared transport profiles, shared RUDP socket transport, 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 surfaces | No need to abandon LiteNetLib before the CultNet adapter fully owns production service adoption |
| Python | Package runtime, local daemon endpoint, raw interop peer, typed state participant | CultCache/CultNet/CultMesh package surface, schema catalogs, shard catalogs/logs, schema-transport factory for raw client request/subscription flows, local TCP CultMesh server, session/prediction/simulation fact helpers, authority leases, streams, 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 |
| 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 reconnect policy/controller, RUDP reconnect-loop helper, branded CultMesh node/schema/shard/Verse/peer/authority/stream ergonomics | Full C# game session/server stack |
| Rust | Low-level cache/transport/runtime substrate | CultCache/CultNet interop lane, schema and shard catalog helpers, transport profiles, TCP-framed port, shared RUDP codec/session/socket transport, RUDP reconnect policy/controller and reconnect-loop helper, schema-v0 MessagePack over RUDP evidence, small CultMesh facade for peer cards, authority leases, RUDP endpoint parsing, and peer-card RUDP client construction | Full CultMesh game-session/server facade, stream catalog, or production game-session server |
| Rust | Low-level cache/transport/runtime substrate | CultCache/CultNet interop lane, schema and shard catalog helpers, transport profiles, TCP-framed port, shared RUDP codec/session/socket transport, 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, RUDP endpoint parsing, and peer-card RUDP client construction | Full CultMesh game-session/server facade, stream catalog, or production game-session server |
| Kotlin | JVM/Android client substrate | Typed MessagePack cache, built-in schema catalog advertisement, schema/shard catalogs with shared schema-message transport fetch/sync helpers, authority leases, stream catalog, branded `CultMesh` facade, WebSocket transport profile/connection helper, RUDP client/server sugar, RUDP reconnect policy/controller and reconnect-loop helper, schema-v0 MessagePack over RUDP evidence | C# SoA store, full C# server daemon, or Unity hot-loop memory layout |
## Evidence Gates

View file

@ -56,10 +56,11 @@ surface:
- shard catalog request/response messages
- the canonical `ghostlight.agent-state` document payload schema
Use `builtin_schema_registry()` when you want the standard catalog, or register
your own closed-world schema set with `CultNetSchemaRegistry`. Discovery stays
explicit on purpose: peers advertise only the contracts they were compiled to
understand, the same way CultCache only consumes the document types you
Use `builtin_schema_registry()` or `CultMesh::create_builtin_schema_registry()`
when you want the standard catalog, or register your own closed-world schema set
with `CultNetSchemaRegistry` / `CultMesh::create_schema_registry()`. Discovery
stays explicit on purpose: peers advertise only the contracts they were compiled
to understand, the same way CultCache only consumes the document types you
registered instead of pretending polymorphism is a public park.
## Shard Catalogs
@ -68,9 +69,9 @@ Rust now exposes the same shard topology vocabulary as the other runtimes
without claiming to be the full C# service body:
```rust
use cultnet_rs::{CultNetMessage, CultNetShardCatalog, CultNetShardDescriptor};
use cultnet_rs::{CultMesh, CultNetMessage, CultNetShardDescriptor};
let mut catalog = CultNetShardCatalog::new();
let mut catalog = CultMesh::create_shard_catalog();
catalog.upsert(CultNetShardDescriptor {
shard_id: "notes-a".to_string(),
owner_runtime_id: "rust-primary".to_string(),
@ -123,9 +124,16 @@ contact and authority ergonomics:
```rust
use cultnet_rs::{
CultMesh, CultMeshPeerCard, CultMeshRudpSocketOptions,
CultMesh, CultMeshPeerCard, CultMeshRudpSocketOptions, CultNetSchemaKind,
};
let schemas = CultMesh::create_builtin_schema_registry()?;
let shared_contracts = schemas.list(&cultnet_rs::CultNetSchemaCatalogOptions {
include_schema_json: false,
schema_ids: None,
kinds: Some(vec![CultNetSchemaKind::SharedContract]),
});
let mut server = CultMesh::create_rudp_server(
"rust-server",
0x1020_3040,

View file

@ -11,6 +11,9 @@ use std::time::Duration;
use crate::CultNetRudpSocketMode;
use crate::CultNetRudpSocketTransportConnection;
use crate::CultNetRudpSocketTransportOptions;
use crate::CultNetSchemaRegistry;
use crate::CultNetShardCatalog;
use crate::builtin_schema_registry;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CultMeshPeerCard {
@ -236,6 +239,18 @@ impl Default for CultMeshRudpSocketOptions {
pub struct CultMesh;
impl CultMesh {
pub fn create_schema_registry() -> CultNetSchemaRegistry {
CultNetSchemaRegistry::new()
}
pub fn create_builtin_schema_registry() -> Result<CultNetSchemaRegistry> {
builtin_schema_registry()
}
pub fn create_shard_catalog() -> CultNetShardCatalog {
CultNetShardCatalog::new()
}
pub fn create_peer_catalog() -> CultMeshPeerCatalog {
CultMeshPeerCatalog::new()
}

View file

@ -28,6 +28,7 @@ use cultnet_rs::CultNetRudpSocketMode;
use cultnet_rs::CultNetRudpSocketTransportConnection;
use cultnet_rs::CultNetRudpSocketTransportOptions;
use cultnet_rs::CultNetSchemaKind;
use cultnet_rs::CultNetSchemaRegistration;
use cultnet_rs::CultNetSchemaRegistry;
use cultnet_rs::CultNetSecret;
use cultnet_rs::CultNetServerSecurityOptions;
@ -1184,6 +1185,66 @@ fn cultmesh_facade_creates_rudp_client_from_peer_endpoint() -> Result<()> {
Ok(())
}
#[test]
fn cultmesh_facade_exposes_schema_registry_and_shard_catalog_owners() -> Result<()> {
let mut schemas = CultMesh::create_schema_registry();
schemas.register(CultNetSchemaRegistration {
schema_id: "rust.cultmesh.note.v1".to_string(),
kind: CultNetSchemaKind::DocumentPayload,
wire_contracts: vec![CultNetWireContract::CultNetSchemaV0],
schema_version: Some("rust.cultmesh.note.v1".to_string()),
document_type: Some("rust.cultmesh.note".to_string()),
title: Some("Rust CultMesh Note".to_string()),
schema_json: Some(
r#"{"$id":"rust.cultmesh.note.v1","type":"object","properties":{"body":{"type":"string"}}}"#
.to_string(),
),
})?;
assert_eq!(
schemas
.get("rust.cultmesh.note.v1", false)
.expect("registered schema is discoverable")
.document_type
.as_deref(),
Some("rust.cultmesh.note")
);
let builtins = CultMesh::create_builtin_schema_registry()?;
let shared_contracts = builtins.list(&cultnet_rs::CultNetSchemaCatalogOptions {
include_schema_json: false,
schema_ids: None,
kinds: Some(vec![CultNetSchemaKind::SharedContract]),
});
assert!(shared_contracts.iter().any(|schema| {
schema.schema_id
== "https://github.com/GameCult/cultnet-ts/contracts/cultnet.transport-profile.schema.json"
&& schema.schema_version.as_deref() == Some("cultnet.transport_profile.v0")
}));
let mut shards = CultMesh::create_shard_catalog();
shards.upsert(CultNetShardDescriptor {
shard_id: "rust-notes-a".to_string(),
owner_runtime_id: "rust-cultmesh".to_string(),
epoch: 7,
is_primary: Some(true),
schema_ids: vec!["rust.cultmesh.note.v1".to_string()],
key_prefix: Some("note:".to_string()),
primary_endpoints: vec!["rudp://127.0.0.1:4100".to_string()],
replica_endpoints: Vec::new(),
read_replica_endpoints: Vec::new(),
region: None,
authority_lease_id: Some("lease:rust-notes-a".to_string()),
})?;
let matching = shards.list(&cultnet_rs::CultNetShardCatalogOptions {
schema_ids: Some(vec!["rust.cultmesh.note.v1".to_string()]),
record_keys: Some(vec!["note:1".to_string()]),
});
assert_eq!(matching.len(), 1);
assert_eq!(matching[0].shard_id, "rust-notes-a");
assert!(shards.get("rust-notes-a").is_some());
Ok(())
}
#[test]
fn cultmesh_authority_leases_gate_peer_contact_hints() -> Result<()> {
let now = Utc::now();