@feltdb/core 0.8.4 → 0.8.5

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 (149) hide show
  1. package/dist/create/package-versions.js +1 -1
  2. package/dist/create/server-source/Cargo.lock +165 -0
  3. package/dist/create/server-source/Cargo.toml +9 -0
  4. package/dist/create/server-source/crates/feltdb/Cargo.toml +3 -0
  5. package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +44 -44
  6. package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +12 -24
  7. package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +7 -13
  8. package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +13 -10
  9. package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +12 -9
  10. package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +78 -25
  11. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +16 -13
  12. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +13 -5
  13. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +41 -22
  14. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +33 -15
  15. package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +100 -33
  16. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +56 -20
  17. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +116 -41
  18. package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +186 -55
  19. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +64 -26
  20. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +46 -15
  21. package/dist/create/server-source/crates/feltdb/src/admission.rs +8 -15
  22. package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +43 -13
  23. package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +15 -42
  24. package/dist/create/server-source/crates/feltdb/src/analytics.rs +65 -19
  25. package/dist/create/server-source/crates/feltdb/src/application.rs +113 -30
  26. package/dist/create/server-source/crates/feltdb/src/authorization_security_tests.rs +475 -140
  27. package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +17 -15
  28. package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +0 -1
  29. package/dist/create/server-source/crates/feltdb/src/causal_backlog_bound.rs +59 -15
  30. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +266 -114
  31. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +25 -7
  32. package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +10 -15
  33. package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +3 -11
  34. package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +14 -5
  35. package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +21 -25
  36. package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +14 -11
  37. package/dist/create/server-source/crates/feltdb/src/dedup_bound_investigation.rs +103 -22
  38. package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +18 -15
  39. package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +12 -8
  40. package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +1 -5
  41. package/dist/create/server-source/crates/feltdb/src/durable_operation_identity.rs +87 -23
  42. package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +3 -7
  43. package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +10 -9
  44. package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +1 -6
  45. package/dist/create/server-source/crates/feltdb/src/indexing.rs +35 -38
  46. package/dist/create/server-source/crates/feltdb/src/lib.rs +507 -6
  47. package/dist/create/server-source/crates/feltdb/src/managed_cas_tests.rs +4 -1
  48. package/dist/create/server-source/crates/feltdb/src/metrics.rs +0 -1
  49. package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +1 -2
  50. package/dist/create/server-source/crates/feltdb/src/multi_operation_transaction.rs +107 -30
  51. package/dist/create/server-source/crates/feltdb/src/observability.rs +19 -6
  52. package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +12 -11
  53. package/dist/create/server-source/crates/feltdb/src/operation_log.rs +9 -4
  54. package/dist/create/server-source/crates/feltdb/src/p1_application_atomicity.rs +65 -18
  55. package/dist/create/server-source/crates/feltdb/src/p1_atomicity_acceptance.rs +193 -57
  56. package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +37 -27
  57. package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +38 -10
  58. package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +20 -14
  59. package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +394 -229
  60. package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +8 -6
  61. package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +11 -13
  62. package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +79 -70
  63. package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +3 -3
  64. package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +33 -11
  65. package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +6 -6
  66. package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +14 -56
  67. package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +29 -27
  68. package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +35 -17
  69. package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +8 -2
  70. package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +59 -15
  71. package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +70 -17
  72. package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +23 -6
  73. package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +12 -3
  74. package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +41 -11
  75. package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +56 -25
  76. package/dist/create/server-source/crates/feltdb/src/policy_evaluation.rs +701 -245
  77. package/dist/create/server-source/crates/feltdb/src/production_api.rs +31 -13
  78. package/dist/create/server-source/crates/feltdb/src/query_performance.rs +6 -8
  79. package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +5 -5
  80. package/dist/create/server-source/crates/feltdb/src/replica_acknowledgements.rs +48 -18
  81. package/dist/create/server-source/crates/feltdb/src/replica_membership.rs +30 -11
  82. package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +6 -3
  83. package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +4 -3
  84. package/dist/create/server-source/crates/feltdb/src/sharding.rs +36 -10
  85. package/dist/create/server-source/crates/feltdb/src/state_conflict_contract.rs +516 -0
  86. package/dist/create/server-source/crates/feltdb/src/state_contract.rs +13 -4
  87. package/dist/create/server-source/crates/feltdb/src/state_diff_contract.rs +222 -0
  88. package/dist/create/server-source/crates/feltdb/src/state_facade.rs +82 -54
  89. package/dist/create/server-source/crates/feltdb/src/state_hash.rs +2 -2
  90. package/dist/create/server-source/crates/feltdb/src/state_model.rs +1514 -537
  91. package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +6 -3
  92. package/dist/create/server-source/crates/feltdb/src/state_trigger.rs +672 -0
  93. package/dist/create/server-source/crates/feltdb/src/submission.rs +5 -11
  94. package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +6 -8
  95. package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +24 -35
  96. package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +24 -8
  97. package/dist/create/server-source/crates/feltdb/src/transaction_preconditions.rs +248 -59
  98. package/dist/create/server-source/crates/feltdb/src/transactions.rs +17 -20
  99. package/dist/create/server-source/crates/feltdb/src/trigger_contract.rs +749 -0
  100. package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +1 -0
  101. package/dist/create/server-source/crates/feltdb/src/workload.rs +512 -4
  102. package/dist/create/server-source/crates/feltdb/src/workload_diagnostics.rs +3 -4
  103. package/dist/create/server-source/crates/feltdb/tests/branching_evidence.rs +299 -0
  104. package/dist/create/server-source/crates/feltdb/tests/current_revision_authority_evidence.rs +288 -0
  105. package/dist/create/server-source/crates/feltdb/tests/durable_format_compatibility.rs +392 -0
  106. package/dist/create/server-source/crates/feltdb/tests/feltdb_state_boundary_tests.rs +436 -220
  107. package/dist/create/server-source/crates/feltdb/tests/fixtures/state_conflict_contract_corpus.json +1916 -0
  108. package/dist/create/server-source/crates/feltdb/tests/fixtures/state_diff_contract_corpus.json +1878 -0
  109. package/dist/create/server-source/crates/feltdb/tests/fixtures/trigger_contract_corpus.json +1862 -0
  110. package/dist/create/server-source/crates/feltdb/tests/pr34_query_collection.rs +2 -1
  111. package/dist/create/server-source/crates/feltdb/tests/pr35_equality_index.rs +80 -25
  112. package/dist/create/server-source/crates/feltdb/tests/pr7_self_authorization_proof.rs +5 -8
  113. package/dist/create/server-source/crates/feltdb/tests/pr8_vocabulary_assessment.rs +52 -44
  114. package/dist/create/server-source/crates/feltdb/tests/pr9_phase2_boundary_tests.rs +33 -16
  115. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3a_path_a_tests.rs +22 -7
  116. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_authorized_mutations.rs +41 -22
  117. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_role_based_authorization.rs +25 -8
  118. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_simple_auth_delete.rs +9 -6
  119. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_team_delete_role_authorization.rs +120 -69
  120. package/dist/create/server-source/crates/feltdb/tests/pr9_teams_role_based_access.rs +21 -10
  121. package/dist/create/server-source/crates/feltdb/tests/production_readiness_contract.rs +1032 -0
  122. package/dist/create/server-source/crates/feltdb/tests/reconciliation_application.rs +868 -0
  123. package/dist/create/server-source/crates/feltdb/tests/reconciliation_wire_format_evidence.rs +221 -0
  124. package/dist/create/server-source/crates/feltdb/tests/resource_scoped_revisions.rs +338 -0
  125. package/dist/create/server-source/crates/feltdb/tests/revision_identity_contract.rs +1039 -0
  126. package/dist/create/server-source/crates/feltdb/tests/revision_model_decision.rs +739 -0
  127. package/dist/create/server-source/crates/feltdb/tests/revision_retention_boundary_evidence.rs +427 -0
  128. package/dist/create/server-source/crates/feltdb/tests/saas_authorization_integration.rs +3 -3
  129. package/dist/create/server-source/crates/feltdb/tests/saas_invitation_lifecycle.rs +25 -22
  130. package/dist/create/server-source/crates/feltdb/tests/state_conflict_contract_conformance.rs +1799 -0
  131. package/dist/create/server-source/crates/feltdb/tests/state_diff_contract_conformance.rs +1316 -0
  132. package/dist/create/server-source/crates/feltdb/tests/state_model_integration.rs +53 -61
  133. package/dist/create/server-source/crates/feltdb/tests/state_persistence_integration.rs +156 -61
  134. package/dist/create/server-source/crates/feltdb/tests/state_store_boundary_evidence.rs +299 -0
  135. package/dist/create/server-source/crates/feltdb/tests/sync_divergence_evidence.rs +255 -0
  136. package/dist/create/server-source/crates/feltdb/tests/three_way_input_boundary_evidence.rs +249 -0
  137. package/dist/create/server-source/crates/feltdb/tests/trigger_contract_conformance.rs +994 -0
  138. package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +2 -1
  139. package/dist/create/server-source/crates/feltdb-server/src/auth.rs +164 -13
  140. package/dist/create/server-source/crates/feltdb-server/src/main.rs +326 -6
  141. package/dist/studio-app/assets/{feltdb_wasm-CVQWgXO-.js → feltdb_wasm-DaNwCLRX.js} +1 -1
  142. package/dist/studio-app/assets/feltdb_wasm_bg-DnsHNv6g.wasm +0 -0
  143. package/dist/studio-app/assets/{index-DwgNAIIX.js → index-j8IlhNqJ.js} +1 -1
  144. package/dist/studio-app/index.html +1 -1
  145. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  146. package/dist/workload.d.ts +2 -1
  147. package/dist/workload.d.ts.map +1 -1
  148. package/package.json +1 -1
  149. package/dist/studio-app/assets/feltdb_wasm_bg-CNVpvaZV.wasm +0 -0
