tidaldb/docs/planning/milestone-8/phase-1/task-05-node-config.md
jordan f4cfd6c81f feat: complete M8 replication primitives + forage enhancements + docs
Milestone 8 (phases 1-4):
- Shard-aware WAL segment naming, BatchHeader v2, ShardRouter
- Transport trait, InProcessTransport, WalShipper, FollowerDb
- HLC, PNCounter, LWWRegister, CrdtSignalState, ReconciliationEngine
- Session replication bridge with SeqNo/HWM, idempotency store

Forage application:
- Multi-source discovery engine with MAB exploration
- Embedding-based label system, server handlers, UI refresh

Other:
- QUICKSTART.md, README.md, milestone-8 planning docs
- Hard negative union semantics, RLHF export enhancements
- Recovery benchmark and visibility test expansions
- Split 8 oversized source files per CODING_GUIDELINES §9

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 13:17:19 -07:00

124 lines
3.5 KiB
Markdown

# Task 05: NodeConfig
## Delivers
Add `NodeConfig` struct to `tidal/src/db/config.rs` extending `Config` with cluster fields (`role`, `shard_id`, `region_id`, `peer_shards`). Defaults produce a single-node config with zero changes to existing embedders.
## Complexity: S
## Dependencies
- Task 01 (ShardId, RegionId, NodeRole types)
- Task 02 (ShardRouter)
## Technical Design
```rust
// tidal/src/db/config.rs
/// Cluster configuration for distributed tidalDB deployments.
///
/// Defaults produce a single-node configuration identical to M0-M7 behavior.
/// Embedded deployments that do not set any cluster fields get single-node.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct NodeConfig {
/// The role of this node.
///
/// Default: `NodeRole::Single` (standalone, accepts reads and writes).
pub role: NodeRole,
/// This node's shard identity.
///
/// Default: `ShardId(0)` (single-node shard).
pub shard_id: ShardId,
/// This node's region identity.
///
/// Default: `RegionId(0)` (single-node region).
pub region_id: RegionId,
/// Shards this node is aware of (including itself).
///
/// Empty for single-node deployments.
pub peer_shards: Vec<ShardId>,
/// Routing strategy for entity-to-shard assignment.
///
/// Default: `ShardRouter::single()` (all entities -> ShardId(0)).
#[serde(skip)]
pub router: ShardRouter,
}
impl Default for NodeConfig {
fn default() -> Self {
Self {
role: NodeRole::Single,
shard_id: ShardId::SINGLE,
region_id: RegionId::SINGLE,
peer_shards: vec![],
router: ShardRouter::single(),
}
}
}
impl NodeConfig {
/// Returns true if this is a standalone single-node deployment.
pub fn is_single_node(&self) -> bool {
self.role == NodeRole::Single
}
/// Returns true if this node accepts writes.
pub fn accepts_writes(&self) -> bool {
matches!(self.role, NodeRole::Single | NodeRole::Leader)
}
}
```
### Integration into Config
```rust
// tidal/src/db/config.rs -- extend existing Config struct
pub struct Config {
// ... existing fields ...
/// Cluster configuration. Default: single-node.
pub cluster: NodeConfig,
}
impl Default for Config {
fn default() -> Self {
Self {
// ... existing defaults ...
cluster: NodeConfig::default(),
}
}
}
```
### Builder integration
```rust
// TidalDb::builder() -- add optional cluster config method
impl TidalDbBuilder {
/// Configure this instance for distributed deployment.
///
/// Not required for single-node embedded use.
pub fn with_cluster(mut self, config: NodeConfig) -> Self {
self.config.cluster = config;
self
}
}
```
## Acceptance Criteria
- [ ] `NodeConfig::default()` produces `role=Single`, `shard_id=ShardId(0)`, `region_id=RegionId(0)`, `peer_shards=[]`, `router=ShardRouter::single()`
- [ ] `NodeConfig::is_single_node()` returns true for `Single`, false for `Leader`/`Follower`
- [ ] `NodeConfig::accepts_writes()` returns true for `Single` and `Leader`, false for `Follower`
- [ ] `Config` gains a `cluster: NodeConfig` field with default `NodeConfig::default()`
- [ ] All existing tests that construct `Config` or use `TidalDb::builder()` pass unchanged (cluster field defaults to single-node)
- [ ] `TidalDbBuilder::with_cluster(config)` sets the cluster config
- [ ] `cargo clippy -D warnings` and `cargo fmt` pass