1use crate::serde_json::Value as JsonValue;
20use crate::storage::UnifiedStore;
21
22#[inline]
23fn num(v: f64) -> JsonValue {
24 JsonValue::Number(v)
25}
26
27#[inline]
28fn text(s: &str) -> JsonValue {
29 JsonValue::String(s.to_string())
30}
31
32#[derive(Debug, Clone)]
35pub struct ConfigDefault {
36 pub key: &'static str,
37 pub tier: Tier,
38 pub default: fn() -> JsonValue,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum Tier {
46 Critical,
48 Optional,
50}
51
52pub const MATRIX: &[ConfigDefault] = &[
54 ConfigDefault {
56 key: "cache.blob.l1_bytes_max",
57 tier: Tier::Critical,
58 default: || num(crate::storage::cache::DEFAULT_BLOB_L1_BYTES_MAX as f64),
59 },
60 ConfigDefault {
61 key: "cache.blob.l2_bytes_max",
62 tier: Tier::Critical,
63 default: || num(crate::storage::cache::DEFAULT_BLOB_L2_BYTES_MAX as f64),
64 },
65 ConfigDefault {
66 key: "cache.blob.max_namespaces",
67 tier: Tier::Critical,
68 default: || num(crate::storage::cache::DEFAULT_BLOB_MAX_NAMESPACES as f64),
69 },
70 ConfigDefault {
72 key: "durability.mode",
73 tier: Tier::Critical,
74 default: || text("sync"),
75 },
76 ConfigDefault {
78 key: "runtime.result_cache.backend",
79 tier: Tier::Critical,
80 default: || text("legacy"),
81 },
82 ConfigDefault {
84 key: "concurrency.locking.enabled",
85 tier: Tier::Critical,
86 default: || JsonValue::Bool(true),
87 },
88 ConfigDefault {
89 key: "concurrency.locking.deadlock_timeout_ms",
90 tier: Tier::Optional,
91 default: || num(5000.0),
92 },
93 ConfigDefault {
95 key: "storage.wal.max_interval_ms",
96 tier: Tier::Critical,
97 default: || num(10.0),
98 },
99 ConfigDefault {
100 key: "storage.wal.min_batch_size",
101 tier: Tier::Optional,
102 default: || num(4.0),
103 },
104 ConfigDefault {
106 key: "storage.bgwriter.delay_ms",
107 tier: Tier::Critical,
108 default: || num(200.0),
109 },
110 ConfigDefault {
111 key: "storage.bgwriter.max_pages_per_round",
112 tier: Tier::Optional,
113 default: || num(100.0),
114 },
115 ConfigDefault {
116 key: "storage.bgwriter.lru_multiplier",
117 tier: Tier::Optional,
118 default: || num(2.0),
119 },
120 ConfigDefault {
122 key: "storage.bulk_insert.max_buffered_rows",
123 tier: Tier::Optional,
124 default: || num(1000.0),
125 },
126 ConfigDefault {
127 key: "storage.bulk_insert.max_buffered_bytes",
128 tier: Tier::Optional,
129 default: || num(65536.0),
130 },
131 ConfigDefault {
133 key: "storage.hot_update.max_chain_hops",
134 tier: Tier::Optional,
135 default: || num(32.0),
136 },
137 ConfigDefault {
139 key: "storage.btree.lehman_yao",
140 tier: Tier::Critical,
141 default: || JsonValue::Bool(true),
142 },
143 ConfigDefault {
147 key: "ai.ner.backend",
148 tier: Tier::Optional,
149 default: || text("heuristic"),
150 },
151 ConfigDefault {
152 key: "ai.ner.endpoint",
153 tier: Tier::Optional,
154 default: || text(""),
155 },
156 ConfigDefault {
157 key: "ai.ner.model",
158 tier: Tier::Optional,
159 default: || text(""),
160 },
161 ConfigDefault {
162 key: "ai.ner.timeout_ms",
163 tier: Tier::Optional,
164 default: || num(5000.0),
165 },
166 ConfigDefault {
167 key: "ai.ner.fallback",
168 tier: Tier::Optional,
169 default: || text("use_heuristic"),
170 },
171 ConfigDefault {
175 key: "runtime.ai.transport_pool_size",
176 tier: Tier::Optional,
177 default: || num(16.0),
178 },
179 ConfigDefault {
180 key: "runtime.ai.transport_timeout_ms",
181 tier: Tier::Optional,
182 default: || num(30000.0),
183 },
184 ConfigDefault {
185 key: "runtime.ai.transport_retry_max_attempts",
186 tier: Tier::Optional,
187 default: || num(3.0),
188 },
189 ConfigDefault {
190 key: "runtime.ai.transport_retry_base_ms",
191 tier: Tier::Optional,
192 default: || num(500.0),
193 },
194 ConfigDefault {
196 key: "cache.blob.policy.extended",
197 tier: Tier::Optional,
198 default: || text("off"),
199 },
200 ConfigDefault {
205 key: "cache.blob.async_promotion",
206 tier: Tier::Optional,
207 default: || text("off"),
208 },
209];
210
211pub fn default_for(key: &str) -> Option<JsonValue> {
215 MATRIX
216 .iter()
217 .find(|entry| entry.key == key)
218 .map(|entry| (entry.default)())
219}
220
221pub fn tier_for(key: &str) -> Option<Tier> {
224 MATRIX
225 .iter()
226 .find(|entry| entry.key == key)
227 .map(|entry| entry.tier)
228}
229
230pub fn heal_critical_keys(store: &UnifiedStore) {
237 for entry in MATRIX {
240 if entry.tier != Tier::Critical {
241 continue;
242 }
243 if is_key_present(store, entry.key) {
244 continue;
245 }
246 store.set_config_tree(entry.key, &(entry.default)());
247 }
248}
249
250fn is_key_present(store: &UnifiedStore, key: &str) -> bool {
253 let Some(manager) = store.get_collection("red_config") else {
254 return false;
255 };
256 let mut found = false;
257 manager.for_each_entity(|entity| {
258 if let Some(row) = entity.data.as_row() {
259 let entry_key = row.get_field("key").and_then(|v| match v {
260 crate::storage::schema::Value::Text(s) => Some(s.as_ref()),
261 _ => None,
262 });
263 if entry_key == Some(key) {
264 found = true;
265 return false; }
267 }
268 true
269 });
270 found
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276
277 #[test]
278 fn every_matrix_entry_has_a_default_that_resolves() {
279 for entry in MATRIX {
280 let value = (entry.default)();
281 assert!(
282 !matches!(value, JsonValue::Null),
283 "matrix key {} has a null default, defeats self-heal",
284 entry.key
285 );
286 }
287 }
288
289 #[test]
290 fn critical_keys_cover_the_core_guarantees() {
291 let required_critical = [
294 "cache.blob.l1_bytes_max",
295 "cache.blob.l2_bytes_max",
296 "cache.blob.max_namespaces",
297 "durability.mode",
298 "runtime.result_cache.backend",
299 "concurrency.locking.enabled",
300 "storage.wal.max_interval_ms",
301 "storage.bgwriter.delay_ms",
302 "storage.btree.lehman_yao",
303 ];
304 for key in required_critical {
305 assert_eq!(
306 tier_for(key),
307 Some(Tier::Critical),
308 "{key} must be a Tier A (Critical) key",
309 );
310 }
311 }
312
313 #[test]
314 fn optional_keys_are_not_self_healed() {
315 let must_be_optional = [
316 "concurrency.locking.deadlock_timeout_ms",
317 "storage.wal.min_batch_size",
318 "storage.bgwriter.max_pages_per_round",
319 "storage.bgwriter.lru_multiplier",
320 "storage.bulk_insert.max_buffered_rows",
321 "storage.bulk_insert.max_buffered_bytes",
322 "storage.hot_update.max_chain_hops",
323 ];
324 for key in must_be_optional {
325 assert_eq!(tier_for(key), Some(Tier::Optional), "{key} tier mismatch");
326 }
327 }
328
329 #[test]
330 fn unknown_key_returns_none() {
331 assert!(default_for("nonexistent.key").is_none());
332 assert!(tier_for("nonexistent.key").is_none());
333 }
334}