@@ -20,7 +20,9 @@ mod phase_7_1_release_economics {
20
20
  // Fill with blocked operations
21
21
  for i in 0..*pending_size {
22
22
  let mut required = VectorClock::new();
23
- required.clocks.insert("node_a".to_string(), (1000 + i) as u64);
23
+ required
24
+ .clocks
25
+ .insert("node_a".to_string(), (1000 + i) as u64);
24
26
  let _ = barrier.receive_operation(format!("pending_{}", i), required);
25
27
  }
26
28
 
@@ -34,7 +36,10 @@ mod phase_7_1_release_economics {
34
36
  let metrics = barrier.metrics();
35
37
  println!(
36
38
  "Pending={:5} | Cost={:?} | Entries examined={} | Released={}",
37
- pending_size, elapsed, metrics.pending_entries_examined, metrics.operations_released
39
+ pending_size,
40
+ elapsed,
41
+ metrics.pending_entries_examined,
42
+ metrics.operations_released
38
43
  );
39
44
  }
40
45
  }
@@ -74,14 +79,19 @@ mod phase_7_1_release_economics {
74
79
 
75
80
  let metrics = barrier.metrics();
76
81
  let released_pct = if metrics.pending_entries_examined > 0 {
77
- (metrics.operations_released as f64 / metrics.pending_entries_examined as f64) * 100.0
82
+ (metrics.operations_released as f64 / metrics.pending_entries_examined as f64)
83
+ * 100.0
78
84
  } else {
79
85
  0.0
80
86
  };
81
87
 
82
88
  println!(
83
89
  "Ready%={:3} | Cost={:?} | Examined={:3} | Released={:3} | Ratio={:.1}%",
84
- ready_percent, elapsed, metrics.pending_entries_examined, metrics.operations_released, released_pct
90
+ ready_percent,
91
+ elapsed,
92
+ metrics.pending_entries_examined,
93
+ metrics.operations_released,
94
+ released_pct
85
95
  );
86
96
  }
