@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,409 @@
1
+ /// Distributed Capability Routing module
2
+ ///
3
+ /// Handles routing capability execution requests to appropriate peers based on:
4
+ /// - Local vs remote capability availability
5
+ /// - Required state version compatibility
6
+ /// - Peer state acquisition capabilities
7
+ /// - Execution ownership semantics
8
+ use crate::{CapabilityExecutionResult, CapabilityRef, DistributedCapabilityAdvertisement};
9
+ use serde::{Deserialize, Serialize};
10
+ use std::collections::HashMap;
11
+
12
+ /// Route decision for capability execution
13
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
14
+ pub enum RouteDecision {
15
+ /// Execute locally
16
+ Local,
17
+ /// Execute remotely at specific peer
18
+ Remote(String), // peer_id
19
+ /// No suitable provider found
20
+ Unavailable,
21
+ }
22
+
23
+ /// State version tracking for a peer
24
+ #[derive(Debug, Clone, Serialize, Deserialize)]
25
+ pub struct PeerStateVersion {
26
+ /// Peer ID
27
+ pub peer_id: String,
28
+ /// Namespace
29
+ pub namespace: String,
30
+ /// Current version at this peer
31
+ pub version: u64,
32
+ /// When the version was last updated
33
+ pub updated_ms: u128,
34
+ }
35
+
36
+ impl PeerStateVersion {
37
+ pub fn new(peer_id: String, namespace: String, version: u64) -> Self {
38
+ Self {
39
+ peer_id,
40
+ namespace,
41
+ version,
42
+ updated_ms: crate::now_ms(),
43
+ }
44
+ }
45
+ }
46
+
47
+ /// State-aware capability routing engine
48
+ pub struct CapabilityRouter {
49
+ /// Local capabilities
50
+ local_capabilities: HashMap<String, DistributedCapabilityAdvertisement>,
51
+ /// Remote capabilities by peer
52
+ remote_capabilities: HashMap<String, Vec<DistributedCapabilityAdvertisement>>,
53
+ /// Peer state versions
54
+ peer_state_versions: HashMap<String, PeerStateVersion>,
55
+ }
56
+
57
+ impl CapabilityRouter {
58
+ pub fn new() -> Self {
59
+ Self {
60
+ local_capabilities: HashMap::new(),
61
+ remote_capabilities: HashMap::new(),
62
+ peer_state_versions: HashMap::new(),
63
+ }
64
+ }
65
+
66
+ /// Register a local capability
67
+ pub fn register_local(&mut self, ad: DistributedCapabilityAdvertisement) {
68
+ self.local_capabilities
69
+ .insert(ad.capability_ref.canonical(), ad);
70
+ }
71
+
72
+ /// Register a remote capability
73
+ pub fn register_remote(&mut self, ad: DistributedCapabilityAdvertisement) {
74
+ let peer_id = ad.peer_id.clone();
75
+ self.remote_capabilities
76
+ .entry(peer_id)
77
+ .or_insert_with(Vec::new)
78
+ .push(ad);
79
+ }
80
+
81
+ /// Update peer state version
82
+ pub fn update_peer_state(&mut self, peer_id: String, namespace: String, version: u64) {
83
+ let key = format!("{}:{}", peer_id, namespace);
84
+ self.peer_state_versions
85
+ .insert(key, PeerStateVersion::new(peer_id, namespace, version));
86
+ }
87
+
88
+ /// Get the state version a peer has for a namespace
89
+ pub fn get_peer_state_version(&self, peer_id: &str, namespace: &str) -> u64 {
90
+ let key = format!("{}:{}", peer_id, namespace);
91
+ self.peer_state_versions
92
+ .get(&key)
93
+ .map(|v| v.version)
94
+ .unwrap_or(0)
95
+ }
96
+
97
+ /// Route a capability execution request
98
+ pub fn route(
99
+ &self,
100
+ cap_ref: &CapabilityRef,
101
+ required_state_version: u64,
102
+ local_peer_id: &str,
103
+ ) -> RouteDecision {
104
+ let canonical = cap_ref.canonical();
105
+
106
+ // Check if capability is available locally
107
+ if self.local_capabilities.contains_key(&canonical) {
108
+ // Check if local state meets requirements
109
+ if self.check_state_compatibility(local_peer_id, cap_ref, required_state_version) {
110
+ return RouteDecision::Local;
111
+ }
112
+ }
113
+
114
+ // Find remote providers with compatible state
115
+ let providers = self.find_compatible_providers(cap_ref, required_state_version);
116
+
117
+ if let Some(provider) = providers.first() {
118
+ RouteDecision::Remote(provider.peer_id.clone())
119
+ } else {
120
+ RouteDecision::Unavailable
121
+ }
122
+ }
123
+
124
+ /// Check if a peer has compatible state version
125
+ fn check_state_compatibility(
126
+ &self,
127
+ peer_id: &str,
128
+ cap_ref: &CapabilityRef,
129
+ required_version: u64,
130
+ ) -> bool {
131
+ let peer_version = self.get_peer_state_version(peer_id, &cap_ref.namespace);
132
+ peer_version >= required_version
133
+ }
134
+
135
+ /// Find providers with compatible state versions
136
+ pub fn find_compatible_providers(
137
+ &self,
138
+ cap_ref: &CapabilityRef,
139
+ required_state_version: u64,
140
+ ) -> Vec<&DistributedCapabilityAdvertisement> {
141
+ let mut compatible = Vec::new();
142
+
143
+ for (peer_id, capabilities) in &self.remote_capabilities {
144
+ for cap_ad in capabilities {
145
+ if cap_ad.capability_ref.canonical() == cap_ref.canonical() {
146
+ if self.check_state_compatibility(peer_id, cap_ref, required_state_version) {
147
+ compatible.push(cap_ad);
148
+ }
149
+ }
150
+ }
151
+ }
152
+
153
+ compatible
154
+ }
155
+
156
+ /// Check if capability requires state acquisition
157
+ pub fn requires_state_acquisition(
158
+ &self,
159
+ provider_peer: &str,
160
+ cap_ref: &CapabilityRef,
161
+ required_state_version: u64,
162
+ ) -> bool {
163
+ let peer_version = self.get_peer_state_version(provider_peer, &cap_ref.namespace);
164
+ peer_version < required_state_version
165
+ }
166
+
167
+ /// Plan state acquisition - list namespaces that need to be acquired
168
+ pub fn plan_state_acquisition(
169
+ &self,
170
+ provider_peer: &str,
171
+ cap_ref: &CapabilityRef,
172
+ required_state_version: u64,
173
+ ) -> Vec<String> {
174
+ let peer_version = self.get_peer_state_version(provider_peer, &cap_ref.namespace);
175
+ if peer_version < required_state_version {
176
+ vec![cap_ref.namespace.clone()]
177
+ } else {
178
+ Vec::new()
179
+ }
180
+ }
181
+ }
182
+
183
+ impl Default for CapabilityRouter {
184
+ fn default() -> Self {
185
+ Self::new()
186
+ }
187
+ }
188
+
189
+ /// Execution claim tracker for single-owner semantics
190
+ pub struct ExecutionClaimer {
191
+ /// Claims by execution ID
192
+ claims: HashMap<String, ExecutionClaim>,
193
+ }
194
+
195
+ /// A claim on an execution
196
+ #[derive(Debug, Clone, Serialize, Deserialize)]
197
+ pub struct ExecutionClaim {
198
+ /// Execution ID
199
+ pub execution_id: String,
200
+ /// Peer that claimed it
201
+ pub claimant: String,
202
+ /// Timestamp of claim
203
+ pub claimed_ms: u128,
204
+ }
205
+
206
+ impl ExecutionClaim {
207
+ pub fn new(execution_id: String, claimant: String) -> Self {
208
+ Self {
209
+ execution_id,
210
+ claimant,
211
+ claimed_ms: crate::now_ms(),
212
+ }
213
+ }
214
+ }
215
+
216
+ impl ExecutionClaimer {
217
+ pub fn new() -> Self {
218
+ Self {
219
+ claims: HashMap::new(),
220
+ }
221
+ }
222
+
223
+ /// Attempt to claim an execution
224
+ /// Returns the claim if successful, None if already claimed
225
+ pub fn try_claim(&mut self, execution_id: String, claimant: String) -> Option<ExecutionClaim> {
226
+ if self.claims.contains_key(&execution_id) {
227
+ None
228
+ } else {
229
+ let claim = ExecutionClaim::new(execution_id.clone(), claimant);
230
+ self.claims.insert(execution_id, claim.clone());
231
+ Some(claim)
232
+ }
233
+ }
234
+
235
+ /// Get the claimant of an execution
236
+ pub fn get_claimant(&self, execution_id: &str) -> Option<&str> {
237
+ self.claims.get(execution_id).map(|c| c.claimant.as_str())
238
+ }
239
+
240
+ /// Check if execution is claimed by a specific peer
241
+ pub fn is_claimed_by(&self, execution_id: &str, claimant: &str) -> bool {
242
+ self.claims
243
+ .get(execution_id)
244
+ .map(|c| c.claimant == claimant)
245
+ .unwrap_or(false)
246
+ }
247
+ }
248
+
249
+ impl Default for ExecutionClaimer {
250
+ fn default() -> Self {
251
+ Self::new()
252
+ }
253
+ }
254
+
255
+ /// Result publication tracker
256
+ pub struct ExecutionResultPublisher {
257
+ /// Published results by execution ID
258
+ results: HashMap<String, CapabilityExecutionResult>,
259
+ }
260
+
261
+ impl ExecutionResultPublisher {
262
+ pub fn new() -> Self {
263
+ Self {
264
+ results: HashMap::new(),
265
+ }
266
+ }
267
+
268
+ /// Publish an execution result
269
+ pub fn publish(&mut self, result: CapabilityExecutionResult) {
270
+ self.results
271
+ .insert(result.execution_ref.execution_id.clone(), result);
272
+ }
273
+
274
+ /// Get a published result
275
+ pub fn get_result(&self, execution_id: &str) -> Option<&CapabilityExecutionResult> {
276
+ self.results.get(execution_id)
277
+ }
278
+
279
+ /// Check if result exists
280
+ pub fn has_result(&self, execution_id: &str) -> bool {
281
+ self.results.contains_key(execution_id)
282
+ }
283
+ }
284
+
285
+ impl Default for ExecutionResultPublisher {
286
+ fn default() -> Self {
287
+ Self::new()
288
+ }
289
+ }
290
+
291
+ #[cfg(test)]
292
+ mod tests {
293
+ use super::*;
294
+ use crate::ExecutionRef;
295
+
296
+ fn make_cap_ref(namespace: &str, capability: &str, version: u32) -> CapabilityRef {
297
+ CapabilityRef::new(namespace.to_string(), capability.to_string(), version)
298
+ }
299
+
300
+ fn make_capability_ad(
301
+ namespace: &str,
302
+ capability: &str,
303
+ version: u32,
304
+ peer_id: &str,
305
+ ) -> DistributedCapabilityAdvertisement {
306
+ DistributedCapabilityAdvertisement::new(
307
+ make_cap_ref(namespace, capability, version),
308
+ peer_id.to_string(),
309
+ )
310
+ }
311
+
312
+ #[test]
313
+ fn test_router_local_capability() {
314
+ let mut router = CapabilityRouter::new();
315
+ let ad = make_capability_ad("docs", "vector-search", 1, "local");
316
+ router.register_local(ad);
317
+
318
+ router.update_peer_state("local".to_string(), "docs".to_string(), 851);
319
+
320
+ let cap_ref = make_cap_ref("docs", "vector-search", 1);
321
+ let decision = router.route(&cap_ref, 851, "local");
322
+ assert_eq!(decision, RouteDecision::Local);
323
+ }
324
+
325
+ #[test]
326
+ fn test_router_remote_capability() {
327
+ let mut router = CapabilityRouter::new();
328
+ let ad = make_capability_ad("docs", "vector-search", 1, "peer-b");
329
+ router.register_remote(ad);
330
+
331
+ router.update_peer_state("peer-b".to_string(), "docs".to_string(), 851);
332
+
333
+ let cap_ref = make_cap_ref("docs", "vector-search", 1);
334
+ let decision = router.route(&cap_ref, 851, "peer-a");
335
+ assert_eq!(decision, RouteDecision::Remote("peer-b".to_string()));
336
+ }
337
+
338
+ #[test]
339
+ fn test_router_unavailable() {
340
+ let router = CapabilityRouter::new();
341
+ let cap_ref = make_cap_ref("docs", "vector-search", 1);
342
+ let decision = router.route(&cap_ref, 851, "peer-a");
343
+ assert_eq!(decision, RouteDecision::Unavailable);
344
+ }
345
+
346
+ #[test]
347
+ fn test_router_state_mismatch() {
348
+ let mut router = CapabilityRouter::new();
349
+ let ad = make_capability_ad("docs", "vector-search", 1, "peer-b");
350
+ router.register_remote(ad);
351
+
352
+ // Peer only has version 800, but we need 851
353
+ router.update_peer_state("peer-b".to_string(), "docs".to_string(), 800);
354
+
355
+ let cap_ref = make_cap_ref("docs", "vector-search", 1);
356
+ let decision = router.route(&cap_ref, 851, "peer-a");
357
+ assert_eq!(decision, RouteDecision::Unavailable);
358
+ }
359
+
360
+ #[test]
361
+ fn test_router_requires_state_acquisition() {
362
+ let mut router = CapabilityRouter::new();
363
+ router.update_peer_state("peer-b".to_string(), "docs".to_string(), 800);
364
+
365
+ let cap_ref = make_cap_ref("docs", "vector-search", 1);
366
+ assert!(router.requires_state_acquisition("peer-b", &cap_ref, 851));
367
+ }
368
+
369
+ #[test]
370
+ fn test_execution_claimer_single_claim() {
371
+ let mut claimer = ExecutionClaimer::new();
372
+ let claim = claimer.try_claim("exec-123".to_string(), "peer-a".to_string());
373
+ assert!(claim.is_some());
374
+ assert_eq!(claim.unwrap().claimant, "peer-a");
375
+ }
376
+
377
+ #[test]
378
+ fn test_execution_claimer_duplicate_claim() {
379
+ let mut claimer = ExecutionClaimer::new();
380
+ let claim1 = claimer.try_claim("exec-123".to_string(), "peer-a".to_string());
381
+ let claim2 = claimer.try_claim("exec-123".to_string(), "peer-b".to_string());
382
+
383
+ assert!(claim1.is_some());
384
+ assert!(claim2.is_none());
385
+ }
386
+
387
+ #[test]
388
+ fn test_execution_claimer_get_claimant() {
389
+ let mut claimer = ExecutionClaimer::new();
390
+ claimer.try_claim("exec-123".to_string(), "peer-a".to_string());
391
+
392
+ let claimant = claimer.get_claimant("exec-123");
393
+ assert_eq!(claimant, Some("peer-a"));
394
+ }
395
+
396
+ #[test]
397
+ fn test_execution_result_publisher() {
398
+ let mut publisher = ExecutionResultPublisher::new();
399
+ let cap_ref = make_cap_ref("docs", "vector-search", 1);
400
+ let exec_ref = ExecutionRef::new("exec-123".to_string(), cap_ref, "peer-b".to_string());
401
+ let result = serde_json::json!({"results": [1, 2, 3]});
402
+ let exec_result = CapabilityExecutionResult::success(exec_ref, result);
403
+
404
+ publisher.publish(exec_result);
405
+
406
+ assert!(publisher.has_result("exec-123"));
407
+ assert!(publisher.get_result("exec-123").is_some());
408
+ }
409
+ }