@feltdb/core 0.4.12 → 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-Q0Nx6gLE.js → components-bHTARBin.js} +156 -46
  161. package/dist/studio/index.js +31 -28
  162. package/dist/studio-app/assets/{index-BHOmLZF-.js → index-BqKquLuU.js} +8 -8
  163. package/dist/studio-app/index.html +1 -1
  164. package/package.json +1 -1
@@ -0,0 +1,251 @@
1
+ use crate::now_ms;
2
+ /// Operation log module for durable append-only mutations
3
+ use serde::{Deserialize, Serialize};
4
+ use serde_json::Value;
5
+ use sha2::{Digest, Sha256};
6
+
7
+ /// A durable operation that can be appended to the log
8
+ #[derive(Debug, Clone, Serialize, Deserialize)]
9
+ pub struct Operation {
10
+ /// Unique operation ID (monotonically increasing)
11
+ pub op_id: u64,
12
+ /// Instance ID - unique identifier for the FeltDB instance that created this operation
13
+ pub instance_id: String,
14
+ /// Sequence number - monotonically increasing sequence per instance
15
+ pub sequence: u64,
16
+ /// Type of operation (insert, update, delete)
17
+ pub op_type: OperationType,
18
+ /// The key being operated on (e.g., "users:123")
19
+ pub key: String,
20
+ /// The value (for insert/update operations)
21
+ pub value: Option<Value>,
22
+ /// Timestamp in milliseconds since UNIX epoch
23
+ pub timestamp_ms: u128,
24
+ /// The data type being operated on
25
+ pub rust_type: String,
26
+ /// Capability/namespace
27
+ pub capability: String,
28
+ /// Content hash - deterministic hash of the operation's content for deduplication
29
+ pub content_hash: String,
30
+ /// Vector clock for causal tracking (optional for backward compatibility)
31
+ #[serde(default)]
32
+ pub vector_clock: Option<std::collections::HashMap<String, u64>>,
33
+ }
34
+
35
+ /// Types of mutations that become durable operations
36
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
37
+ pub enum OperationType {
38
+ /// Insert a new record
39
+ Insert,
40
+ /// Update an existing record
41
+ Update,
42
+ /// Delete an existing record
43
+ Delete,
44
+ }
45
+
46
+ impl Operation {
47
+ /// Create a new insert operation
48
+ pub fn insert(
49
+ op_id: u64,
50
+ instance_id: String,
51
+ sequence: u64,
52
+ key: String,
53
+ value: Value,
54
+ rust_type: String,
55
+ capability: String,
56
+ ) -> Self {
57
+ let op = Self {
58
+ op_id,
59
+ instance_id,
60
+ sequence,
61
+ op_type: OperationType::Insert,
62
+ key,
63
+ value: Some(value),
64
+ timestamp_ms: now_ms(),
65
+ rust_type,
66
+ capability,
67
+ content_hash: String::new(), // Will be computed below
68
+ vector_clock: None,
69
+ };
70
+ let mut result = op;
71
+ result.content_hash = result.compute_content_hash();
72
+ result
73
+ }
74
+
75
+ /// Create a new update operation
76
+ pub fn update(
77
+ op_id: u64,
78
+ instance_id: String,
79
+ sequence: u64,
80
+ key: String,
81
+ value: Value,
82
+ rust_type: String,
83
+ capability: String,
84
+ ) -> Self {
85
+ let op = Self {
86
+ op_id,
87
+ instance_id,
88
+ sequence,
89
+ op_type: OperationType::Update,
90
+ key,
91
+ value: Some(value),
92
+ timestamp_ms: now_ms(),
93
+ rust_type,
94
+ capability,
95
+ content_hash: String::new(), // Will be computed below
96
+ vector_clock: None,
97
+ };
98
+ let mut result = op;
99
+ result.content_hash = result.compute_content_hash();
100
+ result
101
+ }
102
+
103
+ /// Create a new delete operation
104
+ pub fn delete(
105
+ op_id: u64,
106
+ instance_id: String,
107
+ sequence: u64,
108
+ key: String,
109
+ rust_type: String,
110
+ capability: String,
111
+ ) -> Self {
112
+ let op = Self {
113
+ op_id,
114
+ instance_id,
115
+ sequence,
116
+ op_type: OperationType::Delete,
117
+ key,
118
+ value: None,
119
+ timestamp_ms: now_ms(),
120
+ rust_type,
121
+ capability,
122
+ content_hash: String::new(), // Will be computed below
123
+ vector_clock: None,
124
+ };
125
+ let mut result = op;
126
+ result.content_hash = result.compute_content_hash();
127
+ result
128
+ }
129
+
130
+ /// Compute deterministic content hash for this operation
131
+ /// This is used for deduplication across peers
132
+ pub fn compute_content_hash(&self) -> String {
133
+ let mut hasher = Sha256::new();
134
+
135
+ // Hash the operation type
136
+ hasher.update(format!("{:?}", self.op_type).as_bytes());
137
+
138
+ // Hash the key
139
+ hasher.update(self.key.as_bytes());
140
+
141
+ // Hash the value if present
142
+ if let Some(val) = &self.value {
143
+ hasher.update(val.to_string().as_bytes());
144
+ }
145
+
146
+ // Hash the rust type
147
+ hasher.update(self.rust_type.as_bytes());
148
+
149
+ // Hash the capability
150
+ hasher.update(self.capability.as_bytes());
151
+
152
+ let result = hasher.finalize();
153
+ format!("{:x}", result)
154
+ }
155
+
156
+ /// Set the vector clock for this operation
157
+ pub fn with_vector_clock(
158
+ mut self,
159
+ vector_clock: std::collections::HashMap<String, u64>,
160
+ ) -> Self {
161
+ self.vector_clock = Some(vector_clock);
162
+ self
163
+ }
164
+
165
+ /// Get the vector clock for this operation
166
+ pub fn get_vector_clock(&self) -> Option<&std::collections::HashMap<String, u64>> {
167
+ self.vector_clock.as_ref()
168
+ }
169
+ }
170
+
171
+ /// Mutation ordering specification for FeltDB
172
+ /// This defines the order in which mutation side effects occur
173
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
174
+ pub enum MutationOrder {
175
+ /// Conservative: Apply locally first, then persist in background
176
+ /// Mutation → Validate → Apply state transition → Emit diff → Persist
177
+ /// Good for: Interactive feel, optimistic updates
178
+ ApplyFirst,
179
+
180
+ /// Durable: Persist first, then apply and emit
181
+ /// Mutation → Validate → Persist → Apply state transition → Emit diff
182
+ /// Good for: Durability guarantee, no data loss
183
+ PersistFirst,
184
+ }
185
+
186
+ /// The default mutation ordering for FeltDB
187
+ /// We choose PersistFirst to ensure durability guarantees
188
+ pub const DEFAULT_MUTATION_ORDER: MutationOrder = MutationOrder::PersistFirst;
189
+
190
+ #[cfg(test)]
191
+ mod tests {
192
+ use super::*;
193
+
194
+ #[test]
195
+ fn operation_insert_creates_insert_op() {
196
+ let op = Operation::insert(
197
+ 1,
198
+ "inst1".to_string(),
199
+ 1,
200
+ "users:123".to_string(),
201
+ serde_json::json!({"name": "Alice"}),
202
+ "User".to_string(),
203
+ "users".to_string(),
204
+ );
205
+
206
+ assert_eq!(op.op_id, 1);
207
+ assert_eq!(op.instance_id, "inst1");
208
+ assert_eq!(op.sequence, 1);
209
+ assert_eq!(op.op_type, OperationType::Insert);
210
+ assert_eq!(op.key, "users:123");
211
+ assert!(op.value.is_some());
212
+ }
213
+
214
+ #[test]
215
+ fn operation_delete_has_no_value() {
216
+ let op = Operation::delete(
217
+ 2,
218
+ "inst1".to_string(),
219
+ 2,
220
+ "users:456".to_string(),
221
+ "User".to_string(),
222
+ "users".to_string(),
223
+ );
224
+
225
+ assert_eq!(op.op_type, OperationType::Delete);
226
+ assert!(op.value.is_none());
227
+ assert_eq!(op.instance_id, "inst1");
228
+ assert_eq!(op.sequence, 2);
229
+ }
230
+
231
+ #[test]
232
+ fn operations_are_serializable() {
233
+ let op = Operation::update(
234
+ 1,
235
+ "inst1".to_string(),
236
+ 1,
237
+ "users:789".to_string(),
238
+ serde_json::json!({"status": "active"}),
239
+ "User".to_string(),
240
+ "users".to_string(),
241
+ );
242
+
243
+ let json = serde_json::to_string(&op).expect("serialize");
244
+ let deserialized: Operation = serde_json::from_str(&json).expect("deserialize");
245
+
246
+ assert_eq!(deserialized.op_id, op.op_id);
247
+ assert_eq!(deserialized.op_type, op.op_type);
248
+ assert_eq!(deserialized.instance_id, op.instance_id);
249
+ assert_eq!(deserialized.sequence, op.sequence);
250
+ }
251
+ }
@@ -0,0 +1,438 @@
1
+ /// Operation Algebra Registry
2
+ ///
3
+ /// Declares the convergence semantics and merge algebra for every
4
+ /// operation type in FeltDB. Gate 2 requires every replicated operation
5
+ /// to declare how it converges under concurrent application.
6
+ ///
7
+ /// This registry is the foundation of operation-specific CRDT semantics.
8
+
9
+ use std::collections::HashMap;
10
+
11
+ /// Conflict classification for an operation
12
+ #[derive(Clone, Debug, PartialEq, Eq, Hash)]
13
+ pub enum ConflictType {
14
+ /// Commutative: can be applied in any order
15
+ Commutative,
16
+ /// Register: LWW (last-write-wins by timestamp)
17
+ Register,
18
+ /// Set CRDT: union on add, tombstone on remove
19
+ SetCRDT,
20
+ /// Counter CRDT: additive
21
+ CounterCRDT,
22
+ /// Custom: user-provided merge semantics
23
+ Custom(String),
24
+ /// Transaction: requires precondition/consensus
25
+ Transaction,
26
+ }
27
+
28
+ /// How this operation converges with concurrent applications
29
+ #[derive(Clone, Debug, PartialEq, Eq)]
30
+ pub enum ConvergenceSemantic {
31
+ /// All orderings produce identical result
32
+ StrictlyCommutative,
33
+ /// Deterministic merge function resolves concurrent versions
34
+ DeterministicMerge,
35
+ /// Requires consensus/total ordering
36
+ ConsensusRequired,
37
+ }
38
+
39
+ /// Declared convergence algebra for an operation type
40
+ #[derive(Clone, Debug)]
41
+ pub struct OperationAlgebra {
42
+ 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
45
+ pub conflict_type: ConflictType,
46
+ pub convergence_semantic: ConvergenceSemantic,
47
+ 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
50
+ }
51
+
52
+ impl OperationAlgebra {
53
+ pub fn new(
54
+ operation_type: &str,
55
+ read_set_bound: &str,
56
+ write_set_bound: &str,
57
+ conflict_type: ConflictType,
58
+ convergence_semantic: ConvergenceSemantic,
59
+ merge_function_description: &str,
60
+ ) -> Self {
61
+ Self {
62
+ operation_type: operation_type.to_string(),
63
+ read_set_bound: read_set_bound.to_string(),
64
+ write_set_bound: write_set_bound.to_string(),
65
+ conflict_type,
66
+ convergence_semantic,
67
+ merge_function_description: merge_function_description.to_string(),
68
+ commutativity_proof: None,
69
+ determinism_proof: None,
70
+ }
71
+ }
72
+
73
+ pub fn with_proofs(mut self, commutativity: Option<String>, determinism: Option<String>) -> Self {
74
+ self.commutativity_proof = commutativity;
75
+ self.determinism_proof = determinism;
76
+ self
77
+ }
78
+
79
+ pub fn is_commutative(&self) -> bool {
80
+ self.convergence_semantic == ConvergenceSemantic::StrictlyCommutative
81
+ }
82
+
83
+ pub fn is_deterministic(&self) -> bool {
84
+ self.convergence_semantic != ConvergenceSemantic::ConsensusRequired
85
+ }
86
+ }
87
+
88
+ /// Registry of all operation types and their convergence algebra
89
+ pub struct OperationAlgebraRegistry {
90
+ algebras: HashMap<String, OperationAlgebra>,
91
+ }
92
+
93
+ impl OperationAlgebraRegistry {
94
+ /// Create new registry with standard operations
95
+ pub fn new() -> Self {
96
+ let mut registry = Self {
97
+ algebras: HashMap::new(),
98
+ };
99
+ registry.register_standard_operations();
100
+ registry
101
+ }
102
+
103
+ /// Register all standard FeltDB operation types
104
+ fn register_standard_operations(&mut self) {
105
+ // SetField: Last-Write-Wins register
106
+ self.register(
107
+ OperationAlgebra::new(
108
+ "SetField",
109
+ "single_record.field",
110
+ "single_record.field",
111
+ ConflictType::Register,
112
+ ConvergenceSemantic::DeterministicMerge,
113
+ "LWW: max(timestamp, value)",
114
+ )
115
+ .with_proofs(
116
+ None,
117
+ Some("Deterministic: higher timestamp wins deterministically".to_string()),
118
+ ),
119
+ );
120
+
121
+ // Increment: Counter CRDT (commutative addition)
122
+ self.register(
123
+ OperationAlgebra::new(
124
+ "Increment",
125
+ "single_record.field",
126
+ "single_record.field",
127
+ ConflictType::CounterCRDT,
128
+ ConvergenceSemantic::StrictlyCommutative,
129
+ "Counter CRDT: sum(all_increments)",
130
+ )
131
+ .with_proofs(
132
+ Some("Commutative: addition commutes over integers".to_string()),
133
+ Some("Deterministic: sum is deterministic".to_string()),
134
+ ),
135
+ );
136
+
137
+ // AddToSet: Set CRDT (union on add)
138
+ self.register(
139
+ OperationAlgebra::new(
140
+ "AddToSet",
141
+ "single_record.set",
142
+ "single_record.set",
143
+ ConflictType::SetCRDT,
144
+ ConvergenceSemantic::StrictlyCommutative,
145
+ "Set CRDT: union(all_adds)",
146
+ )
147
+ .with_proofs(
148
+ Some("Commutative: set union is commutative".to_string()),
149
+ Some("Deterministic: union is deterministic".to_string()),
150
+ ),
151
+ );
152
+
153
+ // RemoveFromSet: Set CRDT (tombstone semantics)
154
+ self.register(
155
+ OperationAlgebra::new(
156
+ "RemoveFromSet",
157
+ "single_record.set",
158
+ "single_record.set",
159
+ ConflictType::SetCRDT,
160
+ ConvergenceSemantic::DeterministicMerge,
161
+ "Set CRDT: (set - tombstones) ∪ (tombstones resolved by causal ordering)",
162
+ )
163
+ .with_proofs(
164
+ None,
165
+ Some("Deterministic: tombstone semantics with causal ordering".to_string()),
166
+ ),
167
+ );
168
+
169
+ // Create: Conflict detection (earliest timestamp wins deterministically)
170
+ self.register(
171
+ OperationAlgebra::new(
172
+ "Create",
173
+ "none",
174
+ "single_record",
175
+ ConflictType::Register,
176
+ ConvergenceSemantic::DeterministicMerge,
177
+ "Deterministic: min(timestamp, id) for create conflicts",
178
+ )
179
+ .with_proofs(
180
+ None,
181
+ Some("Deterministic: total order via (timestamp, node_id)".to_string()),
182
+ ),
183
+ );
184
+
185
+ // Delete: Tombstone semantics (deterministic)
186
+ self.register(
187
+ OperationAlgebra::new(
188
+ "Delete",
189
+ "single_record",
190
+ "single_record",
191
+ ConflictType::Register,
192
+ ConvergenceSemantic::DeterministicMerge,
193
+ "Tombstone: delete_timestamp determines visibility",
194
+ )
195
+ .with_proofs(
196
+ None,
197
+ Some("Deterministic: tombstone ordering via timestamp and node_id".to_string()),
198
+ ),
199
+ );
200
+
201
+ // Transfer: Business invariant (requires consensus/transaction)
202
+ self.register(
203
+ OperationAlgebra::new(
204
+ "Transfer",
205
+ "source_record,dest_record",
206
+ "source_record,dest_record",
207
+ ConflictType::Transaction,
208
+ ConvergenceSemantic::ConsensusRequired,
209
+ "Transaction: requires precondition validation and consensus ordering",
210
+ )
211
+ .with_proofs(
212
+ None,
213
+ Some("Consensus: total ordering via distributed log".to_string()),
214
+ ),
215
+ );
216
+
217
+ // Append: Sequence ordering (vector clock ordering)
218
+ self.register(
219
+ OperationAlgebra::new(
220
+ "Append",
221
+ "single_sequence",
222
+ "single_sequence",
223
+ ConflictType::Custom("SequenceOrdering".to_string()),
224
+ ConvergenceSemantic::DeterministicMerge,
225
+ "Sequence: vector clock establishes total order",
226
+ )
227
+ .with_proofs(
228
+ None,
229
+ Some("Deterministic: vector clock provides causal lineage".to_string()),
230
+ ),
231
+ );
232
+
233
+ // Noop: No-operation (trivially commutative)
234
+ self.register(
235
+ OperationAlgebra::new(
236
+ "Noop",
237
+ "none",
238
+ "none",
239
+ ConflictType::Commutative,
240
+ ConvergenceSemantic::StrictlyCommutative,
241
+ "No-operation: idempotent, affects nothing",
242
+ )
243
+ .with_proofs(
244
+ Some("Trivially commutative: no state affected".to_string()),
245
+ Some("Trivially deterministic: no change produced".to_string()),
246
+ ),
247
+ );
248
+ }
249
+
250
+ /// Register an operation algebra
251
+ pub fn register(&mut self, algebra: OperationAlgebra) {
252
+ self.algebras.insert(algebra.operation_type.clone(), algebra);
253
+ }
254
+
255
+ /// Look up algebra for operation type
256
+ pub fn get(&self, operation_type: &str) -> Option<&OperationAlgebra> {
257
+ self.algebras.get(operation_type)
258
+ }
259
+
260
+ /// Check if operation type is registered
261
+ pub fn contains(&self, operation_type: &str) -> bool {
262
+ self.algebras.contains_key(operation_type)
263
+ }
264
+
265
+ /// Get all registered algebras
266
+ pub fn all_algebras(&self) -> Vec<&OperationAlgebra> {
267
+ self.algebras.values().collect()
268
+ }
269
+
270
+ /// Verify all registered operations declare convergence semantics
271
+ pub fn verify_all_declared(&self) -> Result<(), Vec<String>> {
272
+ let undeclared: Vec<String> = self
273
+ .algebras
274
+ .values()
275
+ .filter(|a| a.convergence_semantic == ConvergenceSemantic::ConsensusRequired)
276
+ .map(|a| a.operation_type.clone())
277
+ .collect();
278
+
279
+ if undeclared.is_empty() {
280
+ Ok(())
281
+ } else {
282
+ Err(undeclared)
283
+ }
284
+ }
285
+
286
+ /// Count operations by convergence semantic
287
+ pub fn convergence_statistics(&self) -> HashMap<String, usize> {
288
+ let mut stats = HashMap::new();
289
+ for algebra in self.algebras.values() {
290
+ let key = format!("{:?}", algebra.convergence_semantic);
291
+ *stats.entry(key).or_insert(0) += 1;
292
+ }
293
+ stats
294
+ }
295
+ }
296
+
297
+ impl Default for OperationAlgebraRegistry {
298
+ fn default() -> Self {
299
+ Self::new()
300
+ }
301
+ }
302
+
303
+ #[cfg(test)]
304
+ mod tests {
305
+ use super::*;
306
+
307
+ #[test]
308
+ fn test_registry_creation() {
309
+ let registry = OperationAlgebraRegistry::new();
310
+ assert!(registry.algebras.len() > 0);
311
+ }
312
+
313
+ #[test]
314
+ fn test_setfield_is_lww_register() {
315
+ let registry = OperationAlgebraRegistry::new();
316
+ let setfield = registry.get("SetField").unwrap();
317
+
318
+ assert_eq!(setfield.conflict_type, ConflictType::Register);
319
+ assert_eq!(
320
+ setfield.convergence_semantic,
321
+ ConvergenceSemantic::DeterministicMerge
322
+ );
323
+ }
324
+
325
+ #[test]
326
+ fn test_increment_is_commutative() {
327
+ let registry = OperationAlgebraRegistry::new();
328
+ let increment = registry.get("Increment").unwrap();
329
+
330
+ assert!(increment.is_commutative());
331
+ assert_eq!(increment.conflict_type, ConflictType::CounterCRDT);
332
+ }
333
+
334
+ #[test]
335
+ fn test_addtoset_is_commutative() {
336
+ let registry = OperationAlgebraRegistry::new();
337
+ let addtoset = registry.get("AddToSet").unwrap();
338
+
339
+ assert!(addtoset.is_commutative());
340
+ assert_eq!(addtoset.conflict_type, ConflictType::SetCRDT);
341
+ }
342
+
343
+ #[test]
344
+ fn test_transfer_requires_consensus() {
345
+ let registry = OperationAlgebraRegistry::new();
346
+ let transfer = registry.get("Transfer").unwrap();
347
+
348
+ assert!(!transfer.is_commutative());
349
+ assert_eq!(
350
+ transfer.convergence_semantic,
351
+ ConvergenceSemantic::ConsensusRequired
352
+ );
353
+ }
354
+
355
+ #[test]
356
+ fn test_custom_registration() {
357
+ let mut registry = OperationAlgebraRegistry::new();
358
+ let custom = OperationAlgebra::new(
359
+ "MyCustomOp",
360
+ "any",
361
+ "any",
362
+ ConflictType::Custom("my_merge".to_string()),
363
+ ConvergenceSemantic::DeterministicMerge,
364
+ "Custom merge semantics",
365
+ );
366
+
367
+ registry.register(custom);
368
+ assert!(registry.contains("MyCustomOp"));
369
+ }
370
+
371
+ #[test]
372
+ fn test_convergence_statistics() {
373
+ let registry = OperationAlgebraRegistry::new();
374
+ let stats = registry.convergence_statistics();
375
+
376
+ // Should have entries for different convergence semantics
377
+ assert!(stats.len() > 0);
378
+ // Most operations should be deterministic or commutative
379
+ let has_deterministic = stats.values().any(|count| *count > 0);
380
+ assert!(has_deterministic);
381
+ }
382
+
383
+ #[test]
384
+ fn test_algebra_with_proofs() {
385
+ let algebra = OperationAlgebra::new(
386
+ "TestOp",
387
+ "test",
388
+ "test",
389
+ ConflictType::Commutative,
390
+ ConvergenceSemantic::StrictlyCommutative,
391
+ "test merge",
392
+ )
393
+ .with_proofs(
394
+ Some("proof1".to_string()),
395
+ Some("proof2".to_string()),
396
+ );
397
+
398
+ assert!(algebra.commutativity_proof.is_some());
399
+ assert!(algebra.determinism_proof.is_some());
400
+ }
401
+
402
+ #[test]
403
+ fn test_all_standard_operations_registered() {
404
+ let registry = OperationAlgebraRegistry::new();
405
+
406
+ let operations = vec![
407
+ "SetField",
408
+ "Increment",
409
+ "AddToSet",
410
+ "RemoveFromSet",
411
+ "Create",
412
+ "Delete",
413
+ "Transfer",
414
+ "Append",
415
+ "Noop",
416
+ ];
417
+
418
+ for op in operations {
419
+ assert!(registry.contains(op), "Operation {} not registered", op);
420
+ }
421
+ }
422
+
423
+ #[test]
424
+ fn test_operation_is_deterministic() {
425
+ let registry = OperationAlgebraRegistry::new();
426
+
427
+ // Commutative and deterministic merge are deterministic
428
+ let setfield = registry.get("SetField").unwrap();
429
+ assert!(setfield.is_deterministic());
430
+
431
+ let increment = registry.get("Increment").unwrap();
432
+ assert!(increment.is_deterministic());
433
+
434
+ // Consensus operations are NOT deterministic without consensus authority
435
+ let transfer = registry.get("Transfer").unwrap();
436
+ assert!(!transfer.is_deterministic());
437
+ }
438
+ }