Rust API
The Rust API is generated by rustdoc. Build locally with:
cargo doc --workspace --no-deps --open
Top-level surface
| Item | Kind | Purpose |
|---|---|---|
PhaseRouter | struct | Per-request token-stream state machine |
MeridianScheduler | struct | Dual-queue batch scheduler |
BlockManager | trait | Three-tier KV block manager contract |
PhaseAwareBlockManager | struct | Default BlockManager impl |
types | module | ThinkPhase, PhaseEvent, BlockTier, EntropySignal, BlockLocation |
MeridianConfig | struct | Deserialised TOML config |
dspark_bridge | module | Phase-conditioned speculative decoding — bounds, hook, acceptance ledger |
dspark_bridge at a glance
| Item | Kind | Purpose |
|---|---|---|
confidence_model | module | Formal model of DSpark's confidence head and Meridian's EAT/RPDI signal, plus the propositions relating them |
PhaseConditioningHook | struct | Phase label + entropy sample → recommended draft depth |
AcceptanceLedger | struct | Phase-segmented acceptance accounting; Welch comparison |
Provenance | enum | Synthetic-vs-measured gate; the only path to a publishable claim |
SpeculationPhase | enum | Coarsening of ThinkPhase for the speculation path |
Ships uncalibrated, and stays that way until a phase-segmented measurement exists. See ADR-0009 for why an uncalibrated hook can only ever shrink a draft budget, never grow it.
Object lifecycle
PhaseRouter
PhaseRouter is Send + Sync. Create once, share across threads via Arc.
Call process_token(req_id, token_id) from any thread; it returns an
Option<PhaseEvent> and is O(1) per call.
Call reap_stale_older_than(duration) periodically to free entries for
completed requests. The vLLM plugin does this on every batch step.
#![allow(unused)] fn main() { use meridian_core::PhaseRouter; use std::sync::Arc; use std::time::Duration; let router = Arc::new(PhaseRouter::new()); // Per-token — called from the decode loop. if let Some(event) = router.process_token(req_id, token_id) { // Handle PhaseEvent::ExitThink, ForceBudget, etc. } // Periodic cleanup — call from the batch step hook. let reaped = router.reap_stale_older_than(Duration::from_secs(60)); }
MeridianScheduler
MeridianScheduler is Send + Sync. The schedule_batch method takes a
shared reference and returns owned Vec<RequestId> for each queue; it does not
hold a lock across the call boundary.
BlockManager trait
The three required methods:
#![allow(unused)] fn main() { fn allocate(&mut self, request_id: RequestId, tier: BlockTier) -> Result<BlockId>; fn evict_for(&mut self, required_blocks: usize) -> Vec<BlockId>; fn block_location(&self, block_id: BlockId) -> BlockLocation; }
Optional disagg methods (offload_block, ingest_block) have default
implementations that return Err(BlockManagerError::FabricNotConfigured).
Override them when wrapping with a NIXL-backed manager.
Error model
All errors implement std::error::Error and are defined in
meridian_core::error::Error. Configuration errors carry the dotted field
path and a human-readable message:
ConfigValidation { field: "entropy.ema_alpha", reason: "must be in (0, 1]" }
Kernel errors are defined in meridian_kernels::KernelError:
Unavailable— built without thecudafeature or runtime missing.Launch(i32)— CUDA returned a non-zero error code.NullPointer(&'static str)— caller passed a null pointer.
Thread safety
| Type | Thread safety |
|---|---|
PhaseRouter | Send + Sync via DashMap interior mutability |
MeridianScheduler | Send + Sync |
PhaseAwareBlockManager | Send; requires &mut self for mutation — wrap in Mutex for shared access |
NixlContext (feature nixl) | Send; not Sync — one context per thread |
Stability
Pre-1.0. Public API breakage is recorded under BREAKING CHANGE: in
CHANGELOG.md.
The C ABI (meridian_entropy_launch, meridian_eat_launch) is treated as
stable from v0.1.0 — forks consuming the FFI directly will not see unexpected
breakage on patch updates.