87
97
  }
@@ -102,7 +112,10 @@ mod phase_7_1_release_economics {
102
112
  let _ = barrier.receive_operation(format!("seq_{}", i), required);
103
113
  }
104
114
 
105
- println!("Initial pending: {}", barrier.get_pending_operations().len());
115
+ println!(
116
+ "Initial pending: {}",
117
+ barrier.get_pending_operations().len()
118
+ );
106
119
 
107
120
  // Advance frontier multiple times
108
121
  let start = Instant::now();
@@ -137,7 +150,10 @@ mod phase_7_1_release_economics {
137
150
 
138
151
  // Analysis
139
152
  if total_entries_examined > 500 {
140
- println!("⚠️ WARNING: Examined {} entries for 100 pending (10 advances)", total_entries_examined);
153
+ println!(
154
+ "⚠️ WARNING: Examined {} entries for 100 pending (10 advances)",
155
+ total_entries_examined
156
+ );
141
157
  println!(" Expected if O(m): ~100-200");
142
158
  println!(" This suggests possible rescanning behavior");
143
159
  } else {
@@ -159,7 +175,9 @@ mod phase_7_1_release_economics {
159
175
  for i in 0..*pending_size {
160
176
  let mut required = VectorClock::new();
161
177
  let dependency_level = ((i * 997) % 1000) as u64 + 1;
162
- required.clocks.insert("node_a".to_string(), dependency_level);
178
+ required
179
+ .clocks
180
+ .insert("node_a".to_string(), dependency_level);
163
181
  let _ = barrier.receive_operation(format!("mixed_{}", i), required);
164
182
  }
165
183
 
@@ -7,7 +7,6 @@
7
7
  /// - Execution interleaving
8
8
  ///
9
9
  /// Verifies final state matches deterministic reference model.
10
-
11
10
  use crate::convergence::VectorClock;
12
11
  use crate::state_hash::StateHash;
13
12
  use crate::transactions::*;
@@ -71,7 +70,9 @@ impl ConcurrencyFuzzer {
71
70
 
72
71
  /// Generate random transaction
73
72
  fn generate_transaction(&mut self, id: usize) -> FuzzedTransaction {
74
- let num_ops = self.rng.gen_range(1..=self.config.max_operations_per_transaction);
73
+ let num_ops = self
74
+ .rng
75
+ .gen_range(1..=self.config.max_operations_per_transaction);
75
76
  let mut write_set = HashSet::new();
76
77
  let mut read_set = HashSet::new();
77
78
  let mut operations = Vec::new();
@@ -82,10 +83,7 @@ impl ConcurrencyFuzzer {
82
83
  let base_version = StateVersion::new(vc.clone(), format!("genesis_{}", id));
83
84
 
84
85
  for op_idx in 0..num_ops {
85
- let record_id = format!(
86
- "rec_{}",
87
- self.rng.gen_range(0..self.config.max_records)
88
- );
86
+ let record_id = format!("rec_{}", self.rng.gen_range(0..self.config.max_records));
89
87
  let value = self.rng.gen_range(0..1000);
90
88
 
91
89
  let op_id = OperationId::new("fuzzer".to_string(), ((id * 100) + op_idx) as u64);
@@ -109,10 +107,7 @@ impl ConcurrencyFuzzer {
109
107
 
110
108
  // Randomly add read dependencies
111
109
  if self.rng.gen_bool(0.3) {
112
- let read_record = format!(
113
- "rec_{}",
114
- self.rng.gen_range(0..self.config.max_records)
115
- );
110
+ let read_record = format!("rec_{}", self.rng.gen_range(0..self.config.max_records));
116
111
  op = op.with_read_set(vec![StateDependency::new(
117
112
  "fuzzing".to_string(),
118
113
  read_record.clone(),
@@ -190,10 +185,7 @@ impl ConcurrencyFuzzer {
190
185
  let conflict_graph = Self::compute_conflict_graph(workload);
191
186
  let total_conflicts: usize = conflict_graph.iter().map(|(_, v)| v.len()).sum::<usize>() / 2; // Each edge counted twice
192
187
 
193
- let concurrent_transactions = workload
194
- .iter()
195
- .filter(|t| t.operations.len() > 1)
196
- .count();
188
+ let concurrent_transactions = workload.iter().filter(|t| t.operations.len() > 1).count();
197
189
  let sequential_transactions = total_transactions - concurrent_transactions;
198
190
 
199
191
  FuzzingStats {
@@ -422,6 +414,9 @@ mod tests {
422
414
  .filter(|(tx1, tx2)| tx1.write_set != tx2.write_set)
423
415
  .count();
424
416
 
425
- assert!(diff_count > 0, "Different seeds should produce different workloads");
417
+ assert!(
418
+ diff_count > 0,
419
+ "Different seeds should produce different workloads"
420
+ );
426
421
  }
427
422
  }
@@ -18,7 +18,6 @@
18
18
  /// 3. Consensus-Required Operations
19
19
  /// - Must serialize through consensus (strong ordering)
20
20
  /// - Examples: Transfer (requires mutual exclusion)
21
-
22
21
  use crate::operation_algebra::{ConflictType, ConvergenceSemantic, OperationAlgebra};
23
22
  use std::collections::HashMap;
24
23
 
@@ -245,9 +244,7 @@ pub enum NoDowngradeVerificationResult {
245
244
  operations_checked: usize,
246
245
  },
247
246
  /// Silent downgrade detected
248
- DowngradeDetected {
249
- reason: String,
250
- },
247
+ DowngradeDetected { reason: String },
251
248
  }
252
249
 
253
250
  /// Consensus requirement checker
@@ -307,9 +304,7 @@ pub enum ConsensusEnforcementResult {
307
304
  /// No consensus operations
308
305
  NoConsensusOps,
309
306
  /// Consensus requirement satisfied
310
- Satisfied {
311
- consensus_operations: usize,
312
- },
307
+ Satisfied { consensus_operations: usize },
313
308
  /// Consensus requirement violated
314
309
  Violated {
315
310
  operations_requiring_consensus: Vec<String>,
@@ -399,10 +394,7 @@ mod tests {
399
394
  let semantic = ConvergenceSemantic::DeterministicMerge;
400
395
 
401
396
  let result = enforcer.verify_no_downgrade(&semantic);
402
- assert_eq!(
403
- result,
404
- NoDowngradeVerificationResult::NoOperations
405
- );
397
+ assert_eq!(result, NoDowngradeVerificationResult::NoOperations);
406
398
  }
407
399
 
408
400
  #[test]
@@ -18,7 +18,6 @@
18
18
  /// Never:
19
19
  /// - state reflects op but dedup missing (double-apply on retry)
20
20
  /// - dedup has op but state wasn't mutated (phantom operation)
21
-
22
21
  use crate::state_hash::CanonicalState;
23
22
  use std::collections::HashSet;
24
23
 
@@ -37,7 +36,7 @@ pub enum CrashBoundaryPoint {
37
36
  #[derive(Clone, Debug)]
38
37
  pub struct CrashAtomicExecutor {
39
38
  state: CanonicalState,
40
- dedup_set: HashSet<String>, // OperationId set
39
+ dedup_set: HashSet<String>, // OperationId set
41
40
  }
42
41
 
43
42
  impl CrashAtomicExecutor {
@@ -57,7 +56,10 @@ impl CrashAtomicExecutor {
57
56
  ) -> Result<(), String> {
58
57
  // Check for duplicate before applying
59
58
  if self.dedup_set.contains(operation_id) {
60
- return Err(format!("Operation {} already applied (dedup hit)", operation_id));
59
+ return Err(format!(
60
+ "Operation {} already applied (dedup hit)",
61
+ operation_id
62
+ ));
61
63
  }
62
64
 
63
65
  // Simulate state mutation
@@ -114,7 +116,11 @@ impl CrashAtomicExecutor {
114
116
  pub fn recover(&self, crash_state: &CrashRecoveryState) -> RecoveryDecision {
115
117
  let in_dedup = self.dedup_set.contains(&crash_state.operation_id);
116
118
 
117
- match (crash_state.state_mutated, crash_state.dedup_persisted, in_dedup) {
119
+ match (
120
+ crash_state.state_mutated,
121
+ crash_state.dedup_persisted,
122
+ in_dedup,
123
+ ) {
118
124
  // State mutated, dedup persisted → fully applied, don't retry
119
125
  (true, true, true) => RecoveryDecision::AlreadyApplied,
120
126
 
@@ -266,7 +272,10 @@ mod tests {
266
272
  ));
267
273
 
268
274
  let decision = executor.recover(&crash_state);
269
- assert!(matches!(decision, RecoveryDecision::PartiallyApplied { .. }));
275
+ assert!(matches!(
276
+ decision,
277
+ RecoveryDecision::PartiallyApplied { .. }
278
+ ));
270
279
  }
271
280
 
272
281
  #[test]
@@ -2,7 +2,6 @@
2
2
  ///
3
3
  /// Simulates crashes at persistence boundaries to verify recovery behavior.
4
4
  /// Tests that recovery always produces valid state (pre-crash or post-crash, never partial).
5
-
6
5
  use crate::convergence::VectorClock;
7
6
  use crate::operation_log::MemoryOperationLog;
8
7
  use crate::state_hash::{CanonicalState, StateHash};
@@ -34,17 +33,11 @@ pub struct ExecutionCheckpoint {
34
33
  #[derive(Clone, Debug)]
35
34
  pub enum RecoveryResult {
36
35
  /// State is in a valid pre-transaction state
37
- ValidPre {
38
- checkpoint: ExecutionCheckpoint,
39
- },
36
+ ValidPre { checkpoint: ExecutionCheckpoint },
40
37
  /// State is in a valid post-transaction state
41
- ValidPost {
42
- checkpoint: ExecutionCheckpoint,
43
- },
38
+ ValidPost { checkpoint: ExecutionCheckpoint },
44
39
  /// State is corrupted or indeterminate
45
- Invalid {
46
- reason: String,
47
- },
40
+ Invalid { reason: String },
48
41
  }
49
42
 
50
43
  /// Crash injection test harness
@@ -69,7 +62,11 @@ impl CrashInjectionTester {
69
62
 
70
63
  /// Simulate crash before operation log append
71
64
  pub fn crash_before_operation_append(&self, operation: &Operation) -> RecoveryResult {
72
- assert_eq!(self.operation_log.size(), 0, "Operation should not be logged yet");
65
+ assert_eq!(
66
+ self.operation_log.size(),
67
+ 0,
68
+ "Operation should not be logged yet"
69
+ );
73
70
  assert_eq!(
74
71
  self.transition_store.size(),
75
72
  0,
@@ -88,7 +85,9 @@ impl CrashInjectionTester {
88
85
 
89
86
  /// Simulate crash after operation log append (before transition)
90
87
  pub fn crash_after_operation_append(&self, operation: &Operation) -> RecoveryResult {
91
- let op_appended = self.operation_log.contains_operation_id(&operation.operation_id);
88
+ let op_appended = self
89
+ .operation_log
90
+ .contains_operation_id(&operation.operation_id);
92
91
 
93
92
  if !op_appended {
94
93
  return RecoveryResult::Invalid {
@@ -114,9 +113,7 @@ impl CrashInjectionTester {
114
113
 
115
114
  /// Simulate crash after state transition recorded
116
115
  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);
116
+ let transition = self.transition_store.get_by_transaction_id(transaction_id);
120
117
 
121
118
  if transition.is_none() {
122
119
  return RecoveryResult::Invalid {
@@ -279,16 +276,11 @@ mod tests {
279
276
  let mut vc = VectorClock::new();
280
277
  vc.increment("node1");
281
278
 
282
- let from_version = crate::transactions::StateVersion::new(
283
- vc.clone(),
284
- prev_hash.clone(),
285
- );
279
+ let from_version =
280
+ crate::transactions::StateVersion::new(vc.clone(), prev_hash.clone());
286
281
 
287
282
  vc.increment("node1");
288
- let to_version = crate::transactions::StateVersion::new(
289
- vc,
290
- format!("hash{}", i),
291
- );
283
+ let to_version = crate::transactions::StateVersion::new(vc, format!("hash{}", i));
292
284
 
293
285
  let op = create_test_operation(i);
294
286
  let transition = StateTransition::new(
@@ -298,7 +290,10 @@ mod tests {
298
290
  ConsistencyContract::local(),
299
291
  );
300
292
 
301
- tester.transition_store.record_transition(transition).unwrap();
293
+ tester
294
+ .transition_store
295
+ .record_transition(transition)
296
+ .unwrap();
302
297
  prev_hash = format!("hash{}", i);
303
298
  }
304
299
 
@@ -327,7 +322,8 @@ mod tests {
327
322
 
328
323
  let mut vc2 = VectorClock::new();
329
324
  vc2.increment("node1");
330
- let from_version2 = crate::transactions::StateVersion::new(vc2.clone(), "hash_broken".to_string());
325
+ let from_version2 =
326
+ crate::transactions::StateVersion::new(vc2.clone(), "hash_broken".to_string());
331
327
 
332
328
  vc2.increment("node1");
333
329
  let to_version2 = crate::transactions::StateVersion::new(vc2, "hash2".to_string());
@@ -3,7 +3,6 @@
3
3
  /// Comprehensive tests verifying that the transaction system can recover from
4
4
  /// partial failures and crashes. Tests scenarios where operations are logged but
5
5
  /// transitions not persisted, and vice versa.
6
-
7
6
  use crate::convergence::VectorClock;
8
7
  use crate::operation_log::MemoryOperationLog;
9
8
  use crate::state_transition_store::MemoryStateTransitionStore;
@@ -68,7 +67,12 @@ mod crash_recovery {
68
67
 
69
68
  let op_ids: Vec<_> = (1..=5)
70
69
  .map(|i| {
71
- let op = create_test_operation(i, base_version.clone(), &format!("rec{}", i), i as i32 * 10);
70
+ let op = create_test_operation(
71
+ i,
72
+ base_version.clone(),
73
+ &format!("rec{}", i),
74
+ i as i32 * 10,
75
+ );
72
76
  let op_id = op.operation_id.clone();
73
77
  log.append(op).unwrap();
74
78
  op_id
@@ -176,7 +180,8 @@ mod crash_recovery {
176
180
  let base_version = create_version(1, "hash0");
177
181
 
178
182
  for i in 1..=10 {
179
- let op = create_test_operation(i, base_version.clone(), &format!("rec{}", i), i as i32 * 10);
183
+ let op =
184
+ create_test_operation(i, base_version.clone(), &format!("rec{}", i), i as i32 * 10);
180
185
  log.append(op).unwrap();
181
186
  }
182
187
 
@@ -256,12 +261,8 @@ mod crash_recovery {
256
261
  assert!(log.contains_operation_id(&op_id));
257
262
 
258
263
  let ops = vec![create_test_operation(2, base_version.clone(), "rec2", 200)];
259
- let transition = StateTransition::new(
260
- base_version,
261
- ops,
262
- to_version,
263
- ConsistencyContract::local(),
264
- );
264
+ let transition =
265
+ StateTransition::new(base_version, ops, to_version, ConsistencyContract::local());
265
266
 
266
267
  store.record_transition(transition).unwrap();
267
268
  assert_eq!(store.size(), 1);
@@ -275,7 +276,8 @@ mod crash_recovery {
275
276
  let base_version = create_version(1, "hash0");
276
277
 
277
278
  for i in 1..=5 {
278
- let op = create_test_operation(i, base_version.clone(), &format!("rec{}", i), i as i32 * 10);
279
+ let op =
280
+ create_test_operation(i, base_version.clone(), &format!("rec{}", i), i as i32 * 10);
279
281
  log.append(op.clone()).unwrap();
280
282
 
281
283
  let to_version = create_version(i as u64 + 1, &format!("hash{}", i));
@@ -304,7 +306,8 @@ mod crash_recovery {
304
306
  let base_version = create_version(1, "hash0");
305
307
 
306
308
  for i in 1..=10 {
307
- let op = create_test_operation(i, base_version.clone(), &format!("rec{}", i), i as i32 * 10);
309
+ let op =
310
+ create_test_operation(i, base_version.clone(), &format!("rec{}", i), i as i32 * 10);
308
311
  log.append(op).unwrap();
309
312
  }
310
313
 
@@ -55,7 +55,12 @@ mod tests {
55
55
  /// Build an envelope with an explicitly chosen envelope sequence and an
56
56
  /// explicitly chosen causal clock, so the two counters can be moved
57
57
  /// independently -- which is exactly what a restart of the origin does.
58
- fn envelope(origin: &str, sequence: u64, clock: &[(&str, u64)], payload: &str) -> TransactionEnvelope {
58
+ fn envelope(
59
+ origin: &str,
60
+ sequence: u64,
61
+ clock: &[(&str, u64)],
62
+ payload: &str,
63
+ ) -> TransactionEnvelope {
59
64
  let mut fields = HashMap::new();
60
65
  fields.insert("record".to_string(), serde_json::json!(payload));
61
66
  let operation = Operation::new(
@@ -112,7 +117,12 @@ mod tests {
112
117
  for position in 1..=5u64 {
113
118
  let outcome = executor
114
119
  .receive_replicated(
115
- message(envelope("A", position, &[("A", position)], &format!("r{position}"))),
120
+ message(envelope(
121
+ "A",
122
+ position,
123
+ &[("A", position)],
124
+ &format!("r{position}"),
125
+ )),
116
126
  zero_version(),
117
127
  )
118
128
  .expect("receive");
@@ -143,7 +153,10 @@ mod tests {
143
153
 
144
154
  // B's envelope claims to have seen A through position 5.
145
155
  let outcome = executor
146
- .receive_replicated(message(envelope("B", 1, &[("A", 5), ("B", 1)], "b1")), zero_version())
156
+ .receive_replicated(
157
+ message(envelope("B", 1, &[("A", 5), ("B", 1)], "b1")),
158
+ zero_version(),
159
+ )
147
160
  .expect("receive");
148
161
 
149
162
  assert!(
@@ -164,7 +177,12 @@ mod tests {
164
177
  for position in 1..=3u64 {
165
178
  executor
166
179
  .receive_replicated(
167
- message(envelope("A", position, &[("A", position)], &format!("a{position}"))),
180
+ message(envelope(
181
+ "A",
182
+ position,
183
+ &[("A", position)],
184
+ &format!("a{position}"),
185
+ )),
168
186
  zero_version(),
169
187
  )
170
188
  .expect("receive");
@@ -173,7 +191,10 @@ mod tests {
173
191
 
174
192
  // B has seen A through 3, which this replica has too.
175
193
  executor
176
- .receive_replicated(message(envelope("B", 1, &[("A", 3), ("B", 1)], "b1")), zero_version())
194
+ .receive_replicated(
195
+ message(envelope("B", 1, &[("A", 3), ("B", 1)], "b1")),
196
+ zero_version(),
197
+ )
177
198
  .expect("receive");
178
199
 
179
200
  assert_eq!(
@@ -193,12 +214,27 @@ mod tests {
193
214
 
194
215
  // Two origins, interleaved, plus an out-of-order arrival that is held
195
216
  // and later released -- so the applied set is not simply arrival order.
196
- executor.receive_replicated(message(envelope("A", 1, &[("A", 1)], "a1")), zero_version()).unwrap();
197
- executor.receive_replicated(message(envelope("A", 3, &[("A", 3)], "a3")), zero_version()).unwrap();
198
- executor.receive_replicated(message(envelope("A", 2, &[("A", 2)], "a2")), zero_version()).unwrap();
199
- executor.receive_replicated(message(envelope("B", 1, &[("A", 3), ("B", 1)], "b1")), zero_version()).unwrap();
217
+ executor
218
+ .receive_replicated(message(envelope("A", 1, &[("A", 1)], "a1")), zero_version())
219
+ .unwrap();
220
+ executor
221
+ .receive_replicated(message(envelope("A", 3, &[("A", 3)], "a3")), zero_version())
222
+ .unwrap();
223
+ executor
224
+ .receive_replicated(message(envelope("A", 2, &[("A", 2)], "a2")), zero_version())
225
+ .unwrap();
226
+ executor
227
+ .receive_replicated(
228
+ message(envelope("B", 1, &[("A", 3), ("B", 1)], "b1")),
229
+ zero_version(),
230
+ )
231
+ .unwrap();
200
232
 
201
- assert_eq!(executor.pending_causal_count(), 0, "everything was released");
233
+ assert_eq!(
234
+ executor.pending_causal_count(),
235
+ 0,
236
+ "everything was released"
237
+ );
202
238
  assert_eq!(executor.causal_frontier().get("A"), 3);
203
239
  assert_eq!(executor.causal_frontier().get("B"), 1);
204
240
 
@@ -206,7 +242,12 @@ mod tests {
206
242
  // frontier already covers its clock position. So a frontier test would
207
243
  // answer "already applied" for all of them.
208
244
  let frontier = executor.causal_frontier().clone();
209
- let log = executor.operation_log.as_ref().expect("log").load_all().expect("load");
245
+ let log = executor
246
+ .operation_log
247
+ .as_ref()
248
+ .expect("log")
249
+ .load_all()
250
+ .expect("load");
210
251
  for envelope in &log {
211
252
  let origin = &envelope.originating_node;
212
253
  let position = envelope.vector_clock.get(origin);
@@ -238,7 +279,12 @@ mod tests {
238
279
  for position in 1..=3u64 {
239
280
  executor
240
281
  .receive_replicated(
241
- message(envelope("A", position, &[("A", position)], &format!("a{position}"))),
282
+ message(envelope(
283
+ "A",
284
+ position,
285
+ &[("A", position)],
286
+ &format!("a{position}"),
287
+ )),
242
288
  zero_version(),
243
289
  )
244
290
  .expect("receive");
@@ -253,13 +299,21 @@ mod tests {
253
299
  .expect("executor");
254
300
  recovered.load_from_disk(path).expect("recover");
255
301
 
256
- assert_eq!(recovered.causal_frontier().get("A"), 3, "the frontier is rebuilt from the log");
302
+ assert_eq!(
303
+ recovered.causal_frontier().get("A"),
304
+ 3,
305
+ "the frontier is rebuilt from the log"
306
+ );
257
307
 
258
308
  // A retransmission of an already-applied operation after the restart.
259
309
  let again = recovered
260
310
  .receive_replicated(message(envelope("A", 2, &[("A", 2)], "a2")), zero_version())
261
311
  .expect("receive");
262
- assert_eq!(again, ReceiveOutcome::AlreadyKnown, "a duplicate after restart is refused");
312
+ assert_eq!(
313
+ again,
314
+ ReceiveOutcome::AlreadyKnown,
315
+ "a duplicate after restart is refused"
316
+ );
263
317
  }
264
318
 
265
319
  // ---------------------------------------------------------------------
@@ -273,13 +327,22 @@ mod tests {
273
327
  for position in 1..=200u64 {
274
328
  executor
275
329
  .receive_replicated(
276
- message(envelope("A", position, &[("A", position)], &format!("a{position}"))),
330
+ message(envelope(
331
+ "A",
332
+ position,
333
+ &[("A", position)],
334
+ &format!("a{position}"),
335
+ )),
277
336
  zero_version(),
278
337
  )
279
338
  .expect("receive");
280
339
  }
281
340
 
282
- assert_eq!(executor.pending_causal_count(), 0, "the bounded population is empty");
341
+ assert_eq!(
342
+ executor.pending_causal_count(),
343
+ 0,
344
+ "the bounded population is empty"
345
+ );
283
346
  assert_eq!(executor.deferred_causal_count(), 0);
284
347
  assert_eq!(
285
348
  executor.envelopes_seen.len(),
@@ -322,7 +385,10 @@ mod tests {
322
385
 
323
386
  // Before the origin restarts: A's first operation, sequence 1, clock 1.
324
387
  let first = executor
325
- .receive_replicated(message(envelope("A", 1, &[("A", 1)], "before")), zero_version())
388
+ .receive_replicated(
389
+ message(envelope("A", 1, &[("A", 1)], "before")),
390
+ zero_version(),
391
+ )
326
392
  .expect("receive");
327
393
  assert!(matches!(first, ReceiveOutcome::Applied { .. }));
328
394
 
@@ -347,7 +413,9 @@ mod tests {
347
413
  );
348
414
  let state = executor.canonical_state().expect("state");
349
415
  assert!(
350
- !state.records.contains_key(&("items".to_string(), "after".to_string())),
416
+ !state
417
+ .records
418
+ .contains_key(&("items".to_string(), "after".to_string())),
351
419
  "and the write is simply absent: no error, no divergence signal, no retry"
352
420
  );
353
421
 
@@ -374,19 +442,32 @@ mod tests {
374
442
  // before it died.
375
443
  let (mut executor, _dir) = receiver();
376
444
  executor
377
- .receive_replicated(message(envelope("A", 1, &[("A", 1)], "one")), zero_version())
445
+ .receive_replicated(
446
+ message(envelope("A", 1, &[("A", 1)], "one")),
447
+ zero_version(),
448
+ )
378
449
  .expect("receive");
379
450
 
380
451
  // Origin restarts after one operation and commits two more. Sequences
381
452
  // 1 and 2; clock positions 2 and 3.
382
453
  let dropped = executor
383
- .receive_replicated(message(envelope("A", 1, &[("A", 2)], "two")), zero_version())
454
+ .receive_replicated(
455
+ message(envelope("A", 1, &[("A", 2)], "two")),
456
+ zero_version(),
457
+ )
384
458
  .expect("receive");
385
459
  let admitted = executor
386
- .receive_replicated(message(envelope("A", 2, &[("A", 3)], "three")), zero_version())
460
+ .receive_replicated(
461
+ message(envelope("A", 2, &[("A", 3)], "three")),
462
+ zero_version(),
463
+ )
387
464
  .expect("receive");
388
465
 
389
- assert_eq!(dropped, ReceiveOutcome::AlreadyKnown, "the first collides and is lost");
466
+ assert_eq!(
467
+ dropped,
468
+ ReceiveOutcome::AlreadyKnown,
469
+ "the first collides and is lost"
470
+ );
390
471
  assert!(
391
472
  matches!(admitted, ReceiveOutcome::PendingDependencies { .. }),
392
473
  "the second does not collide, is admitted, and is then held forever waiting on \