@feltdb/core 0.4.11 → 0.4.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/dist/cli/commands.js +5 -2
  2. package/dist/cli/index.js +1 -1
  3. package/dist/create/cli.js +16 -1
  4. package/dist/create/create.js +30 -16
  5. package/dist/create/docker-compose-generator.js +48 -9
  6. package/dist/create/package-versions.js +1 -1
  7. package/dist/create/server-source/Cargo.lock +2238 -0
  8. package/dist/create/server-source/Cargo.toml +7 -0
  9. package/dist/create/server-source/crates/feltdb/Cargo.lock +175 -0
  10. package/dist/create/server-source/crates/feltdb/Cargo.toml +79 -0
  11. package/dist/create/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +370 -0
  12. package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +589 -0
  13. package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +259 -0
  14. package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +446 -0
  15. package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +272 -0
  16. package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +378 -0
  17. package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +414 -0
  18. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +486 -0
  19. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +273 -0
  20. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +587 -0
  21. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +513 -0
  22. package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +395 -0
  23. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +469 -0
  24. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +409 -0
  25. package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +627 -0
  26. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +383 -0
  27. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +298 -0
  28. package/dist/create/server-source/crates/feltdb/src/acceptance_tests.rs +1698 -0
  29. package/dist/create/server-source/crates/feltdb/src/acquisition.rs +286 -0
  30. package/dist/create/server-source/crates/feltdb/src/admission.rs +192 -0
  31. package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +477 -0
  32. package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +566 -0
  33. package/dist/create/server-source/crates/feltdb/src/analytics.rs +475 -0
  34. package/dist/create/server-source/crates/feltdb/src/application.rs +2244 -0
  35. package/dist/create/server-source/crates/feltdb/src/application_runtime.rs +1070 -0
  36. package/dist/create/server-source/crates/feltdb/src/authorization.rs +1030 -0
  37. package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +266 -0
  38. package/dist/create/server-source/crates/feltdb/src/capabilities/mod.rs +8 -0
  39. package/dist/create/server-source/crates/feltdb/src/capabilities/search.rs +418 -0
  40. package/dist/create/server-source/crates/feltdb/src/capabilities/vector.rs +482 -0
  41. package/dist/create/server-source/crates/feltdb/src/capability.rs +903 -0
  42. package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +261 -0
  43. package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +78 -0
  44. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +2214 -0
  45. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +194 -0
  46. package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +427 -0
  47. package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +453 -0
  48. package/dist/create/server-source/crates/feltdb/src/content_distribution.rs +465 -0
  49. package/dist/create/server-source/crates/feltdb/src/convergence.rs +618 -0
  50. package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +418 -0
  51. package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +380 -0
  52. package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +362 -0
  53. package/dist/create/server-source/crates/feltdb/src/cron.rs +294 -0
  54. package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +474 -0
  55. package/dist/create/server-source/crates/feltdb/src/distributed_tests.rs +1003 -0
  56. package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +536 -0
  57. package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +364 -0
  58. package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +235 -0
  59. package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +207 -0
  60. package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +316 -0
  61. package/dist/create/server-source/crates/feltdb/src/execution.rs +426 -0
  62. package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +219 -0
  63. package/dist/create/server-source/crates/feltdb/src/indexing.rs +779 -0
  64. package/dist/create/server-source/crates/feltdb/src/lib.rs +2838 -0
  65. package/dist/create/server-source/crates/feltdb/src/materialization.rs +184 -0
  66. package/dist/create/server-source/crates/feltdb/src/metrics.rs +267 -0
  67. package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +311 -0
  68. package/dist/create/server-source/crates/feltdb/src/observability.rs +366 -0
  69. package/dist/create/server-source/crates/feltdb/src/operation.rs +251 -0
  70. package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +438 -0
  71. package/dist/create/server-source/crates/feltdb/src/operation_log.rs +344 -0
  72. package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +477 -0
  73. package/dist/create/server-source/crates/feltdb/src/peer_registry.rs +166 -0
  74. package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +261 -0
  75. package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +560 -0
  76. package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +3226 -0
  77. package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +201 -0
  78. package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +263 -0
  79. package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +484 -0
  80. package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +216 -0
  81. package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +281 -0
  82. package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +323 -0
  83. package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +573 -0
  84. package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +404 -0
  85. package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +418 -0
  86. package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +381 -0
  87. package/dist/create/server-source/crates/feltdb/src/phase_1c_three_node.rs +523 -0
  88. package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +334 -0
  89. package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +306 -0
  90. package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +355 -0
  91. package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +395 -0
  92. package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +346 -0
  93. package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +430 -0
  94. package/dist/create/server-source/crates/feltdb/src/production_api.rs +400 -0
  95. package/dist/create/server-source/crates/feltdb/src/provenance.rs +207 -0
  96. package/dist/create/server-source/crates/feltdb/src/query_performance.rs +217 -0
  97. package/dist/create/server-source/crates/feltdb/src/references.rs +404 -0
  98. package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +401 -0
  99. package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +160 -0
  100. package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +132 -0
  101. package/dist/create/server-source/crates/feltdb/src/routing.rs +409 -0
  102. package/dist/create/server-source/crates/feltdb/src/sharding.rs +523 -0
  103. package/dist/create/server-source/crates/feltdb/src/state_contract.rs +3118 -0
  104. package/dist/create/server-source/crates/feltdb/src/state_hash.rs +291 -0
  105. package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +376 -0
  106. package/dist/create/server-source/crates/feltdb/src/storage.rs +267 -0
  107. package/dist/create/server-source/crates/feltdb/src/submission.rs +477 -0
  108. package/dist/create/server-source/crates/feltdb/src/sync.rs +483 -0
  109. package/dist/create/server-source/crates/feltdb/src/sync_contract.rs +822 -0
  110. package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +366 -0
  111. package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +473 -0
  112. package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +949 -0
  113. package/dist/create/server-source/crates/feltdb/src/transactions.rs +646 -0
  114. package/dist/create/server-source/crates/feltdb/src/trigger.rs +390 -0
  115. package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +928 -0
  116. package/dist/create/server-source/crates/feltdb/src/workflow.rs +713 -0
  117. package/dist/create/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +510 -0
  118. package/dist/create/server-source/crates/feltdb/src/workflow_integration.rs +354 -0
  119. package/dist/create/server-source/crates/feltdb/src/workflow_runtime.rs +594 -0
  120. package/dist/create/server-source/crates/feltdb/src/workload.rs +1310 -0
  121. package/dist/create/server-source/crates/feltdb-server/Cargo.toml +23 -0
  122. package/dist/create/server-source/crates/feltdb-server/README.md +79 -0
  123. package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +73 -0
  124. package/dist/create/server-source/crates/feltdb-server/src/application_contract.rs +425 -0
  125. package/dist/create/server-source/crates/feltdb-server/src/artifacts.rs +449 -0
  126. package/dist/create/server-source/crates/feltdb-server/src/audit.rs +59 -0
  127. package/dist/create/server-source/crates/feltdb-server/src/auth.rs +308 -0
  128. package/dist/create/server-source/crates/feltdb-server/src/authorization.rs +228 -0
  129. package/dist/create/server-source/crates/feltdb-server/src/backup.rs +416 -0
  130. package/dist/create/server-source/crates/feltdb-server/src/causal.rs +218 -0
  131. package/dist/create/server-source/crates/feltdb-server/src/certification.rs +223 -0
  132. package/dist/create/server-source/crates/feltdb-server/src/clock.rs +132 -0
  133. package/dist/create/server-source/crates/feltdb-server/src/cluster.rs +165 -0
  134. package/dist/create/server-source/crates/feltdb-server/src/connections.rs +1044 -0
  135. package/dist/create/server-source/crates/feltdb-server/src/content.rs +111 -0
  136. package/dist/create/server-source/crates/feltdb-server/src/identity.rs +250 -0
  137. package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +78 -0
  138. package/dist/create/server-source/crates/feltdb-server/src/key_provider.rs +247 -0
  139. package/dist/create/server-source/crates/feltdb-server/src/leases.rs +123 -0
  140. package/dist/create/server-source/crates/feltdb-server/src/lib.rs +25 -0
  141. package/dist/create/server-source/crates/feltdb-server/src/main.rs +8715 -0
  142. package/dist/create/server-source/crates/feltdb-server/src/metrics.rs +97 -0
  143. package/dist/create/server-source/crates/feltdb-server/src/portable_bundle.rs +350 -0
  144. package/dist/create/server-source/crates/feltdb-server/src/principals.rs +510 -0
  145. package/dist/create/server-source/crates/feltdb-server/src/providers.rs +269 -0
  146. package/dist/create/server-source/crates/feltdb-server/src/releases.rs +2563 -0
  147. package/dist/create/server-source/crates/feltdb-server/src/sessions.rs +156 -0
  148. package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +1097 -0
  149. package/dist/create/server-source/crates/feltdb-server/src/versions.rs +264 -0
  150. package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +31 -0
  151. package/dist/create/server-source/crates/feltdb-wasm/src/lib.rs +1086 -0
  152. package/dist/create/server-source/crates/feltdb-wasm/test.db +0 -0
  153. package/dist/flowspec.d.ts +2 -0
  154. package/dist/flowspec.d.ts.map +1 -1
  155. package/dist/flowspec.js +28 -4
  156. package/dist/state-contract.d.ts +7 -1
  157. package/dist/state-contract.d.ts.map +1 -1
  158. package/dist/studio/components/ApplicationDesigner.d.ts.map +1 -1
  159. package/dist/studio/components/index.js +1 -1
  160. package/dist/studio/{components-q43NSTTH.js → components-bHTARBin.js} +160 -89
  161. package/dist/studio/index.js +31 -28
  162. package/dist/studio-app/assets/{index-DZpBoVMp.js → index-BqKquLuU.js} +8 -8
  163. package/dist/studio-app/index.html +1 -1
  164. package/package.json +1 -1
