lattice_embed/backfill/types.rs
1//! Defines migration-time routing decisions and backfill configuration.
2//!
3//! The routing configuration separates query and write model selection so a completed
4//! cutover can retain source writes during its rollback window.
5//!
6//! See [docs/backfill.md](../../docs/backfill.md) for the routing contract and defaults.
7
8use serde::{Deserialize, Serialize};
9
10use crate::model::EmbeddingModel;
11
12/// Routing decision for an embedding request during migration.
13///
14/// Determines which model should handle an embedding operation based on
15/// the current migration state and the nature of the request.
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub enum EmbeddingRoute {
18 /// Use the current (legacy) model -- no migration active or migration
19 /// incomplete for this operation type.
20 Legacy,
21 /// Use the new (target) model -- migration complete or sufficient
22 /// progress for query routing.
23 Target,
24 /// Embed with both models (dual-write) -- during active migration
25 /// for new documents to ensure both indexes stay current.
26 DualWrite,
27}
28
29/// Phase of the migration lifecycle for routing decisions.
30///
31/// Distinguishes between normal operation, active migration, and the
32/// post-cutover rollback window where dual-writing continues to enable
33/// safe rollback without data loss.
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
35#[serde(rename_all = "snake_case")]
36pub enum RoutingPhase {
37 /// Normal operation, no migration active.
38 Stable,
39 /// Active migration in progress.
40 Migrating,
41 /// Post-cutover rollback window (still dual-writing).
42 ///
43 /// During this phase, queries use the target model but writes go to
44 /// both models. This enables instant rollback without losing atoms
45 /// created after cutover.
46 RollbackWindow,
47}
48
49/// Configuration for embedding request routing.
50///
51/// Query and write selections are separate so a rollback window can preserve source writes.
52/// See [docs/backfill.md](../../docs/backfill.md) for how each phase is represented.
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct EmbeddingRoutingConfig {
55 /// Which model to query against.
56 pub query_model: EmbeddingModel,
57 /// Which models to write to (may be multiple for dual-write).
58 pub write_models: Vec<EmbeddingModel>,
59 /// Current routing phase.
60 pub phase: RoutingPhase,
61 /// Migration ID if in migration/rollback phase.
62 pub migration_id: Option<String>,
63}
64
65/// Configuration for the backfill coordinator.
66///
67/// Controls batch sizing, caller-managed concurrency, routing, and rollback timing.
68/// See [docs/backfill.md](../../docs/backfill.md) for default values and policy semantics.
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct BackfillConfig {
71 /// Batch size for backfill operations.
72 pub batch_size: usize,
73 /// Maximum concurrent backfill batches.
74 pub max_concurrent: usize,
75 /// Whether new documents should be dual-written during migration.
76 pub dual_write: bool,
77 /// Raw progress threshold at which query routing may choose the target model.
78 pub target_query_threshold: f64,
79 /// Seconds to retain both write models after a completed cutover.
80 pub rollback_window_secs: u64,
81}
82
83impl Default for BackfillConfig {
84 fn default() -> Self {
85 Self {
86 batch_size: 100,
87 max_concurrent: 4,
88 dual_write: true,
89 target_query_threshold: 0.8,
90 rollback_window_secs: 86400, // 24 hours
91 }
92 }
93}