Skip to main content

kevy_scope/
lib.rs

1//! kevy-scope — scoped multi-writer ownership table.
2//!
3//! Phase 3 of the v3-cluster RFC: a key prefix (`app:billing:`) is
4//! declared to belong to one writer node; writes landing on any
5//! other node answer `-MISDIRECTED writer is <host:port>`. This crate
6//! is the pure-data "stone" layer — config-driven ownership table,
7//! longest-prefix routing, MOVE-SCOPE quiesce-window state machine —
8//! without any I/O. The kevy server's cement layer plugs it in.
9//!
10//! See `.claude/rfcs/2026-06-18-v3-cluster.md` `## Q3 resolution`
11//! for the locked design (MOVE-SCOPE = option (a) quiesce-window;
12//! no write-shadowing, no 2PC, no per-key MIGRATE/ASK).
13//!
14//! Anti-scope (don't add):
15//! - Cross-scope transactions (a single MULTI/EXEC may not touch keys
16//!   in two scopes; the client splits by scope).
17//! - Automatic scope migration on `kevy-elect` ANNOUNCE — operator-
18//!   issued only.
19//! - Write-shadowing during migration; the writer quiesces, ships,
20//!   and only then flips ownership.
21//!
22//! # Quick start (config side)
23//!
24//! ```rust
25//! use kevy_scope::{OwnershipTable, Scope};
26//!
27//! let table = OwnershipTable::new(vec![
28//!     Scope::new(b"app:billing:".to_vec(), "embed-billing-1".to_string())
29//!         .with_fallback("server-eu-1".to_string()),
30//!     Scope::new(b"app:auth:".to_vec(), "embed-auth-1".to_string()),
31//! ])
32//! .expect("non-overlapping prefixes");
33//!
34//! // Local node looks up routing for a key.
35//! let routing = table.route(b"app:billing:invoice:42", "embed-billing-1");
36//! assert!(routing.is_local_writer());
37//!
38//! // Same key arriving on the wrong node:
39//! let routing = table.route(b"app:billing:invoice:42", "server-eu-1");
40//! // server-eu-1 is the fallback, not the live writer — depending on
41//! // F4 fallback state, routing is Misdirected or Owned. See the
42//! // `route_with_fallback_state` API for the state-aware lookup.
43//! assert!(matches!(routing, kevy_scope::Routing::Misdirected { .. }));
44//! ```
45#![forbid(unsafe_code)]
46
47mod migration;
48mod ownership;
49mod routing;
50mod scope;
51
52pub use migration::{MigrationError, MigrationState, MigrationTable};
53pub use ownership::{OwnershipError, OwnershipTable};
54pub use routing::Routing;
55pub use scope::Scope;