@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,222 +0,0 @@
|
|
|
1
|
-
//! The deterministic contract behind FeltDB's semantic state diff.
|
|
2
|
-
//!
|
|
3
|
-
//! This is the second specimen of the pattern established by
|
|
4
|
-
//! [`crate::trigger_contract`]: a decision FeltDB already makes, drawn behind a
|
|
5
|
-
//! runtime-independent boundary so that more than one implementation can be
|
|
6
|
-
//! held to it.
|
|
7
|
-
//!
|
|
8
|
-
//! ```text
|
|
9
|
-
//! canonical state A + canonical state B
|
|
10
|
-
//! │
|
|
11
|
-
//! ┌──────────────┴──────────────┐
|
|
12
|
-
//! │ │
|
|
13
|
-
//! native evaluation WASM evaluation
|
|
14
|
-
//! │ │
|
|
15
|
-
//! └──────────────┬──────────────┘
|
|
16
|
-
//! │
|
|
17
|
-
//! canonical diff bytes
|
|
18
|
-
//! ```
|
|
19
|
-
//!
|
|
20
|
-
//! # This module adds no diff semantics
|
|
21
|
-
//!
|
|
22
|
-
//! [`SemanticDiff::compute`] is untouched and remains authoritative. Everything
|
|
23
|
-
//! here is envelope: identity, version, canonical encoding, and the decision to
|
|
24
|
-
//! report an unusable input rather than fail. If this module and
|
|
25
|
-
//! `SemanticDiff::compute` ever disagree, `SemanticDiff::compute` is right.
|
|
26
|
-
//!
|
|
27
|
-
//! # Determinism budget
|
|
28
|
-
//!
|
|
29
|
-
//! Evaluation reads nothing but its two states. No clock, filesystem, network,
|
|
30
|
-
//! random source, process identity, authentication context, authority metadata
|
|
31
|
-
//! or process-global mutable state participates, and the audit that produced
|
|
32
|
-
//! this contract found none in the implementation either.
|
|
33
|
-
//!
|
|
34
|
-
//! # What the audit established about the semantics
|
|
35
|
-
//!
|
|
36
|
-
//! These are properties of the existing implementation, recorded here because
|
|
37
|
-
//! the contract is defined against them rather than against an idea of what a
|
|
38
|
-
//! diff should do:
|
|
39
|
-
//!
|
|
40
|
-
//! - **Arrays are positional.** A reorder is not detected; `[1,2] -> [2,1]`
|
|
41
|
-
//! reports `Changed` at index 0 and at index 1. Elements past the shorter
|
|
42
|
-
//! length become `Added` or `Removed` at their index.
|
|
43
|
-
//! - **Absence and null are different, in both directions.** `missing -> value`
|
|
44
|
-
//! is `Added`, `null -> value` is `Changed`, `value -> missing` is `Removed`,
|
|
45
|
-
//! `value -> null` is `Changed`.
|
|
46
|
-
//! - **`old_value` and `new_value` are `Option`, encoded as `null` when absent.**
|
|
47
|
-
//! That is ambiguous with a JSON null on its own, and `kind` is what
|
|
48
|
-
//! disambiguates: `missing -> null` is `Added` with `new_value: null`.
|
|
49
|
-
//! - **Numbers compare by `serde_json` variant.** `42` and `42.0` differ, so
|
|
50
|
-
//! they report `Changed`; `-0` is a float and so differs from the integer
|
|
51
|
-
//! `0`; `-0.0` and `0.0` are equal under IEEE equality and report nothing.
|
|
52
|
-
//! - **A type transition is one `Changed`,** carrying both whole values, at the
|
|
53
|
-
//! path where it happens — including at the empty path, for the states
|
|
54
|
-
//! themselves.
|
|
55
|
-
//! - **Ordering is total.** Changes sort by path, then by kind. Paths are
|
|
56
|
-
//! unique within one diff, so the ordering does not depend on sort stability.
|
|
57
|
-
|
|
58
|
-
use crate::state_model::SemanticDiff;
|
|
59
|
-
use serde::{Deserialize, Serialize};
|
|
60
|
-
use serde_json::Value;
|
|
61
|
-
use sha2::{Digest, Sha256};
|
|
62
|
-
|
|
63
|
-
/// Stable identity of this contract.
|
|
64
|
-
pub const STATE_DIFF_CONTRACT_ID: &str = "feltdb.state.diff";
|
|
65
|
-
|
|
66
|
-
/// Version of this contract's input shape, output shape and semantics.
|
|
67
|
-
///
|
|
68
|
-
/// The output shape is [`SemanticDiff`]'s own serialization, so a change to
|
|
69
|
-
/// that type is a change to this contract and must bump this.
|
|
70
|
-
pub const STATE_DIFF_CONTRACT_VERSION: u32 = 1;
|
|
71
|
-
|
|
72
|
-
/// The complete deterministic input: two states, and the contract's identity.
|
|
73
|
-
///
|
|
74
|
-
/// Members are declared alphabetically so the canonical struct encoding matches
|
|
75
|
-
/// the sorted-key encoding `serde_json` gives every JSON object.
|
|
76
|
-
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
77
|
-
#[serde(deny_unknown_fields)]
|
|
78
|
-
pub struct StateDiffInput {
|
|
79
|
-
pub contract: String,
|
|
80
|
-
pub state_a: Value,
|
|
81
|
-
pub state_b: Value,
|
|
82
|
-
pub version: u32,
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
impl StateDiffInput {
|
|
86
|
-
/// Builds an input stamped with this contract's identity and version.
|
|
87
|
-
pub fn new(state_a: Value, state_b: Value) -> Self {
|
|
88
|
-
Self {
|
|
89
|
-
contract: STATE_DIFF_CONTRACT_ID.to_string(),
|
|
90
|
-
state_a,
|
|
91
|
-
state_b,
|
|
92
|
-
version: STATE_DIFF_CONTRACT_VERSION,
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/// Why an input could not be evaluated.
|
|
98
|
-
///
|
|
99
|
-
/// Three codes, matching the vocabulary [`crate::trigger_contract`] uses. As
|
|
100
|
-
/// there, an error carries a code and nothing else: a free-form message would
|
|
101
|
-
/// be a divergence surface between implementations that says nothing about the
|
|
102
|
-
/// semantics under test.
|
|
103
|
-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
104
|
-
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
|
105
|
-
pub enum ContractErrorCode {
|
|
106
|
-
/// The bytes are not a well-formed instance of this contract's input.
|
|
107
|
-
ContractInputInvalid,
|
|
108
|
-
/// The input declares a different contract.
|
|
109
|
-
ContractIdMismatch,
|
|
110
|
-
/// The input declares a version this implementation does not implement.
|
|
111
|
-
ContractVersionUnsupported,
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/// The error body of a contract output.
|
|
115
|
-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
116
|
-
#[serde(deny_unknown_fields)]
|
|
117
|
-
pub struct ContractErrorBody {
|
|
118
|
-
pub code: ContractErrorCode,
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/// The complete deterministic output.
|
|
122
|
-
///
|
|
123
|
-
/// Exactly one of `diff` and `error` is present. `diff` is [`SemanticDiff`]
|
|
124
|
-
/// serialized exactly as it already serializes — this contract does not
|
|
125
|
-
/// reshape it, because the existing semantic result *is* the contract.
|
|
126
|
-
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
127
|
-
#[serde(deny_unknown_fields)]
|
|
128
|
-
pub struct StateDiffOutput {
|
|
129
|
-
pub contract: String,
|
|
130
|
-
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
131
|
-
pub diff: Option<SemanticDiff>,
|
|
132
|
-
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
133
|
-
pub error: Option<ContractErrorBody>,
|
|
134
|
-
pub version: u32,
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
impl StateDiffOutput {
|
|
138
|
-
fn computed(diff: SemanticDiff) -> Self {
|
|
139
|
-
Self {
|
|
140
|
-
contract: STATE_DIFF_CONTRACT_ID.to_string(),
|
|
141
|
-
diff: Some(diff),
|
|
142
|
-
error: None,
|
|
143
|
-
version: STATE_DIFF_CONTRACT_VERSION,
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
fn failure(code: ContractErrorCode) -> Self {
|
|
148
|
-
Self {
|
|
149
|
-
contract: STATE_DIFF_CONTRACT_ID.to_string(),
|
|
150
|
-
diff: None,
|
|
151
|
-
error: Some(ContractErrorBody { code }),
|
|
152
|
-
version: STATE_DIFF_CONTRACT_VERSION,
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/// The runtime that executed a contract, recorded in evidence.
|
|
158
|
-
///
|
|
159
|
-
/// Only [`ContractRuntime::Native`] is wired anywhere. As with the trigger
|
|
160
|
-
/// contract, the WASM variant exists so a recorded runtime can be named
|
|
161
|
-
/// honestly; it is not a selection switch.
|
|
162
|
-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
163
|
-
#[serde(rename_all = "snake_case")]
|
|
164
|
-
pub enum ContractRuntime {
|
|
165
|
-
Native,
|
|
166
|
-
Wasm,
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
impl ContractRuntime {
|
|
170
|
-
pub fn as_str(self) -> &'static str {
|
|
171
|
-
match self {
|
|
172
|
-
Self::Native => "native",
|
|
173
|
-
Self::Wasm => "wasm",
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/// The deterministic contract, natively implemented.
|
|
179
|
-
///
|
|
180
|
-
/// A thin adapter over the existing implementation, deliberately holding no
|
|
181
|
-
/// diff logic of its own.
|
|
182
|
-
pub fn diff_states(state_a: &Value, state_b: &Value) -> SemanticDiff {
|
|
183
|
-
SemanticDiff::compute(state_a, state_b)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/// The canonical byte encoding of a contract input.
|
|
187
|
-
pub fn canonical_input_bytes(input: &StateDiffInput) -> Vec<u8> {
|
|
188
|
-
serde_json::to_vec(input).expect("contract input is always serializable")
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/// The canonical byte encoding of a contract output.
|
|
192
|
-
pub fn canonical_output_bytes(output: &StateDiffOutput) -> Vec<u8> {
|
|
193
|
-
serde_json::to_vec(output).expect("contract output is always serializable")
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/// Content identity of a contract input, for provenance.
|
|
197
|
-
pub fn input_digest(input: &StateDiffInput) -> String {
|
|
198
|
-
format!("sha256:{:x}", Sha256::digest(canonical_input_bytes(input)))
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/// The runtime-independent entry point: canonical bytes in, canonical bytes out.
|
|
202
|
-
///
|
|
203
|
-
/// This is the exact shape a foreign runtime implements. It never panics and
|
|
204
|
-
/// never returns anything but a canonical output encoding, so an unusable input
|
|
205
|
-
/// is a contract decision rather than a host-specific failure mode.
|
|
206
|
-
pub fn evaluate_canonical(input: &[u8]) -> Vec<u8> {
|
|
207
|
-
canonical_output_bytes(&evaluate_canonical_output(input))
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/// [`evaluate_canonical`] before encoding, for callers that want the value.
|
|
211
|
-
pub fn evaluate_canonical_output(input: &[u8]) -> StateDiffOutput {
|
|
212
|
-
let Ok(parsed) = serde_json::from_slice::<StateDiffInput>(input) else {
|
|
213
|
-
return StateDiffOutput::failure(ContractErrorCode::ContractInputInvalid);
|
|
214
|
-
};
|
|
215
|
-
if parsed.contract != STATE_DIFF_CONTRACT_ID {
|
|
216
|
-
return StateDiffOutput::failure(ContractErrorCode::ContractIdMismatch);
|
|
217
|
-
}
|
|
218
|
-
if parsed.version != STATE_DIFF_CONTRACT_VERSION {
|
|
219
|
-
return StateDiffOutput::failure(ContractErrorCode::ContractVersionUnsupported);
|
|
220
|
-
}
|
|
221
|
-
StateDiffOutput::computed(diff_states(&parsed.state_a, &parsed.state_b))
|
|
222
|
-
}
|
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
//! Canonical FeltDB State Subsystem Public API Facade
|
|
2
|
-
//!
|
|
3
|
-
//! This module presents the graduated state model as a unified, product-facing
|
|
4
|
-
//! subsystem. Applications should use this facade to access FeltDB's state
|
|
5
|
-
//! primitives rather than reimplementing them.
|
|
6
|
-
//!
|
|
7
|
-
//! Proven Contracts:
|
|
8
|
-
//! - Deterministic content-addressed state identifiers
|
|
9
|
-
//! - Immutable revisions with explicit ancestry
|
|
10
|
-
//! - Durable persistence with restart recovery
|
|
11
|
-
//! - Causal topology tracking
|
|
12
|
-
//! - Semantic diff computation
|
|
13
|
-
//! - Conflict classification
|
|
14
|
-
//! - Explicit reconciliation (no automatic merge)
|
|
15
|
-
|
|
16
|
-
use crate::state_model::{
|
|
17
|
-
ConflictClassification, ReconciliationPlan, Relationship, SemanticDiff, StateId,
|
|
18
|
-
StateReconciliationResult, StateRevision, StateStore, StateTopology, STATE_MODEL_VERSION,
|
|
19
|
-
};
|
|
20
|
-
use crate::FeltDb;
|
|
21
|
-
use std::sync::Arc;
|
|
22
|
-
|
|
23
|
-
/// FeltDB State System - canonical state subsystem public API
|
|
24
|
-
pub struct FeltDBStateSystem;
|
|
25
|
-
|
|
26
|
-
impl FeltDBStateSystem {
|
|
27
|
-
/// Create a new state store for an application with FeltDB persistence
|
|
28
|
-
///
|
|
29
|
-
/// Returns a StateStore that provides:
|
|
30
|
-
/// - Durable persistence through FeltDB's canonical operation log
|
|
31
|
-
/// - Immutable revisions
|
|
32
|
-
/// - Deterministic state identifiers
|
|
33
|
-
/// - Restart recovery (once implemented)
|
|
34
|
-
///
|
|
35
|
-
/// Applications MUST provide a FeltDb instance. This ensures all state
|
|
36
|
-
/// mutations are persisted through FeltDB's canonical persistence boundary.
|
|
37
|
-
///
|
|
38
|
-
/// # Arguments
|
|
39
|
-
/// * `db` - Arc<FeltDb> instance for durable storage
|
|
40
|
-
///
|
|
41
|
-
/// # Returns
|
|
42
|
-
/// * `Ok(StateStore)` - Successfully initialized store with FeltDB backing
|
|
43
|
-
/// * `Err(String)` - If initialization fails
|
|
44
|
-
///
|
|
45
|
-
/// # Example
|
|
46
|
-
/// ```ignore
|
|
47
|
-
/// let db = FeltDb::open("./data")?;
|
|
48
|
-
/// let store = FeltDBStateSystem::create_store(&Arc::new(db))?;
|
|
49
|
-
/// let initial = store.create("docs:1", json_string, "app-authority")?;
|
|
50
|
-
/// let same = store.get(&initial.id).expect("retrieved by identity");
|
|
51
|
-
/// ```
|
|
52
|
-
pub fn create_store(db: &Arc<FeltDb>) -> Result<StateStore, String> {
|
|
53
|
-
StateStore::with_feltdb(db.clone())
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/// Create a volatile (in-memory only) state store for testing
|
|
57
|
-
///
|
|
58
|
-
/// This store is NOT persisted and will lose all data when dropped.
|
|
59
|
-
/// This is test-only and should not be used in production.
|
|
60
|
-
///
|
|
61
|
-
/// For production, use `create_store(&db)` which requires FeltDB persistence.
|
|
62
|
-
pub fn create_test_store() -> StateStore {
|
|
63
|
-
StateStore::new_volatile()
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/// Get the version of the canonical state model
|
|
67
|
-
pub fn version() -> u32 {
|
|
68
|
-
STATE_MODEL_VERSION
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/// Documentation: This is the canonical way to access FeltDB's state
|
|
72
|
-
/// primitives. Do not reimplement StateId, StateRevision, StateHistory,
|
|
73
|
-
/// StateStore, or related primitives.
|
|
74
|
-
pub fn documentation() -> &'static str {
|
|
75
|
-
r#"
|
|
76
|
-
FeltDB State Subsystem - Canonical Primitives
|
|
77
|
-
|
|
78
|
-
Applications should:
|
|
79
|
-
1. Initialize FeltDB: let db = FeltDb::open(path)?;
|
|
80
|
-
2. Use FeltDBStateSystem::create_store(&Arc::new(db)) to initialize state
|
|
81
|
-
3. Call store.create() for initial state
|
|
82
|
-
4. Call store.commit() for transitions
|
|
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)
|
|
86
|
-
6. Use StateTopology to inspect causal relationships
|
|
87
|
-
7. Use SemanticDiff to compute changes between states
|
|
88
|
-
8. Use ConflictClassification to analyze divergence
|
|
89
|
-
9. Use ReconciliationPlan with explicit caller policy
|
|
90
|
-
|
|
91
|
-
Applications should NOT:
|
|
92
|
-
- Reimplement StateId
|
|
93
|
-
- Reimplement StateRevision
|
|
94
|
-
- Reimplement StateStore
|
|
95
|
-
- Compute diffs independently
|
|
96
|
-
- Implement their own conflict classification
|
|
97
|
-
- Use implicit/automatic merge
|
|
98
|
-
- Create StateStore without FeltDB backing (use new_volatile() for testing only)
|
|
99
|
-
"#
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Note: All types are re-exported at lib.rs level for public API
|
|
104
|
-
|
|
105
|
-
#[cfg(test)]
|
|
106
|
-
mod facade_tests {
|
|
107
|
-
use super::*;
|
|
108
|
-
use crate::{
|
|
109
|
-
state_model::StateStore, ConflictClass, ConflictClassification, Relationship, SemanticDiff,
|
|
110
|
-
StateTopology,
|
|
111
|
-
};
|
|
112
|
-
use serde_json::json;
|
|
113
|
-
|
|
114
|
-
#[test]
|
|
115
|
-
fn test_facade_creates_store() {
|
|
116
|
-
// For testing, use new_volatile() - production must use create_store(&db)
|
|
117
|
-
let store = StateStore::new_volatile();
|
|
118
|
-
let initial = store
|
|
119
|
-
.create(
|
|
120
|
-
"docs:1",
|
|
121
|
-
r#"{"data":"test"}"#.to_string(),
|
|
122
|
-
"test-auth".to_string(),
|
|
123
|
-
)
|
|
124
|
-
.expect("Failed to create initial state");
|
|
125
|
-
|
|
126
|
-
let stored = store
|
|
127
|
-
.get(&initial.id)
|
|
128
|
-
.expect("the revision is retrievable by identity");
|
|
129
|
-
assert_eq!(stored.id, initial.id);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
#[test]
|
|
133
|
-
fn test_facade_version() {
|
|
134
|
-
assert_eq!(FeltDBStateSystem::version(), 1);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
#[test]
|
|
138
|
-
fn test_facade_comprehensive_workflow() {
|
|
139
|
-
// Initialize - for testing, use new_volatile()
|
|
140
|
-
let store = StateStore::new_volatile();
|
|
141
|
-
|
|
142
|
-
// Create initial state
|
|
143
|
-
let initial = store
|
|
144
|
-
.create(
|
|
145
|
-
"docs:1",
|
|
146
|
-
r#"{"users":{"alice":100}}"#.to_string(),
|
|
147
|
-
"app-auth".to_string(),
|
|
148
|
-
)
|
|
149
|
-
.expect("Failed to create");
|
|
150
|
-
|
|
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);
|
|
154
|
-
|
|
155
|
-
// Divergence 1: alice updates
|
|
156
|
-
let branch1 = store
|
|
157
|
-
.commit(
|
|
158
|
-
r#"{"users":{"alice":150}}"#.to_string(),
|
|
159
|
-
&initial,
|
|
160
|
-
"alice-auth".to_string(),
|
|
161
|
-
)
|
|
162
|
-
.expect("Failed branch 1");
|
|
163
|
-
|
|
164
|
-
// Divergence 2: from the same parent
|
|
165
|
-
let branch2 = store
|
|
166
|
-
.commit(
|
|
167
|
-
r#"{"users":{"alice":100,"bob":50}}"#.to_string(),
|
|
168
|
-
&initial,
|
|
169
|
-
"bob-auth".to_string(),
|
|
170
|
-
)
|
|
171
|
-
.expect("Failed branch 2");
|
|
172
|
-
|
|
173
|
-
// Inspect topology
|
|
174
|
-
let mut topology = StateTopology::new();
|
|
175
|
-
topology.add_revision(initial.clone());
|
|
176
|
-
topology.add_revision(branch1.clone());
|
|
177
|
-
topology.add_revision(branch2.clone());
|
|
178
|
-
|
|
179
|
-
// Verify relationships
|
|
180
|
-
match topology.relationship(&branch1.id, &branch2.id) {
|
|
181
|
-
Relationship::Diverged => {
|
|
182
|
-
// Expected: both descended from initial but different
|
|
183
|
-
}
|
|
184
|
-
_ => panic!("Expected Diverged relationship"),
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Compute diff using JSON values
|
|
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();
|
|
192
|
-
let diff = SemanticDiff::compute(&initial_json, &branch1_json);
|
|
193
|
-
assert!(!diff.changes.is_empty());
|
|
194
|
-
|
|
195
|
-
// Classify conflict
|
|
196
|
-
let classification = ConflictClassification::classify(&initial, &branch1, &branch2);
|
|
197
|
-
assert_eq!(classification.overall, ConflictClass::Independent);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
#[test]
|
|
201
|
-
fn test_facade_immutability() {
|
|
202
|
-
let store = StateStore::new_volatile();
|
|
203
|
-
let initial = store
|
|
204
|
-
.create("docs:1", r#"{"v":1}"#.to_string(), "auth".to_string())
|
|
205
|
-
.unwrap();
|
|
206
|
-
|
|
207
|
-
let initial_id = initial.id.clone();
|
|
208
|
-
|
|
209
|
-
// Create another state
|
|
210
|
-
let second = store
|
|
211
|
-
.commit(r#"{"v":2}"#.to_string(), &initial, "auth".to_string())
|
|
212
|
-
.unwrap();
|
|
213
|
-
|
|
214
|
-
// Verify first state is unchanged
|
|
215
|
-
assert_eq!(store.get(&initial_id).unwrap().content, r#"{"v":1}"#);
|
|
216
|
-
assert_eq!(initial_id, initial.id);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
#[test]
|
|
220
|
-
fn test_facade_restart_recovery() {
|
|
221
|
-
let store1 = StateStore::new_volatile();
|
|
222
|
-
let initial = store1
|
|
223
|
-
.create(
|
|
224
|
-
"docs:1",
|
|
225
|
-
r#"{"data":"test"}"#.to_string(),
|
|
226
|
-
"auth".to_string(),
|
|
227
|
-
)
|
|
228
|
-
.unwrap();
|
|
229
|
-
|
|
230
|
-
// Simulate restart: new store instance
|
|
231
|
-
let _store2 = StateStore::new_volatile();
|
|
232
|
-
|
|
233
|
-
// Note: In real scenario, store would load from persistent storage
|
|
234
|
-
// Here we demonstrate the API contract: states retrieved by id are valid
|
|
235
|
-
assert!(store1.exists(&initial.id));
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
#[test]
|
|
239
|
-
fn test_facade_authority_neutrality() {
|
|
240
|
-
let store = StateStore::new_volatile();
|
|
241
|
-
let initial = store
|
|
242
|
-
.create(
|
|
243
|
-
"docs:1",
|
|
244
|
-
r#"{"balance":100}"#.to_string(),
|
|
245
|
-
"alice".to_string(),
|
|
246
|
-
)
|
|
247
|
-
.unwrap();
|
|
248
|
-
|
|
249
|
-
let update1 = store
|
|
250
|
-
.commit(
|
|
251
|
-
r#"{"balance":150}"#.to_string(),
|
|
252
|
-
&initial,
|
|
253
|
-
"alice".to_string(),
|
|
254
|
-
)
|
|
255
|
-
.unwrap();
|
|
256
|
-
|
|
257
|
-
let update2 = store
|
|
258
|
-
.commit(
|
|
259
|
-
r#"{"balance":150}"#.to_string(),
|
|
260
|
-
&initial,
|
|
261
|
-
"bob".to_string(),
|
|
262
|
-
)
|
|
263
|
-
.unwrap();
|
|
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.
|
|
268
|
-
assert_eq!(update1.id, update2.id);
|
|
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.
|
|
275
|
-
assert_eq!(update1.authority, "alice");
|
|
276
|
-
assert_eq!(update2.authority, "alice");
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
#[test]
|
|
280
|
-
fn test_facade_read_only_operations() {
|
|
281
|
-
let store = StateStore::new_volatile();
|
|
282
|
-
let initial = store
|
|
283
|
-
.create("docs:1", r#"{"v":1}"#.to_string(), "auth".to_string())
|
|
284
|
-
.unwrap();
|
|
285
|
-
|
|
286
|
-
let update = store
|
|
287
|
-
.commit(r#"{"v":2}"#.to_string(), &initial, "auth".to_string())
|
|
288
|
-
.unwrap();
|
|
289
|
-
|
|
290
|
-
// Topology operations should not mutate
|
|
291
|
-
let mut topology = StateTopology::new();
|
|
292
|
-
topology.add_revision(initial.clone());
|
|
293
|
-
topology.add_revision(update.clone());
|
|
294
|
-
|
|
295
|
-
let rel = topology.relationship(&initial.id, &update.id);
|
|
296
|
-
assert!(matches!(rel, Relationship::Ancestor));
|
|
297
|
-
|
|
298
|
-
// Verify both states still exist unchanged
|
|
299
|
-
assert_eq!(store.get(&initial.id).unwrap().id, initial.id);
|
|
300
|
-
assert_eq!(store.get(&update.id).unwrap().id, update.id);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
#[test]
|
|
304
|
-
fn test_facade_no_git_dependency() {
|
|
305
|
-
// This test verifies we can use the state system without any .git access
|
|
306
|
-
let store = StateStore::new_volatile();
|
|
307
|
-
let state = store
|
|
308
|
-
.create(
|
|
309
|
-
"docs:1",
|
|
310
|
-
r#"{"test":"no-git"}"#.to_string(),
|
|
311
|
-
"auth".to_string(),
|
|
312
|
-
)
|
|
313
|
-
.expect("State creation should work without .git");
|
|
314
|
-
|
|
315
|
-
// Topology and diff operations should work without git
|
|
316
|
-
let mut topology = StateTopology::new();
|
|
317
|
-
topology.add_revision(state.clone());
|
|
318
|
-
assert!(topology.is_ancestor(&state.id, &state.id));
|
|
319
|
-
}
|
|
320
|
-
}
|