@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
@@ -173,7 +173,10 @@ fn lease_is_checked_with_the_server_clock_inside_cas() {
173
173
  current_epoch: 3,
174
174
  }
175
175
  );
176
- assert_eq!(db.get_value(expired_key).unwrap().unwrap()["value"], "before");
176
+ assert_eq!(
177
+ db.get_value(expired_key).unwrap().unwrap()["value"],
178
+ "before"
179
+ );
177
180
 
178
181
  drop(db);
179
182
  let _ = fs::remove_file(path);
@@ -7,7 +7,6 @@
7
7
  /// - Node health (operations applied, crash count)
8
8
  /// - Recovery metrics (duration, type)
9
9
  /// - Operation status (acknowledged, committed, diverged, lost)
10
-
11
10
  use std::sync::atomic::{AtomicU64, Ordering};
12
11
  use std::sync::Arc;
13
12
  use std::time::{Duration, SystemTime, UNIX_EPOCH};
@@ -5,7 +5,6 @@
5
5
  ///
6
6
  /// This is the core Gate 1 test: does operation-specific merge
7
7
  /// semantics guarantee convergence despite arbitrary delivery order?
8
-
9
8
  use crate::operation_log::MemoryOperationLog;
10
9
  use crate::permutation_scheduler::{OperationSchedule, PermutationScheduler};
11
10
  use crate::replay_fuzzing::ReplayFuzzer;