@@ -0,0 +1,261 @@
1
+ /// Diagnostic utilities for investigating cardinality reconstruction issues.
2
+ ///
3
+ /// This module provides tools to understand how collection cardinality is reconstructed
4
+ /// during startup and how it compares to query-time lookups.
5
+
6
+ use crate::{AtomicMutation, FeltDb};
7
+ use std::collections::HashMap;
8
+
9
+ /// Diagnostic information about a single collection's cardinality.
10
+ #[derive(Debug, Clone)]
11
+ pub struct CardinalityDiagnostic {
12
+ /// Collection name (e.g., "github_webhook_deliveries")
13
+ pub collection: String,
14
+
15
+ /// Capability keys actually found in persisted rows during replay_log
16
+ pub persisted_capabilities: Vec<String>,
17
+
18
+ /// Count of non-deleted rows found under each capability
19
+ pub persisted_row_counts: HashMap<String, u64>,
20
+
21
+ /// Total rows for this collection across all capability variants
22
+ pub total_persisted_rows: u64,
23
+
24
+ /// Maintained cardinality value stored in collection_cardinality HashMap
25
+ pub maintained_count: u64,
26
+
27
+ /// What capability string query execution looks for
28
+ pub query_capability: String,
29
+
30
+ /// Whether query_capability matches any persisted capability
31
+ pub match_status: String,
32
+
33
+ /// Delta between total persisted and maintained cardinality
34
+ pub delta: i64,
35
+ }
36
+
37
+ /// Analyze the cardinality mismatch between persisted state and query-time lookups.
38
+ ///
39
+ /// Returns diagnostic information for collections with mismatches.
40
+ ///
41
+ /// # Arguments
42
+ /// * `db` - The FeltDb instance
43
+ /// * `state_namespace` - The state namespace from query context
44
+ /// * `application_id` - The application ID
45
+ /// * `collection_name` - The collection to diagnose (without namespace)
46
+ pub fn diagnose_cardinality(
47
+ db: &FeltDb,
48
+ state_namespace: &str,
49
+ application_id: &str,
50
+ collection_name: &str,
51
+ ) -> CardinalityDiagnostic {
52
+ // What the query executor will look for
53
+ let query_capability = format!("{}:{}", state_namespace, collection_name);
54
+
55
+ // What the maintained cardinality HashMap contains
56
+ let maintained_count = db.collection_cardinality(&query_capability).unwrap_or(0);
57
+
58
+ // We can't directly inspect inner.rows from outside, but we can reason about it:
59
+ // During replay_log, rows are loaded with whatever capability was in the persisted log.
60
+ // If there's a mismatch, the query_capability won't find anything.
61
+
62
+ CardinalityDiagnostic {
63
+ collection: collection_name.to_string(),
64
+ persisted_capabilities: vec![], // Would need access to inner.rows to populate
65
+ persisted_row_counts: HashMap::new(),
66
+ total_persisted_rows: 0, // Would need to scan inner.rows
67
+ maintained_count,
68
+ query_capability,
69
+ match_status: if maintained_count == 0 {
70
+ "MISMATCH: maintained_count is 0".to_string()
71
+ } else {
72
+ "OK".to_string()
73
+ },
74
+ delta: 0, // Can't compute without authoritative row count
75
+ }
76
+ }
77
+
78
+ /// Create a test scenario with mixed capability formats to reproduce the issue.
79
+ #[cfg(test)]
80
+ mod tests {
81
+ use super::*;
82
+ use crate::{open, AtomicMutation};
83
+ use std::fs;
84
+ use std::path::PathBuf;
85
+ use std::sync::atomic::{AtomicU64, Ordering};
86
+ use std::time::SystemTime;
87
+ use std::time::UNIX_EPOCH;
88
+
89
+ static TEMP_FILE_SEQUENCE: AtomicU64 = AtomicU64::new(0);
90
+
91
+ fn temp_file() -> PathBuf {
92
+ let nanos = SystemTime::now()
93
+ .duration_since(UNIX_EPOCH)
94
+ .expect("time")
95
+ .as_nanos();
96
+ let sequence = TEMP_FILE_SEQUENCE.fetch_add(1, Ordering::Relaxed);
97
+ std::env::temp_dir().join(format!(
98
+ "feltdb-diag-{}-{nanos}-{sequence}.data",
99
+ std::process::id()
100
+ ))
101
+ }
102
+
103
+ #[test]
104
+ fn test_capability_mismatch_scenario() {
105
+ // This test demonstrates the hypothesis:
106
+ // If rows are persisted under "collection_name" but queried as "namespace:collection_name",
107
+ // cardinality will be 0 on restart.
108
+
109
+ let path = temp_file();
110
+
111
+ {
112
+ let db = open(&path).unwrap();
113
+ let capability = "github_webhook_deliveries"; // Just collection name, no namespace
114
+
115
+ let mutations = vec![
116
+ AtomicMutation {
117
+ capability: capability.to_string(),
118
+ key: "webhook-1".to_string(),
119
+ value: Some(serde_json::json!({"id": 1})),
120
+ },
121
+ AtomicMutation {
122
+ capability: capability.to_string(),
123
+ key: "webhook-2".to_string(),
124
+ value: Some(serde_json::json!({"id": 2})),
125
+ },
126
+ ];
127
+
128
+ db.apply_atomic_transaction("txn-1", None, &[], &mutations, None).unwrap();
129
+
130
+ // At this point, cardinality should be 2 for the key "github_webhook_deliveries"
131
+ let count = db.collection_cardinality(capability).unwrap();
132
+ assert_eq!(count, 2, "Cardinality before restart");
133
+ }
134
+
135
+ // After restart, cardinality is recomputed
136
+ let reopened = open(&path).unwrap();
137
+ let capability = "github_webhook_deliveries";
138
+ let count_after = reopened.collection_cardinality(capability).unwrap();
139
+ assert_eq!(count_after, 2, "Cardinality after restart should match");
140
+
141
+ // But if query looks for a DIFFERENT capability:
142
+ let namespaced_capability = "default:github_webhook_deliveries";
143
+ let count_namespaced = reopened.collection_cardinality(namespaced_capability).unwrap();
144
+
145
+ // If the persisted rows were stored under the non-namespaced key,
146
+ // this will return 0 - demonstrating the mismatch
147
+ println!(
148
+ "Rows under '{}': {}",
149
+ capability, count_after
150
+ );
151
+ println!(
152
+ "Rows under '{}': {}",
153
+ namespaced_capability, count_namespaced
154
+ );
155
+
156
+ // This is the mismatch that causes Gate A to fail
157
+ if count_namespaced != count_after {
158
+ println!(
159
+ "CAPABILITY MISMATCH DETECTED: {} != {}",
160
+ count_after, count_namespaced
161
+ );
162
+ }
163
+
164
+ let _ = fs::remove_file(path);
165
+ }
166
+
167
+ #[test]
168
+ fn test_mixed_capability_formats_in_single_db() {
169
+ // This test shows the exact problem:
170
+ // Some rows use "app:collection", others use "namespace:collection"
171
+ // Cardinality is recomputed based on what's in the persisted log
172
+ // But queries might look for a different format
173
+
174
+ let path = temp_file();
175
+
176
+ {
177
+ let db = open(&path).unwrap();
178
+
179
+ // Simulate old rows stored under application_id format
180
+ let app_id = "my-app";
181
+ let namespace = "default";
182
+ let collection = "github_webhook_deliveries";
183
+
184
+ // Write rows with one format
185
+ let old_format_capability = format!("{}:{}", app_id, collection);
186
+ let mutations_old = vec![
187
+ AtomicMutation {
188
+ capability: old_format_capability.clone(),
189
+ key: "old-webhook-1".to_string(),
190
+ value: Some(serde_json::json!({"id": 1})),
191
+ },
192
+ AtomicMutation {
193
+ capability: old_format_capability.clone(),
194
+ key: "old-webhook-2".to_string(),
195
+ value: Some(serde_json::json!({"id": 2})),
196
+ },
197
+ ];
198
+
199
+ db.apply_atomic_transaction("txn-old", None, &[], &mutations_old, None)
200
+ .unwrap();
201
+
202
+ // Write rows with new format (namespace-based)
203
+ let new_format_capability = format!("{}:{}", namespace, collection);
204
+ let mutations_new = vec![
205
+ AtomicMutation {
206
+ capability: new_format_capability.clone(),
207
+ key: "new-webhook-3".to_string(),
208
+ value: Some(serde_json::json!({"id": 3})),
209
+ },
210
+ AtomicMutation {
211
+ capability: new_format_capability.clone(),
212
+ key: "new-webhook-4".to_string(),
213
+ value: Some(serde_json::json!({"id": 4})),
214
+ },
215
+ ];
216
+
217
+ db.apply_atomic_transaction("txn-new", None, &[], &mutations_new, None)
218
+ .unwrap();
219
+
220
+ // Before restart, both formats should be queryable
221
+ assert_eq!(db.collection_cardinality(&old_format_capability).unwrap(), 2);
222
+ assert_eq!(db.collection_cardinality(&new_format_capability).unwrap(), 2);
223
+ println!(
224
+ "Before restart: old_format={}, new_format={}",
225
+ 2, 2
226
+ );
227
+ }
228
+
229
+ // After restart, cardinality is recomputed from persisted log
230
+ let reopened = open(&path).unwrap();
231
+ let old_format = format!("{}:{}", "my-app", "github_webhook_deliveries");
232
+ let new_format = format!("{}:{}", "default", "github_webhook_deliveries");
233
+
234
+ let old_count = reopened.collection_cardinality(&old_format).unwrap();
235
+ let new_count = reopened.collection_cardinality(&new_format).unwrap();
236
+
237
+ println!(
238
+ "After restart: old_format={}, new_format={}",
239
+ old_count, new_count
240
+ );
241
+ println!(
242
+ "Cardinalities after restart: {}",
243
+ reopened
244
+ .list_cardinalities()
245
+ .unwrap()
246
+ .iter()
247
+ .map(|(k, v)| format!("'{}': {}", k, v))
248
+ .collect::<Vec<_>>()
249
+ .join(", ")
250
+ );
251
+
252
+ // Both should still exist with their own counts
253
+ assert_eq!(old_count, 2, "Old format rows should be reconstructed");
254
+ assert_eq!(new_count, 2, "New format rows should be reconstructed");
255
+
256
+ // But if query only looks for new_format and old data was migrated incorrectly,
257
+ // the query would see 0 instead of the total.
258
+
259
+ let _ = fs::remove_file(path);
260
+ }
261
+ }
@@ -0,0 +1,78 @@
1
+ /// HTTP diagnostic endpoint for cardinality state inspection
2
+ ///
3
+ /// This module provides a debug/diagnostic HTTP endpoint that exposes cardinality
4
+ /// reconstruction state without returning actual row data.
5
+
6
+ use serde::{Deserialize, Serialize};
7
+
8
+ #[derive(Debug, Clone, Serialize, Deserialize)]
9
+ pub struct CardinalityDiagnosticResponse {
10
+ /// Name of the collection being diagnosed
11
+ pub collection_pattern: String,
12
+
13
+ /// Actual row count for collections matching the pattern
14
+ pub actual_row_count: usize,
15
+
16
+ /// Maintained cardinality value stored in HashMap
17
+ pub maintained_cardinality: u64,
18
+
19
+ /// Mismatch indicator
20
+ pub mismatch: bool,
21
+
22
+ /// All capability keys found in HashMap that contain this pattern
23
+ pub cardinality_keys: Vec<(String, u64)>,
24
+
25
+ /// Context information for debugging
26
+ pub context: CardinalityContext,
27
+ }
28
+
29
+ #[derive(Debug, Clone, Serialize, Deserialize)]
30
+ pub struct CardinalityContext {
31
+ /// List of all non-zero cardinalities (collection_name = count)
32
+ /// Sorted by count descending
33
+ pub all_cardinalities: Vec<(String, u64)>,
34
+
35
+ /// Actual persisted capability strings matching pattern from inner.rows
36
+ pub persisted_capability_keys: Vec<String>,
37
+
38
+ /// Capability keys in cardinality HashMap matching pattern
39
+ pub cardinality_map_keys: Vec<String>,
40
+
41
+ /// Timestamp of diagnostic
42
+ pub timestamp_ms: u64,
43
+
44
+ /// Total collections with data
45
+ pub total_collections: usize,
46
+
47
+ /// Collections with cardinality 0
48
+ pub zero_cardinality_count: usize,
49
+
50
+ /// Total persisted rows across all collections
51
+ pub total_rows: usize,
52
+ }
53
+
54
+ impl CardinalityDiagnosticResponse {
55
+ pub fn new(
56
+ collection_pattern: String,
57
+ actual_row_count: usize,
58
+ maintained_cardinality: u64,
59
+ cardinality_keys: Vec<(String, u64)>,
60
+ ) -> Self {
61
+ Self {
62
+ collection_pattern,
63
+ actual_row_count,
64
+ maintained_cardinality,
65
+ mismatch: actual_row_count > 0 && maintained_cardinality == 0,
66
+ cardinality_keys,
67
+ context: CardinalityContext {
68
+ all_cardinalities: vec![],
69
+ persisted_capability_keys: vec![],
70
+ cardinality_map_keys: vec![],
71
+ timestamp_ms: 0,
72
+ total_collections: 0,
73
+ zero_cardinality_count: 0,
74
+ total_rows: 0,
75
+ },
76
+ }
77
+ }
78
+ }