@feltdb/core 0.4.11 → 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands.js +5 -2
- package/dist/cli/index.js +1 -1
- package/dist/create/cli.js +16 -1
- package/dist/create/create.js +30 -16
- package/dist/create/docker-compose-generator.js +48 -9
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/Cargo.lock +2238 -0
- package/dist/create/server-source/Cargo.toml +7 -0
- package/dist/create/server-source/crates/feltdb/Cargo.lock +175 -0
- package/dist/create/server-source/crates/feltdb/Cargo.toml +79 -0
- package/dist/create/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +370 -0
- package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +589 -0
- package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +259 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +446 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +272 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +378 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +414 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +486 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +273 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +587 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +513 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +395 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +469 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +409 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +627 -0
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +383 -0
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +298 -0
- package/dist/create/server-source/crates/feltdb/src/acceptance_tests.rs +1698 -0
- package/dist/create/server-source/crates/feltdb/src/acquisition.rs +286 -0
- package/dist/create/server-source/crates/feltdb/src/admission.rs +192 -0
- package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +566 -0
- package/dist/create/server-source/crates/feltdb/src/analytics.rs +475 -0
- package/dist/create/server-source/crates/feltdb/src/application.rs +2244 -0
- package/dist/create/server-source/crates/feltdb/src/application_runtime.rs +1070 -0
- package/dist/create/server-source/crates/feltdb/src/authorization.rs +1030 -0
- package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +266 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/mod.rs +8 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/search.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/vector.rs +482 -0
- package/dist/create/server-source/crates/feltdb/src/capability.rs +903 -0
- package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +261 -0
- package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +78 -0
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +2214 -0
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +194 -0
- package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +427 -0
- package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +453 -0
- package/dist/create/server-source/crates/feltdb/src/content_distribution.rs +465 -0
- package/dist/create/server-source/crates/feltdb/src/convergence.rs +618 -0
- package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +380 -0
- package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +362 -0
- package/dist/create/server-source/crates/feltdb/src/cron.rs +294 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +474 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_tests.rs +1003 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +536 -0
- package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +364 -0
- package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +235 -0
- package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +207 -0
- package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +316 -0
- package/dist/create/server-source/crates/feltdb/src/execution.rs +426 -0
- package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +219 -0
- package/dist/create/server-source/crates/feltdb/src/indexing.rs +779 -0
- package/dist/create/server-source/crates/feltdb/src/lib.rs +2838 -0
- package/dist/create/server-source/crates/feltdb/src/materialization.rs +184 -0
- package/dist/create/server-source/crates/feltdb/src/metrics.rs +267 -0
- package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +311 -0
- package/dist/create/server-source/crates/feltdb/src/observability.rs +366 -0
- package/dist/create/server-source/crates/feltdb/src/operation.rs +251 -0
- package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +438 -0
- package/dist/create/server-source/crates/feltdb/src/operation_log.rs +344 -0
- package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/peer_registry.rs +166 -0
- package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +261 -0
- package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +560 -0
- package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +3226 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +201 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +263 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +484 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +216 -0
- package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +281 -0
- package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +323 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +573 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +404 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +381 -0
- package/dist/create/server-source/crates/feltdb/src/phase_1c_three_node.rs +523 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +334 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +306 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +355 -0
- package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +395 -0
- package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +346 -0
- package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +430 -0
- package/dist/create/server-source/crates/feltdb/src/production_api.rs +400 -0
- package/dist/create/server-source/crates/feltdb/src/provenance.rs +207 -0
- package/dist/create/server-source/crates/feltdb/src/query_performance.rs +217 -0
- package/dist/create/server-source/crates/feltdb/src/references.rs +404 -0
- package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +401 -0
- package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +160 -0
- package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +132 -0
- package/dist/create/server-source/crates/feltdb/src/routing.rs +409 -0
- package/dist/create/server-source/crates/feltdb/src/sharding.rs +523 -0
- package/dist/create/server-source/crates/feltdb/src/state_contract.rs +3118 -0
- package/dist/create/server-source/crates/feltdb/src/state_hash.rs +291 -0
- package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +376 -0
- package/dist/create/server-source/crates/feltdb/src/storage.rs +267 -0
- package/dist/create/server-source/crates/feltdb/src/submission.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/sync.rs +483 -0
- package/dist/create/server-source/crates/feltdb/src/sync_contract.rs +822 -0
- package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +366 -0
- package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +473 -0
- package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +949 -0
- package/dist/create/server-source/crates/feltdb/src/transactions.rs +646 -0
- package/dist/create/server-source/crates/feltdb/src/trigger.rs +390 -0
- package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +928 -0
- package/dist/create/server-source/crates/feltdb/src/workflow.rs +713 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +510 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_integration.rs +354 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_runtime.rs +594 -0
- package/dist/create/server-source/crates/feltdb/src/workload.rs +1310 -0
- package/dist/create/server-source/crates/feltdb-server/Cargo.toml +23 -0
- package/dist/create/server-source/crates/feltdb-server/README.md +79 -0
- package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +73 -0
- package/dist/create/server-source/crates/feltdb-server/src/application_contract.rs +425 -0
- package/dist/create/server-source/crates/feltdb-server/src/artifacts.rs +449 -0
- package/dist/create/server-source/crates/feltdb-server/src/audit.rs +59 -0
- package/dist/create/server-source/crates/feltdb-server/src/auth.rs +308 -0
- package/dist/create/server-source/crates/feltdb-server/src/authorization.rs +228 -0
- package/dist/create/server-source/crates/feltdb-server/src/backup.rs +416 -0
- package/dist/create/server-source/crates/feltdb-server/src/causal.rs +218 -0
- package/dist/create/server-source/crates/feltdb-server/src/certification.rs +223 -0
- package/dist/create/server-source/crates/feltdb-server/src/clock.rs +132 -0
- package/dist/create/server-source/crates/feltdb-server/src/cluster.rs +165 -0
- package/dist/create/server-source/crates/feltdb-server/src/connections.rs +1044 -0
- package/dist/create/server-source/crates/feltdb-server/src/content.rs +111 -0
- package/dist/create/server-source/crates/feltdb-server/src/identity.rs +250 -0
- package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +78 -0
- package/dist/create/server-source/crates/feltdb-server/src/key_provider.rs +247 -0
- package/dist/create/server-source/crates/feltdb-server/src/leases.rs +123 -0
- package/dist/create/server-source/crates/feltdb-server/src/lib.rs +25 -0
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +8715 -0
- package/dist/create/server-source/crates/feltdb-server/src/metrics.rs +97 -0
- package/dist/create/server-source/crates/feltdb-server/src/portable_bundle.rs +350 -0
- package/dist/create/server-source/crates/feltdb-server/src/principals.rs +510 -0
- package/dist/create/server-source/crates/feltdb-server/src/providers.rs +269 -0
- package/dist/create/server-source/crates/feltdb-server/src/releases.rs +2563 -0
- package/dist/create/server-source/crates/feltdb-server/src/sessions.rs +156 -0
- package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +1097 -0
- package/dist/create/server-source/crates/feltdb-server/src/versions.rs +264 -0
- package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +31 -0
- package/dist/create/server-source/crates/feltdb-wasm/src/lib.rs +1086 -0
- package/dist/create/server-source/crates/feltdb-wasm/test.db +0 -0
- package/dist/flowspec.d.ts +2 -0
- package/dist/flowspec.d.ts.map +1 -1
- package/dist/flowspec.js +28 -4
- package/dist/state-contract.d.ts +7 -1
- package/dist/state-contract.d.ts.map +1 -1
- package/dist/studio/components/ApplicationDesigner.d.ts.map +1 -1
- package/dist/studio/components/index.js +1 -1
- package/dist/studio/{components-q43NSTTH.js → components-bHTARBin.js} +160 -89
- package/dist/studio/index.js +31 -28
- package/dist/studio-app/assets/{index-DZpBoVMp.js → index-BqKquLuU.js} +8 -8
- package/dist/studio-app/index.html +1 -1
- 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
|
+
}
|