This is an automated email from the ASF dual-hosted git repository.

numinnex pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iggy.git


The following commit(s) were added to refs/heads/master by this push:
     new 8ed41c7db refactor(server): consensus restore, fail-stop, linear 
cleanup batch (#3911)
8ed41c7db is described below

commit 8ed41c7db2221d0e1fb3b2859e0586afc172f3db
Author: Grzegorz Koszyk <[email protected]>
AuthorDate: Thu Aug 20 12:42:41 2026 +0200

    refactor(server): consensus restore, fail-stop, linear cleanup batch (#3911)
---
 core/configs/src/common/server.rs          |  14 +-
 core/configs/src/server_config/cluster.rs  |  37 +++++
 core/configs/src/server_config/defaults.rs |   4 +-
 core/metadata/src/impls/metadata.rs        |   9 +-
 core/partitions/src/iggy_partition.rs      |   9 +-
 core/partitions/src/lib.rs                 |   6 +-
 core/partitions/src/types.rs               |  82 +++++-----
 core/server/config.toml                    |  13 ++
 core/server/src/bootstrap.rs               |  81 ++++++----
 core/server/src/dispatch.rs                |   7 +-
 core/server/src/main.rs                    |   4 +-
 core/server/src/partition_reconciler.rs    | 233 ++++++++++++++++++++++++++++-
 core/server/src/responses.rs               | 176 +++++++++++++++++-----
 core/server_common/src/buffer.rs           |   4 +-
 core/server_common/src/executor.rs         | 100 +++++++++++--
 core/server_common/src/lib.rs              |   2 +-
 core/server_common/src/memory_pool.rs      |  23 ++-
 core/shard/src/config.rs                   |   9 +-
 core/shard/src/lib.rs                      |   8 +-
 core/simulator/src/bin/simulator-ui.rs     |   4 +-
 core/simulator/src/bin/workload-fuzz.rs    |   4 +-
 core/simulator/src/lib.rs                  |  56 +++----
 core/simulator/src/replica.rs              |   3 +-
 23 files changed, 671 insertions(+), 217 deletions(-)

diff --git a/core/configs/src/common/server.rs 
b/core/configs/src/common/server.rs
index 315abeadc..887cfe8ab 100644
--- a/core/configs/src/common/server.rs
+++ b/core/configs/src/common/server.rs
@@ -20,7 +20,7 @@ use iggy_common::{IggyByteSize, IggyDuration};
 use serde::{Deserialize, Serialize};
 use serde_with::DisplayFromStr;
 use serde_with::serde_as;
-use server_common::MemoryPoolConfigOther;
+use server_common::MemoryPoolSettings;
 use server_common::log::{TelemetryEndpointSettings, TelemetrySettings};
 
 pub use server_common::log::TelemetryTransport;
@@ -34,12 +34,12 @@ pub struct MemoryPoolConfig {
     pub bucket_capacity: u32,
 }
 
-impl MemoryPoolConfig {
-    pub fn into_other(&self) -> MemoryPoolConfigOther {
-        MemoryPoolConfigOther {
-            enabled: self.enabled,
-            size: self.size,
-            bucket_capacity: self.bucket_capacity,
+impl From<&MemoryPoolConfig> for MemoryPoolSettings {
+    fn from(config: &MemoryPoolConfig) -> Self {
+        Self {
+            enabled: config.enabled,
+            size: config.size,
+            bucket_capacity: config.bucket_capacity,
         }
     }
 }
diff --git a/core/configs/src/server_config/cluster.rs 
b/core/configs/src/server_config/cluster.rs
index a1874a640..d71f86ae6 100644
--- a/core/configs/src/server_config/cluster.rs
+++ b/core/configs/src/server_config/cluster.rs
@@ -299,6 +299,41 @@ pub struct ClusterConfig {
     /// Replica-to-replica TLS settings for the consensus (`tcp_replica`) port.
     #[serde(default)]
     pub tls: ClusterTlsConfig,
+    /// Shard-0 coordinator placement tunables.
+    #[serde(default)]
+    pub coordinator: ClusterCoordinatorConfig,
+}
+
+/// Placement tunables for the shard-0 coordinator, converted into the shard
+/// crate's `CoordinatorConfig` at bootstrap (the domain type lives there
+/// because `configs` and `shard` share no dependency edge).
+#[derive(Debug, Deserialize, Serialize, Clone, ConfigEnv)]
+#[serde(deny_unknown_fields)]
+pub struct ClusterCoordinatorConfig {
+    /// When `total_shards > 1`, exclude shard 0 from replica placement.
+    /// Shard 0 already hosts the coordinator, the metadata writer, and both
+    /// listeners; replicas are long-lived steady flows, so offload them to
+    /// peer shards by default.
+    #[serde(default = "default_skip_shard_zero_for_replicas")]
+    pub skip_shard_zero_for_replicas: bool,
+    /// When `total_shards > 1`, exclude shard 0 from client placement.
+    /// Default false: client connections are short-lived and benefit from
+    /// shard-0 parallelism more than replicas do.
+    #[serde(default)]
+    pub skip_shard_zero_for_clients: bool,
+}
+
+fn default_skip_shard_zero_for_replicas() -> bool {
+    true
+}
+
+impl Default for ClusterCoordinatorConfig {
+    fn default() -> Self {
+        Self {
+            skip_shard_zero_for_replicas: 
default_skip_shard_zero_for_replicas(),
+            skip_shard_zero_for_clients: false,
+        }
+    }
 }
 
 /// Replica-to-replica authentication for the consensus (`tcp_replica`) port.
@@ -1451,6 +1486,7 @@ mod tests {
                 previous_shared_secret: 
"retiring-psk-MUST-NOT-be-persisted".to_owned(),
             },
             tls: ClusterTlsConfig::default(),
+            coordinator: ClusterCoordinatorConfig::default(),
         };
         let serialized = serde_json::to_string(&config).expect("serialize 
cluster config");
         assert!(
@@ -1783,6 +1819,7 @@ mod cluster_validate_tests {
             nodes,
             auth: ClusterAuthConfig::default(),
             tls: ClusterTlsConfig::default(),
+            coordinator: ClusterCoordinatorConfig::default(),
         }
     }
 
diff --git a/core/configs/src/server_config/defaults.rs 
b/core/configs/src/server_config/defaults.rs
index 1705e861b..f752d3265 100644
--- a/core/configs/src/server_config/defaults.rs
+++ b/core/configs/src/server_config/defaults.rs
@@ -24,7 +24,8 @@
 //! [`crate::common::defaults`].
 
 use super::cluster::{
-    ClusterAuthConfig, ClusterConfig, ClusterNodeConfig, ClusterTlsConfig, 
TransportPorts,
+    ClusterAuthConfig, ClusterConfig, ClusterCoordinatorConfig, 
ClusterNodeConfig,
+    ClusterTlsConfig, TransportPorts,
 };
 use super::message_bus::MessageBusConfig;
 use super::metadata::MetadataConfig;
@@ -148,6 +149,7 @@ impl Default for ClusterConfig {
                 .collect(),
             auth: ClusterAuthConfig::default(),
             tls: ClusterTlsConfig::default(),
+            coordinator: ClusterCoordinatorConfig::default(),
         }
     }
 }
diff --git a/core/metadata/src/impls/metadata.rs 
b/core/metadata/src/impls/metadata.rs
index ee67e1097..1fda606d1 100644
--- a/core/metadata/src/impls/metadata.rs
+++ b/core/metadata/src/impls/metadata.rs
@@ -1138,10 +1138,6 @@ where
             return;
         }
 
-        // TODO add assertions for valid state here.
-
-        // TODO handle gap in ops.
-
         // Verify hash chain integrity BEFORE checkpoint. 
`checkpoint_if_needed`
         // can drain WAL entries, making previous_header return None.
         if let Some(previous) = journal.handle().previous_header(&header) {
@@ -3423,12 +3419,11 @@ where
 
         let header = *message.header();
 
-        // TODO: calculate the index;
         #[allow(clippy::cast_possible_truncation)]
-        let idx = header.op as usize;
+        let op = header.op as usize;
         assert_eq!(header.command, Command::Prepare);
         assert!(
-            journal.handle().header(idx).is_some(),
+            journal.handle().header(op).is_some(),
             "replicate: prepare must be durable in local journal before 
chain-forward"
         );
         if let Err(e) = replicate_to_next_in_chain(consensus, message).await {
diff --git a/core/partitions/src/iggy_partition.rs 
b/core/partitions/src/iggy_partition.rs
index 4a366076d..369db555a 100644
--- a/core/partitions/src/iggy_partition.rs
+++ b/core/partitions/src/iggy_partition.rs
@@ -3704,10 +3704,10 @@ where
         let enforce_fsync = self.effective_enforce_fsync(config);
         let preallocate_segments = self.effective_preallocate_segments(config);
         let segment = Segment::new(start_offset, segment_size);
-        // `PartitionsConfig::get_messages_path` is a stub (`/tmp/iggy_stub`);
-        // the partition's real directory is only known to the server config
-        // that created the initial segment, so derive the rotated paths from
-        // the active writer's location.
+        // Prefer the active writer's location: a per-topic path override or a
+        // config change after the initial segment was created must not scatter
+        // one partition's segments across two directories. The config layout
+        // only decides for a partition with no writer yet.
         let (messages_path, index_path) = self.partition_dir().map_or_else(
             || {
                 (
@@ -6531,6 +6531,7 @@ mod tests {
             segment_size: IggyByteSize::from(1024 * 1024),
             preallocate_segments: false,
             encryptor: None,
+            path_layout: crate::PartitionPathLayout::default(),
         }
     }
 
diff --git a/core/partitions/src/lib.rs b/core/partitions/src/lib.rs
index 6d14d4b6b..4649af829 100644
--- a/core/partitions/src/lib.rs
+++ b/core/partitions/src/lib.rs
@@ -46,9 +46,9 @@ pub use segment::Segment;
 use server_common::Message;
 pub use server_common::send_messages::{IggyMessage, IggyMessageHeader, 
IggyMessages};
 pub use types::{
-    AppendResult, Fragment, PartitionOffsets, PartitionsConfig, PollFragments, 
PollQueryResult,
-    PollingArgs, PollingConsumer, REPAIR_RETRY_TICKS, RepairConclusion, 
RepairSession,
-    SendMessagesResult,
+    AppendResult, Fragment, PartitionOffsets, PartitionPathLayout, 
PartitionsConfig, PollFragments,
+    PollQueryResult, PollingArgs, PollingConsumer, REPAIR_RETRY_TICKS, 
RepairConclusion,
+    RepairSession, SendMessagesResult,
 };
 
 /// Partition-level data plane operations.
diff --git a/core/partitions/src/types.rs b/core/partitions/src/types.rs
index dcf4eb0b9..df15b4393 100644
--- a/core/partitions/src/types.rs
+++ b/core/partitions/src/types.rs
@@ -256,6 +256,32 @@ pub enum RepairConclusion {
     FloorRefused { floor: u64, to_op: u64 },
 }
 
+/// Where partition directories live on disk, mirroring the server's
+/// `SystemConfig` path scheme so segment files created by the partition plane
+/// land next to the ones the server bootstrap created.
+#[derive(Debug, Clone)]
+pub struct PartitionPathLayout {
+    /// `{system.path}/{stream.path}`: the directory holding per-stream dirs.
+    pub streams_root: String,
+    /// Directory name of the per-topic level (`topic.path`).
+    pub topics_dir: String,
+    /// Directory name of the per-partition level (`partition.path`).
+    pub partitions_dir: String,
+}
+
+/// Synthetic layout for tests and the simulator, where paths only key the
+/// sim storage and never touch a real filesystem. The server always wires
+/// the real layout from its `SystemConfig`.
+impl Default for PartitionPathLayout {
+    fn default() -> Self {
+        Self {
+            streams_root: "/tmp/iggy_stub/streams".to_string(),
+            topics_dir: "topics".to_string(),
+            partitions_dir: "partitions".to_string(),
+        }
+    }
+}
+
 /// Configuration for partition operations.
 ///
 /// Mirrors the relevant fields from the server's `PartitionConfig` and
@@ -286,6 +312,8 @@ pub struct PartitionsConfig {
     /// decrypts uniformly whether a fragment came from the resident journal
     /// or from disk.
     pub encryptor: Option<Arc<EncryptorKind>>,
+    /// On-disk location scheme for partition directories.
+    pub path_layout: PartitionPathLayout,
 }
 
 impl PartitionsConfig {
@@ -296,14 +324,15 @@ impl PartitionsConfig {
         topic_id: usize,
         partition_id: usize,
     ) -> String {
-        
format!("/tmp/iggy_stub/streams/{stream_id}/topics/{topic_id}/partitions/{partition_id}")
+        format!(
+            "{}/{stream_id}/{}/{topic_id}/{}/{partition_id}",
+            self.path_layout.streams_root,
+            self.path_layout.topics_dir,
+            self.path_layout.partitions_dir,
+        )
     }
 
     /// Constructs the file path for segment messages.
-    ///
-    /// TODO: This is a stub waiting for completion of issue to move server 
config
-    /// to shared module. Real implementation should use:
-    /// 
`{base_path}/{streams_path}/{stream_id}/{topics_path}/{topic_id}/{partitions_path}/{partition_id}/{start_offset:0>20}.log`
     #[must_use]
     pub fn get_messages_path(
         &self,
@@ -319,10 +348,6 @@ impl PartitionsConfig {
     }
 
     /// Constructs the file path for segment indexes.
-    ///
-    /// TODO: This is a stub waiting for completion of issue to move server 
config
-    /// to shared module. Real implementation should use:
-    /// 
`{base_path}/{streams_path}/{stream_id}/{topics_path}/{topic_id}/{partitions_path}/{partition_id}/{start_offset:0>20}.index`
     #[must_use]
     pub fn get_index_path(
         &self,
@@ -336,43 +361,4 @@ impl PartitionsConfig {
             self.get_partition_path(stream_id, topic_id, partition_id)
         )
     }
-
-    #[must_use]
-    pub fn get_offsets_path(
-        &self,
-        stream_id: usize,
-        topic_id: usize,
-        partition_id: usize,
-    ) -> String {
-        format!(
-            "{}/offsets",
-            self.get_partition_path(stream_id, topic_id, partition_id)
-        )
-    }
-
-    #[must_use]
-    pub fn get_consumer_offsets_path(
-        &self,
-        stream_id: usize,
-        topic_id: usize,
-        partition_id: usize,
-    ) -> String {
-        format!(
-            "{}/consumers",
-            self.get_offsets_path(stream_id, topic_id, partition_id)
-        )
-    }
-
-    #[must_use]
-    pub fn get_consumer_group_offsets_path(
-        &self,
-        stream_id: usize,
-        topic_id: usize,
-        partition_id: usize,
-    ) -> String {
-        format!(
-            "{}/groups",
-            self.get_offsets_path(stream_id, topic_id, partition_id)
-        )
-    }
 }
diff --git a/core/server/config.toml b/core/server/config.toml
index f420aeeb3..d5046c509 100644
--- a/core/server/config.toml
+++ b/core/server/config.toml
@@ -622,6 +622,19 @@ key_file = ""
 # use hostnames in the roster if the certificates only have DNS SANs.
 ca_file = ""
 
+# Shard-0 coordinator placement.
+[cluster.coordinator]
+# When the server runs more than one shard, exclude shard 0 from replica
+# placement. Shard 0 already hosts the coordinator, the metadata writer, and
+# both listeners; replica connections are long-lived steady flows, so they are
+# offloaded to peer shards by default.
+skip_shard_zero_for_replicas = true
+
+# When the server runs more than one shard, exclude shard 0 from client
+# placement. Off by default: client connections are short-lived and benefit
+# from shard-0 parallelism more than replicas do.
+skip_shard_zero_for_clients = false
+
 # Full roster of cluster members. Byte-identical on every node. The running
 # node's identity is resolved at launch from the '--replica-id <N>' CLI
 # flag, which selects the entry in this list that describes the current
diff --git a/core/server/src/bootstrap.rs b/core/server/src/bootstrap.rs
index 01ef2d1fa..f3cf877ce 100644
--- a/core/server/src/bootstrap.rs
+++ b/core/server/src/bootstrap.rs
@@ -989,7 +989,12 @@ async fn shard_main(
     let poll_interval = 
config.system.sharding.shutdown_poll_interval.get_duration();
 
     let shutdown_flag_for_handoff = Arc::clone(&shutdown_flag);
-    spawn_shutdown_watchdog(Rc::clone(&bus), shutdown_flag, drain_timeout, 
poll_interval);
+    let mut shutdown_watchdog = Some(spawn_shutdown_watchdog(
+        Rc::clone(&bus),
+        shutdown_flag,
+        drain_timeout,
+        poll_interval,
+    ));
 
     // Metadata bootstrap is single-writer: shard 0 owns the WAL and the
     // only `WriteHandle`-bearing `MuxStateMachine`. Peer shards receive
@@ -1194,20 +1199,17 @@ async fn shard_main(
     );
 
     // Re-check the cross-thread shutdown flag here, *before* spawning the
-    // message pump. A sibling shard may have failed in the window between
-    // the metadata broadcast and this point; gating before spawn keeps the
-    // bus' `background_tasks` vec empty on the shutdown path. Spawn-then-
-    // check would leave `bus.track_background(pump_handle)` registering a
-    // `JoinHandle` that only `bus.shutdown()` drains, but the watchdog
-    // driving `bus.shutdown()` is `.detach()`'d (see TODO at
-    // `spawn_shutdown_watchdog`) and may not be scheduled before this
-    // function returns `Ok(())` and the compio runtime drops, cancelling
-    // the pump mid-`write_vectored_all`.
-    //
-    // Without this gate shard 0 would also still open TCP/QUIC/WS
+    // message pump: it keeps the bus' `background_tasks` vec empty on the
+    // shutdown path, and shard 0 would otherwise still open TCP/QUIC/WS
     // listeners for a server that is already tearing down, briefly
     // accepting connections that immediately get torn by the watchdog.
+    //
+    // The flag is set, so the watchdog is (about to be) driving
+    // `bus.shutdown()`; await it so the runtime does not drop mid-drain.
     if shutdown_flag_for_handoff.load(Ordering::Relaxed) {
+        if let Some(watchdog) = shutdown_watchdog.take() {
+            let _ = watchdog.await;
+        }
         return Ok(());
     }
 
@@ -1420,6 +1422,12 @@ async fn shard_main(
             // The bind failure is the primary fault; the drain verdict only
             // matters for the log it emits.
             let _ = await_pump_drain(pump_handle.take(), config, 
shard_id).await;
+            // Neither the flag nor the bus token has fired yet on this path,
+            // so the watchdog is still idle-looping; awaiting it would hang.
+            // Detach and let `run_shard_thread`'s unwind flip the flag.
+            if let Some(watchdog) = shutdown_watchdog.take() {
+                watchdog.detach();
+            }
             return Err(error);
         }
 
@@ -1446,7 +1454,15 @@ async fn shard_main(
         let _ = tx.try_send(());
     }
 
-    await_pump_drain(pump_handle.take(), config, shard_id).await?;
+    // Await the watchdog even when the drain verdict is an error: the token
+    // has fired, so it either stands down within one poll interval or is
+    // mid-`bus.shutdown()`, and dropping it there truncates in-flight
+    // `ClientForwardFailed` replies.
+    let pump_verdict = await_pump_drain(pump_handle.take(), config, 
shard_id).await;
+    if let Some(watchdog) = shutdown_watchdog.take() {
+        let _ = watchdog.await;
+    }
+    pump_verdict?;
 
     info!(shard = shard_id, "server shard exited cleanly");
     Ok(())
@@ -1662,16 +1678,27 @@ async fn await_bootstrap_complete(
 /// is the only Send signal we have; the bus' shutdown machinery is
 /// `!Send` (`Rc<Cell<bool>>` + per-shard `async_channel`), so it must be
 /// triggered from within the runtime that owns the bus.
+///
+/// The caller owns the returned handle and must await it on the exit paths
+/// where shutdown is in progress (flag set or bus token triggered):
+/// dropping it there cancels the watchdog mid-`bus.shutdown()`, truncating
+/// in-flight `ClientForwardFailed` replies (terminal per `SendError` docs).
+/// It cannot go through `bus.track_background` instead: the watchdog itself
+/// drives `bus.shutdown()`, and the bg-drain loop in `shutdown()` would
+/// re-enter awaiting the watchdog's own pending shutdown call
+/// (self-deadlock). The await is bounded: once the token fires the loop
+/// stands down within one poll interval, and the shutdown call itself is
+/// capped by `drain_timeout`.
 #[allow(clippy::needless_pass_by_value)]
 fn spawn_shutdown_watchdog(
     bus: Rc<IggyMessageBus>,
     shutdown_flag: Arc<AtomicBool>,
     drain_timeout: Duration,
     poll_interval: Duration,
-) {
+) -> compio::runtime::JoinHandle<()> {
     let bus_for_task = Rc::clone(&bus);
     let bus_token = bus.token();
-    let watchdog = compio::runtime::spawn(async move {
+    compio::runtime::spawn(async move {
         loop {
             if shutdown_flag.load(Ordering::Relaxed) {
                 break;
@@ -1684,19 +1711,7 @@ fn spawn_shutdown_watchdog(
             compio::time::sleep(poll_interval).await;
         }
         let _ = bus_for_task.shutdown(drain_timeout).await;
-    });
-    // TODO(hubcio): `.detach()` races bus shutdown: when `bus.token()` is
-    // triggered, `shard_main` returns and the runtime drops the watchdog
-    // mid-`bus.shutdown()`, truncating in-flight `ClientForwardFailed`
-    // replies (terminal per `SendError` docs). Cannot use
-    // `bus.track_background(watchdog)` here because the watchdog itself
-    // drives `bus.shutdown()`, and the bg-drain loop in `shutdown()`
-    // would re-enter awaiting the watchdog's own pending shutdown call
-    // (self-deadlock). Fix: extract a `core/task_registry` crate mirroring
-    // `core/server`'s task-tracking mechanism, share it between the bus
-    // and server so background tasks can be reaped without coupling
-    // to the bus shutdown order.
-    watchdog.detach();
+    })
 }
 
 /// Copy the configured cluster roster plus this node's own client ports into
@@ -1790,6 +1805,11 @@ async fn build_shard_for_thread(
             segment_size: 
IggyByteSize::from(iggy_common::DEFAULT_SEGMENT_SIZE),
             preallocate_segments: iggy_common::DEFAULT_PREALLOCATE_SEGMENTS,
             encryptor,
+            path_layout: partitions::PartitionPathLayout {
+                streams_root: config.system.get_streams_path(),
+                topics_dir: config.system.topic.path.clone(),
+                partitions_dir: config.system.partition.path.clone(),
+            },
         },
         owned_partitions_capacity,
     );
@@ -2007,7 +2027,10 @@ async fn build_shard_for_thread(
             shard::ReplicaTopology::new(topology.self_replica_id, 
topology.replica_count),
             Rc::clone(&bus),
         ),
-        CoordinatorConfig::default(),
+        CoordinatorConfig {
+            skip_shard_zero_for_replicas: 
config.cluster.coordinator.skip_shard_zero_for_replicas,
+            skip_shard_zero_for_clients: 
config.cluster.coordinator.skip_shard_zero_for_clients,
+        },
         metrics,
     )
     .build()
diff --git a/core/server/src/dispatch.rs b/core/server/src/dispatch.rs
index 9251bf925..d3821b15b 100644
--- a/core/server/src/dispatch.rs
+++ b/core/server/src/dispatch.rs
@@ -3842,7 +3842,7 @@ mod tests {
     use metadata::stm::stream::Streams;
     use metadata::stm::user::Users;
     use metadata::{IggyMetadata, MuxStateMachine};
-    use partitions::{IggyPartitions, PartitionsConfig};
+    use partitions::{IggyPartitions, PartitionPathLayout, PartitionsConfig};
     use server_common::iobuf::Frozen;
     use server_common::sharding::ShardId;
     use server_common::{MESSAGE_ALIGN, Message, MessageBag};
@@ -3999,6 +3999,7 @@ mod tests {
                 segment_size: iggy_common::IggyByteSize::from(1_048_576_u64),
                 preallocate_segments: false,
                 encryptor: None,
+                path_layout: PartitionPathLayout::default(),
             },
         );
         TestShard::without_inbox(
@@ -4165,6 +4166,7 @@ mod tests {
                 segment_size: iggy_common::IggyByteSize::from(1_048_576_u64),
                 preallocate_segments: false,
                 encryptor: None,
+                path_layout: PartitionPathLayout::default(),
             },
         );
         let shard = Rc::new(TestShard::without_inbox(
@@ -4286,6 +4288,7 @@ mod tests {
                 segment_size: iggy_common::IggyByteSize::from(1_048_576_u64),
                 preallocate_segments: false,
                 encryptor: None,
+                path_layout: PartitionPathLayout::default(),
             },
         );
         let shard = Rc::new(TestShard::without_inbox(
@@ -4410,6 +4413,7 @@ mod tests {
                 segment_size: iggy_common::IggyByteSize::from(1_048_576_u64),
                 preallocate_segments: false,
                 encryptor: None,
+                path_layout: PartitionPathLayout::default(),
             },
         );
         let shard = Rc::new(TestShard::without_inbox(
@@ -4474,6 +4478,7 @@ mod tests {
                 segment_size: iggy_common::IggyByteSize::from(1_048_576_u64),
                 preallocate_segments: false,
                 encryptor: None,
+                path_layout: PartitionPathLayout::default(),
             },
         );
         // Real sender ring so the staged deny is observable: the test holds
diff --git a/core/server/src/main.rs b/core/server/src/main.rs
index f6a8e63e3..e2547efc7 100644
--- a/core/server/src/main.rs
+++ b/core/server/src/main.rs
@@ -71,7 +71,9 @@ fn main() -> Result<(), ServerError> {
     let bootstrap_result: Result<ServerConfig, ServerError> = 
bootstrap_runtime.block_on(async {
         let config = load_config().await?;
         prepare_runtime_dirs(&config, &mut logging, args.fresh).await?;
-        
server_common::MemoryPool::init_pool(&config.system.memory_pool.into_other());
+        let memory_pool_settings =
+            
server_common::MemoryPoolSettings::from(&config.system.memory_pool);
+        server_common::MemoryPool::init_pool(&memory_pool_settings);
 
         Ok(config)
     });
diff --git a/core/server/src/partition_reconciler.rs 
b/core/server/src/partition_reconciler.rs
index b456a30b8..fbf99df6b 100644
--- a/core/server/src/partition_reconciler.rs
+++ b/core/server/src/partition_reconciler.rs
@@ -1183,8 +1183,8 @@ mod tests {
         PurgeTopicRequest,
     };
     use iggy_binary_protocol::{
-        Command, Operation, PrepareHeader, ReplyHeader, RoutedRequestHeader, 
WireIdentifier,
-        WireOptions,
+        Command, Operation, PrepareHeader, RepairRangeReplyHeader, ReplyHeader,
+        RequestPreparesHeader, RoutedRequestHeader, WireIdentifier, 
WireOptions,
     };
     use message_bus::IggyMessageBus;
     use metadata::IggyMetadata;
@@ -1193,7 +1193,7 @@ mod tests {
     use metadata::stm::StateMachine;
     use metadata::stm::stream::Streams;
     use metadata::stm::user::Users;
-    use partitions::{IggyPartitions, PartitionsConfig};
+    use partitions::{IggyPartitions, PartitionPathLayout, PartitionsConfig, 
RepairSession};
     use server_common::sharding::{IggyNamespace, ShardId};
     use server_common::{Message, MessageBag};
     use shard::shards_table::{PapayaShardsTable, ShardsTable, 
calculate_shard_assignment};
@@ -1318,6 +1318,54 @@ mod tests {
         MessageBag::Request(msg)
     }
 
+    /// Build a partition-plane `RepairRangeReply` as the serving peer would
+    /// send it. Only the fields the receive path reads are stamped: routing
+    /// (`group`), session (`nonce`), and the verdict (`command`, `op`).
+    fn build_repair_range_reply(
+        namespace: IggyNamespace,
+        command: Command,
+        nonce: u128,
+        op: u64,
+    ) -> MessageBag {
+        let header_size = size_of::<RepairRangeReplyHeader>();
+        let mut msg = Message::<RepairRangeReplyHeader>::new(header_size);
+        let header = 
bytemuck::checked::try_from_bytes_mut::<RepairRangeReplyHeader>(
+            &mut msg.as_mut_slice()[..header_size],
+        )
+        .expect("zeroed bytes form a valid RepairRangeReplyHeader");
+        header.command = command;
+        header.size = u32::try_from(header_size).expect("header size fits 
u32");
+        header.nonce = nonce;
+        header.op = op;
+        header.group = namespace.inner();
+        MessageBag::RepairRangeReply(msg)
+    }
+
+    /// Build a partition-plane `RequestPrepares` as a rejoining peer would
+    /// send it. `replica` is the requester the serve path replies to.
+    fn build_request_prepares(
+        namespace: IggyNamespace,
+        replica: u8,
+        nonce: u128,
+        from_op: u64,
+        to_op: u64,
+    ) -> MessageBag {
+        let header_size = size_of::<RequestPreparesHeader>();
+        let mut msg = Message::<RequestPreparesHeader>::new(header_size);
+        let header = 
bytemuck::checked::try_from_bytes_mut::<RequestPreparesHeader>(
+            &mut msg.as_mut_slice()[..header_size],
+        )
+        .expect("zeroed bytes form a valid RequestPreparesHeader");
+        header.command = Command::RequestPrepares;
+        header.size = u32::try_from(header_size).expect("header size fits 
u32");
+        header.replica = replica;
+        header.nonce = nonce;
+        header.from_op = from_op;
+        header.to_op = to_op;
+        header.group = namespace.inner();
+        MessageBag::RequestPrepares(msg)
+    }
+
     fn assignment(partition_id: u32, consensus_group_id: u64) -> 
CreatedPartitionAssignment {
         CreatedPartitionAssignment {
             partition_id,
@@ -1468,6 +1516,7 @@ mod tests {
                 segment_size: 
iggy_common::IggyByteSize::from(iggy_common::DEFAULT_SEGMENT_SIZE),
                 preallocate_segments: false,
                 encryptor: None,
+                path_layout: PartitionPathLayout::default(),
             },
         );
         let shards_table = PapayaShardsTable::new();
@@ -2285,6 +2334,184 @@ mod tests {
         );
     }
 
+    /// Receive half of the purge gate in `on_repair_range_reply`: while a
+    /// committed purge has not applied locally, a repair verdict must be
+    /// deferred wholesale -- installing the peer's floor against pre-purge
+    /// segments silently loses the post-purge batches (offsets restarting at
+    /// 0 flush-skip below the stale durable line).
+    #[compio::test]
+    async fn repair_completion_defers_until_committed_purge_applies() {
+        const NONCE: u128 = 7;
+        let tmp = TempDir::new().expect("tempdir for system path");
+        let config = test_config(&tmp);
+        let mux = TestMux::default();
+        seed_stream(&mux, 1, "stream-repair-gate");
+        seed_topic(&mux, 2, 0, "topic-repair-gate", vec![assignment(0, 1)]);
+
+        let shard = build_test_shard(0, &config, mux);
+        let ctx = make_ctx(Rc::clone(&shard), 1, Rc::new(config));
+        reconcile_pass(&ctx).await;
+
+        let ns = IggyNamespace::new(0, 0, 0);
+        shard
+            .plane
+            .partitions()
+            .get_mut_by_ns(&ns)
+            .expect("partition is materialised")
+            .repair = Some(RepairSession {
+            nonce: NONCE,
+            to_op: 5,
+            floor: None,
+            peer: 1,
+            first_batch_offset: None,
+            idle_ticks: 0,
+        });
+
+        // Committed purge: generation 1 > applied 0.
+        let purge = PurgeTopicRequest {
+            stream_id: WireIdentifier::numeric(0),
+            topic_id: WireIdentifier::numeric(0),
+        };
+        shard
+            .plane
+            .metadata()
+            .mux_stm
+            .update(build_prepare(3, Operation::PurgeTopic, &purge))
+            .expect("PurgeTopic apply succeeds");
+
+        let deferred_before = shard
+            .metrics()
+            .partition_repair_serves_deferred_purge_value();
+        shard
+            .on_message(build_repair_range_reply(
+                ns,
+                Command::RangeEvicted,
+                NONCE,
+                4,
+            ))
+            .await;
+        let session = shard
+            .plane
+            .partitions()
+            .get_mut_by_ns(&ns)
+            .expect("partition survives the deferral")
+            .repair
+            .expect("deferral must leave the repair session armed");
+        assert_eq!(
+            session.floor, None,
+            "a deferred RangeEvicted must not install the peer's floor"
+        );
+        assert_eq!(
+            shard
+                .metrics()
+                .partition_repair_serves_deferred_purge_value(),
+            deferred_before + 1,
+            "the deferral must be visible on the purge-deferred counter"
+        );
+
+        // Apply the purge; the same frame now lands.
+        let partitions_config = shard.plane.partitions().config().clone();
+        shard
+            .plane
+            .partitions()
+            .get_mut_by_ns(&ns)
+            .expect("purged partition is materialised")
+            .purge(&partitions_config, 1)
+            .await
+            .expect("apply staged purge");
+        shard
+            .on_message(build_repair_range_reply(
+                ns,
+                Command::RangeEvicted,
+                NONCE,
+                4,
+            ))
+            .await;
+        let session = shard
+            .plane
+            .partitions()
+            .get_mut_by_ns(&ns)
+            .expect("partition survives the retry")
+            .repair
+            .expect("RangeEvicted records the floor but keeps the session");
+        assert_eq!(
+            session.floor,
+            Some(3),
+            "after the purge applies, the retried frame must install the floor"
+        );
+        assert_eq!(
+            shard
+                .metrics()
+                .partition_repair_serves_deferred_purge_value(),
+            deferred_before + 1,
+            "the retried frame must pass the gate without another deferral"
+        );
+    }
+
+    /// Serve half of the purge gate in `on_request_prepares`: while a
+    /// committed purge has not applied locally, the journal still holds
+    /// pre-purge entries with no floor to fence them, so serving a rejoiner
+    /// must be deferred (no reply; the requester's stall retry re-asks).
+    #[compio::test]
+    async fn repair_serve_defers_until_committed_purge_applies() {
+        const NONCE: u128 = 11;
+        let tmp = TempDir::new().expect("tempdir for system path");
+        let config = test_config(&tmp);
+        let mux = TestMux::default();
+        seed_stream(&mux, 1, "stream-serve-gate");
+        seed_topic(&mux, 2, 0, "topic-serve-gate", vec![assignment(0, 1)]);
+
+        let shard = build_test_shard(0, &config, mux);
+        let ctx = make_ctx(Rc::clone(&shard), 1, Rc::new(config));
+        reconcile_pass(&ctx).await;
+
+        let ns = IggyNamespace::new(0, 0, 0);
+        let purge = PurgeTopicRequest {
+            stream_id: WireIdentifier::numeric(0),
+            topic_id: WireIdentifier::numeric(0),
+        };
+        shard
+            .plane
+            .metadata()
+            .mux_stm
+            .update(build_prepare(3, Operation::PurgeTopic, &purge))
+            .expect("PurgeTopic apply succeeds");
+
+        let deferred_before = shard
+            .metrics()
+            .partition_repair_serves_deferred_purge_value();
+        shard
+            .on_message(build_request_prepares(ns, 1, NONCE, 1, 5))
+            .await;
+        assert_eq!(
+            shard
+                .metrics()
+                .partition_repair_serves_deferred_purge_value(),
+            deferred_before + 1,
+            "an unapplied purge must defer the serve"
+        );
+
+        let partitions_config = shard.plane.partitions().config().clone();
+        shard
+            .plane
+            .partitions()
+            .get_mut_by_ns(&ns)
+            .expect("purged partition is materialised")
+            .purge(&partitions_config, 1)
+            .await
+            .expect("apply staged purge");
+        shard
+            .on_message(build_request_prepares(ns, 1, NONCE, 1, 5))
+            .await;
+        assert_eq!(
+            shard
+                .metrics()
+                .partition_repair_serves_deferred_purge_value(),
+            deferred_before + 1,
+            "once the purge applies, the retried request must be served, not 
deferred"
+        );
+    }
+
     /// Permanent-tombstone-wedge regression: a teardown whose disk delete
     /// fails sets the tombstone and removes the `shards_table` row but never
     /// enqueues `ConfirmRemove`, so the tombstone never lifts. If the same
diff --git a/core/server/src/responses.rs b/core/server/src/responses.rs
index 6b7fc4ec5..5f9073ed5 100644
--- a/core/server/src/responses.rs
+++ b/core/server/src/responses.rs
@@ -703,6 +703,51 @@ where
     }
 }
 
+/// `(streams, topics, partitions, segments, message bytes, messages)` for the
+/// whole node, from committed metadata plus the shared stats registry.
+///
+/// Segments are summed PER PARTITION through the same floor the detail
+/// responses apply (see [`partition_response`]), not from the stream's 
rolled-up
+/// counter: that counter only advances once a partition materialises, which
+/// trails its commit by a reconciler pass. Summing it made `[stats]` report
+/// fewer segments than `get_topic` did for the same partitions, and let the
+/// total climb between two reads with no write in between.
+fn aggregate_stats_totals(
+    streams: &metadata::stm::stream::StreamsInner,
+) -> Result<(u32, u32, u32, u32, u64, u64), IggyError> {
+    let mut topics_count = 0u32;
+    let mut partitions_count = 0u32;
+    let mut segments_count = 0u32;
+    let mut messages_size_bytes = 0u64;
+    let mut messages_count = 0u64;
+    for (_, stream) in &streams.items {
+        topics_count = 
topics_count.saturating_add(usize_to_u32(stream.topics.len())?);
+        messages_size_bytes =
+            
messages_size_bytes.saturating_add(stream.stats.size_bytes_inconsistent());
+        messages_count = 
messages_count.saturating_add(stream.stats.messages_count_inconsistent());
+        for (_, topic) in &stream.topics {
+            partitions_count =
+                
partitions_count.saturating_add(usize_to_u32(topic.partitions.len())?);
+            for partition in &topic.partitions {
+                segments_count = 
segments_count.saturating_add(partition_segments_count(
+                    streams,
+                    stream.id,
+                    topic.id,
+                    partition.id,
+                ));
+            }
+        }
+    }
+    Ok((
+        usize_to_u32(streams.items.len())?,
+        topics_count,
+        partitions_count,
+        segments_count,
+        messages_size_bytes,
+        messages_count,
+    ))
+}
+
 fn build_stats_response<B, MJ, S, SB>(
     shard: &Rc<ShellShard<B, MJ, S, SB>>,
     clients_count: u32,
@@ -726,36 +771,7 @@ where
         .metadata()
         .mux_stm
         .streams()
-        .read(|streams| -> Result<_, IggyError> {
-            let mut topics_count = 0u32;
-            let mut partitions_count = 0u32;
-            let mut segments_count = 0u32;
-            let mut messages_size_bytes = 0u64;
-            let mut messages_count = 0u64;
-            for (_, stream) in &streams.items {
-                topics_count = 
topics_count.saturating_add(usize_to_u32(stream.topics.len())?);
-                messages_size_bytes =
-                    
messages_size_bytes.saturating_add(stream.stats.size_bytes_inconsistent());
-                messages_count =
-                    
messages_count.saturating_add(stream.stats.messages_count_inconsistent());
-                // Segment counts roll up from the partition plane through
-                // the shared stats registry (partition -> topic -> stream).
-                segments_count =
-                    
segments_count.saturating_add(stream.stats.segments_count_inconsistent());
-                for (_, topic) in &stream.topics {
-                    partitions_count =
-                        
partitions_count.saturating_add(usize_to_u32(topic.partitions.len())?);
-                }
-            }
-            Ok((
-                usize_to_u32(streams.items.len())?,
-                topics_count,
-                partitions_count,
-                segments_count,
-                messages_size_bytes,
-                messages_count,
-            ))
-        })?;
+        .read(aggregate_stats_totals)?;
     let consumer_groups_count = usize_to_u32(
         shard
             .plane
@@ -1325,6 +1341,29 @@ fn topic_header(topic: &metadata::stm::stream::Topic) -> 
Result<StreamTopicHeade
     })
 }
 
+/// Segments a committed partition reports before its storage exists.
+/// [`partition_response`] carries the reasoning.
+const MATERIALIZED_SEGMENTS_FLOOR: u32 = 1;
+
+/// Segments one committed partition reports. The single source for every
+/// client-facing segment count, so the `[stats]` total and the per-partition
+/// detail cannot disagree about the same partition.
+fn partition_segments_count(
+    streams: &metadata::stm::stream::StreamsInner,
+    stream_id: usize,
+    topic_id: usize,
+    partition_id: usize,
+) -> u32 {
+    streams
+        .stats_registry
+        .partition_get(stream_id, topic_id, partition_id)
+        .map_or(MATERIALIZED_SEGMENTS_FLOOR, |stats| {
+            stats
+                .segments_count_inconsistent()
+                .max(MATERIALIZED_SEGMENTS_FLOOR)
+        })
+}
+
 fn partition_response(
     streams: &metadata::stm::stream::StreamsInner,
     stream_id: usize,
@@ -1353,19 +1392,17 @@ fn partition_response(
     let stats = streams
         .stats_registry
         .partition_get(stream_id, topic_id, partition.id);
-    let (segments_count, current_offset, size_bytes, messages_count) =
-        stats.map_or((1, 0, 0, 0), |stats| {
-            (
-                stats.segments_count_inconsistent().max(1),
-                stats.current_offset(),
-                stats.size_bytes_inconsistent(),
-                stats.messages_count_inconsistent(),
-            )
-        });
+    let (current_offset, size_bytes, messages_count) = stats.map_or((0, 0, 0), 
|stats| {
+        (
+            stats.current_offset(),
+            stats.size_bytes_inconsistent(),
+            stats.messages_count_inconsistent(),
+        )
+    });
     Ok(PartitionResponse {
         id: usize_to_u32(partition.id)?,
         created_at: partition.created_at.as_micros(),
-        segments_count,
+        segments_count: partition_segments_count(streams, stream_id, topic_id, 
partition.id),
         current_offset,
         size_bytes,
         messages_count,
@@ -1857,6 +1894,65 @@ mod tests {
         assert_eq!(live.size_bytes, 64);
     }
 
+    #[test]
+    fn stats_totals_count_every_committed_partition_before_it_materialises() {
+        use iggy_common::{StreamStats, TopicStats};
+        use metadata::stm::stream::{Partition, Stream, StreamsInner, Topic};
+        use std::sync::atomic::AtomicUsize;
+
+        let created_at = IggyTimestamp::from(1u64);
+        let mut streams = StreamsInner::new();
+        let mut stream = Stream::new(Arc::from("stream"), created_at);
+        let topic_stats = Arc::new(TopicStats::new(stream.stats.clone()));
+        stream.topics.insert(Topic {
+            id: 0,
+            name: Arc::from("topic"),
+            created_at,
+            message_expiry: iggy_common::IggyExpiry::NeverExpire,
+            compression_algorithm: iggy_common::CompressionAlgorithm::None,
+            max_topic_size: iggy_common::MaxTopicSize::Unlimited,
+            options: iggy_common::ResourceOptions::default(),
+            stats: topic_stats.clone(),
+            partitions: vec![
+                Partition::new(0, 1, created_at, 0),
+                Partition::new(1, 1, created_at, 0),
+            ],
+            round_robin_counter: Arc::new(AtomicUsize::new(0)),
+            consumer_groups: ahash::AHashMap::default(),
+            consumer_group_index: ahash::AHashMap::default(),
+            next_consumer_group_id: 0,
+        });
+        streams.items.insert(stream);
+
+        // Only partition 0 has materialised. Counting the stream's rolled-up
+        // counter reported 1 here, so a caller polling `[stats]` twice saw the
+        // total climb to 2 with no write in between (and `get_topic` already
+        // reported 2 for the same partitions).
+        let stats = streams.stats_registry.partition(0, 0, 0, topic_stats);
+        stats.increment_segments_count(1);
+
+        let (_, _, partitions, segments, _, _) =
+            aggregate_stats_totals(&streams).expect("totals aggregate");
+        assert_eq!(partitions, 2);
+        assert_eq!(
+            segments, 2,
+            "an unmaterialised partition must contribute the same floor the 
detail response reports"
+        );
+
+        // Materialising the second partition changes nothing: the total was
+        // already the steady-state answer.
+        let late = streams.stats_registry.partition(
+            0,
+            0,
+            1,
+            Arc::new(TopicStats::new(Arc::new(StreamStats::default()))),
+        );
+        late.increment_segments_count(1);
+        let (_, _, _, segments_after, _, _) =
+            aggregate_stats_totals(&streams).expect("totals aggregate");
+        assert_eq!(segments_after, 2);
+    }
+
     #[test]
     fn topic_header_echoes_stored_size_and_expiry_verbatim() {
         use iggy_common::{
diff --git a/core/server_common/src/buffer.rs b/core/server_common/src/buffer.rs
index aa84101b7..79b018716 100644
--- a/core/server_common/src/buffer.rs
+++ b/core/server_common/src/buffer.rs
@@ -434,7 +434,7 @@ mod miri_tests {
     #[cfg(not(miri))]
     mod split_to {
         use super::*;
-        use crate::memory_pool::{MemoryPool, MemoryPoolConfigOther};
+        use crate::memory_pool::{MemoryPool, MemoryPoolSettings};
         use iggy_common::IggyByteSize;
         use serial_test::serial;
         use std::str::FromStr;
@@ -444,7 +444,7 @@ mod miri_tests {
 
         fn init_pool_for_split_to_tests() {
             MIRI_POOL_INIT.call_once(|| {
-                let config = MemoryPoolConfigOther {
+                let config = MemoryPoolSettings {
                     enabled: true,
                     size: IggyByteSize::from_str("64MiB").unwrap(),
                     bucket_capacity: 16,
diff --git a/core/server_common/src/executor.rs 
b/core/server_common/src/executor.rs
index ed8ea3637..8fb8cc842 100644
--- a/core/server_common/src/executor.rs
+++ b/core/server_common/src/executor.rs
@@ -20,6 +20,13 @@ use compio::runtime::Runtime;
 const DEFAULT_SHARD_RUNTIME_CAPACITY: u32 = 4096;
 const SHARD_RUNTIME_CAPACITY_ENV: &str = "IGGY_SHARD_RUNTIME_CAPACITY";
 
+/// How many tasks the runtime polls between driver (io_uring) sweeps. The
+/// default suits the stock task population; a deployment expecting far more
+/// connected clients (each connection is roughly one task) can raise it via
+/// [`SHARD_EVENT_INTERVAL_ENV`] to amortise driver sweeps across more work.
+const DEFAULT_SHARD_EVENT_INTERVAL: usize = 128;
+const SHARD_EVENT_INTERVAL_ENV: &str = "IGGY_SHARD_EVENT_INTERVAL";
+
 /// Resolves the per-shard io_uring SQ/CQ capacity from 
`IGGY_SHARD_RUNTIME_CAPACITY`,
 /// falling back to [`DEFAULT_SHARD_RUNTIME_CAPACITY`] when the var is missing 
or
 /// fails to parse as `u32`.
@@ -30,12 +37,26 @@ fn shard_capacity_from_env() -> u32 {
         .unwrap_or(DEFAULT_SHARD_RUNTIME_CAPACITY)
 }
 
+/// Resolves the runtime event interval from `IGGY_SHARD_EVENT_INTERVAL`,
+/// falling back to [`DEFAULT_SHARD_EVENT_INTERVAL`] when the var is missing,
+/// fails to parse, or is zero (compio treats the interval as a divisor).
+fn shard_event_interval_from_env() -> usize {
+    std::env::var(SHARD_EVENT_INTERVAL_ENV)
+        .ok()
+        .and_then(|v| v.parse::<usize>().ok())
+        .filter(|&interval| interval > 0)
+        .unwrap_or(DEFAULT_SHARD_EVENT_INTERVAL)
+}
+
 /// Creates a compio runtime for a shard thread, with shard-specific 
`io_uring` flags.
 ///
 /// The per-ring SQ/CQ capacity defaults to `4096` and can be overridden via 
the
 /// `IGGY_SHARD_RUNTIME_CAPACITY` env var, which the multi-node integration
 /// harness sets to `256` so N nodes * M shards fit under an 8 MiB
-/// `RLIMIT_MEMLOCK` budget without `ENOMEM` at ring setup.
+/// `RLIMIT_MEMLOCK` budget without `ENOMEM` at ring setup. The runtime event
+/// interval defaults to `128` and can be overridden via
+/// `IGGY_SHARD_EVENT_INTERVAL` for deployments whose task count (roughly the
+/// connected-client count) makes a different poll-to-sweep ratio pay off.
 ///
 /// # Errors
 ///
@@ -47,9 +68,6 @@ fn shard_capacity_from_env() -> u32 {
 /// Falling back to default flags would silently degrade shard performance -
 /// do not add a retry with reduced flags here.
 pub fn create_shard_executor() -> Result<Runtime, std::io::Error> {
-    // TODO: The event interval tick, could be configured based on the fact
-    // How many clients we expect to have connected.
-    // This roughly estimates the number of tasks we will create.
     let mut proactor = compio::driver::ProactorBuilder::new();
 
     proactor
@@ -57,45 +75,56 @@ pub fn create_shard_executor() -> Result<Runtime, 
std::io::Error> {
         .coop_taskrun(true)
         .taskrun_flag(true);
 
-    // FIXME(hubcio): Only set thread_pool_limit(0) on non-macOS platforms
-    // This causes a freeze on macOS with compio fs operations
-    // see https://github.com/compio-rs/compio/issues/446
+    // Permanent divergence, not a workaround to revisit: macOS runs compio's
+    // polling driver, which routes fs operations through the blocking pool, so
+    // a zero limit cannot work there by design. Upstream closed
+    // https://github.com/compio-rs/compio/issues/446 by making blocking-pool
+    // dispatch with no workers panic ("the thread pool is needed but no worker
+    // thread is running", compio-driver asyncify.rs) instead of freeze.
+    // io_uring targets keep the zero limit: no blocking pool exists on shard
+    // threads, which `core/partitions` messages_writer relies on to justify
+    // running fallocate inline (`spawn_blocking` would hit that same panic).
     #[cfg(not(all(target_os = "macos", target_arch = "aarch64")))]
     proactor.thread_pool_limit(0);
 
     compio::runtime::RuntimeBuilder::new()
         .with_proactor(proactor.to_owned())
-        .event_interval(128)
+        .event_interval(shard_event_interval_from_env())
         .build()
 }
 
 #[cfg(test)]
 mod tests {
     use super::{
-        DEFAULT_SHARD_RUNTIME_CAPACITY, SHARD_RUNTIME_CAPACITY_ENV, 
shard_capacity_from_env,
+        DEFAULT_SHARD_EVENT_INTERVAL, DEFAULT_SHARD_RUNTIME_CAPACITY, 
SHARD_EVENT_INTERVAL_ENV,
+        SHARD_RUNTIME_CAPACITY_ENV, shard_capacity_from_env, 
shard_event_interval_from_env,
     };
     use serial_test::serial;
 
-    fn with_capacity_env<R>(value: Option<&str>, f: impl FnOnce() -> R) -> R {
+    fn with_env<R>(name: &str, value: Option<&str>, f: impl FnOnce() -> R) -> 
R {
         // SAFETY: tests in this module are #[serial], so no other thread races
         // on the process-wide environment while the guard is active.
-        let prev = std::env::var(SHARD_RUNTIME_CAPACITY_ENV).ok();
+        let prev = std::env::var(name).ok();
         unsafe {
             match value {
-                Some(v) => std::env::set_var(SHARD_RUNTIME_CAPACITY_ENV, v),
-                None => std::env::remove_var(SHARD_RUNTIME_CAPACITY_ENV),
+                Some(v) => std::env::set_var(name, v),
+                None => std::env::remove_var(name),
             }
         }
         let out = f();
         unsafe {
             match prev {
-                Some(v) => std::env::set_var(SHARD_RUNTIME_CAPACITY_ENV, v),
-                None => std::env::remove_var(SHARD_RUNTIME_CAPACITY_ENV),
+                Some(v) => std::env::set_var(name, v),
+                None => std::env::remove_var(name),
             }
         }
         out
     }
 
+    fn with_capacity_env<R>(value: Option<&str>, f: impl FnOnce() -> R) -> R {
+        with_env(SHARD_RUNTIME_CAPACITY_ENV, value, f)
+    }
+
     #[test]
     #[serial]
     fn shard_capacity_from_env_uses_parsed_value() {
@@ -127,4 +156,45 @@ mod tests {
             assert_eq!(shard_capacity_from_env(), 
DEFAULT_SHARD_RUNTIME_CAPACITY);
         });
     }
+
+    #[test]
+    #[serial]
+    fn shard_event_interval_from_env_uses_parsed_value() {
+        with_env(SHARD_EVENT_INTERVAL_ENV, Some("512"), || {
+            assert_eq!(shard_event_interval_from_env(), 512);
+        });
+    }
+
+    #[test]
+    #[serial]
+    fn shard_event_interval_from_env_falls_back_when_unset() {
+        with_env(SHARD_EVENT_INTERVAL_ENV, None, || {
+            assert_eq!(
+                shard_event_interval_from_env(),
+                DEFAULT_SHARD_EVENT_INTERVAL
+            );
+        });
+    }
+
+    #[test]
+    #[serial]
+    fn shard_event_interval_from_env_falls_back_on_unparsable() {
+        with_env(SHARD_EVENT_INTERVAL_ENV, Some("not-a-number"), || {
+            assert_eq!(
+                shard_event_interval_from_env(),
+                DEFAULT_SHARD_EVENT_INTERVAL
+            );
+        });
+    }
+
+    #[test]
+    #[serial]
+    fn shard_event_interval_from_env_falls_back_on_zero() {
+        with_env(SHARD_EVENT_INTERVAL_ENV, Some("0"), || {
+            assert_eq!(
+                shard_event_interval_from_env(),
+                DEFAULT_SHARD_EVENT_INTERVAL
+            );
+        });
+    }
 }
diff --git a/core/server_common/src/lib.rs b/core/server_common/src/lib.rs
index c8fa01d42..f7b710658 100644
--- a/core/server_common/src/lib.rs
+++ b/core/server_common/src/lib.rs
@@ -39,7 +39,7 @@ pub use consensus_message::{
     MutableBacking, RequestBacking, RequestBackingKind, ResponseBacking, 
ResponseBackingKind,
 };
 pub use executor::create_shard_executor;
-pub use memory_pool::{MEMORY_POOL, MemoryPool, MemoryPoolConfigOther, 
memory_pool};
+pub use memory_pool::{MEMORY_POOL, MemoryPool, MemoryPoolSettings, 
memory_pool};
 pub use segment_storage::{
     IndexReader, IndexWriter, MessagesReader, MessagesWriter, SegmentStorage,
 };
diff --git a/core/server_common/src/memory_pool.rs 
b/core/server_common/src/memory_pool.rs
index b55c1c64a..a30ed4b2e 100644
--- a/core/server_common/src/memory_pool.rs
+++ b/core/server_common/src/memory_pool.rs
@@ -70,12 +70,11 @@ pub fn memory_pool() -> &'static MemoryPool {
         .expect("Memory pool not initialized - MemoryPool::init_pool should be 
called first")
 }
 
-// TODO: Extract shared domain types (IggyByteSize, IggyDuration, etc.) into 
an `iggy_types`
-// leaf crate so `iggy_common` can depend on `configs` directly. That lets us 
delete this
-// duplicate and use `configs::server::MemoryPoolConfig` here instead.
-/// Configuration for the memory pool.
+/// Pool settings, converted from the serde-facing config type in
+/// `configs::server::MemoryPoolConfig` (which depends on this crate, so the
+/// domain type has to live here - same split as 
[`crate::log::TelemetrySettings`]).
 #[derive(Debug)]
-pub struct MemoryPoolConfigOther {
+pub struct MemoryPoolSettings {
     /// Whether the pool is enabled.
     pub enabled: bool,
     /// Maximum size of the pool.
@@ -162,11 +161,11 @@ impl MemoryPool {
         }
     }
 
-    /// Initialize the global pool from the given config.
-    pub fn init_pool(config: &MemoryPoolConfigOther) {
-        let is_enabled = config.enabled;
-        let memory_limit = config.size.as_bytes_usize();
-        let bucket_capacity = config.bucket_capacity as usize;
+    /// Initialize the global pool from the given settings.
+    pub fn init_pool(settings: &MemoryPoolSettings) {
+        let is_enabled = settings.enabled;
+        let memory_limit = settings.size.as_bytes_usize();
+        let bucket_capacity = settings.bucket_capacity as usize;
 
         let _ =
             MEMORY_POOL.get_or_init(|| MemoryPool::new(is_enabled, 
memory_limit, bucket_capacity));
@@ -502,12 +501,12 @@ mod tests {
 
     fn initialize_pool_for_tests() {
         TEST_INIT.call_once(|| {
-            let config = MemoryPoolConfigOther {
+            let settings = MemoryPoolSettings {
                 enabled: true,
                 size: IggyByteSize::from_str("4GiB").unwrap(),
                 bucket_capacity: 8192,
             };
-            MemoryPool::init_pool(&config);
+            MemoryPool::init_pool(&settings);
         });
     }
 
diff --git a/core/shard/src/config.rs b/core/shard/src/config.rs
index 27535c2e9..0406210b1 100644
--- a/core/shard/src/config.rs
+++ b/core/shard/src/config.rs
@@ -17,11 +17,10 @@
 
 //! Runtime tunables for the shard-0 coordinator.
 //!
-//! TODO: move this module into `core/configs` (as a `CoordinatorConfig`
-//! section nested under `ClusterConfig`) once downstream bootstrap
-//! wiring that constructs [`crate::coordinator::ShardZeroCoordinator`]
-//! from `ServerConfig` lands. Kept in-crate for now to avoid churning
-//! the configs crate ahead of that wiring.
+//! The serde-facing section lives in `core/configs` as
+//! `[cluster.coordinator]` (`ClusterCoordinatorConfig`); the server's
+//! bootstrap converts it into this domain type. The split exists because
+//! `configs` and `shard` share no dependency edge.
 
 /// Tunables for [`crate::coordinator::ShardZeroCoordinator`].
 #[derive(Debug, Clone)]
diff --git a/core/shard/src/lib.rs b/core/shard/src/lib.rs
index 4e20691b0..a51dfa25f 100644
--- a/core/shard/src/lib.rs
+++ b/core/shard/src/lib.rs
@@ -4611,11 +4611,9 @@ where
         // Defer the whole reply: the purge is one reconciler wake away and
         // resets the line to `None`, and the stall retry re-asks, so the peer
         // re-emits both `RangeEvicted` and `RepairDone` for the same window.
-        // TODO(hubcio): no direct test drives this gate -- 
`on_repair_range_reply`
-        // is only reachable through the real message bus and the shard crate 
has
-        // no fixture for it (the serve-side gate shares the gap). The loss 
shape
-        // is pinned at the partition level instead; a bus fixture would let 
both
-        // gates be exercised end to end.
+        // Pinned by `repair_completion_defers_until_committed_purge_applies`
+        // (server crate, partition_reconciler tests), driven through the pub
+        // `on_message` entry; the serve-side twin has its own pin there.
         let committed_purge = self
             .plane
             .metadata()
diff --git a/core/simulator/src/bin/simulator-ui.rs 
b/core/simulator/src/bin/simulator-ui.rs
index 3de3100b6..041a7c886 100644
--- a/core/simulator/src/bin/simulator-ui.rs
+++ b/core/simulator/src/bin/simulator-ui.rs
@@ -20,7 +20,7 @@ use iggy_binary_protocol::ReplyHeader;
 use iggy_common::{IggyByteSize, PollingStrategy};
 use partitions::{PollingArgs, PollingConsumer};
 use server_common::sharding::IggyNamespace;
-use server_common::{MemoryPool, MemoryPoolConfigOther, Message};
+use server_common::{MemoryPool, MemoryPoolSettings, Message};
 use simulator::Simulator;
 use simulator::client::SimClient;
 use simulator::packet::PacketSimulatorOptions;
@@ -41,7 +41,7 @@ fn step_until_reply(sim: &mut Simulator, max_ticks: u64) -> 
Vec<Message<ReplyHea
 fn main() {
     // PooledBuffer::from (used by poll_messages) panics if the global pool is 
uninitialized.
     // Disabled pooling just falls through to the system allocator.
-    MemoryPool::init_pool(&MemoryPoolConfigOther {
+    MemoryPool::init_pool(&MemoryPoolSettings {
         enabled: false,
         size: IggyByteSize::from(0u64),
         bucket_capacity: 1,
diff --git a/core/simulator/src/bin/workload-fuzz.rs 
b/core/simulator/src/bin/workload-fuzz.rs
index fc495f8af..11d8c865f 100644
--- a/core/simulator/src/bin/workload-fuzz.rs
+++ b/core/simulator/src/bin/workload-fuzz.rs
@@ -38,7 +38,7 @@
 use clap::Parser;
 use iggy_common::IggyByteSize;
 use server_common::sharding::IggyNamespace;
-use server_common::{MemoryPool, MemoryPoolConfigOther};
+use server_common::{MemoryPool, MemoryPoolSettings};
 use simulator::Simulator;
 use simulator::client::SimClient;
 use simulator::packet::PacketSimulatorOptions;
@@ -102,7 +102,7 @@ fn main() {
 
     // poll_messages / reply paths panic without an initialized pool; disabled
     // pooling falls through to the system allocator.
-    MemoryPool::init_pool(&MemoryPoolConfigOther {
+    MemoryPool::init_pool(&MemoryPoolSettings {
         enabled: false,
         size: IggyByteSize::from(0u64),
         bucket_capacity: 1,
diff --git a/core/simulator/src/lib.rs b/core/simulator/src/lib.rs
index fa5b3e316..17f24a620 100644
--- a/core/simulator/src/lib.rs
+++ b/core/simulator/src/lib.rs
@@ -994,7 +994,7 @@ mod tests {
     /// heartbeat timeout and elect a new primary via view change.
     #[test]
     fn view_change_after_primary_crash() {
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -1092,7 +1092,7 @@ mod tests {
     /// Impossible before the superblock, since a rebuilt consensus starts at 
view 0.
     #[test]
     fn 
given_advanced_view_when_metadata_replica_restarts_should_recover_view_from_superblock()
 {
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -1202,7 +1202,7 @@ mod tests {
 
     #[test]
     fn 
given_committed_metadata_when_solo_replica_restarts_should_recover_from_own_wal()
 {
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -1300,7 +1300,7 @@ mod tests {
 
     #[test]
     fn 
given_registered_client_when_solo_replica_restarts_should_recover_session_from_own_wal()
 {
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -1367,7 +1367,7 @@ mod tests {
         // split-brain on its restart. The positive control is
         // `given_advanced_view_when_metadata_replica_restarts_...`, which 
elects a new
         // primary from the same crash with healthy superblocks.
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -1456,7 +1456,7 @@ mod tests {
     /// dedup if they need at-most-once-per-payload.
     #[test]
     fn failover_retry_re_executes_under_at_least_once() {
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -1571,7 +1571,7 @@ mod tests {
     /// `handle_commit_message_timeout` used to assert `commit_min == 
commit_max`.
     #[test]
     fn view_change_behind_backup_becomes_primary() {
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -1639,7 +1639,7 @@ mod tests {
     /// and workload) produces an identical reply-header sequence.
     #[test]
     fn workload_replay_is_deterministic() {
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -1696,7 +1696,7 @@ mod tests {
         };
         use strum::{EnumCount, IntoEnumIterator};
 
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -1766,7 +1766,7 @@ mod tests {
         };
         use strum::{EnumCount, IntoEnumIterator};
 
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -1832,7 +1832,7 @@ mod tests {
             options::{ActionWeights, WorkloadOptions},
         };
 
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -1905,7 +1905,7 @@ mod tests {
             oracle,
         };
 
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -1963,7 +1963,7 @@ mod tests {
             options::{ActionWeights, WorkloadOptions},
             oracle,
         };
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -2029,7 +2029,7 @@ mod tests {
             options::{ActionWeights, WorkloadOptions},
         };
 
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -2119,7 +2119,7 @@ mod tests {
             options::{ActionWeights, WorkloadOptions},
         };
 
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -2212,7 +2212,7 @@ mod tests {
             options::{ActionWeights, WorkloadOptions},
         };
 
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -2394,7 +2394,7 @@ mod tests {
         use consensus::MetadataHandle;
         use shard::shards_table::{ShardsTable, calculate_shard_assignment};
 
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -2445,7 +2445,7 @@ mod tests {
     fn peer_shard_resolves_namespace_via_shard0_read_handle() {
         use iggy_binary_protocol::WireIdentifier;
 
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -2499,7 +2499,7 @@ mod tests {
     /// post-change send commits through the mesh.
     #[test]
     fn multi_shard_view_change_after_primary_crash() {
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -2598,7 +2598,7 @@ mod tests {
     /// Schedule hash for `seed` after stepping the consensus plane with no
     /// client traffic, with the dispatch shell on or off.
     fn consensus_schedule_hash(seed: u64, shell: bool) -> u64 {
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -2650,7 +2650,7 @@ mod tests {
     /// plus its metadata, log a client in against root, produce one message,
     /// then poll. Returns the poll reply's raw bytes and the schedule hash.
     fn shell_produce_poll(seed: u64) -> (Vec<u8>, u64) {
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -2760,7 +2760,7 @@ mod tests {
         use consensus::PartitionsHandle;
         use std::panic::{AssertUnwindSafe, catch_unwind};
 
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -2859,7 +2859,7 @@ mod tests {
         use consensus::PartitionsHandle;
         use std::panic::{AssertUnwindSafe, catch_unwind};
 
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -2957,7 +2957,7 @@ mod tests {
         use consensus::MetadataHandle;
         use journal::{Journal, JournalHandle};
 
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -3069,7 +3069,7 @@ mod tests {
             header.group == BLOCKED_NS.load(Ordering::Relaxed)
         }
 
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -3177,7 +3177,7 @@ mod tests {
             oracle,
         };
 
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -3295,7 +3295,7 @@ mod view_change_data_loss_tests {
     #[test]
     fn 
given_committed_op_missing_on_next_primary_when_primary_crashes_should_survive_view_change()
     {
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
@@ -3393,7 +3393,7 @@ mod view_change_data_loss_tests {
     #[test]
     fn 
given_a_register_inside_the_view_start_persist_when_the_pipeline_rebuilds_should_commit_once()
      {
-        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolConfigOther {
+        
server_common::MemoryPool::init_pool(&server_common::MemoryPoolSettings {
             enabled: false,
             size: iggy_common::IggyByteSize::from(0u64),
             bucket_capacity: 1,
diff --git a/core/simulator/src/replica.rs b/core/simulator/src/replica.rs
index 2764b96da..362f3a144 100644
--- a/core/simulator/src/replica.rs
+++ b/core/simulator/src/replica.rs
@@ -27,7 +27,7 @@ use metadata::stm::mux::WithFactory;
 use metadata::stm::stream::{Streams, StreamsInner};
 use metadata::stm::user::{Users, UsersInner};
 use metadata::{IggyMetadata, apply_committed_prepare};
-use partitions::{IggyPartitions, PartitionsConfig};
+use partitions::{IggyPartitions, PartitionPathLayout, PartitionsConfig};
 use server::bootstrap::{ShellHandlers, ShellShardHandle, wire_shell_handlers};
 use server_common::crypto;
 use server_common::sharding::{METADATA_GROUP, ShardId};
@@ -287,6 +287,7 @@ pub fn new_shard(
         segment_size: IggyByteSize::from(1024 * 1024 * 1024),
         preallocate_segments: false,
         encryptor: None,
+        path_layout: PartitionPathLayout::default(),
     };
 
     // Shard id is the NODE-LOCAL shard index, never the replica id: the

Reply via email to