@feltdb/core 0.15.0 → 0.16.0
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/agent-state.d.ts +20 -0
- package/dist/agent-state.d.ts.map +1 -1
- package/dist/agent-state.js +36 -0
- package/dist/build-identity.json +12 -4
- package/dist/cli/commands.js +187 -4
- package/dist/cli/publish-engine.js +116 -16
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +3 -0
- package/dist/create/build-identity.json +12 -4
- package/dist/create/managed-account.js +93 -35
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/Cargo.lock +6 -509
- package/dist/create/server-source/Cargo.toml +2 -13
- package/dist/create/server-source/crates/feltdb-client/Cargo.toml +1 -1
- package/dist/create/server-source/crates/feltdb-server/Cargo.toml +1 -1
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +255 -12
- package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +1 -1
- package/dist/db.d.ts +11 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +15 -2
- package/dist/error-codes.d.ts +5 -0
- package/dist/error-codes.d.ts.map +1 -1
- package/dist/error-codes.js +9 -1
- package/dist/http-db.d.ts +16 -0
- package/dist/http-db.d.ts.map +1 -1
- package/dist/http-db.js +36 -6
- package/dist/managed-recovery.d.ts +6 -0
- package/dist/managed-recovery.d.ts.map +1 -1
- package/dist/managed-recovery.js +9 -0
- package/dist/studio-app/assets/{feltdb_wasm-BjM1ylL3.js → feltdb_wasm-DtybUY0q.js} +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-DsgIUwaB.wasm +0 -0
- package/dist/studio-app/assets/index-C4OffsZl.js +37 -0
- package/dist/studio-app/index.html +1 -1
- package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
- package/dist/wasm/package.json +1 -1
- package/dist/workload.d.ts +55 -3
- package/dist/workload.d.ts.map +1 -1
- package/dist/workload.js +23 -0
- package/dist/workspace/workspace-connection.d.ts.map +1 -1
- package/dist/workspace/workspace-connection.js +14 -3
- package/package.json +1 -1
- package/dist/create/server-source/crates/feltdb/Cargo.lock +0 -175
- package/dist/create/server-source/crates/feltdb/Cargo.toml +0 -102
- package/dist/create/server-source/crates/feltdb/LICENSE +0 -21
- package/dist/create/server-source/crates/feltdb/README.md +0 -75
- package/dist/create/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +0 -370
- package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +0 -589
- package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +0 -247
- package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +0 -440
- package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +0 -275
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +0 -381
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +0 -467
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +0 -489
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +0 -281
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +0 -606
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +0 -531
- package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +0 -462
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +0 -505
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +0 -484
- package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +0 -758
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +0 -421
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +0 -329
- package/dist/create/server-source/crates/feltdb/src/acceptance_tests.rs +0 -1705
- package/dist/create/server-source/crates/feltdb/src/acquisition.rs +0 -286
- package/dist/create/server-source/crates/feltdb/src/admission.rs +0 -185
- package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +0 -507
- package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +0 -539
- package/dist/create/server-source/crates/feltdb/src/agent_state.rs +0 -320
- package/dist/create/server-source/crates/feltdb/src/agent_transition_contract.rs +0 -1545
- package/dist/create/server-source/crates/feltdb/src/analytics.rs +0 -521
- package/dist/create/server-source/crates/feltdb/src/application.rs +0 -2674
- package/dist/create/server-source/crates/feltdb/src/application_runtime.rs +0 -1070
- package/dist/create/server-source/crates/feltdb/src/authority.rs +0 -479
- package/dist/create/server-source/crates/feltdb/src/authority_failover.rs +0 -847
- package/dist/create/server-source/crates/feltdb/src/authorization.rs +0 -1030
- package/dist/create/server-source/crates/feltdb/src/authorization_security_tests.rs +0 -1122
- package/dist/create/server-source/crates/feltdb/src/bin/feltdb-authority-client.rs +0 -32
- package/dist/create/server-source/crates/feltdb/src/bin/feltdb-authority.rs +0 -19
- package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +0 -1474
- package/dist/create/server-source/crates/feltdb/src/capabilities/mod.rs +0 -8
- package/dist/create/server-source/crates/feltdb/src/capabilities/search.rs +0 -418
- package/dist/create/server-source/crates/feltdb/src/capabilities/vector.rs +0 -482
- package/dist/create/server-source/crates/feltdb/src/capability.rs +0 -903
- package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +0 -263
- package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +0 -77
- package/dist/create/server-source/crates/feltdb/src/causal_backlog_bound.rs +0 -496
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +0 -2574
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +0 -212
- package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +0 -422
- package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +0 -445
- package/dist/create/server-source/crates/feltdb/src/content_distribution.rs +0 -465
- package/dist/create/server-source/crates/feltdb/src/convergence.rs +0 -634
- package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +0 -427
- package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +0 -376
- package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +0 -365
- package/dist/create/server-source/crates/feltdb/src/cron.rs +0 -294
- package/dist/create/server-source/crates/feltdb/src/dedup_bound_investigation.rs +0 -483
- package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +0 -477
- package/dist/create/server-source/crates/feltdb/src/distributed_tests.rs +0 -1003
- package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +0 -1334
- package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +0 -368
- package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +0 -231
- package/dist/create/server-source/crates/feltdb/src/durable_operation_identity.rs +0 -482
- package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +0 -203
- package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +0 -317
- package/dist/create/server-source/crates/feltdb/src/equality_index.rs +0 -595
- package/dist/create/server-source/crates/feltdb/src/execution.rs +0 -426
- package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +0 -214
- package/dist/create/server-source/crates/feltdb/src/indexing.rs +0 -776
- package/dist/create/server-source/crates/feltdb/src/lib.rs +0 -7365
- package/dist/create/server-source/crates/feltdb/src/managed_cas_tests.rs +0 -234
- package/dist/create/server-source/crates/feltdb/src/materialization.rs +0 -184
- package/dist/create/server-source/crates/feltdb/src/metrics.rs +0 -266
- package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +0 -310
- package/dist/create/server-source/crates/feltdb/src/multi_operation_transaction.rs +0 -736
- package/dist/create/server-source/crates/feltdb/src/observability.rs +0 -379
- package/dist/create/server-source/crates/feltdb/src/operation.rs +0 -290
- package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +0 -439
- package/dist/create/server-source/crates/feltdb/src/operation_log.rs +0 -349
- package/dist/create/server-source/crates/feltdb/src/p1_application_atomicity.rs +0 -332
- package/dist/create/server-source/crates/feltdb/src/p1_atomicity_acceptance.rs +0 -718
- package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +0 -487
- package/dist/create/server-source/crates/feltdb/src/peer_registry.rs +0 -166
- package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +0 -289
- package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +0 -566
- package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +0 -3391
- package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +0 -203
- package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +0 -261
- package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +0 -502
- package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +0 -216
- package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +0 -303
- package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +0 -323
- package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +0 -531
- package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +0 -406
- package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +0 -436
- package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +0 -387
- package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +0 -378
- package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +0 -359
- package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +0 -372
- package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +0 -404
- package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +0 -376
- package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +0 -461
- package/dist/create/server-source/crates/feltdb/src/policy_evaluation.rs +0 -2125
- package/dist/create/server-source/crates/feltdb/src/production_api.rs +0 -418
- package/dist/create/server-source/crates/feltdb/src/provenance.rs +0 -207
- package/dist/create/server-source/crates/feltdb/src/query_execution_diagnostics.rs +0 -126
- package/dist/create/server-source/crates/feltdb/src/query_performance.rs +0 -218
- package/dist/create/server-source/crates/feltdb/src/read_basis.rs +0 -257
- package/dist/create/server-source/crates/feltdb/src/references.rs +0 -404
- package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +0 -401
- package/dist/create/server-source/crates/feltdb/src/replica_acknowledgements.rs +0 -501
- package/dist/create/server-source/crates/feltdb/src/replica_membership.rs +0 -680
- package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +0 -163
- package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +0 -133
- package/dist/create/server-source/crates/feltdb/src/routing.rs +0 -409
- package/dist/create/server-source/crates/feltdb/src/semantic_decision.rs +0 -2029
- package/dist/create/server-source/crates/feltdb/src/semantic_query.rs +0 -599
- package/dist/create/server-source/crates/feltdb/src/sharding.rs +0 -549
- package/dist/create/server-source/crates/feltdb/src/state_conflict_contract.rs +0 -516
- package/dist/create/server-source/crates/feltdb/src/state_contract.rs +0 -6003
- package/dist/create/server-source/crates/feltdb/src/state_diff_contract.rs +0 -222
- package/dist/create/server-source/crates/feltdb/src/state_facade.rs +0 -320
- package/dist/create/server-source/crates/feltdb/src/state_hash.rs +0 -291
- package/dist/create/server-source/crates/feltdb/src/state_model.rs +0 -4158
- package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +0 -379
- package/dist/create/server-source/crates/feltdb/src/state_trigger.rs +0 -673
- package/dist/create/server-source/crates/feltdb/src/storage.rs +0 -273
- package/dist/create/server-source/crates/feltdb/src/submission.rs +0 -471
- package/dist/create/server-source/crates/feltdb/src/sync.rs +0 -495
- package/dist/create/server-source/crates/feltdb/src/sync_contract.rs +0 -822
- package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +0 -433
- package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +0 -462
- package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +0 -965
- package/dist/create/server-source/crates/feltdb/src/transaction_preconditions.rs +0 -1120
- package/dist/create/server-source/crates/feltdb/src/transactions.rs +0 -643
- package/dist/create/server-source/crates/feltdb/src/trigger.rs +0 -390
- package/dist/create/server-source/crates/feltdb/src/trigger_contract.rs +0 -749
- package/dist/create/server-source/crates/feltdb/src/versioned_object_substrate.rs +0 -708
- package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +0 -1269
- package/dist/create/server-source/crates/feltdb/src/workflow.rs +0 -713
- package/dist/create/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +0 -510
- package/dist/create/server-source/crates/feltdb/src/workflow_integration.rs +0 -354
- package/dist/create/server-source/crates/feltdb/src/workflow_runtime.rs +0 -594
- package/dist/create/server-source/crates/feltdb/src/workload.rs +0 -4222
- package/dist/create/server-source/crates/feltdb/src/workload_diagnostics.rs +0 -456
- package/dist/create/server-source/crates/feltdb/tests/agent_state_native.rs +0 -1188
- package/dist/create/server-source/crates/feltdb/tests/agent_transition_contract_conformance.rs +0 -2884
- package/dist/create/server-source/crates/feltdb/tests/authority_process.rs +0 -297
- package/dist/create/server-source/crates/feltdb/tests/authority_transaction_identity.rs +0 -534
- package/dist/create/server-source/crates/feltdb/tests/bounded_read_contract.rs +0 -132
- package/dist/create/server-source/crates/feltdb/tests/branching_evidence.rs +0 -299
- package/dist/create/server-source/crates/feltdb/tests/common/mod.rs +0 -96
- package/dist/create/server-source/crates/feltdb/tests/compaction_stall_contract.rs +0 -272
- package/dist/create/server-source/crates/feltdb/tests/crash_durability_contract.rs +0 -467
- package/dist/create/server-source/crates/feltdb/tests/current_revision_authority_evidence.rs +0 -309
- package/dist/create/server-source/crates/feltdb/tests/durable_backup_contract.rs +0 -445
- package/dist/create/server-source/crates/feltdb/tests/durable_corruption_contract.rs +0 -518
- package/dist/create/server-source/crates/feltdb/tests/durable_format_compatibility.rs +0 -392
- package/dist/create/server-source/crates/feltdb/tests/feltdb_state_boundary_tests.rs +0 -850
- package/dist/create/server-source/crates/feltdb/tests/fixtures/agent_transition_corpus.json +0 -23340
- package/dist/create/server-source/crates/feltdb/tests/fixtures/state_conflict_contract_corpus.json +0 -1916
- package/dist/create/server-source/crates/feltdb/tests/fixtures/state_diff_contract_corpus.json +0 -1878
- package/dist/create/server-source/crates/feltdb/tests/fixtures/trigger_contract_corpus.json +0 -1862
- package/dist/create/server-source/crates/feltdb/tests/generalized_version_control_evidence.rs +0 -123
- package/dist/create/server-source/crates/feltdb/tests/generalized_version_control_substrate_completion.rs +0 -299
- package/dist/create/server-source/crates/feltdb/tests/local_process_ownership.rs +0 -69
- package/dist/create/server-source/crates/feltdb/tests/managed_incident_regression.rs +0 -191
- package/dist/create/server-source/crates/feltdb/tests/operational_health_contract.rs +0 -278
- package/dist/create/server-source/crates/feltdb/tests/pr34_query_collection.rs +0 -234
- package/dist/create/server-source/crates/feltdb/tests/pr35_equality_index.rs +0 -947
- package/dist/create/server-source/crates/feltdb/tests/pr7_self_authorization_proof.rs +0 -404
- package/dist/create/server-source/crates/feltdb/tests/pr8_vocabulary_assessment.rs +0 -916
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase2_boundary_tests.rs +0 -1045
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3a_path_a_tests.rs +0 -347
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_authorized_mutations.rs +0 -361
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_role_based_authorization.rs +0 -330
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_simple_auth_delete.rs +0 -93
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_team_delete_role_authorization.rs +0 -622
- package/dist/create/server-source/crates/feltdb/tests/pr9_teams_role_based_access.rs +0 -517
- package/dist/create/server-source/crates/feltdb/tests/production_certification.rs +0 -1153
- package/dist/create/server-source/crates/feltdb/tests/production_contract.rs +0 -771
- package/dist/create/server-source/crates/feltdb/tests/production_readiness_contract.rs +0 -1383
- package/dist/create/server-source/crates/feltdb/tests/reconciliation_application.rs +0 -868
- package/dist/create/server-source/crates/feltdb/tests/reconciliation_wire_format_evidence.rs +0 -221
- package/dist/create/server-source/crates/feltdb/tests/replicated_history_contract.rs +0 -417
- package/dist/create/server-source/crates/feltdb/tests/resource_scoped_revisions.rs +0 -338
- package/dist/create/server-source/crates/feltdb/tests/revision_identity_contract.rs +0 -1039
- package/dist/create/server-source/crates/feltdb/tests/revision_model_decision.rs +0 -739
- package/dist/create/server-source/crates/feltdb/tests/revision_retention_boundary_evidence.rs +0 -452
- package/dist/create/server-source/crates/feltdb/tests/saas_authorization_integration.rs +0 -81
- package/dist/create/server-source/crates/feltdb/tests/saas_invitation_lifecycle.rs +0 -438
- package/dist/create/server-source/crates/feltdb/tests/semantic_decision.rs +0 -1165
- package/dist/create/server-source/crates/feltdb/tests/semantic_query.rs +0 -767
- package/dist/create/server-source/crates/feltdb/tests/semantic_query_contract.rs +0 -363
- package/dist/create/server-source/crates/feltdb/tests/state_conflict_contract_conformance.rs +0 -1799
- package/dist/create/server-source/crates/feltdb/tests/state_diff_contract_conformance.rs +0 -1316
- package/dist/create/server-source/crates/feltdb/tests/state_model_integration.rs +0 -358
- package/dist/create/server-source/crates/feltdb/tests/state_persistence_integration.rs +0 -365
- package/dist/create/server-source/crates/feltdb/tests/state_ref_authority.rs +0 -918
- package/dist/create/server-source/crates/feltdb/tests/state_store_boundary_evidence.rs +0 -299
- package/dist/create/server-source/crates/feltdb/tests/storage_independent_versioned_object_substrate.rs +0 -328
- package/dist/create/server-source/crates/feltdb/tests/sync_divergence_evidence.rs +0 -255
- package/dist/create/server-source/crates/feltdb/tests/three_way_input_boundary_evidence.rs +0 -249
- package/dist/create/server-source/crates/feltdb/tests/trigger_contract_conformance.rs +0 -994
- package/dist/create/server-source/crates/feltdb/tests/workload_envelope_contract.rs +0 -484
- package/dist/studio-app/assets/feltdb_wasm_bg-TseJn2Ax.wasm +0 -0
- package/dist/studio-app/assets/index-1wd0uKua.js +0 -30
|
@@ -1,502 +0,0 @@
|
|
|
1
|
-
/// Track 1c.3 Acceptance Tests: Real Recovery Orchestration
|
|
2
|
-
///
|
|
3
|
-
/// Objective: Prove production recovery flow handles all failure modes
|
|
4
|
-
///
|
|
5
|
-
/// Invariant: A restarted executor cannot enter normal replication until:
|
|
6
|
-
/// 1. Its durable state has been reconciled with the authoritative peer
|
|
7
|
-
/// 2. The resulting state has passed 14C correctness checks
|
|
8
|
-
///
|
|
9
|
-
/// State machine: RECOVERING → READY only after verification
|
|
10
|
-
/// Never: restart → READY directly
|
|
11
|
-
|
|
12
|
-
#[cfg(test)]
|
|
13
|
-
mod tests {
|
|
14
|
-
use crate::convergence::VectorClock;
|
|
15
|
-
use crate::distributed_transactions::{
|
|
16
|
-
DistributedTransactionExecutor, ReplicationMessage, TransactionEnvelope,
|
|
17
|
-
};
|
|
18
|
-
use crate::state_hash::StateHash;
|
|
19
|
-
use crate::transactions::{ConsistencyContract, ConsistencyLevel};
|
|
20
|
-
use std::collections::HashMap;
|
|
21
|
-
use tempfile::TempDir;
|
|
22
|
-
|
|
23
|
-
#[derive(Clone, Debug, PartialEq)]
|
|
24
|
-
enum RecoveryState {
|
|
25
|
-
Recovering,
|
|
26
|
-
Ready,
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/// Recovery orchestrator for a restarted executor
|
|
30
|
-
struct RecoveryOrchestrator {
|
|
31
|
-
executor: DistributedTransactionExecutor,
|
|
32
|
-
state: RecoveryState,
|
|
33
|
-
missing_operations: Vec<TransactionEnvelope>,
|
|
34
|
-
peer_node_id: String,
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
impl RecoveryOrchestrator {
|
|
38
|
-
fn new(executor: DistributedTransactionExecutor, peer_node_id: String) -> Self {
|
|
39
|
-
Self {
|
|
40
|
-
executor,
|
|
41
|
-
state: RecoveryState::Recovering,
|
|
42
|
-
missing_operations: Vec::new(),
|
|
43
|
-
peer_node_id,
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/// Reconcile with peer: determine what operations are missing
|
|
48
|
-
fn reconcile_with_peer(
|
|
49
|
-
&mut self,
|
|
50
|
-
peer_state: &DistributedTransactionExecutor,
|
|
51
|
-
) -> Result<(), String> {
|
|
52
|
-
let local_replica = self
|
|
53
|
-
.executor
|
|
54
|
-
.get_replica_state(&self.executor.get_local_node_id())
|
|
55
|
-
.ok_or("Local replica not found")?;
|
|
56
|
-
|
|
57
|
-
let peer_replica = peer_state
|
|
58
|
-
.get_replica_state(&self.peer_node_id)
|
|
59
|
-
.ok_or("Peer replica not found")?;
|
|
60
|
-
|
|
61
|
-
// Verify peer has more operations than us (or same state)
|
|
62
|
-
if peer_replica.operations_applied < local_replica.operations_applied {
|
|
63
|
-
return Err("Peer has fewer operations than local".to_string());
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
Ok(())
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/// Apply missing operations from peer
|
|
70
|
-
fn apply_missing_operations(
|
|
71
|
-
&mut self,
|
|
72
|
-
missing: Vec<TransactionEnvelope>,
|
|
73
|
-
) -> Result<(), String> {
|
|
74
|
-
for envelope in missing {
|
|
75
|
-
// Check if already applied (duplicate prevention)
|
|
76
|
-
if self.executor.envelopes_seen.contains(&envelope.envelope_id) {
|
|
77
|
-
continue; // Already applied, skip
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Create replication message from peer
|
|
81
|
-
let message = ReplicationMessage::new(
|
|
82
|
-
envelope.clone(),
|
|
83
|
-
self.peer_node_id.clone(),
|
|
84
|
-
self.executor.get_local_node_id(),
|
|
85
|
-
envelope.envelope_id.sequence,
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
// Execute through executor (which validates via 14C)
|
|
89
|
-
// For now, just mark as seen to simulate application
|
|
90
|
-
self.executor
|
|
91
|
-
.envelopes_seen
|
|
92
|
-
.insert(envelope.envelope_id.clone());
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
Ok(())
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/// Verify recovered state against peer (14C validation)
|
|
99
|
-
fn verify_convergence(&mut self) -> Result<bool, String> {
|
|
100
|
-
Ok(self.executor.check_convergence())
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/// Transition to READY after verification
|
|
104
|
-
fn finalize_recovery(&mut self) -> Result<(), String> {
|
|
105
|
-
if self.state != RecoveryState::Recovering {
|
|
106
|
-
return Err("Already recovered".to_string());
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Verify convergence before transitioning
|
|
110
|
-
if !self.verify_convergence()? {
|
|
111
|
-
return Err("State not converged after recovery".to_string());
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
self.state = RecoveryState::Ready;
|
|
115
|
-
Ok(())
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
fn get_state(&self) -> RecoveryState {
|
|
119
|
-
self.state.clone()
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
fn create_test_envelope(node: &str, sequence: u64) -> TransactionEnvelope {
|
|
124
|
-
TransactionEnvelope::new(
|
|
125
|
-
node.to_string(),
|
|
126
|
-
sequence,
|
|
127
|
-
format!("tx{}", sequence),
|
|
128
|
-
Vec::new(),
|
|
129
|
-
ConsistencyContract {
|
|
130
|
-
level: ConsistencyLevel::Causal,
|
|
131
|
-
timeout_ms: Some(1000),
|
|
132
|
-
required_acks: None,
|
|
133
|
-
},
|
|
134
|
-
)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/// TC-1c.3-A: Zero missing operations (node fully synchronized)
|
|
138
|
-
///
|
|
139
|
-
/// Scenario: Node crashes and restarts, but has all operations peer has
|
|
140
|
-
/// Expected: Recovery completes quickly, RECOVERING → READY
|
|
141
|
-
#[test]
|
|
142
|
-
fn test_recovery_zero_missing_operations() -> Result<(), Box<dyn std::error::Error>> {
|
|
143
|
-
let temp_dir = TempDir::new()?;
|
|
144
|
-
let log_path = temp_dir.path().join("operations.log");
|
|
145
|
-
|
|
146
|
-
// Setup: Node A and B both have operations 1-3
|
|
147
|
-
let mut node_a = DistributedTransactionExecutor::with_log(
|
|
148
|
-
"nodeA".to_string(),
|
|
149
|
-
StateHash::from_hex("hash0".to_string()),
|
|
150
|
-
Some(log_path.clone()),
|
|
151
|
-
)?;
|
|
152
|
-
|
|
153
|
-
let node_b = DistributedTransactionExecutor::new(
|
|
154
|
-
"nodeB".to_string(),
|
|
155
|
-
StateHash::from_hex("hash0".to_string()),
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
// Simulate: Both nodes have same state
|
|
159
|
-
node_a.register_replica(
|
|
160
|
-
"nodeB".to_string(),
|
|
161
|
-
StateHash::from_hex("hash0".to_string()),
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
// Verify convergence
|
|
165
|
-
assert!(node_a.check_convergence());
|
|
166
|
-
|
|
167
|
-
// Recovery orchestration
|
|
168
|
-
let mut recovery = RecoveryOrchestrator::new(node_a, "nodeB".to_string());
|
|
169
|
-
recovery.reconcile_with_peer(&node_b)?;
|
|
170
|
-
recovery.apply_missing_operations(Vec::new())?; // No missing ops
|
|
171
|
-
recovery.finalize_recovery()?;
|
|
172
|
-
|
|
173
|
-
assert_eq!(recovery.get_state(), RecoveryState::Ready);
|
|
174
|
-
|
|
175
|
-
Ok(())
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/// TC-1c.3-B: One missing operation (simplest real recovery case)
|
|
179
|
-
///
|
|
180
|
-
/// Scenario: Node crashes after peer applies an operation, restarts behind
|
|
181
|
-
/// Expected: Recovery fetches 1 op, applies it, converges, RECOVERING → READY
|
|
182
|
-
#[test]
|
|
183
|
-
fn test_recovery_one_missing_operation() -> Result<(), Box<dyn std::error::Error>> {
|
|
184
|
-
let temp_dir = TempDir::new()?;
|
|
185
|
-
let log_path = temp_dir.path().join("operations.log");
|
|
186
|
-
|
|
187
|
-
// Setup: Node A (restarted, missing op), Node B (authoritative)
|
|
188
|
-
let mut node_a = DistributedTransactionExecutor::with_log(
|
|
189
|
-
"nodeA".to_string(),
|
|
190
|
-
StateHash::from_hex("hash0".to_string()),
|
|
191
|
-
Some(log_path.clone()),
|
|
192
|
-
)?;
|
|
193
|
-
|
|
194
|
-
let mut node_b = DistributedTransactionExecutor::new(
|
|
195
|
-
"nodeB".to_string(),
|
|
196
|
-
StateHash::from_hex("hash0".to_string()),
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
// Register each other
|
|
200
|
-
node_a.register_replica(
|
|
201
|
-
"nodeB".to_string(),
|
|
202
|
-
StateHash::from_hex("hash0".to_string()),
|
|
203
|
-
);
|
|
204
|
-
node_b.register_replica(
|
|
205
|
-
"nodeA".to_string(),
|
|
206
|
-
StateHash::from_hex("hash0".to_string()),
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
// Peer (B) has operation 1
|
|
210
|
-
let missing_op = create_test_envelope("nodeB", 1);
|
|
211
|
-
|
|
212
|
-
// Recovery: Node A is restarted, discovers it's missing op 1
|
|
213
|
-
let mut recovery = RecoveryOrchestrator::new(node_a, "nodeB".to_string());
|
|
214
|
-
recovery.reconcile_with_peer(&node_b)?;
|
|
215
|
-
recovery.apply_missing_operations(vec![missing_op])?;
|
|
216
|
-
recovery.finalize_recovery()?;
|
|
217
|
-
|
|
218
|
-
assert_eq!(recovery.get_state(), RecoveryState::Ready);
|
|
219
|
-
|
|
220
|
-
Ok(())
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/// TC-1c.3-C: Multiple missing operations (verify strict sequence/order)
|
|
224
|
-
///
|
|
225
|
-
/// Scenario: Node crashes, restarts missing multiple sequential operations
|
|
226
|
-
/// Expected: All ops applied in order, state converges, RECOVERING → READY
|
|
227
|
-
#[test]
|
|
228
|
-
fn test_recovery_multiple_missing_operations() -> Result<(), Box<dyn std::error::Error>> {
|
|
229
|
-
let temp_dir = TempDir::new()?;
|
|
230
|
-
let log_path = temp_dir.path().join("operations.log");
|
|
231
|
-
|
|
232
|
-
let mut node_a = DistributedTransactionExecutor::with_log(
|
|
233
|
-
"nodeA".to_string(),
|
|
234
|
-
StateHash::from_hex("hash0".to_string()),
|
|
235
|
-
Some(log_path.clone()),
|
|
236
|
-
)?;
|
|
237
|
-
|
|
238
|
-
let mut node_b = DistributedTransactionExecutor::new(
|
|
239
|
-
"nodeB".to_string(),
|
|
240
|
-
StateHash::from_hex("hash0".to_string()),
|
|
241
|
-
);
|
|
242
|
-
|
|
243
|
-
node_a.register_replica(
|
|
244
|
-
"nodeB".to_string(),
|
|
245
|
-
StateHash::from_hex("hash0".to_string()),
|
|
246
|
-
);
|
|
247
|
-
node_b.register_replica(
|
|
248
|
-
"nodeA".to_string(),
|
|
249
|
-
StateHash::from_hex("hash0".to_string()),
|
|
250
|
-
);
|
|
251
|
-
|
|
252
|
-
// Peer has operations 1-5
|
|
253
|
-
let missing_ops: Vec<_> = (1..=5)
|
|
254
|
-
.map(|seq| create_test_envelope("nodeB", seq))
|
|
255
|
-
.collect();
|
|
256
|
-
|
|
257
|
-
let mut recovery = RecoveryOrchestrator::new(node_a, "nodeB".to_string());
|
|
258
|
-
recovery.reconcile_with_peer(&node_b)?;
|
|
259
|
-
recovery.apply_missing_operations(missing_ops)?;
|
|
260
|
-
recovery.finalize_recovery()?;
|
|
261
|
-
|
|
262
|
-
assert_eq!(recovery.get_state(), RecoveryState::Ready);
|
|
263
|
-
|
|
264
|
-
Ok(())
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/// TC-1c.3-D: Duplicate recovery (peer sends already-durable operation)
|
|
268
|
-
///
|
|
269
|
-
/// Scenario: Peer resends op already in our durable log (from before crash)
|
|
270
|
-
/// Expected: Duplicate rejected by dedup, recovery proceeds cleanly
|
|
271
|
-
#[test]
|
|
272
|
-
fn test_recovery_duplicate_operation_prevention() -> Result<(), Box<dyn std::error::Error>> {
|
|
273
|
-
let temp_dir = TempDir::new()?;
|
|
274
|
-
let log_path = temp_dir.path().join("operations.log");
|
|
275
|
-
|
|
276
|
-
let mut node_a = DistributedTransactionExecutor::with_log(
|
|
277
|
-
"nodeA".to_string(),
|
|
278
|
-
StateHash::from_hex("hash0".to_string()),
|
|
279
|
-
Some(log_path.clone()),
|
|
280
|
-
)?;
|
|
281
|
-
|
|
282
|
-
let node_b = DistributedTransactionExecutor::new(
|
|
283
|
-
"nodeB".to_string(),
|
|
284
|
-
StateHash::from_hex("hash0".to_string()),
|
|
285
|
-
);
|
|
286
|
-
|
|
287
|
-
// Pre-populate node_a's seen set to simulate prior durability
|
|
288
|
-
let envelope = create_test_envelope("nodeB", 1);
|
|
289
|
-
node_a.envelopes_seen.insert(envelope.envelope_id.clone());
|
|
290
|
-
|
|
291
|
-
// Recovery tries to apply same envelope (duplicate)
|
|
292
|
-
let mut recovery = RecoveryOrchestrator::new(node_a, "nodeB".to_string());
|
|
293
|
-
recovery.reconcile_with_peer(&node_b)?;
|
|
294
|
-
recovery.apply_missing_operations(vec![envelope.clone()])?;
|
|
295
|
-
|
|
296
|
-
// Should not error on duplicate—dedup handles it
|
|
297
|
-
assert!(recovery
|
|
298
|
-
.executor
|
|
299
|
-
.envelopes_seen
|
|
300
|
-
.contains(&envelope.envelope_id));
|
|
301
|
-
recovery.finalize_recovery()?;
|
|
302
|
-
|
|
303
|
-
assert_eq!(recovery.get_state(), RecoveryState::Ready);
|
|
304
|
-
|
|
305
|
-
Ok(())
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/// TC-1c.3-E: Recovery interrupted (crash halfway, resume without corruption)
|
|
309
|
-
///
|
|
310
|
-
/// Scenario: Recovery starts, crashes mid-replay, restarts again
|
|
311
|
-
/// Expected: Restarting recovery is idempotent, no corruption
|
|
312
|
-
#[test]
|
|
313
|
-
fn test_recovery_interrupted_and_resumed() -> Result<(), Box<dyn std::error::Error>> {
|
|
314
|
-
let temp_dir = TempDir::new()?;
|
|
315
|
-
let log_path = temp_dir.path().join("operations.log");
|
|
316
|
-
|
|
317
|
-
// First recovery attempt (simulated interruption)
|
|
318
|
-
let node_a_attempt1 = DistributedTransactionExecutor::with_log(
|
|
319
|
-
"nodeA".to_string(),
|
|
320
|
-
StateHash::from_hex("hash0".to_string()),
|
|
321
|
-
Some(log_path.clone()),
|
|
322
|
-
)?;
|
|
323
|
-
|
|
324
|
-
let node_b = DistributedTransactionExecutor::new(
|
|
325
|
-
"nodeB".to_string(),
|
|
326
|
-
StateHash::from_hex("hash0".to_string()),
|
|
327
|
-
);
|
|
328
|
-
|
|
329
|
-
let ops: Vec<_> = (1..=3)
|
|
330
|
-
.map(|seq| create_test_envelope("nodeB", seq))
|
|
331
|
-
.collect();
|
|
332
|
-
|
|
333
|
-
let mut recovery1 = RecoveryOrchestrator::new(node_a_attempt1, "nodeB".to_string());
|
|
334
|
-
recovery1.reconcile_with_peer(&node_b)?;
|
|
335
|
-
// Only apply first 2 ops before "crash"
|
|
336
|
-
recovery1.apply_missing_operations(ops[0..2].to_vec())?;
|
|
337
|
-
|
|
338
|
-
// Second recovery attempt (after restart)
|
|
339
|
-
let mut node_a_attempt2 = DistributedTransactionExecutor::with_log(
|
|
340
|
-
"nodeA".to_string(),
|
|
341
|
-
StateHash::from_hex("hash0".to_string()),
|
|
342
|
-
Some(log_path.clone()),
|
|
343
|
-
)?;
|
|
344
|
-
node_a_attempt2
|
|
345
|
-
.envelopes_seen
|
|
346
|
-
.extend(recovery1.executor.envelopes_seen.clone());
|
|
347
|
-
|
|
348
|
-
let mut recovery2 = RecoveryOrchestrator::new(node_a_attempt2, "nodeB".to_string());
|
|
349
|
-
recovery2.reconcile_with_peer(&node_b)?;
|
|
350
|
-
// Complete recovery with all 3 ops
|
|
351
|
-
recovery2.apply_missing_operations(ops)?;
|
|
352
|
-
recovery2.finalize_recovery()?;
|
|
353
|
-
|
|
354
|
-
assert_eq!(recovery2.get_state(), RecoveryState::Ready);
|
|
355
|
-
|
|
356
|
-
Ok(())
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/// TC-1c.3-F: Peer unavailable (node remains in clearly identifiable recovery state)
|
|
360
|
-
///
|
|
361
|
-
/// Scenario: Node restarts, tries to recover, peer is offline
|
|
362
|
-
/// Expected: Recovery fails with clear error, executor stays RECOVERING
|
|
363
|
-
#[test]
|
|
364
|
-
fn test_recovery_peer_unavailable() -> Result<(), Box<dyn std::error::Error>> {
|
|
365
|
-
let temp_dir = TempDir::new()?;
|
|
366
|
-
let log_path = temp_dir.path().join("operations.log");
|
|
367
|
-
|
|
368
|
-
let node_a = DistributedTransactionExecutor::with_log(
|
|
369
|
-
"nodeA".to_string(),
|
|
370
|
-
StateHash::from_hex("hash0".to_string()),
|
|
371
|
-
Some(log_path.clone()),
|
|
372
|
-
)?;
|
|
373
|
-
|
|
374
|
-
// No peer available - simulate peer_state being unavailable
|
|
375
|
-
let mut recovery = RecoveryOrchestrator::new(node_a, "unavailable_peer".to_string());
|
|
376
|
-
|
|
377
|
-
// Try to reconcile with missing peer (create minimal stub)
|
|
378
|
-
let stub_peer = DistributedTransactionExecutor::new(
|
|
379
|
-
"different_node".to_string(),
|
|
380
|
-
StateHash::from_hex("hash0".to_string()),
|
|
381
|
-
);
|
|
382
|
-
|
|
383
|
-
let result = recovery.reconcile_with_peer(&stub_peer);
|
|
384
|
-
|
|
385
|
-
// Recovery should fail to find peer state
|
|
386
|
-
assert!(result.is_err());
|
|
387
|
-
// Executor should still be RECOVERING, not READY
|
|
388
|
-
assert_eq!(recovery.get_state(), RecoveryState::Recovering);
|
|
389
|
-
|
|
390
|
-
Ok(())
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
/// TC-1c.3-G: Recovery completes (state verification succeeds → RECOVERING → READY)
|
|
394
|
-
///
|
|
395
|
-
/// Scenario: Full recovery flow: restore → reconcile → apply → verify → transition
|
|
396
|
-
/// Expected: Each step succeeds, state machine progresses RECOVERING → READY
|
|
397
|
-
#[test]
|
|
398
|
-
fn test_recovery_complete_state_machine_progression() -> Result<(), Box<dyn std::error::Error>>
|
|
399
|
-
{
|
|
400
|
-
let temp_dir = TempDir::new()?;
|
|
401
|
-
let log_path = temp_dir.path().join("operations.log");
|
|
402
|
-
|
|
403
|
-
// Create synchronized peer
|
|
404
|
-
let mut peer = DistributedTransactionExecutor::new(
|
|
405
|
-
"peer".to_string(),
|
|
406
|
-
StateHash::from_hex("hash0".to_string()),
|
|
407
|
-
);
|
|
408
|
-
|
|
409
|
-
// Create restarted node with same initial hash
|
|
410
|
-
let mut local = DistributedTransactionExecutor::with_log(
|
|
411
|
-
"local".to_string(),
|
|
412
|
-
StateHash::from_hex("hash0".to_string()),
|
|
413
|
-
Some(log_path.clone()),
|
|
414
|
-
)?;
|
|
415
|
-
|
|
416
|
-
// Register each other with same state
|
|
417
|
-
local.register_replica("peer".to_string(), StateHash::from_hex("hash0".to_string()));
|
|
418
|
-
peer.register_replica(
|
|
419
|
-
"local".to_string(),
|
|
420
|
-
StateHash::from_hex("hash0".to_string()),
|
|
421
|
-
);
|
|
422
|
-
|
|
423
|
-
// Reconcile: Both have same state
|
|
424
|
-
let mut recovery = RecoveryOrchestrator::new(local, "peer".to_string());
|
|
425
|
-
assert_eq!(recovery.get_state(), RecoveryState::Recovering);
|
|
426
|
-
|
|
427
|
-
recovery.reconcile_with_peer(&peer)?;
|
|
428
|
-
|
|
429
|
-
// Apply (empty in this case - already synchronized)
|
|
430
|
-
recovery.apply_missing_operations(Vec::new())?;
|
|
431
|
-
|
|
432
|
-
// Verify convergence
|
|
433
|
-
let converged = recovery.verify_convergence()?;
|
|
434
|
-
assert!(converged);
|
|
435
|
-
|
|
436
|
-
// Finalize: RECOVERING → READY
|
|
437
|
-
recovery.finalize_recovery()?;
|
|
438
|
-
assert_eq!(recovery.get_state(), RecoveryState::Ready);
|
|
439
|
-
|
|
440
|
-
Ok(())
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
/// Integration: Restarted executor loads from disk and recovers
|
|
444
|
-
///
|
|
445
|
-
/// End-to-end test: persist operations → crash → restart → recover
|
|
446
|
-
#[test]
|
|
447
|
-
fn test_executor_restart_and_recovery_integration() -> Result<(), Box<dyn std::error::Error>> {
|
|
448
|
-
let temp_dir = TempDir::new()?;
|
|
449
|
-
let log_path = temp_dir.path().join("operations.log");
|
|
450
|
-
|
|
451
|
-
// Phase 1: Initial execution and persistence
|
|
452
|
-
{
|
|
453
|
-
let executor = DistributedTransactionExecutor::with_log(
|
|
454
|
-
"nodeA".to_string(),
|
|
455
|
-
StateHash::from_hex("hash0".to_string()),
|
|
456
|
-
Some(log_path.clone()),
|
|
457
|
-
)?;
|
|
458
|
-
|
|
459
|
-
let _node_id = executor.get_local_node_id();
|
|
460
|
-
assert_eq!(_node_id, "nodeA");
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
// Phase 2: "Crash" and restart
|
|
464
|
-
let mut recovered_executor = DistributedTransactionExecutor::with_log(
|
|
465
|
-
"nodeA".to_string(),
|
|
466
|
-
StateHash::from_hex("hash0".to_string()),
|
|
467
|
-
Some(log_path.clone()),
|
|
468
|
-
)?;
|
|
469
|
-
|
|
470
|
-
// Phase 3: Load from disk (reconstruct dedup from operation log)
|
|
471
|
-
let count = recovered_executor.load_from_disk(log_path)?;
|
|
472
|
-
assert_eq!(count, 0); // No operations in this test
|
|
473
|
-
|
|
474
|
-
// Phase 4: Recovery orchestration with peer
|
|
475
|
-
let peer = DistributedTransactionExecutor::new(
|
|
476
|
-
"nodeB".to_string(),
|
|
477
|
-
StateHash::from_hex("hash0".to_string()),
|
|
478
|
-
);
|
|
479
|
-
|
|
480
|
-
// The peer is registered at the state the recovered node actually
|
|
481
|
-
// holds, read back rather than restated. `load_from_disk` recomputes
|
|
482
|
-
// the local replica's hash from the replayed log, so a fabricated
|
|
483
|
-
// literal here would describe a peer that has diverged and the
|
|
484
|
-
// convergence check below would be asserting the opposite of what this
|
|
485
|
-
// test is about.
|
|
486
|
-
let recovered_hash = recovered_executor
|
|
487
|
-
.get_replica_state("nodeA")
|
|
488
|
-
.expect("the recovered node has a local replica")
|
|
489
|
-
.state_hash;
|
|
490
|
-
recovered_executor.register_replica("nodeB".to_string(), recovered_hash);
|
|
491
|
-
|
|
492
|
-
let mut recovery = RecoveryOrchestrator::new(recovered_executor, "nodeB".to_string());
|
|
493
|
-
recovery.reconcile_with_peer(&peer)?;
|
|
494
|
-
recovery.apply_missing_operations(Vec::new())?;
|
|
495
|
-
recovery.finalize_recovery()?;
|
|
496
|
-
|
|
497
|
-
// Executor is now READY
|
|
498
|
-
assert_eq!(recovery.get_state(), RecoveryState::Ready);
|
|
499
|
-
|
|
500
|
-
Ok(())
|
|
501
|
-
}
|
|
502
|
-
}
|