@feltdb/core 0.8.3 → 0.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands.js +4 -1
- package/dist/cli/provisioning-neutrality.js +79 -0
- package/dist/collection.d.ts +43 -1
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +192 -22
- package/dist/create/create.js +25 -21
- package/dist/create/managed-account.js +11 -0
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/Cargo.lock +165 -0
- package/dist/create/server-source/Cargo.toml +9 -0
- package/dist/create/server-source/crates/feltdb/Cargo.toml +3 -0
- package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +44 -44
- package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +12 -24
- package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +7 -13
- package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +13 -10
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +12 -9
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +78 -25
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +16 -13
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +13 -5
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +41 -22
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +33 -15
- package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +100 -33
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +56 -20
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +116 -41
- package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +186 -55
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +64 -26
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +46 -15
- package/dist/create/server-source/crates/feltdb/src/admission.rs +8 -15
- package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +43 -13
- package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +15 -42
- package/dist/create/server-source/crates/feltdb/src/analytics.rs +65 -19
- package/dist/create/server-source/crates/feltdb/src/application.rs +113 -30
- package/dist/create/server-source/crates/feltdb/src/authorization_security_tests.rs +475 -140
- package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +17 -15
- package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +0 -1
- package/dist/create/server-source/crates/feltdb/src/causal_backlog_bound.rs +59 -15
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +266 -114
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +25 -7
- package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +10 -15
- package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +3 -11
- package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +14 -5
- package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +21 -25
- package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +14 -11
- package/dist/create/server-source/crates/feltdb/src/dedup_bound_investigation.rs +103 -22
- package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +18 -15
- package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +12 -8
- package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +1 -5
- package/dist/create/server-source/crates/feltdb/src/durable_operation_identity.rs +87 -23
- package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +3 -7
- package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +10 -9
- package/dist/create/server-source/crates/feltdb/src/equality_index.rs +595 -0
- package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +1 -6
- package/dist/create/server-source/crates/feltdb/src/indexing.rs +35 -38
- package/dist/create/server-source/crates/feltdb/src/lib.rs +1050 -117
- package/dist/create/server-source/crates/feltdb/src/managed_cas_tests.rs +4 -1
- package/dist/create/server-source/crates/feltdb/src/metrics.rs +0 -1
- package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +1 -2
- package/dist/create/server-source/crates/feltdb/src/multi_operation_transaction.rs +107 -30
- package/dist/create/server-source/crates/feltdb/src/observability.rs +19 -6
- package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +12 -11
- package/dist/create/server-source/crates/feltdb/src/operation_log.rs +9 -4
- package/dist/create/server-source/crates/feltdb/src/p1_application_atomicity.rs +65 -18
- package/dist/create/server-source/crates/feltdb/src/p1_atomicity_acceptance.rs +193 -57
- package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +37 -27
- package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +38 -10
- package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +20 -14
- package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +394 -229
- package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +8 -6
- package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +11 -13
- package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +90 -72
- package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +3 -3
- package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +33 -11
- package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +6 -6
- package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +14 -56
- package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +29 -27
- package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +35 -17
- package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +8 -2
- package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +59 -15
- package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +70 -17
- package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +23 -6
- package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +12 -3
- package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +41 -11
- package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +56 -25
- package/dist/create/server-source/crates/feltdb/src/policy_evaluation.rs +701 -245
- package/dist/create/server-source/crates/feltdb/src/production_api.rs +31 -13
- package/dist/create/server-source/crates/feltdb/src/query_execution_diagnostics.rs +126 -0
- package/dist/create/server-source/crates/feltdb/src/query_performance.rs +6 -8
- package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +5 -5
- package/dist/create/server-source/crates/feltdb/src/replica_acknowledgements.rs +48 -18
- package/dist/create/server-source/crates/feltdb/src/replica_membership.rs +30 -11
- package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +6 -3
- package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +4 -3
- package/dist/create/server-source/crates/feltdb/src/sharding.rs +36 -10
- package/dist/create/server-source/crates/feltdb/src/state_conflict_contract.rs +516 -0
- package/dist/create/server-source/crates/feltdb/src/state_contract.rs +305 -6
- package/dist/create/server-source/crates/feltdb/src/state_diff_contract.rs +222 -0
- package/dist/create/server-source/crates/feltdb/src/state_facade.rs +82 -54
- package/dist/create/server-source/crates/feltdb/src/state_hash.rs +2 -2
- package/dist/create/server-source/crates/feltdb/src/state_model.rs +1514 -537
- package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +6 -3
- package/dist/create/server-source/crates/feltdb/src/state_trigger.rs +672 -0
- package/dist/create/server-source/crates/feltdb/src/submission.rs +5 -11
- package/dist/create/server-source/crates/feltdb/src/sync.rs +12 -0
- package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +6 -8
- package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +24 -35
- package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +24 -8
- package/dist/create/server-source/crates/feltdb/src/transaction_preconditions.rs +248 -59
- package/dist/create/server-source/crates/feltdb/src/transactions.rs +17 -20
- package/dist/create/server-source/crates/feltdb/src/trigger_contract.rs +749 -0
- package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +1 -0
- package/dist/create/server-source/crates/feltdb/src/workload.rs +512 -4
- package/dist/create/server-source/crates/feltdb/src/workload_diagnostics.rs +442 -0
- package/dist/create/server-source/crates/feltdb/tests/branching_evidence.rs +299 -0
- package/dist/create/server-source/crates/feltdb/tests/current_revision_authority_evidence.rs +288 -0
- package/dist/create/server-source/crates/feltdb/tests/durable_format_compatibility.rs +392 -0
- package/dist/create/server-source/crates/feltdb/tests/feltdb_state_boundary_tests.rs +436 -220
- package/dist/create/server-source/crates/feltdb/tests/fixtures/state_conflict_contract_corpus.json +1916 -0
- package/dist/create/server-source/crates/feltdb/tests/fixtures/state_diff_contract_corpus.json +1878 -0
- package/dist/create/server-source/crates/feltdb/tests/fixtures/trigger_contract_corpus.json +1862 -0
- package/dist/create/server-source/crates/feltdb/tests/pr34_query_collection.rs +234 -0
- package/dist/create/server-source/crates/feltdb/tests/pr35_equality_index.rs +947 -0
- package/dist/create/server-source/crates/feltdb/tests/pr7_self_authorization_proof.rs +5 -8
- package/dist/create/server-source/crates/feltdb/tests/pr8_vocabulary_assessment.rs +52 -44
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase2_boundary_tests.rs +33 -16
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3a_path_a_tests.rs +22 -7
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_authorized_mutations.rs +41 -22
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_role_based_authorization.rs +25 -8
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_simple_auth_delete.rs +9 -6
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_team_delete_role_authorization.rs +120 -69
- package/dist/create/server-source/crates/feltdb/tests/pr9_teams_role_based_access.rs +21 -10
- package/dist/create/server-source/crates/feltdb/tests/production_readiness_contract.rs +1032 -0
- package/dist/create/server-source/crates/feltdb/tests/reconciliation_application.rs +868 -0
- package/dist/create/server-source/crates/feltdb/tests/reconciliation_wire_format_evidence.rs +221 -0
- package/dist/create/server-source/crates/feltdb/tests/resource_scoped_revisions.rs +338 -0
- package/dist/create/server-source/crates/feltdb/tests/revision_identity_contract.rs +1039 -0
- package/dist/create/server-source/crates/feltdb/tests/revision_model_decision.rs +739 -0
- package/dist/create/server-source/crates/feltdb/tests/revision_retention_boundary_evidence.rs +427 -0
- package/dist/create/server-source/crates/feltdb/tests/saas_authorization_integration.rs +3 -3
- package/dist/create/server-source/crates/feltdb/tests/saas_invitation_lifecycle.rs +25 -22
- package/dist/create/server-source/crates/feltdb/tests/state_conflict_contract_conformance.rs +1799 -0
- package/dist/create/server-source/crates/feltdb/tests/state_diff_contract_conformance.rs +1316 -0
- package/dist/create/server-source/crates/feltdb/tests/state_model_integration.rs +53 -61
- package/dist/create/server-source/crates/feltdb/tests/state_persistence_integration.rs +156 -61
- package/dist/create/server-source/crates/feltdb/tests/state_store_boundary_evidence.rs +299 -0
- package/dist/create/server-source/crates/feltdb/tests/sync_divergence_evidence.rs +255 -0
- package/dist/create/server-source/crates/feltdb/tests/three_way_input_boundary_evidence.rs +249 -0
- package/dist/create/server-source/crates/feltdb/tests/trigger_contract_conformance.rs +994 -0
- package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +2 -1
- package/dist/create/server-source/crates/feltdb-server/src/audit.rs +1137 -29
- package/dist/create/server-source/crates/feltdb-server/src/auth.rs +164 -13
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +800 -34
- package/dist/db.d.ts +33 -34
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +74 -20
- package/dist/deployment.d.ts +30 -0
- package/dist/deployment.d.ts.map +1 -0
- package/dist/deployment.js +130 -0
- package/dist/embedded-transaction.d.ts +22 -4
- package/dist/embedded-transaction.d.ts.map +1 -1
- package/dist/embedded-transaction.js +51 -5
- package/dist/feltdb.d.ts +14 -2
- package/dist/feltdb.d.ts.map +1 -1
- package/dist/file-db.js +1 -1
- package/dist/http-client.d.ts +14 -0
- package/dist/http-client.d.ts.map +1 -1
- package/dist/http-client.js +23 -5
- package/dist/http-db.d.ts +119 -1
- package/dist/http-db.d.ts.map +1 -1
- package/dist/http-db.js +346 -31
- package/dist/index-core.d.ts +2 -0
- package/dist/index-core.d.ts.map +1 -1
- package/dist/index-core.js +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/indexeddb-db.d.ts.map +1 -1
- package/dist/indexeddb-db.js +35 -21
- package/dist/managed-recovery.d.ts +192 -0
- package/dist/managed-recovery.d.ts.map +1 -0
- package/dist/managed-recovery.js +242 -0
- package/dist/memory-db.js +1 -1
- package/dist/studio-app/assets/{feltdb_wasm-DB8cX151.js → feltdb_wasm-DaNwCLRX.js} +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-DnsHNv6g.wasm +0 -0
- package/dist/studio-app/assets/index-j8IlhNqJ.js +29 -0
- package/dist/studio-app/index.html +1 -1
- package/dist/transaction.d.ts +30 -0
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +41 -0
- package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
- package/dist/workload.d.ts +2 -1
- package/dist/workload.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-ClhDHp0S.wasm +0 -0
- package/dist/studio-app/assets/index-B0k4UAlI.js +0 -29
|
@@ -14,9 +14,8 @@
|
|
|
14
14
|
//! - Explicit reconciliation (no automatic merge)
|
|
15
15
|
|
|
16
16
|
use crate::state_model::{
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
StateReconciliationResult, STATE_MODEL_VERSION,
|
|
17
|
+
ConflictClassification, ReconciliationPlan, Relationship, SemanticDiff, StateId,
|
|
18
|
+
StateReconciliationResult, StateRevision, StateStore, StateTopology, STATE_MODEL_VERSION,
|
|
20
19
|
};
|
|
21
20
|
use crate::FeltDb;
|
|
22
21
|
use std::sync::Arc;
|
|
@@ -47,8 +46,8 @@ impl FeltDBStateSystem {
|
|
|
47
46
|
/// ```ignore
|
|
48
47
|
/// let db = FeltDb::open("./data")?;
|
|
49
48
|
/// let store = FeltDBStateSystem::create_store(&Arc::new(db))?;
|
|
50
|
-
/// let initial = store.create(json_string, "app-authority")?;
|
|
51
|
-
/// let
|
|
49
|
+
/// let initial = store.create("docs:1", json_string, "app-authority")?;
|
|
50
|
+
/// let same = store.get(&initial.id).expect("retrieved by identity");
|
|
52
51
|
/// ```
|
|
53
52
|
pub fn create_store(db: &Arc<FeltDb>) -> Result<StateStore, String> {
|
|
54
53
|
StateStore::with_feltdb(db.clone())
|
|
@@ -81,7 +80,9 @@ impl FeltDBStateSystem {
|
|
|
81
80
|
2. Use FeltDBStateSystem::create_store(&Arc::new(db)) to initialize state
|
|
82
81
|
3. Call store.create() for initial state
|
|
83
82
|
4. Call store.commit() for transitions
|
|
84
|
-
5. Call store.
|
|
83
|
+
5. Call store.get(&id) to retrieve a revision by identity
|
|
84
|
+
(the store does not track which revision is "current" — see
|
|
85
|
+
StateStore's own documentation for why that is a separate concern)
|
|
85
86
|
6. Use StateTopology to inspect causal relationships
|
|
86
87
|
7. Use SemanticDiff to compute changes between states
|
|
87
88
|
8. Use ConflictClassification to analyze divergence
|
|
@@ -104,7 +105,10 @@ impl FeltDBStateSystem {
|
|
|
104
105
|
#[cfg(test)]
|
|
105
106
|
mod facade_tests {
|
|
106
107
|
use super::*;
|
|
107
|
-
use crate::{
|
|
108
|
+
use crate::{
|
|
109
|
+
state_model::StateStore, ConflictClass, ConflictClassification, Relationship, SemanticDiff,
|
|
110
|
+
StateTopology,
|
|
111
|
+
};
|
|
108
112
|
use serde_json::json;
|
|
109
113
|
|
|
110
114
|
#[test]
|
|
@@ -112,11 +116,17 @@ mod facade_tests {
|
|
|
112
116
|
// For testing, use new_volatile() - production must use create_store(&db)
|
|
113
117
|
let store = StateStore::new_volatile();
|
|
114
118
|
let initial = store
|
|
115
|
-
.create(
|
|
119
|
+
.create(
|
|
120
|
+
"docs:1",
|
|
121
|
+
r#"{"data":"test"}"#.to_string(),
|
|
122
|
+
"test-auth".to_string(),
|
|
123
|
+
)
|
|
116
124
|
.expect("Failed to create initial state");
|
|
117
|
-
|
|
118
|
-
let
|
|
119
|
-
|
|
125
|
+
|
|
126
|
+
let stored = store
|
|
127
|
+
.get(&initial.id)
|
|
128
|
+
.expect("the revision is retrievable by identity");
|
|
129
|
+
assert_eq!(stored.id, initial.id);
|
|
120
130
|
}
|
|
121
131
|
|
|
122
132
|
#[test]
|
|
@@ -128,19 +138,21 @@ mod facade_tests {
|
|
|
128
138
|
fn test_facade_comprehensive_workflow() {
|
|
129
139
|
// Initialize - for testing, use new_volatile()
|
|
130
140
|
let store = StateStore::new_volatile();
|
|
131
|
-
|
|
141
|
+
|
|
132
142
|
// Create initial state
|
|
133
143
|
let initial = store
|
|
134
144
|
.create(
|
|
145
|
+
"docs:1",
|
|
135
146
|
r#"{"users":{"alice":100}}"#.to_string(),
|
|
136
147
|
"app-auth".to_string(),
|
|
137
148
|
)
|
|
138
149
|
.expect("Failed to create");
|
|
139
150
|
|
|
140
|
-
// Verify
|
|
141
|
-
|
|
151
|
+
// Verify the revision is retrievable by identity. The store tracks no
|
|
152
|
+
// "current" pointer; the caller holds the ids it cares about.
|
|
153
|
+
assert_eq!(store.get(&initial.id).unwrap().id, initial.id);
|
|
142
154
|
|
|
143
|
-
//
|
|
155
|
+
// Divergence 1: alice updates
|
|
144
156
|
let branch1 = store
|
|
145
157
|
.commit(
|
|
146
158
|
r#"{"users":{"alice":150}}"#.to_string(),
|
|
@@ -149,11 +161,7 @@ mod facade_tests {
|
|
|
149
161
|
)
|
|
150
162
|
.expect("Failed branch 1");
|
|
151
163
|
|
|
152
|
-
|
|
153
|
-
.create_branch("alice-branch".to_string(), branch1.id.clone())
|
|
154
|
-
.expect("Failed to create alice-branch");
|
|
155
|
-
|
|
156
|
-
// Branch 2: create from initial
|
|
164
|
+
// Divergence 2: from the same parent
|
|
157
165
|
let branch2 = store
|
|
158
166
|
.commit(
|
|
159
167
|
r#"{"users":{"alice":100,"bob":50}}"#.to_string(),
|
|
@@ -162,10 +170,6 @@ mod facade_tests {
|
|
|
162
170
|
)
|
|
163
171
|
.expect("Failed branch 2");
|
|
164
172
|
|
|
165
|
-
store
|
|
166
|
-
.create_branch("bob-branch".to_string(), branch2.id.clone())
|
|
167
|
-
.expect("Failed to create bob-branch");
|
|
168
|
-
|
|
169
173
|
// Inspect topology
|
|
170
174
|
let mut topology = StateTopology::new();
|
|
171
175
|
topology.add_revision(initial.clone());
|
|
@@ -181,12 +185,10 @@ mod facade_tests {
|
|
|
181
185
|
}
|
|
182
186
|
|
|
183
187
|
// Compute diff using JSON values
|
|
184
|
-
let initial_json: serde_json::Value =
|
|
185
|
-
r#"{"users":{"alice":100}}"
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
r#"{"users":{"alice":150}}"#,
|
|
189
|
-
).unwrap();
|
|
188
|
+
let initial_json: serde_json::Value =
|
|
189
|
+
serde_json::from_str(r#"{"users":{"alice":100}}"#).unwrap();
|
|
190
|
+
let branch1_json: serde_json::Value =
|
|
191
|
+
serde_json::from_str(r#"{"users":{"alice":150}}"#).unwrap();
|
|
190
192
|
let diff = SemanticDiff::compute(&initial_json, &branch1_json);
|
|
191
193
|
assert!(!diff.changes.is_empty());
|
|
192
194
|
|
|
@@ -199,16 +201,16 @@ mod facade_tests {
|
|
|
199
201
|
fn test_facade_immutability() {
|
|
200
202
|
let store = StateStore::new_volatile();
|
|
201
203
|
let initial = store
|
|
202
|
-
.create(r#"{"v":1}"#.to_string(), "auth".to_string())
|
|
204
|
+
.create("docs:1", r#"{"v":1}"#.to_string(), "auth".to_string())
|
|
203
205
|
.unwrap();
|
|
204
|
-
|
|
206
|
+
|
|
205
207
|
let initial_id = initial.id.clone();
|
|
206
|
-
|
|
208
|
+
|
|
207
209
|
// Create another state
|
|
208
210
|
let second = store
|
|
209
211
|
.commit(r#"{"v":2}"#.to_string(), &initial, "auth".to_string())
|
|
210
212
|
.unwrap();
|
|
211
|
-
|
|
213
|
+
|
|
212
214
|
// Verify first state is unchanged
|
|
213
215
|
assert_eq!(store.get(&initial_id).unwrap().content, r#"{"v":1}"#);
|
|
214
216
|
assert_eq!(initial_id, initial.id);
|
|
@@ -218,12 +220,16 @@ mod facade_tests {
|
|
|
218
220
|
fn test_facade_restart_recovery() {
|
|
219
221
|
let store1 = StateStore::new_volatile();
|
|
220
222
|
let initial = store1
|
|
221
|
-
.create(
|
|
223
|
+
.create(
|
|
224
|
+
"docs:1",
|
|
225
|
+
r#"{"data":"test"}"#.to_string(),
|
|
226
|
+
"auth".to_string(),
|
|
227
|
+
)
|
|
222
228
|
.unwrap();
|
|
223
|
-
|
|
229
|
+
|
|
224
230
|
// Simulate restart: new store instance
|
|
225
231
|
let _store2 = StateStore::new_volatile();
|
|
226
|
-
|
|
232
|
+
|
|
227
233
|
// Note: In real scenario, store would load from persistent storage
|
|
228
234
|
// Here we demonstrate the API contract: states retrieved by id are valid
|
|
229
235
|
assert!(store1.exists(&initial.id));
|
|
@@ -233,44 +239,62 @@ mod facade_tests {
|
|
|
233
239
|
fn test_facade_authority_neutrality() {
|
|
234
240
|
let store = StateStore::new_volatile();
|
|
235
241
|
let initial = store
|
|
236
|
-
.create(
|
|
242
|
+
.create(
|
|
243
|
+
"docs:1",
|
|
244
|
+
r#"{"balance":100}"#.to_string(),
|
|
245
|
+
"alice".to_string(),
|
|
246
|
+
)
|
|
237
247
|
.unwrap();
|
|
238
|
-
|
|
248
|
+
|
|
239
249
|
let update1 = store
|
|
240
|
-
.commit(
|
|
250
|
+
.commit(
|
|
251
|
+
r#"{"balance":150}"#.to_string(),
|
|
252
|
+
&initial,
|
|
253
|
+
"alice".to_string(),
|
|
254
|
+
)
|
|
241
255
|
.unwrap();
|
|
242
|
-
|
|
256
|
+
|
|
243
257
|
let update2 = store
|
|
244
|
-
.commit(
|
|
258
|
+
.commit(
|
|
259
|
+
r#"{"balance":150}"#.to_string(),
|
|
260
|
+
&initial,
|
|
261
|
+
"bob".to_string(),
|
|
262
|
+
)
|
|
245
263
|
.unwrap();
|
|
246
|
-
|
|
247
|
-
//
|
|
264
|
+
|
|
265
|
+
// The same state, from the same parent, is the same historical fact —
|
|
266
|
+
// so it is one revision, whoever committed it. Authority is recorded
|
|
267
|
+
// but takes no part in identity.
|
|
248
268
|
assert_eq!(update1.id, update2.id);
|
|
249
|
-
|
|
250
|
-
|
|
269
|
+
assert_eq!(update1.content_id, update2.content_id);
|
|
270
|
+
|
|
271
|
+
// And because authority takes no part in identity, the second commit
|
|
272
|
+
// is a no-op that returns what was already recorded. The authority on a
|
|
273
|
+
// revision is whoever first committed that historical fact, not
|
|
274
|
+
// whoever last asked for it.
|
|
251
275
|
assert_eq!(update1.authority, "alice");
|
|
252
|
-
assert_eq!(update2.authority, "
|
|
276
|
+
assert_eq!(update2.authority, "alice");
|
|
253
277
|
}
|
|
254
278
|
|
|
255
279
|
#[test]
|
|
256
280
|
fn test_facade_read_only_operations() {
|
|
257
281
|
let store = StateStore::new_volatile();
|
|
258
282
|
let initial = store
|
|
259
|
-
.create(r#"{"v":1}"#.to_string(), "auth".to_string())
|
|
283
|
+
.create("docs:1", r#"{"v":1}"#.to_string(), "auth".to_string())
|
|
260
284
|
.unwrap();
|
|
261
|
-
|
|
285
|
+
|
|
262
286
|
let update = store
|
|
263
287
|
.commit(r#"{"v":2}"#.to_string(), &initial, "auth".to_string())
|
|
264
288
|
.unwrap();
|
|
265
|
-
|
|
289
|
+
|
|
266
290
|
// Topology operations should not mutate
|
|
267
291
|
let mut topology = StateTopology::new();
|
|
268
292
|
topology.add_revision(initial.clone());
|
|
269
293
|
topology.add_revision(update.clone());
|
|
270
|
-
|
|
294
|
+
|
|
271
295
|
let rel = topology.relationship(&initial.id, &update.id);
|
|
272
296
|
assert!(matches!(rel, Relationship::Ancestor));
|
|
273
|
-
|
|
297
|
+
|
|
274
298
|
// Verify both states still exist unchanged
|
|
275
299
|
assert_eq!(store.get(&initial.id).unwrap().id, initial.id);
|
|
276
300
|
assert_eq!(store.get(&update.id).unwrap().id, update.id);
|
|
@@ -281,9 +305,13 @@ mod facade_tests {
|
|
|
281
305
|
// This test verifies we can use the state system without any .git access
|
|
282
306
|
let store = StateStore::new_volatile();
|
|
283
307
|
let state = store
|
|
284
|
-
.create(
|
|
308
|
+
.create(
|
|
309
|
+
"docs:1",
|
|
310
|
+
r#"{"test":"no-git"}"#.to_string(),
|
|
311
|
+
"auth".to_string(),
|
|
312
|
+
)
|
|
285
313
|
.expect("State creation should work without .git");
|
|
286
|
-
|
|
314
|
+
|
|
287
315
|
// Topology and diff operations should work without git
|
|
288
316
|
let mut topology = StateTopology::new();
|
|
289
317
|
topology.add_revision(state.clone());
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
///
|
|
3
3
|
/// Produces SHA-256 hashes of canonical state serializations.
|
|
4
4
|
/// Invariant: same state → same hash, different state → different hash (except negligible crypto collision)
|
|
5
|
-
|
|
6
5
|
use serde_json::{json, Value};
|
|
7
6
|
use std::collections::BTreeMap;
|
|
8
7
|
|
|
@@ -27,7 +26,8 @@ impl CanonicalState {
|
|
|
27
26
|
|
|
28
27
|
/// Get a record
|
|
29
28
|
pub fn get_record(&self, collection: &str, record_id: &str) -> Option<&Value> {
|
|
30
|
-
self.records
|
|
29
|
+
self.records
|
|
30
|
+
.get(&(collection.to_string(), record_id.to_string()))
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/// Canonical serialization for hashing (deterministic ordering)
|