@@ -201,7 +200,7 @@ impl ConvergenceAggregation {
201
200
  mod tests {
202
201
  use super::*;
203
202
  use crate::convergence::VectorClock;
204
- use crate::transactions::{OperationId, OperationCommand, StateVersion};
203
+ use crate::transactions::{OperationCommand, OperationId, StateVersion};
205
204
  use std::collections::HashMap;
206
205
 
207
206
  fn create_test_operation(seq: u64, collection: &str, record_id: &str, value: i32) -> Operation {
@@ -169,7 +169,10 @@ impl TransactionRecord {
169
169
 
170
170
  /// Records touched by this transaction, for conflict detection.
171
171
  pub fn touched_keys(&self) -> HashSet<(String, String)> {
172
- self.operations.iter().map(|operation| operation.key()).collect()
172
+ self.operations
173
+ .iter()
174
+ .map(|operation| operation.key())
175
+ .collect()
173
176
  }
174
177
  }
175
178
 
@@ -177,12 +180,18 @@ impl TransactionRecord {
177
180
  #[derive(Clone, Debug, PartialEq, Eq)]
178
181
  pub enum RejectionReason {
179
182
  /// A precondition did not hold. Carries the operation index and a reason.
180
- PreconditionFailed { operation_index: usize, detail: String },
183
+ PreconditionFailed {
184
+ operation_index: usize,
185
+ detail: String,
186
+ },
181
187
  /// The transaction contained no operations.
182
188
  Empty,
183
189
  /// The transaction writes the same record twice, so its outcome would
184
190
  /// depend on operation order rather than on the transaction as a whole.
185
- ConflictingWritesWithinTransaction { collection: String, record_id: String },
191
+ ConflictingWritesWithinTransaction {
192
+ collection: String,
193
+ record_id: String,
194
+ },
186
195
  }
187
196
 
188
197
  /// The outcome of applying a record to derived state.
@@ -265,7 +274,10 @@ impl AtomicTransactionLog {
265
274
  /// Read the log without modifying it.
266
275
  pub fn read_log(path: &Path) -> Result<RecoveryReport, std::io::Error> {
267
276
  if !path.exists() {
268
- return Ok(RecoveryReport { committed: Vec::new(), discarded_tail: None });
277
+ return Ok(RecoveryReport {
278
+ committed: Vec::new(),
279
+ discarded_tail: None,
280
+ });
269
281
  }
270
282
 
271
283
  let reader = BufReader::new(File::open(path)?);
@@ -286,7 +298,9 @@ impl AtomicTransactionLog {
286
298
  }
287
299
  line_number += 1;
288
300
  let terminated = buffer.ends_with(b"\n");
289
- let text = String::from_utf8_lossy(&buffer).trim_end_matches('\n').to_string();
301
+ let text = String::from_utf8_lossy(&buffer)
302
+ .trim_end_matches('\n')
303
+ .to_string();
290
304
  entries.push((line_number, text, terminated));
291
305
  }
292
306
 
@@ -311,21 +325,28 @@ impl AtomicTransactionLog {
311
325
  // An unterminated, unparseable, or checksum-failing final entry
312
326
  // is a transaction that was still being written when the
313
327
  // process died. It never committed.
314
- defect = Some(LogDefect::TornTail { bytes: text.len() + usize::from(terminated) });
328
+ defect = Some(LogDefect::TornTail {
329
+ bytes: text.len() + usize::from(terminated),
330
+ });
315
331
  } else {
316
332
  return Err(std::io::Error::new(
317
333
  std::io::ErrorKind::InvalidData,
318
334
  format!(
319
335
  "transaction log corrupted at line {}: {}",
320
336
  number,
321
- parsed.err().map(|error| error.to_string())
337
+ parsed
338
+ .err()
339
+ .map(|error| error.to_string())
322
340
  .unwrap_or_else(|| "checksum mismatch".to_string())
323
341
  ),
324
342
  ));
325
343
  }
326
344
  }
327
345
 
328
- Ok(RecoveryReport { committed, discarded_tail: defect })
346
+ Ok(RecoveryReport {
347
+ committed,
348
+ discarded_tail: defect,
349
+ })
329
350
  }
330
351
 
331
352
  /// Commit a record: one write, one fsync. This is the atomic commit point.
@@ -420,7 +441,11 @@ pub struct TransactionExecutor {
420
441
 
421
442
  impl TransactionExecutor {
422
443
  pub fn new() -> Self {
423
- Self { state: CanonicalState::new(), applied: HashSet::new(), applied_order: Vec::new() }
444
+ Self {
445
+ state: CanonicalState::new(),
446
+ applied: HashSet::new(),
447
+ applied_order: Vec::new(),
448
+ }
424
449
  }
425
450
 
426
451
  pub fn state(&self) -> &CanonicalState {
@@ -455,8 +480,12 @@ impl TransactionExecutor {
455
480
  }
456
481
 
457
482
  for (index, operation) in record.operations.iter().enumerate() {
458
- let Some(precondition) = &operation.precondition else { continue };
459
- let current = self.state.get_record(&operation.collection, &operation.record_id);
483
+ let Some(precondition) = &operation.precondition else {
484
+ continue;
485
+ };
486
+ let current = self
487
+ .state
488
+ .get_record(&operation.collection, &operation.record_id);
460
489
  let failure = match (precondition, current) {
461
490
  (Precondition::MustExist, None) => Some("record does not exist".to_string()),
462
491
  (Precondition::MustNotExist, Some(_)) => Some("record already exists".to_string()),
@@ -467,7 +496,10 @@ impl TransactionExecutor {
467
496
  _ => None,
468
497
  };
469
498
  if let Some(detail) = failure {
470
- return Err(RejectionReason::PreconditionFailed { operation_index: index, detail });
499
+ return Err(RejectionReason::PreconditionFailed {
500
+ operation_index: index,
501
+ detail,
502
+ });
471
503
  }
472
504
  }
473
505
 
@@ -486,8 +518,11 @@ impl TransactionExecutor {
486
518
  // Preflight succeeded, so every mutation below is known to be legal.
487
519
  // Staging them first keeps the mutation phase free of any decision that
488
520
  // could fail half-way through.
489
- let staged: Vec<(&TransactionOperation, ())> =
490
- record.operations.iter().map(|operation| (operation, ())).collect();
521
+ let staged: Vec<(&TransactionOperation, ())> = record
522
+ .operations
523
+ .iter()
524
+ .map(|operation| (operation, ()))
525
+ .collect();
491
526
  for (operation, ()) in staged {
492
527
  match &operation.op {
493
528
  TransactionOp::Set(value) => self.state.set_record(
@@ -526,11 +561,14 @@ impl TransactionExecutor {
526
561
  .iter()
527
562
  .filter(|operation| match &operation.op {
528
563
  TransactionOp::Set(value) => {
529
- self.state.get_record(&operation.collection, &operation.record_id) == Some(value)
530
- }
531
- TransactionOp::Delete => {
532
- self.state.get_record(&operation.collection, &operation.record_id).is_none()
564
+ self.state
565
+ .get_record(&operation.collection, &operation.record_id)
566
+ == Some(value)
533
567
  }
568
+ TransactionOp::Delete => self
569
+ .state
570
+ .get_record(&operation.collection, &operation.record_id)
571
+ .is_none(),
534
572
  })
535
573
  .count()
536
574
  }
@@ -554,12 +592,29 @@ pub struct TransactionalNode {
554
592
 
555
593
  impl TransactionalNode {
556
594
  /// Start a node, recovering derived state from the durable log.
557
- pub fn open<P: AsRef<Path>>(path: P, node_id: &str) -> Result<(Self, RecoveryReport), std::io::Error> {
595
+ pub fn open<P: AsRef<Path>>(
596
+ path: P,
597
+ node_id: &str,
598
+ ) -> Result<(Self, RecoveryReport), std::io::Error> {
558
599
  let (log, report) = AtomicTransactionLog::open(path)?;
559
600
  let mut executor = TransactionExecutor::new();
560
601
  executor.recover(&report.committed);
561
- let next_sequence = report.committed.iter().map(|record| record.sequence).max().unwrap_or(0) + 1;
562
- Ok((Self { log, executor, node_id: node_id.to_string(), next_sequence }, report))
602
+ let next_sequence = report
603
+ .committed
604
+ .iter()
605
+ .map(|record| record.sequence)
606
+ .max()
607
+ .unwrap_or(0)
608
+ + 1;
609
+ Ok((
610
+ Self {
611
+ log,
612
+ executor,
613
+ node_id: node_id.to_string(),
614
+ next_sequence,
615
+ },
616
+ report,
617
+ ))
563
618
  }
564
619
 
565
620
  pub fn state(&self) -> &CanonicalState {
@@ -574,8 +629,17 @@ impl TransactionalNode {
574
629
  &mut self.log
575
630
  }
576
631
 
577
- pub fn build(&mut self, transaction_id: &str, operations: Vec<TransactionOperation>) -> TransactionRecord {
578
- let record = TransactionRecord::new(transaction_id, &self.node_id, self.next_sequence, operations);
632
+ pub fn build(
633
+ &mut self,
634
+ transaction_id: &str,
635
+ operations: Vec<TransactionOperation>,
636
+ ) -> TransactionRecord {
637
+ let record = TransactionRecord::new(
638
+ transaction_id,
639
+ &self.node_id,
640
+ self.next_sequence,
641
+ operations,
642
+ );
579
643
  self.next_sequence += 1;
580
644
  record
581
645
  }
@@ -585,7 +649,11 @@ impl TransactionalNode {
585
649
  /// A rejected transaction is never written to the log, so a failed
586
650
  /// precondition leaves no trace in durable state.
587
651
  pub fn commit(&mut self, record: &TransactionRecord) -> Result<ApplyOutcome, std::io::Error> {
588
- if self.executor.applied_transactions().contains(&record.transaction_id) {
652
+ if self
653
+ .executor
654
+ .applied_transactions()
655
+ .contains(&record.transaction_id)
656
+ {
589
657
  return Ok(ApplyOutcome::AlreadyApplied);
590
658
  }
591
659
  if let Err(reason) = self.executor.preflight(record) {
@@ -640,14 +708,23 @@ impl TransactionalNode {
640
708
  /// Applying a replicated transaction is the same all-or-nothing path, and
641
709
  /// a transaction already applied here is ignored, so duplicate delivery is
642
710
  /// safe.
643
- pub fn accept_replicated(&mut self, record: &TransactionRecord) -> Result<ApplyOutcome, std::io::Error> {
711
+ pub fn accept_replicated(
712
+ &mut self,
713
+ record: &TransactionRecord,
714
+ ) -> Result<ApplyOutcome, std::io::Error> {
644
715
  if !record.verify_checksum() {
645
- return Ok(ApplyOutcome::Rejected(RejectionReason::PreconditionFailed {
646
- operation_index: 0,
647
- detail: "replicated record failed its integrity check".to_string(),
648
- }));
716
+ return Ok(ApplyOutcome::Rejected(
717
+ RejectionReason::PreconditionFailed {
718
+ operation_index: 0,
719
+ detail: "replicated record failed its integrity check".to_string(),
720
+ },
721
+ ));
649
722
  }
650
- if self.executor.applied_transactions().contains(&record.transaction_id) {
723
+ if self
724
+ .executor
725
+ .applied_transactions()
726
+ .contains(&record.transaction_id)
727
+ {
651
728
  return Ok(ApplyOutcome::AlreadyApplied);
652
729
  }
653
730
  if let Err(reason) = self.executor.preflight(record) {
@@ -7,11 +7,10 @@
7
7
  /// - Rejected operations tracking
8
8
  /// - Index health metrics
9
9
  /// - Recovery state visibility
10
-
11
10
  use serde::{Deserialize, Serialize};
12
11
  use std::collections::HashMap;
13
- use std::sync::Arc;
14
12
  use std::sync::atomic::{AtomicU64, Ordering};
13
+ use std::sync::Arc;
15
14
 
16
15
  #[derive(Debug, Clone, Serialize, Deserialize)]
17
16
  pub struct ReplicationLagMetric {
@@ -102,7 +101,13 @@ impl ObservabilityManager {
102
101
  }
103
102
  }
104
103
 
105
- pub fn record_replication_lag(&mut self, source: String, target: String, lag_ms: u64, pending: u64) {
104
+ pub fn record_replication_lag(
105
+ &mut self,
106
+ source: String,
107
+ target: String,
108
+ lag_ms: u64,
109
+ pending: u64,
110
+ ) {
106
111
  let now = std::time::SystemTime::now()
107
112
  .duration_since(std::time::UNIX_EPOCH)
108
113
  .unwrap_or_default()
@@ -250,7 +255,8 @@ impl ObservabilityManager {
250
255
  }
251
256
 
252
257
  pub fn record_operation_throughput(&self, ops_per_sec: u64) {
253
- self.operation_throughput.store(ops_per_sec, Ordering::Relaxed);
258
+ self.operation_throughput
259
+ .store(ops_per_sec, Ordering::Relaxed);
254
260
  }
255
261
 
256
262
  pub fn get_health_report(&self) -> HealthReport {
@@ -259,7 +265,8 @@ impl ObservabilityManager {
259
265
  .unwrap_or_default()
260
266
  .as_secs();
261
267
 
262
- let overall_status = if self.convergence_status
268
+ let overall_status = if self
269
+ .convergence_status
263
270
  .values()
264
271
  .all(|c| c.diverged_peers.is_empty())
265
272
  {
@@ -273,7 +280,13 @@ impl ObservabilityManager {
273
280
  overall_status: overall_status.to_string(),
274
281
  replication_lag: self.replication_lags.values().cloned().collect(),
275
282
  convergence: self.convergence_status.values().cloned().collect(),
276
- rejected_operations: self.rejected_operations.iter().rev().take(100).cloned().collect(),
283
+ rejected_operations: self
284
+ .rejected_operations
285
+ .iter()
286
+ .rev()
287
+ .take(100)
288
+ .cloned()
289
+ .collect(),
277
290
  index_health: self.index_health.values().cloned().collect(),
278
291
  recovery_states: self.recovery_states.values().cloned().collect(),
279
292
  query_latency_p99: self.query_latency_p99.load(Ordering::Relaxed),
@@ -5,7 +5,6 @@
5
5
  /// to declare how it converges under concurrent application.
6
6
  ///
7
7
  /// This registry is the foundation of operation-specific CRDT semantics.
8
-
9
8
  use std::collections::HashMap;
10
9
 
11
10
  /// Conflict classification for an operation
@@ -40,13 +39,13 @@ pub enum ConvergenceSemantic {
40
39
  #[derive(Clone, Debug)]
41
40
  pub struct OperationAlgebra {
42
41
  pub operation_type: String,
43
- pub read_set_bound: String, // "single_record", "multiple_records", etc
44
- pub write_set_bound: String, // "single_record", "multiple_records", etc
42
+ pub read_set_bound: String, // "single_record", "multiple_records", etc
43
+ pub write_set_bound: String, // "single_record", "multiple_records", etc
45
44
  pub conflict_type: ConflictType,
46
45
  pub convergence_semantic: ConvergenceSemantic,
47
46
  pub merge_function_description: String,
48
- pub commutativity_proof: Option<String>, // Reference to commutative algebra proof
49
- pub determinism_proof: Option<String>, // Reference to determinism proof
47
+ pub commutativity_proof: Option<String>, // Reference to commutative algebra proof
48
+ pub determinism_proof: Option<String>, // Reference to determinism proof
50
49
  }
51
50
 
52
51
  impl OperationAlgebra {
@@ -70,7 +69,11 @@ impl OperationAlgebra {
70
69
  }
71
70
  }
72
71
 
73
- pub fn with_proofs(mut self, commutativity: Option<String>, determinism: Option<String>) -> Self {
72
+ pub fn with_proofs(
73
+ mut self,
74
+ commutativity: Option<String>,
75
+ determinism: Option<String>,
76
+ ) -> Self {
74
77
  self.commutativity_proof = commutativity;
75
78
  self.determinism_proof = determinism;
76
79
  self
@@ -249,7 +252,8 @@ impl OperationAlgebraRegistry {
249
252
 
250
253
  /// Register an operation algebra
251
254
  pub fn register(&mut self, algebra: OperationAlgebra) {
252
- self.algebras.insert(algebra.operation_type.clone(), algebra);
255
+ self.algebras
256
+ .insert(algebra.operation_type.clone(), algebra);
253
257
  }
254
258
 
255
259
  /// Look up algebra for operation type
@@ -390,10 +394,7 @@ mod tests {
390
394
  ConvergenceSemantic::StrictlyCommutative,
391
395
  "test merge",
392
396
  )
393
- .with_proofs(
394
- Some("proof1".to_string()),
395
- Some("proof2".to_string()),
396
- );
397
+ .with_proofs(Some("proof1".to_string()), Some("proof2".to_string()));
397
398
 
398
399
  assert!(algebra.commutativity_proof.is_some());
399
400
  assert!(algebra.determinism_proof.is_some());
@@ -3,8 +3,7 @@
3
3
  /// Append-only log storing all executed operations for durability, replay, and recovery.
4
4
  /// Operations are immutable once appended; the log is the authoritative source for
5
5
  /// what has been executed in the system.
6
-
7
- use crate::transactions::{OperationId, Operation, StateVersion};
6
+ use crate::transactions::{Operation, OperationId, StateVersion};
8
7
  use std::collections::HashMap;
9
8
  use std::sync::{Arc, Mutex};
10
9
 
@@ -39,7 +38,10 @@ impl MemoryOperationLog {
39
38
  let mut entries = self.entries.lock().unwrap();
40
39
  let mut by_id = self.by_id.lock().unwrap();
41
40
 
42
- let op_id_key = format!("{}:{}", operation.operation_id.node_id, operation.operation_id.sequence);
41
+ let op_id_key = format!(
42
+ "{}:{}",
43
+ operation.operation_id.node_id, operation.operation_id.sequence
44
+ );
43
45
 
44
46
  if by_id.contains_key(&op_id_key) {
45
47
  return Err(format!("Operation already logged: {}", op_id_key));
@@ -125,7 +127,10 @@ impl MemoryOperationLog {
125
127
 
126
128
  let removed: Vec<_> = entries.drain(truncate_at as usize..).collect();
127
129
  for entry in removed {
128
- let op_id_key = format!("{}:{}", entry.operation_id.node_id, entry.operation_id.sequence);
130
+ let op_id_key = format!(
131
+ "{}:{}",
132
+ entry.operation_id.node_id, entry.operation_id.sequence
133
+ );
129
134
  by_id.remove(&op_id_key);
130
135
  }
131
136
 
@@ -25,8 +25,16 @@ mod tests {
25
25
  fn user_order_audit() -> Vec<AtomicMutation> {
26
26
  vec![
27
27
  mutation("users", "users:u1", json!({ "id": "u1", "name": "Ada" })),
28
- mutation("orders", "orders:o1", json!({ "id": "o1", "user": "u1", "total": 42 })),
29
- mutation("audit", "audit:a1", json!({ "id": "a1", "event": "order.created" })),
28
+ mutation(
29
+ "orders",
30
+ "orders:o1",
31
+ json!({ "id": "o1", "user": "u1", "total": 42 }),
32
+ ),
33
+ mutation(
34
+ "audit",
35
+ "audit:a1",
36
+ json!({ "id": "a1", "event": "order.created" }),
37
+ ),
30
38
  ]
31
39
  }
32
40
 
@@ -42,7 +50,8 @@ mod tests {
42
50
  }
43
51
 
44
52
  #[test]
45
- fn a_cross_collection_transaction_commits_every_operation() -> Result<(), Box<dyn std::error::Error>> {
53
+ fn a_cross_collection_transaction_commits_every_operation(
54
+ ) -> Result<(), Box<dyn std::error::Error>> {
46
55
  let dir = TempDir::new()?;
47
56
  let path = dir.path().join("app.log");
48
57
  let db = FeltDb::open(&path)?;
@@ -65,12 +74,17 @@ mod tests {
65
74
  }
66
75
 
67
76
  let reopened = FeltDb::open(&path)?;
68
- assert_eq!(visible_count(&reopened), 3, "every row must recover together");
77
+ assert_eq!(
78
+ visible_count(&reopened),
79
+ 3,
80
+ "every row must recover together"
81
+ );
69
82
  Ok(())
70
83
  }
71
84
 
72
85
  #[test]
73
- fn a_failed_precondition_leaves_no_operation_applied() -> Result<(), Box<dyn std::error::Error>> {
86
+ fn a_failed_precondition_leaves_no_operation_applied() -> Result<(), Box<dyn std::error::Error>>
87
+ {
74
88
  let dir = TempDir::new()?;
75
89
  let path = dir.path().join("app.log");
76
90
  let db = FeltDb::open(&path)?;
@@ -82,8 +96,12 @@ mod tests {
82
96
  expected_version: Some(7),
83
97
  }];
84
98
 
85
- let outcome = db.apply_atomic_transaction("tx-bad", None, &preconditions, &user_order_audit(), None);
86
- assert!(outcome.is_err(), "a failed precondition must reject the transaction");
99
+ let outcome =
100
+ db.apply_atomic_transaction("tx-bad", None, &preconditions, &user_order_audit(), None);
101
+ assert!(
102
+ outcome.is_err(),
103
+ "a failed precondition must reject the transaction"
104
+ );
87
105
 
88
106
  assert_eq!(visible_count(&db), 0, "no operation may be applied");
89
107
  drop(db);
@@ -102,7 +120,10 @@ mod tests {
102
120
  let first = db.apply_atomic_transaction("tx-1", None, &[], &user_order_audit(), None)?;
103
121
  assert!(!first.duplicate);
104
122
  let second = db.apply_atomic_transaction("tx-1", None, &[], &user_order_audit(), None)?;
105
- assert!(second.duplicate, "the same transaction id must not apply twice");
123
+ assert!(
124
+ second.duplicate,
125
+ "the same transaction id must not apply twice"
126
+ );
106
127
  assert_eq!(visible_count(&db), 3);
107
128
  Ok(())
108
129
  }
@@ -118,8 +139,12 @@ mod tests {
118
139
  }
119
140
 
120
141
  let reopened = FeltDb::open(&path)?;
121
- let replayed = reopened.apply_atomic_transaction("tx-stable", None, &[], &user_order_audit(), None)?;
122
- assert!(replayed.duplicate, "identity must be restored so redelivery stays idempotent");
142
+ let replayed =
143
+ reopened.apply_atomic_transaction("tx-stable", None, &[], &user_order_audit(), None)?;
144
+ assert!(
145
+ replayed.duplicate,
146
+ "identity must be restored so redelivery stays idempotent"
147
+ );
123
148
  assert_eq!(visible_count(&reopened), 3);
124
149
  Ok(())
125
150
  }
@@ -132,8 +157,8 @@ mod tests {
132
157
  /// intact. Refusing to open at all would turn a normal crash into an
133
158
  /// outage.
134
159
  #[test]
135
- fn a_torn_transaction_record_is_discarded_and_the_store_still_opens()
136
- -> Result<(), Box<dyn std::error::Error>> {
160
+ fn a_torn_transaction_record_is_discarded_and_the_store_still_opens(
161
+ ) -> Result<(), Box<dyn std::error::Error>> {
137
162
  let dir = TempDir::new()?;
138
163
  let path = dir.path().join("app.log");
139
164
 
@@ -154,7 +179,11 @@ mod tests {
154
179
  let recovered = FeltDb::open(&path).map_err(|error| {
155
180
  format!("a torn tail must not stop the store from opening: {error}")
156
181
  })?;
157
- assert_eq!(visible_count(&recovered), 3, "committed history must survive");
182
+ assert_eq!(
183
+ visible_count(&recovered),
184
+ 3,
185
+ "committed history must survive"
186
+ );
158
187
  Ok(())
159
188
  }
160
189
 
@@ -178,7 +207,11 @@ mod tests {
178
207
  "tx-2",
179
208
  None,
180
209
  &[],
181
- &[mutation("users", "users:u2", json!({ "id": "u2", "name": "Grace" }))],
210
+ &[mutation(
211
+ "users",
212
+ "users:u2",
213
+ json!({ "id": "u2", "name": "Grace" }),
214
+ )],
182
215
  None,
183
216
  )?;
184
217
  }
@@ -193,8 +226,15 @@ mod tests {
193
226
  drop(file);
194
227
 
195
228
  let recovered = FeltDb::open(&path)?;
196
- assert_eq!(visible_count(&recovered), 3, "the committed transaction survives");
197
- assert!(!present(&recovered, "users:u2"), "a torn transaction must apply nothing");
229
+ assert_eq!(
230
+ visible_count(&recovered),
231
+ 3,
232
+ "the committed transaction survives"
233
+ );
234
+ assert!(
235
+ !present(&recovered, "users:u2"),
236
+ "a torn transaction must apply nothing"
237
+ );
198
238
  Ok(())
199
239
  }
200
240
 
@@ -245,9 +285,16 @@ mod tests {
245
285
  }
246
286
 
247
287
  let reopened = FeltDb::open(&path)?;
248
- assert!(present(&reopened, "users:solo"), "single writes must still recover");
288
+ assert!(
289
+ present(&reopened, "users:solo"),
290
+ "single writes must still recover"
291
+ );
249
292
  assert!(present(&reopened, "users:solo2"));
250
- assert_eq!(visible_count(&reopened), 3, "transaction rows recover alongside them");
293
+ assert_eq!(
294
+ visible_count(&reopened),
295
+ 3,
296
+ "transaction rows recover alongside them"
297
+ );
251
298
  Ok(())
252
299
  }
253
300