@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,380 @@
1
+ /// Crash Injection Testing Framework
2
+ ///
3
+ /// Simulates crashes at persistence boundaries to verify recovery behavior.
4
+ /// Tests that recovery always produces valid state (pre-crash or post-crash, never partial).
5
+
6
+ use crate::convergence::VectorClock;
7
+ use crate::operation_log::MemoryOperationLog;
8
+ use crate::state_hash::{CanonicalState, StateHash};
9
+ use crate::state_transition_store::MemoryStateTransitionStore;
10
+ use crate::transactions::*;
11
+ use std::collections::HashMap;
12
+
13
+ /// Point in the transaction pipeline where crash can occur
14
+ #[derive(Clone, Debug, PartialEq, Eq)]
15
+ pub enum CrashPoint {
16
+ BeforeOperationLogAppend,
17
+ AfterOperationLogAppend,
18
+ BeforeStateTransitionRecord,
19
+ AfterStateTransitionRecord,
20
+ BeforeStateHashUpdate,
21
+ AfterStateHashUpdate,
22
+ }
23
+
24
+ /// Transaction execution checkpoint tracking
25
+ #[derive(Clone, Debug)]
26
+ pub struct ExecutionCheckpoint {
27
+ pub transaction_id: String,
28
+ pub operations_appended: bool,
29
+ pub transition_recorded: bool,
30
+ pub state_hash_updated: bool,
31
+ }
32
+
33
+ /// Result of crash recovery attempt
34
+ #[derive(Clone, Debug)]
35
+ pub enum RecoveryResult {
36
+ /// State is in a valid pre-transaction state
37
+ ValidPre {
38
+ checkpoint: ExecutionCheckpoint,
39
+ },
40
+ /// State is in a valid post-transaction state
41
+ ValidPost {
42
+ checkpoint: ExecutionCheckpoint,
43
+ },
44
+ /// State is corrupted or indeterminate
45
+ Invalid {
46
+ reason: String,
47
+ },
48
+ }
49
+
50
+ /// Crash injection test harness
51
+ pub struct CrashInjectionTester {
52
+ operation_log: MemoryOperationLog,
53
+ transition_store: MemoryStateTransitionStore,
54
+ pre_crash_state: CanonicalState,
55
+ post_crash_state: CanonicalState,
56
+ checkpoints: Vec<ExecutionCheckpoint>,
57
+ }
58
+
59
+ impl CrashInjectionTester {
60
+ pub fn new() -> Self {
61
+ Self {
62
+ operation_log: MemoryOperationLog::new(),
63
+ transition_store: MemoryStateTransitionStore::new(),
64
+ pre_crash_state: CanonicalState::new(),
65
+ post_crash_state: CanonicalState::new(),
66
+ checkpoints: Vec::new(),
67
+ }
68
+ }
69
+
70
+ /// Simulate crash before operation log append
71
+ pub fn crash_before_operation_append(&self, operation: &Operation) -> RecoveryResult {
72
+ assert_eq!(self.operation_log.size(), 0, "Operation should not be logged yet");
73
+ assert_eq!(
74
+ self.transition_store.size(),
75
+ 0,
76
+ "Transition should not be recorded yet"
77
+ );
78
+
79
+ RecoveryResult::ValidPre {
80
+ checkpoint: ExecutionCheckpoint {
81
+ transaction_id: operation.transaction_id.clone().unwrap_or_default(),
82
+ operations_appended: false,
83
+ transition_recorded: false,
84
+ state_hash_updated: false,
85
+ },
86
+ }
87
+ }
88
+
89
+ /// Simulate crash after operation log append (before transition)
90
+ pub fn crash_after_operation_append(&self, operation: &Operation) -> RecoveryResult {
91
+ let op_appended = self.operation_log.contains_operation_id(&operation.operation_id);
92
+
93
+ if !op_appended {
94
+ return RecoveryResult::Invalid {
95
+ reason: "Operation should be appended before crash".to_string(),
96
+ };
97
+ }
98
+
99
+ assert_eq!(
100
+ self.transition_store.size(),
101
+ 0,
102
+ "Transition should not be recorded yet"
103
+ );
104
+
105
+ RecoveryResult::ValidPre {
106
+ checkpoint: ExecutionCheckpoint {
107
+ transaction_id: operation.transaction_id.clone().unwrap_or_default(),
108
+ operations_appended: true,
109
+ transition_recorded: false,
110
+ state_hash_updated: false,
111
+ },
112
+ }
113
+ }
114
+
115
+ /// Simulate crash after state transition recorded
116
+ pub fn crash_after_transition_recorded(&self, transaction_id: &str) -> RecoveryResult {
117
+ let transition = self
118
+ .transition_store
119
+ .get_by_transaction_id(transaction_id);
120
+
121
+ if transition.is_none() {
122
+ return RecoveryResult::Invalid {
123
+ reason: "Transition should be recorded before crash".to_string(),
124
+ };
125
+ }
126
+
127
+ RecoveryResult::ValidPost {
128
+ checkpoint: ExecutionCheckpoint {
129
+ transaction_id: transaction_id.to_string(),
130
+ operations_appended: true,
131
+ transition_recorded: true,
132
+ state_hash_updated: true,
133
+ },
134
+ }
135
+ }
136
+
137
+ /// Record pre-crash state
138
+ pub fn set_pre_crash_state(&mut self, state: CanonicalState) {
139
+ self.pre_crash_state = state;
140
+ }
141
+
142
+ /// Record post-crash state (expected state after recovery)
143
+ pub fn set_post_crash_state(&mut self, state: CanonicalState) {
144
+ self.post_crash_state = state;
145
+ }
146
+
147
+ /// Verify recovery never produces invalid state
148
+ pub fn verify_no_partial_state(&self) -> bool {
149
+ // No partial operations should exist (all or nothing)
150
+ // No orphaned transitions (operation log and store should be consistent)
151
+
152
+ let operation_log_size = self.operation_log.size();
153
+ let transition_store_size = self.transition_store.size();
154
+
155
+ if operation_log_size > 0 && transition_store_size == 0 {
156
+ return true; // Valid partial: operations logged but transition pending
157
+ }
158
+
159
+ if operation_log_size > 0 && transition_store_size > 0 {
160
+ return true; // Valid complete: both logged
161
+ }
162
+
163
+ if operation_log_size == 0 && transition_store_size == 0 {
164
+ return true; // Valid empty: nothing executed
165
+ }
166
+
167
+ false // Invalid: orphaned state
168
+ }
169
+
170
+ /// Verify no duplicate operations after recovery
171
+ pub fn verify_no_duplicates(&self) -> bool {
172
+ let all_ops = self.operation_log.iter();
173
+ let mut seen_ids = std::collections::HashSet::new();
174
+
175
+ for entry in all_ops {
176
+ let op_id_key = format!(
177
+ "{}:{}",
178
+ entry.operation_id.node_id, entry.operation_id.sequence
179
+ );
180
+ if seen_ids.contains(&op_id_key) {
181
+ return false; // Duplicate detected
182
+ }
183
+ seen_ids.insert(op_id_key);
184
+ }
185
+
186
+ true
187
+ }
188
+
189
+ /// Verify state lineage is consistent
190
+ pub fn verify_state_lineage(&self) -> bool {
191
+ let all_transitions = self.transition_store.iter();
192
+
193
+ let mut current_hash = "genesis".to_string();
194
+ for record in all_transitions {
195
+ if record.transition.from_version.state_hash != current_hash {
196
+ return false; // Broken lineage
197
+ }
198
+ current_hash = record.transition.to_version.state_hash.clone();
199
+ }
200
+
201
+ true
202
+ }
203
+ }
204
+
205
+ impl Default for CrashInjectionTester {
206
+ fn default() -> Self {
207
+ Self::new()
208
+ }
209
+ }
210
+
211
+ #[cfg(test)]
212
+ mod tests {
213
+ use super::*;
214
+
215
+ fn create_test_operation(sequence: u64) -> Operation {
216
+ let mut vc = VectorClock::new();
217
+ vc.increment("node1");
218
+ let version = crate::transactions::StateVersion::new(vc, "hash0".to_string());
219
+
220
+ Operation::new(
221
+ OperationId::new("node1".to_string(), sequence),
222
+ version,
223
+ format!("Op{}", sequence),
224
+ OperationCommand {
225
+ op_type: "UpdateField".to_string(),
226
+ collection: "test".to_string(),
227
+ record_id: format!("rec{}", sequence),
228
+ fields: {
229
+ let mut m = HashMap::new();
230
+ m.insert("value".to_string(), serde_json::json!(sequence));
231
+ m
232
+ },
233
+ },
234
+ "user".to_string(),
235
+ )
236
+ }
237
+
238
+ #[test]
239
+ fn test_crash_before_operation_append() {
240
+ let tester = CrashInjectionTester::new();
241
+ let op = create_test_operation(1);
242
+
243
+ let result = tester.crash_before_operation_append(&op);
244
+
245
+ match result {
246
+ RecoveryResult::ValidPre { checkpoint } => {
247
+ assert!(!checkpoint.operations_appended);
248
+ assert!(!checkpoint.transition_recorded);
249
+ }
250
+ _ => panic!("Expected ValidPre"),
251
+ }
252
+ }
253
+
254
+ #[test]
255
+ fn test_verify_no_duplicates() {
256
+ let tester = CrashInjectionTester::new();
257
+
258
+ assert!(tester.verify_no_duplicates());
259
+
260
+ let op = create_test_operation(1);
261
+ tester.operation_log.append(op).unwrap();
262
+
263
+ assert!(tester.verify_no_duplicates());
264
+ }
265
+
266
+ #[test]
267
+ fn test_verify_no_partial_state_empty() {
268
+ let tester = CrashInjectionTester::new();
269
+
270
+ assert!(tester.verify_no_partial_state());
271
+ }
272
+
273
+ #[test]
274
+ fn test_verify_state_lineage_linear_chain() {
275
+ let mut tester = CrashInjectionTester::new();
276
+
277
+ let mut prev_hash = "genesis".to_string();
278
+ for i in 1..=3 {
279
+ let mut vc = VectorClock::new();
280
+ vc.increment("node1");
281
+
282
+ let from_version = crate::transactions::StateVersion::new(
283
+ vc.clone(),
284
+ prev_hash.clone(),
285
+ );
286
+
287
+ vc.increment("node1");
288
+ let to_version = crate::transactions::StateVersion::new(
289
+ vc,
290
+ format!("hash{}", i),
291
+ );
292
+
293
+ let op = create_test_operation(i);
294
+ let transition = StateTransition::new(
295
+ from_version,
296
+ vec![op],
297
+ to_version.clone(),
298
+ ConsistencyContract::local(),
299
+ );
300
+
301
+ tester.transition_store.record_transition(transition).unwrap();
302
+ prev_hash = format!("hash{}", i);
303
+ }
304
+
305
+ assert!(tester.verify_state_lineage());
306
+ }
307
+
308
+ #[test]
309
+ fn test_verify_state_lineage_broken_chain() {
310
+ let mut tester = CrashInjectionTester::new();
311
+
312
+ let mut vc = VectorClock::new();
313
+ vc.increment("node1");
314
+ let from_version1 = crate::transactions::StateVersion::new(vc.clone(), "hash0".to_string());
315
+
316
+ vc.increment("node1");
317
+ let to_version1 = crate::transactions::StateVersion::new(vc.clone(), "hash1".to_string());
318
+
319
+ let op1 = create_test_operation(1);
320
+ let t1 = StateTransition::new(
321
+ from_version1,
322
+ vec![op1],
323
+ to_version1,
324
+ ConsistencyContract::local(),
325
+ );
326
+ tester.transition_store.record_transition(t1).unwrap();
327
+
328
+ let mut vc2 = VectorClock::new();
329
+ vc2.increment("node1");
330
+ let from_version2 = crate::transactions::StateVersion::new(vc2.clone(), "hash_broken".to_string());
331
+
332
+ vc2.increment("node1");
333
+ let to_version2 = crate::transactions::StateVersion::new(vc2, "hash2".to_string());
334
+
335
+ let op2 = create_test_operation(2);
336
+ let t2 = StateTransition::new(
337
+ from_version2,
338
+ vec![op2],
339
+ to_version2,
340
+ ConsistencyContract::local(),
341
+ );
342
+ tester.transition_store.record_transition(t2).unwrap();
343
+
344
+ assert!(!tester.verify_state_lineage());
345
+ }
346
+
347
+ #[test]
348
+ fn test_crash_recovery_idempotence() {
349
+ let mut tester = CrashInjectionTester::new();
350
+ let op = create_test_operation(1);
351
+
352
+ let result1 = tester.crash_before_operation_append(&op);
353
+ let result2 = tester.crash_before_operation_append(&op);
354
+
355
+ match (&result1, &result2) {
356
+ (RecoveryResult::ValidPre { .. }, RecoveryResult::ValidPre { .. }) => {
357
+ // Both should produce same recovery result
358
+ }
359
+ _ => panic!("Expected ValidPre for both"),
360
+ }
361
+ }
362
+
363
+ #[test]
364
+ fn test_crash_after_append_recovery() {
365
+ let tester = CrashInjectionTester::new();
366
+ let op = create_test_operation(1);
367
+
368
+ tester.operation_log.append(op.clone()).unwrap();
369
+
370
+ let result = tester.crash_after_operation_append(&op);
371
+
372
+ match result {
373
+ RecoveryResult::ValidPre { checkpoint } => {
374
+ assert!(checkpoint.operations_appended);
375
+ assert!(!checkpoint.transition_recorded);
376
+ }
377
+ _ => panic!("Expected ValidPre"),
378
+ }
379
+ }
380
+ }