From 84399673b508bf1636e03a5af7ec4743901db767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Mingo=20Suarez?= Date: Sat, 2 May 2026 16:29:40 +0300 Subject: [PATCH 1/4] Initialize epic branch: epic/test-doc-pass --- .epic-init | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .epic-init diff --git a/.epic-init b/.epic-init new file mode 100644 index 0000000..e69de29 From 3c936d25e9b25f6fdbe6b1706958a862727f7c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Mingo=20Suarez?= Date: Sat, 2 May 2026 16:43:41 +0300 Subject: [PATCH 2/4] docs: add doc comments to IClusteringModel and related types (#97) (#100) Adds /// doc comments to all public types and their fields in crates/arcane-core/src/clustering_model.rs: WorldStateView, ClusterInfo, PlayerInfo, ClusterDecision, DecisionType, DecisionReason, ModelInfo, and ValidationResult. Co-authored-by: Claude Sonnet 4.6 --- crates/arcane-core/src/clustering_model.rs | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/crates/arcane-core/src/clustering_model.rs b/crates/arcane-core/src/clustering_model.rs index 594bc3e..a38997b 100644 --- a/crates/arcane-core/src/clustering_model.rs +++ b/crates/arcane-core/src/clustering_model.rs @@ -9,59 +9,92 @@ use uuid::Uuid; /// View of world state passed to the clustering model. ClusterManager maintains this from SpacetimeDB subscriptions. #[derive(Clone, Debug)] pub struct WorldStateView { + /// Monotonic timestamp (seconds since epoch) of the snapshot. pub timestamp: f64, + /// Maximum wall-clock ms the model may spend on this evaluation cycle. pub evaluation_budget_ms: u32, + /// All clusters visible in the live view at this instant. pub clusters: Vec, + /// All players visible in the live view at this instant. pub players: Vec, } /// Per-cluster info in the live view. #[derive(Clone, Debug)] pub struct ClusterInfo { + /// Unique identifier for this cluster. pub cluster_id: Uuid, + /// Hostname of the server serving this cluster. pub server_host: String, + /// Player UUIDs assigned to this cluster. pub player_ids: Vec, + /// Cached player count (derived from `player_ids.len()`). pub player_count: u32, + /// CPU utilisation as a percentage (0.0–100.0). pub cpu_pct: f32, + /// Spatial centroid of the cluster's players in world coordinates. pub centroid: Vec2, + /// Maximum distance of any player from the centroid. pub spread_radius: f32, + /// Outbound cross-cluster RPCs per second from this cluster. pub rpc_rate_out: f32, } /// Per-player info in the live view. #[derive(Clone, Debug)] pub struct PlayerInfo { + /// Unique identifier for this player. pub player_id: Uuid, + /// Cluster the player is currently assigned to. pub cluster_id: Uuid, + /// Current world-space position. pub position: Vec2, + /// Current velocity vector (units/second). pub velocity: Vec2, + /// Guild this player belongs to, if any. pub guild_id: Option, + /// Party this player belongs to, if any. pub party_id: Option, } /// A single merge or split decision from the model. #[derive(Clone, Debug)] pub struct ClusterDecision { + /// Whether this is a merge or split decision. pub decision_type: DecisionType, + /// Execution priority (1 = highest, 10 = lowest). pub priority: u8, + /// Machine- and human-readable reason for the decision. pub reason: DecisionReason, + /// Model confidence (0.0–1.0). Static rules always return 1.0. pub confidence: f32, + /// For merge decisions: the source cluster whose players move to `target_cluster_id`. pub source_cluster_id: Option, + /// For merge decisions: the target cluster receiving the source cluster's players. pub target_cluster_id: Option, + /// For split decisions: the cluster being split into two groups. pub cluster_id: Option, + /// For split decisions: first subgroup of player UUIDs. pub split_group_a: Option>, + /// For split decisions: second subgroup of player UUIDs. pub split_group_b: Option>, } +/// Whether a decision proposes merging two clusters or splitting one cluster into two. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum DecisionType { + /// Combine `source_cluster_id` into `target_cluster_id`. Merge, + /// Divide `cluster_id` into two groups. Split, } +/// Machine- and human-readable reason code for a clustering decision. #[derive(Clone, Debug)] pub struct DecisionReason { + /// Machine-readable code (e.g. `"PARTY_SEPARATED"`, `"SPATIAL_PROXIMITY"`). pub code: String, + /// Human-readable explanation for logging and debugging. pub detail: String, } @@ -77,17 +110,26 @@ pub trait IClusteringModel: Send + Sync { fn validate_view(&self, view: &WorldStateView) -> ValidationResult; } +/// Metadata describing a clustering model implementation. #[derive(Clone, Debug)] pub struct ModelInfo { + /// Human-readable model type (e.g. `"static_rules"`, `"ml_model"`). pub model_type: String, + /// Semantic version or build identifier for the model. pub version: String, + /// Unix timestamp of the model's training, if applicable. pub trained_at: Option, + /// Number of features the ML model was trained on, if applicable. pub feature_count: Option, } +/// Outcome of a `validate_view` call: whether the view is structurally valid and any diagnostics. #[derive(Clone, Debug)] pub struct ValidationResult { + /// Whether the view passed all validation checks. pub valid: bool, + /// Non-fatal diagnostics that may be of interest to operators. pub warnings: Vec, + /// Fatal validation failures that make the view unsuitable for evaluation. pub errors: Vec, } From c8d5782e558a01549d9d6f7d047bff1c9ad8261b Mon Sep 17 00:00:00 2001 From: martinjms Date: Sat, 2 May 2026 17:03:03 +0300 Subject: [PATCH 3/4] docs: add doc comments to four-bucket state model types (#98) Add doc comments to all fields, enum variants, and methods in the replication_channel module (ChannelConfig, EntityStateDelta, EntityStateEntry, CloseReason, IReplicationChannel). Co-Authored-By: Claude Sonnet 4.6 --- crates/arcane-core/src/replication_channel.rs | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/crates/arcane-core/src/replication_channel.rs b/crates/arcane-core/src/replication_channel.rs index 090619a..43206a9 100644 --- a/crates/arcane-core/src/replication_channel.rs +++ b/crates/arcane-core/src/replication_channel.rs @@ -13,23 +13,33 @@ use crate::types::Vec3; use uuid::Uuid; -/// Configuration for a replication channel (one neighbor). +/// Configuration for a replication channel to one neighbor. #[derive(Clone, Debug)] pub struct ChannelConfig { + /// Spatial radius (world units) within which entities are replicated to this neighbor. pub observation_radius: f64, + /// Maximum number of pending deltas before the channel starts dropping. pub max_queue_depth: usize, + /// Minimum interval (ms) between consecutive sends to this neighbor. pub send_interval_ms: u32, + /// Whether to compress delta payloads before transmission. pub compression_enabled: bool, } /// Entity state delta sent to a neighbor. Fire-and-forget; no ack. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] pub struct EntityStateDelta { + /// Cluster that produced and sent this delta. pub source_cluster_id: Uuid, + /// Monotonic sequence number for ordering deltas from this source. pub seq: i64, + /// Simulation tick at which this delta was produced. pub tick: u64, + /// Monotonic timestamp (seconds since epoch) of the snapshot. pub timestamp: f64, + /// Entities that were created or updated since the last delta. pub updated: Vec, + /// Entity UUIDs that were removed since the last delta. pub removed: Vec, } @@ -47,10 +57,13 @@ pub struct EntityStateDelta { /// `local_data` uses [`serde::Serialize`] with skip — it does not cross the replication mesh. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] pub struct EntityStateEntry { + /// Unique identifier for this entity (bucket 1 — spine, routing). pub entity_id: Uuid, /// Cluster that owns this entity (for client colorization and ownership display). pub cluster_id: Uuid, + /// World-space position of the entity (bucket 1 — spine, pose). pub position: Vec3, + /// Velocity vector in world units per second (bucket 1 — spine, pose). pub velocity: Vec3, /// **Bucket 2** — replicated game JSON (neighbors, clients). Default `null`; omitted when null. #[serde(default, skip_serializing_if = "serde_json::Value::is_null")] @@ -64,6 +77,8 @@ pub struct EntityStateEntry { } impl EntityStateEntry { + /// Create a new entry with only bucket-1 spine fields. `user_data` and `local_data` start as + /// [`serde_json::Value::Null`]; callers set them after construction when needed. pub fn new(entity_id: Uuid, cluster_id: Uuid, position: Vec3, velocity: Vec3) -> Self { Self { entity_id, @@ -76,20 +91,24 @@ impl EntityStateEntry { } } -/// Reason for closing a channel. +/// Reason a replication channel was closed. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum CloseReason { + /// The neighbor cluster left the region or disconnected. NeighborDepartured, + /// The two clusters merged into one; the channel between them is no longer needed. ClustersMerged, + /// The local cluster or whole simulation is shutting down. Shutdown, } -/// Contract for publishing/subscribing to a neighbor's state. One instance per neighbor. +/// Contract for publishing/subscribing to a neighbor cluster's entity state. One instance per neighbor. pub trait IReplicationChannel: Send + Sync { - /// Enqueue a delta for transmission. Non-blocking; may drop if queue full. + /// Enqueue a delta for transmission. Non-blocking; may return a congestion signal or silently + /// drop when the queue is full. fn send(&self, delta: EntityStateDelta); - /// Close the channel and flush pending sends. + /// Close the channel, flush pending sends, and release transport resources. fn close(&self, reason: CloseReason); } From d36c2a9de01ad0e00e9abdb24788d4837baee9a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Mingo=20Suarez?= Date: Sat, 2 May 2026 17:51:52 +0300 Subject: [PATCH 4/4] docs: add doc comments to connection types and protocol enums (#99) (#102) Adds /// doc comments to all public struct fields, enum variants, and trait methods in crates/arcane-core/src/server_pool.rs (connection types), cluster_simulation.rs, world_simulator.rs, and types.rs. Co-Authored-By: Claude Sonnet 4.6 { + /// Unique identifier for this cluster. pub cluster_id: Uuid, /// Monotonic tick index that will be assigned to the upcoming replication delta's `tick` field. pub tick: u64, + /// Simulation time step (seconds) since the last tick. pub dt_seconds: f64, + /// Mutable reference to the cluster's entity storage. pub entities: &'a mut HashMap, /// Processed after `on_tick` returns so the next delta lists these ids under `removed`. pub pending_removals: &'a mut Vec, @@ -59,5 +62,7 @@ pub struct ClusterTickContext<'a> { /// Custom simulation step for entities owned by this cluster. pub trait ClusterSimulation: Send + Sync { + /// Advance simulation state by one tick. Called once per tick after client updates and injected + /// entities are applied, and before the replication delta is built. fn on_tick(&self, ctx: &mut ClusterTickContext<'_>); } diff --git a/crates/arcane-core/src/server_pool.rs b/crates/arcane-core/src/server_pool.rs index 7459abc..47759fa 100644 --- a/crates/arcane-core/src/server_pool.rs +++ b/crates/arcane-core/src/server_pool.rs @@ -8,36 +8,54 @@ use uuid::Uuid; /// Handle to an allocated cluster server. #[derive(Clone, Debug)] pub struct ServerHandle { + /// Unique identifier for this server instance. pub server_id: Uuid, + /// Hostname or IP address of the server. pub host: String, + /// WebSocket port for client connections. pub ws_port: u16, + /// RPC port for inter-cluster communication. pub rpc_port: u16, + /// Metrics / observability port. pub metrics_port: u16, + /// Monotonic timestamp (seconds since epoch) when the server was allocated. pub allocated_at: f64, } /// Error from pool operations. #[derive(Clone, Debug)] pub struct PoolError { + /// Machine-readable error code. pub code: PoolErrorCode, + /// Human-readable error detail for logging and debugging. pub detail: String, } +/// Reasons a pool operation can fail. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum PoolErrorCode { + /// All servers are allocated; no capacity remaining. PoolExhausted, + /// An allocation request exceeded the timeout. AllocationTimeout, + /// The target server is in an unhealthy state. ServerUnhealthy, } /// Current pool capacity and health. #[derive(Clone, Debug)] pub struct PoolStatus { + /// Total number of server slots in the pool. pub total_capacity: u32, + /// Number of servers currently free for allocation. pub available: u32, + /// Number of servers currently allocated to clusters. pub allocated: u32, + /// Number of servers in a failed state. pub failed: u32, + /// Minimum desired free capacity; below this triggers scaling. pub min_available: u32, + /// P99 allocation latency in milliseconds. pub allocation_p99_ms: f32, } @@ -56,15 +74,22 @@ pub trait IServerPool: Send + Sync { fn get_status(&self) -> PoolStatus; } +/// Category of server failure reported to the pool. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum FailureType { + /// Server is not reachable over the network. Unreachable, + /// Server process crashed (e.g. segfault, OOM). SimulationCrashed, + /// Server is reachable but operating outside acceptable performance bounds. PerformanceDegraded, } +/// Result of a failure report: an optional replacement server and expected wait time. #[derive(Clone, Debug)] pub struct ReplacementHandle { + /// Replacement server handle, if one was immediately available. pub handle: Option, + /// Estimated time (ms) until a replacement is ready, if not immediate. pub eta_ms: Option, } diff --git a/crates/arcane-core/src/types.rs b/crates/arcane-core/src/types.rs index e9f8f06..4fbe01f 100644 --- a/crates/arcane-core/src/types.rs +++ b/crates/arcane-core/src/types.rs @@ -11,11 +11,14 @@ pub use uuid::Uuid as EntityId; /// 2D vector (e.g. centroid in 2D plane, or x/z). #[derive(Clone, Copy, Debug, PartialEq)] pub struct Vec2 { + /// X-axis component. pub x: f64, + /// Y-axis component. pub y: f64, } impl Vec2 { + /// Create a new 2D vector from its x and y components. pub fn new(x: f64, y: f64) -> Self { Self { x, y } } @@ -24,12 +27,16 @@ impl Vec2 { /// 3D position (world position, centroid with height). #[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize)] pub struct Vec3 { + /// X-axis coordinate. pub x: f64, + /// Y-axis coordinate. pub y: f64, + /// Z-axis coordinate. pub z: f64, } impl Vec3 { + /// Create a new 3D vector from its x, y, and z components. pub fn new(x: f64, y: f64, z: f64) -> Self { Self { x, y, z } } @@ -46,9 +53,13 @@ impl Vec3 { /// Per-cluster geometry from SpatialIndex (IN-03). Used for neighbor lists and WorldStateView. #[derive(Clone, Debug, PartialEq)] pub struct ClusterGeometry { + /// Unique identifier for this cluster. pub cluster_id: Uuid, + /// Spatial centroid of the cluster. pub centroid: Vec3, + /// Maximum distance of any entity from the centroid. pub spread_radius: f64, + /// Number of entities assigned to this cluster. pub entity_count: u32, } diff --git a/crates/arcane-core/src/world_simulator.rs b/crates/arcane-core/src/world_simulator.rs index d82017a..2c09ab7 100644 --- a/crates/arcane-core/src/world_simulator.rs +++ b/crates/arcane-core/src/world_simulator.rs @@ -9,29 +9,43 @@ use uuid::Uuid; /// Last known state of an entity when it was last observed. #[derive(Clone, Debug)] pub struct LastKnownState { + /// Unique identifier for this entity. pub entity_id: Uuid, + /// Timestamp (seconds since epoch) when the entity was last observed. pub last_observed: f64, + /// Last observed world-space position. pub position: Vec3, + /// Last observed velocity vector (units per second). pub velocity: Vec3, + /// Current health value. pub health: i32, + /// Maximum health value. pub health_max: i32, + /// Game-defined behavior state (e.g. `"idle"`, `"patrolling"`). pub behavior_state: String, + /// Spawn or anchor position the entity returns to. pub home_position: Vec3, + /// Distance from home_position the entity may wander before returning. pub territory_radius: f64, } /// Context at simulation time (optional, for FastForward/ML). #[derive(Clone, Debug)] pub struct WorldContext { + /// Current simulation timestamp (seconds since epoch). pub current_time: f64, } /// Plausible state after simulating forward from last_known. #[derive(Clone, Debug)] pub struct SimulatedState { + /// Unique identifier for this entity. pub entity_id: Uuid, + /// Simulated world-space position. pub position: Vec3, + /// Simulated velocity vector (units per second). pub velocity: Vec3, + /// Simulated health value. pub health: i32, }