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: "ask.max_prompt_tokens",
57 tier: Tier::Optional,
58 default: || num(8192.0),
59 },
60 ConfigDefault {
61 key: "ask.max_completion_tokens",
62 tier: Tier::Optional,
63 default: || num(1024.0),
64 },
65 ConfigDefault {
66 key: "ask.max_sources_bytes",
67 tier: Tier::Optional,
68 default: || num(262_144.0),
69 },
70 ConfigDefault {
71 key: "ask.timeout_ms",
72 tier: Tier::Optional,
73 default: || num(30_000.0),
74 },
75 ConfigDefault {
76 key: "ask.daily_cost_cap_usd",
77 tier: Tier::Optional,
78 default: || text(""),
79 },
80 ConfigDefault {
81 key: "ask.audit.include_answer",
82 tier: Tier::Optional,
83 default: || JsonValue::Bool(false),
84 },
85 ConfigDefault {
86 key: "ask.audit.retention_days",
87 tier: Tier::Optional,
88 default: || num(90.0),
89 },
90 ConfigDefault {
91 key: "ask.cache.enabled",
92 tier: Tier::Optional,
93 default: || JsonValue::Bool(false),
94 },
95 ConfigDefault {
96 key: "ask.cache.default_ttl",
97 tier: Tier::Optional,
98 default: || text(""),
99 },
100 ConfigDefault {
101 key: "ask.cache.max_entries",
102 tier: Tier::Optional,
103 default: || num(1024.0),
104 },
105 ConfigDefault {
107 key: "cache.blob.l1_bytes_max",
108 tier: Tier::Critical,
109 default: || num(crate::storage::cache::DEFAULT_BLOB_L1_BYTES_MAX as f64),
110 },
111 ConfigDefault {
112 key: "cache.blob.l2_bytes_max",
113 tier: Tier::Critical,
114 default: || num(crate::storage::cache::DEFAULT_BLOB_L2_BYTES_MAX as f64),
115 },
116 ConfigDefault {
117 key: "cache.blob.namespace_bytes_max",
118 tier: Tier::Critical,
119 default: || num(crate::storage::cache::DEFAULT_BLOB_NAMESPACE_BYTES_MAX as f64),
120 },
121 ConfigDefault {
122 key: "cache.blob.max_namespaces",
123 tier: Tier::Critical,
124 default: || num(crate::storage::cache::DEFAULT_BLOB_MAX_NAMESPACES as f64),
125 },
126 ConfigDefault {
129 key: "routing.red.advertise_addr",
130 tier: Tier::Optional,
131 default: || text(""),
132 },
133 ConfigDefault {
134 key: "routing.reds.advertise_addr",
135 tier: Tier::Optional,
136 default: || text(""),
137 },
138 ConfigDefault {
139 key: "routing.grpc.advertise_addr",
140 tier: Tier::Optional,
141 default: || text(""),
142 },
143 ConfigDefault {
144 key: "routing.grpcs.advertise_addr",
145 tier: Tier::Optional,
146 default: || text(""),
147 },
148 ConfigDefault {
149 key: "routing.http.advertise_addr",
150 tier: Tier::Optional,
151 default: || text(""),
152 },
153 ConfigDefault {
154 key: "routing.https.advertise_addr",
155 tier: Tier::Optional,
156 default: || text(""),
157 },
158 ConfigDefault {
159 key: "routing.ws.advertise_addr",
160 tier: Tier::Optional,
161 default: || text(""),
162 },
163 ConfigDefault {
164 key: "routing.wss.advertise_addr",
165 tier: Tier::Optional,
166 default: || text(""),
167 },
168 ConfigDefault {
174 key: "storage.binary_document_body",
175 tier: Tier::Optional,
176 default: || JsonValue::Bool(true),
177 },
178 ConfigDefault {
180 key: "durability.mode",
181 tier: Tier::Critical,
182 default: || text("sync"),
183 },
184 ConfigDefault {
189 key: "runtime.result_cache.enabled",
190 tier: Tier::Critical,
191 default: || JsonValue::Bool(true),
192 },
193 ConfigDefault {
196 key: "runtime.result_cache.ttl_seconds",
197 tier: Tier::Optional,
198 default: || num(30.0),
199 },
200 ConfigDefault {
203 key: "runtime.result_cache.capacity_entries",
204 tier: Tier::Optional,
205 default: || num(1000.0),
206 },
207 ConfigDefault {
209 key: "concurrency.locking.enabled",
210 tier: Tier::Critical,
211 default: || JsonValue::Bool(true),
212 },
213 ConfigDefault {
214 key: "concurrency.locking.deadlock_timeout_ms",
215 tier: Tier::Optional,
216 default: || num(5000.0),
217 },
218 ConfigDefault {
220 key: "storage.wal.max_interval_ms",
221 tier: Tier::Critical,
222 default: || num(10.0),
223 },
224 ConfigDefault {
225 key: "storage.wal.min_batch_size",
226 tier: Tier::Optional,
227 default: || num(4.0),
228 },
229 ConfigDefault {
231 key: "storage.deploy.profile",
232 tier: Tier::Critical,
233 default: || text("embedded"),
234 },
235 ConfigDefault {
236 key: "storage.deploy.packaging",
237 tier: Tier::Critical,
238 default: || text("single-file"),
239 },
240 ConfigDefault {
241 key: "storage.deploy.preset",
242 tier: Tier::Critical,
243 default: || text("embedded"),
244 },
245 ConfigDefault {
246 key: "storage.deploy.replica_count",
247 tier: Tier::Critical,
248 default: || num(0.0),
249 },
250 ConfigDefault {
251 key: "storage.deploy.managed_backup",
252 tier: Tier::Critical,
253 default: || JsonValue::Bool(false),
254 },
255 ConfigDefault {
256 key: "storage.deploy.wal_retention",
257 tier: Tier::Critical,
258 default: || JsonValue::Bool(false),
259 },
260 ConfigDefault {
262 key: "storage.bgwriter.delay_ms",
263 tier: Tier::Critical,
264 default: || num(200.0),
265 },
266 ConfigDefault {
267 key: "storage.bgwriter.max_pages_per_round",
268 tier: Tier::Optional,
269 default: || num(100.0),
270 },
271 ConfigDefault {
272 key: "storage.bgwriter.lru_multiplier",
273 tier: Tier::Optional,
274 default: || num(2.0),
275 },
276 ConfigDefault {
278 key: "storage.bulk_insert.max_buffered_rows",
279 tier: Tier::Optional,
280 default: || num(1000.0),
281 },
282 ConfigDefault {
283 key: "storage.bulk_insert.max_buffered_bytes",
284 tier: Tier::Optional,
285 default: || num(65536.0),
286 },
287 ConfigDefault {
289 key: "storage.hot_update.max_chain_hops",
290 tier: Tier::Optional,
291 default: || num(32.0),
292 },
293 ConfigDefault {
295 key: "storage.time_series.max_series_per_collection",
296 tier: Tier::Optional,
297 default: || num(1_000_000.0),
298 },
299 ConfigDefault {
301 key: "storage.btree.lehman_yao",
302 tier: Tier::Critical,
303 default: || JsonValue::Bool(true),
304 },
305 ConfigDefault {
309 key: "ai.ner.backend",
310 tier: Tier::Optional,
311 default: || text("heuristic"),
312 },
313 ConfigDefault {
314 key: "ai.ner.endpoint",
315 tier: Tier::Optional,
316 default: || text(""),
317 },
318 ConfigDefault {
319 key: "ai.ner.model",
320 tier: Tier::Optional,
321 default: || text(""),
322 },
323 ConfigDefault {
324 key: "ai.ner.timeout_ms",
325 tier: Tier::Optional,
326 default: || num(5000.0),
327 },
328 ConfigDefault {
329 key: "ai.ner.fallback",
330 tier: Tier::Optional,
331 default: || text("use_heuristic"),
332 },
333 ConfigDefault {
337 key: "runtime.ai.transport_pool_size",
338 tier: Tier::Optional,
339 default: || num(16.0),
340 },
341 ConfigDefault {
342 key: "runtime.ai.transport_timeout_ms",
343 tier: Tier::Optional,
344 default: || num(30000.0),
345 },
346 ConfigDefault {
347 key: "runtime.ai.transport_retry_max_attempts",
348 tier: Tier::Optional,
349 default: || num(3.0),
350 },
351 ConfigDefault {
352 key: "runtime.ai.transport_retry_base_ms",
353 tier: Tier::Optional,
354 default: || num(500.0),
355 },
356 ConfigDefault {
358 key: "cache.blob.policy.extended",
359 tier: Tier::Optional,
360 default: || text("off"),
361 },
362 ConfigDefault {
367 key: "cache.blob.async_promotion",
368 tier: Tier::Optional,
369 default: || text("off"),
370 },
371];
372
373pub fn default_for(key: &str) -> Option<JsonValue> {
377 MATRIX
378 .iter()
379 .find(|entry| entry.key == key)
380 .map(|entry| (entry.default)())
381}
382
383pub fn tier_for(key: &str) -> Option<Tier> {
386 MATRIX
387 .iter()
388 .find(|entry| entry.key == key)
389 .map(|entry| entry.tier)
390}
391
392pub fn heal_critical_keys(store: &UnifiedStore) {
399 for entry in MATRIX {
402 if entry.tier != Tier::Critical {
403 continue;
404 }
405 if is_key_present(store, entry.key) {
406 continue;
407 }
408 store.set_config_tree(entry.key, &(entry.default)());
409 }
410}
411
412fn is_key_present(store: &UnifiedStore, key: &str) -> bool {
415 match store.try_get_config(key) {
416 Ok(value) => value.is_some(),
417 Err(error) => {
418 tracing::warn!(key, %error, "cannot read persisted configuration; skipping seed");
421 true
422 }
423 }
424}
425
426#[cfg(test)]
427mod tests {
428 use super::*;
429
430 #[test]
431 fn every_matrix_entry_has_a_default_that_resolves() {
432 for entry in MATRIX {
433 let value = (entry.default)();
434 assert!(
435 !matches!(value, JsonValue::Null),
436 "matrix key {} has a null default, defeats self-heal",
437 entry.key
438 );
439 }
440 }
441
442 #[test]
443 fn critical_keys_cover_the_core_guarantees() {
444 let required_critical = [
447 "cache.blob.l1_bytes_max",
448 "cache.blob.l2_bytes_max",
449 "cache.blob.namespace_bytes_max",
450 "cache.blob.max_namespaces",
451 "durability.mode",
452 "concurrency.locking.enabled",
453 "storage.wal.max_interval_ms",
454 "storage.deploy.profile",
455 "storage.deploy.packaging",
456 "storage.deploy.preset",
457 "storage.deploy.replica_count",
458 "storage.deploy.managed_backup",
459 "storage.deploy.wal_retention",
460 "storage.bgwriter.delay_ms",
461 "storage.btree.lehman_yao",
462 ];
463 for key in required_critical {
464 assert_eq!(
465 tier_for(key),
466 Some(Tier::Critical),
467 "{key} must be a Tier A (Critical) key",
468 );
469 }
470 }
471
472 #[test]
473 fn optional_keys_are_not_self_healed() {
474 let must_be_optional = [
475 "concurrency.locking.deadlock_timeout_ms",
476 "storage.wal.min_batch_size",
477 "storage.bgwriter.max_pages_per_round",
478 "storage.bgwriter.lru_multiplier",
479 "storage.bulk_insert.max_buffered_rows",
480 "storage.bulk_insert.max_buffered_bytes",
481 "storage.hot_update.max_chain_hops",
482 "storage.time_series.max_series_per_collection",
483 ];
484 for key in must_be_optional {
485 assert_eq!(tier_for(key), Some(Tier::Optional), "{key} tier mismatch");
486 }
487 }
488
489 #[test]
490 fn unknown_key_returns_none() {
491 assert!(default_for("nonexistent.key").is_none());
492 assert!(tier_for("nonexistent.key").is_none());
493 }
494}