@feltdb/core 0.13.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.
Files changed (300) hide show
  1. package/dist/agent-runtime.d.ts +64 -2
  2. package/dist/agent-runtime.d.ts.map +1 -1
  3. package/dist/agent-runtime.js +121 -11
  4. package/dist/agent-state.d.ts +68 -0
  5. package/dist/agent-state.d.ts.map +1 -1
  6. package/dist/agent-state.js +210 -12
  7. package/dist/agent.d.ts +10 -1
  8. package/dist/agent.d.ts.map +1 -1
  9. package/dist/agent.js +10 -1
  10. package/dist/build-identity.json +12 -4
  11. package/dist/cli/commands.js +214 -10
  12. package/dist/cli/publish-engine.js +116 -16
  13. package/dist/collection.d.ts +3 -1
  14. package/dist/collection.d.ts.map +1 -1
  15. package/dist/collection.js +33 -8
  16. package/dist/create/build-identity.json +12 -4
  17. package/dist/create/cli.js +1 -1
  18. package/dist/create/create.js +4 -6
  19. package/dist/create/managed-account.js +93 -35
  20. package/dist/create/package-versions.js +1 -1
  21. package/dist/create/server-source/Cargo.lock +8 -511
  22. package/dist/create/server-source/Cargo.toml +2 -13
  23. package/dist/create/server-source/crates/feltdb-client/Cargo.toml +1 -1
  24. package/dist/create/server-source/crates/feltdb-server/Cargo.toml +1 -1
  25. package/dist/create/server-source/crates/feltdb-server/README.md +6 -1
  26. package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +9 -1
  27. package/dist/create/server-source/crates/feltdb-server/src/auth.rs +85 -25
  28. package/dist/create/server-source/crates/feltdb-server/src/backup.rs +4 -0
  29. package/dist/create/server-source/crates/feltdb-server/src/console_accounts.rs +1009 -0
  30. package/dist/create/server-source/crates/feltdb-server/src/control_authorization.rs +441 -0
  31. package/dist/create/server-source/crates/feltdb-server/src/identity.rs +68 -6
  32. package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +355 -23
  33. package/dist/create/server-source/crates/feltdb-server/src/lib.rs +3 -0
  34. package/dist/create/server-source/crates/feltdb-server/src/main.rs +1134 -96
  35. package/dist/create/server-source/crates/feltdb-server/src/redaction.rs +208 -0
  36. package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +198 -19
  37. package/dist/create/server-source/crates/feltdb-server/tests/transaction_precondition_contract.rs +403 -0
  38. package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +1 -1
  39. package/dist/db.d.ts +75 -10
  40. package/dist/db.d.ts.map +1 -1
  41. package/dist/db.js +168 -29
  42. package/dist/deployment.d.ts +19 -0
  43. package/dist/deployment.d.ts.map +1 -1
  44. package/dist/deployment.js +38 -2
  45. package/dist/embedded-query.d.ts.map +1 -1
  46. package/dist/embedded-query.js +5 -4
  47. package/dist/embedded-transaction.d.ts +8 -4
  48. package/dist/embedded-transaction.d.ts.map +1 -1
  49. package/dist/embedded-transaction.js +55 -19
  50. package/dist/error-codes.d.ts +36 -2
  51. package/dist/error-codes.d.ts.map +1 -1
  52. package/dist/error-codes.js +50 -3
  53. package/dist/feltdb.d.ts +7 -0
  54. package/dist/feltdb.d.ts.map +1 -1
  55. package/dist/file-db.d.ts +27 -0
  56. package/dist/file-db.d.ts.map +1 -1
  57. package/dist/file-db.js +145 -7
  58. package/dist/http-client.d.ts +11 -3
  59. package/dist/http-client.d.ts.map +1 -1
  60. package/dist/http-client.js +27 -14
  61. package/dist/http-db.d.ts +43 -1
  62. package/dist/http-db.d.ts.map +1 -1
  63. package/dist/http-db.js +287 -59
  64. package/dist/index.js +1 -1
  65. package/dist/local-state-lock.d.ts +34 -0
  66. package/dist/local-state-lock.d.ts.map +1 -0
  67. package/dist/local-state-lock.js +225 -0
  68. package/dist/managed-recovery.d.ts +6 -0
  69. package/dist/managed-recovery.d.ts.map +1 -1
  70. package/dist/managed-recovery.js +9 -0
  71. package/dist/reactive-graph.d.ts +0 -3
  72. package/dist/reactive-graph.d.ts.map +1 -1
  73. package/dist/reactive-graph.js +11 -1
  74. package/dist/runtime-registry.d.ts +7 -2
  75. package/dist/runtime-registry.d.ts.map +1 -1
  76. package/dist/runtime-registry.js +2 -2
  77. package/dist/studio/components/index.js +1 -1
  78. package/dist/studio/{components-BSGmHfif.js → components-CJmzntBi.js} +2 -1
  79. package/dist/studio/index.js +1 -1
  80. package/dist/studio-app/assets/{feltdb_wasm-3hDngl1h.js → feltdb_wasm-DtybUY0q.js} +1 -1
  81. package/dist/studio-app/assets/feltdb_wasm_bg-DsgIUwaB.wasm +0 -0
  82. package/dist/studio-app/assets/index-C4OffsZl.js +37 -0
  83. package/dist/studio-app/index.html +1 -1
  84. package/dist/transaction.d.ts +27 -11
  85. package/dist/transaction.d.ts.map +1 -1
  86. package/dist/transaction.js +20 -14
  87. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  88. package/dist/wasm/package.json +1 -1
  89. package/dist/workload.d.ts +86 -6
  90. package/dist/workload.d.ts.map +1 -1
  91. package/dist/workload.js +51 -3
  92. package/dist/workspace/workspace-connection.d.ts.map +1 -1
  93. package/dist/workspace/workspace-connection.js +14 -3
  94. package/package.json +1 -1
  95. package/dist/create/server-source/crates/feltdb/Cargo.lock +0 -175
  96. package/dist/create/server-source/crates/feltdb/Cargo.toml +0 -102
  97. package/dist/create/server-source/crates/feltdb/LICENSE +0 -21
  98. package/dist/create/server-source/crates/feltdb/README.md +0 -75
  99. package/dist/create/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +0 -370
  100. package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +0 -589
  101. package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +0 -247
  102. package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +0 -440
  103. package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +0 -275
  104. package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +0 -381
  105. package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +0 -467
  106. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +0 -489
  107. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +0 -281
  108. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +0 -606
  109. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +0 -531
  110. package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +0 -462
  111. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +0 -505
  112. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +0 -484
  113. package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +0 -758
  114. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +0 -421
  115. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +0 -329
  116. package/dist/create/server-source/crates/feltdb/src/acceptance_tests.rs +0 -1705
  117. package/dist/create/server-source/crates/feltdb/src/acquisition.rs +0 -286
  118. package/dist/create/server-source/crates/feltdb/src/admission.rs +0 -185
  119. package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +0 -507
  120. package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +0 -539
  121. package/dist/create/server-source/crates/feltdb/src/agent_state.rs +0 -320
  122. package/dist/create/server-source/crates/feltdb/src/agent_transition_contract.rs +0 -1545
  123. package/dist/create/server-source/crates/feltdb/src/analytics.rs +0 -521
  124. package/dist/create/server-source/crates/feltdb/src/application.rs +0 -2674
  125. package/dist/create/server-source/crates/feltdb/src/application_runtime.rs +0 -1070
  126. package/dist/create/server-source/crates/feltdb/src/authority.rs +0 -479
  127. package/dist/create/server-source/crates/feltdb/src/authority_failover.rs +0 -847
  128. package/dist/create/server-source/crates/feltdb/src/authorization.rs +0 -1030
  129. package/dist/create/server-source/crates/feltdb/src/authorization_security_tests.rs +0 -1122
  130. package/dist/create/server-source/crates/feltdb/src/bin/feltdb-authority-client.rs +0 -32
  131. package/dist/create/server-source/crates/feltdb/src/bin/feltdb-authority.rs +0 -19
  132. package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +0 -1474
  133. package/dist/create/server-source/crates/feltdb/src/capabilities/mod.rs +0 -8
  134. package/dist/create/server-source/crates/feltdb/src/capabilities/search.rs +0 -418
  135. package/dist/create/server-source/crates/feltdb/src/capabilities/vector.rs +0 -482
  136. package/dist/create/server-source/crates/feltdb/src/capability.rs +0 -903
  137. package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +0 -263
  138. package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +0 -77
  139. package/dist/create/server-source/crates/feltdb/src/causal_backlog_bound.rs +0 -496
  140. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +0 -2574
  141. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +0 -212
  142. package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +0 -422
  143. package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +0 -445
  144. package/dist/create/server-source/crates/feltdb/src/content_distribution.rs +0 -465
  145. package/dist/create/server-source/crates/feltdb/src/convergence.rs +0 -634
  146. package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +0 -427
  147. package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +0 -376
  148. package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +0 -365
  149. package/dist/create/server-source/crates/feltdb/src/cron.rs +0 -294
  150. package/dist/create/server-source/crates/feltdb/src/dedup_bound_investigation.rs +0 -483
  151. package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +0 -477
  152. package/dist/create/server-source/crates/feltdb/src/distributed_tests.rs +0 -1003
  153. package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +0 -1334
  154. package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +0 -368
  155. package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +0 -231
  156. package/dist/create/server-source/crates/feltdb/src/durable_operation_identity.rs +0 -482
  157. package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +0 -203
  158. package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +0 -317
  159. package/dist/create/server-source/crates/feltdb/src/equality_index.rs +0 -595
  160. package/dist/create/server-source/crates/feltdb/src/execution.rs +0 -426
  161. package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +0 -214
  162. package/dist/create/server-source/crates/feltdb/src/indexing.rs +0 -776
  163. package/dist/create/server-source/crates/feltdb/src/lib.rs +0 -7274
  164. package/dist/create/server-source/crates/feltdb/src/managed_cas_tests.rs +0 -234
  165. package/dist/create/server-source/crates/feltdb/src/materialization.rs +0 -184
  166. package/dist/create/server-source/crates/feltdb/src/metrics.rs +0 -266
  167. package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +0 -310
  168. package/dist/create/server-source/crates/feltdb/src/multi_operation_transaction.rs +0 -736
  169. package/dist/create/server-source/crates/feltdb/src/observability.rs +0 -379
  170. package/dist/create/server-source/crates/feltdb/src/operation.rs +0 -290
  171. package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +0 -439
  172. package/dist/create/server-source/crates/feltdb/src/operation_log.rs +0 -349
  173. package/dist/create/server-source/crates/feltdb/src/p1_application_atomicity.rs +0 -332
  174. package/dist/create/server-source/crates/feltdb/src/p1_atomicity_acceptance.rs +0 -718
  175. package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +0 -487
  176. package/dist/create/server-source/crates/feltdb/src/peer_registry.rs +0 -166
  177. package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +0 -289
  178. package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +0 -566
  179. package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +0 -3391
  180. package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +0 -203
  181. package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +0 -261
  182. package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +0 -502
  183. package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +0 -216
  184. package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +0 -303
  185. package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +0 -323
  186. package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +0 -531
  187. package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +0 -406
  188. package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +0 -436
  189. package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +0 -387
  190. package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +0 -378
  191. package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +0 -359
  192. package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +0 -372
  193. package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +0 -404
  194. package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +0 -376
  195. package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +0 -461
  196. package/dist/create/server-source/crates/feltdb/src/policy_evaluation.rs +0 -2125
  197. package/dist/create/server-source/crates/feltdb/src/production_api.rs +0 -418
  198. package/dist/create/server-source/crates/feltdb/src/provenance.rs +0 -207
  199. package/dist/create/server-source/crates/feltdb/src/query_execution_diagnostics.rs +0 -126
  200. package/dist/create/server-source/crates/feltdb/src/query_performance.rs +0 -218
  201. package/dist/create/server-source/crates/feltdb/src/read_basis.rs +0 -257
  202. package/dist/create/server-source/crates/feltdb/src/references.rs +0 -404
  203. package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +0 -401
  204. package/dist/create/server-source/crates/feltdb/src/replica_acknowledgements.rs +0 -501
  205. package/dist/create/server-source/crates/feltdb/src/replica_membership.rs +0 -680
  206. package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +0 -163
  207. package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +0 -133
  208. package/dist/create/server-source/crates/feltdb/src/routing.rs +0 -409
  209. package/dist/create/server-source/crates/feltdb/src/semantic_decision.rs +0 -2029
  210. package/dist/create/server-source/crates/feltdb/src/semantic_query.rs +0 -599
  211. package/dist/create/server-source/crates/feltdb/src/sharding.rs +0 -549
  212. package/dist/create/server-source/crates/feltdb/src/state_conflict_contract.rs +0 -516
  213. package/dist/create/server-source/crates/feltdb/src/state_contract.rs +0 -5894
  214. package/dist/create/server-source/crates/feltdb/src/state_diff_contract.rs +0 -222
  215. package/dist/create/server-source/crates/feltdb/src/state_facade.rs +0 -320
  216. package/dist/create/server-source/crates/feltdb/src/state_hash.rs +0 -291
  217. package/dist/create/server-source/crates/feltdb/src/state_model.rs +0 -4158
  218. package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +0 -379
  219. package/dist/create/server-source/crates/feltdb/src/state_trigger.rs +0 -673
  220. package/dist/create/server-source/crates/feltdb/src/storage.rs +0 -273
  221. package/dist/create/server-source/crates/feltdb/src/submission.rs +0 -471
  222. package/dist/create/server-source/crates/feltdb/src/sync.rs +0 -495
  223. package/dist/create/server-source/crates/feltdb/src/sync_contract.rs +0 -822
  224. package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +0 -433
  225. package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +0 -462
  226. package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +0 -965
  227. package/dist/create/server-source/crates/feltdb/src/transaction_preconditions.rs +0 -1120
  228. package/dist/create/server-source/crates/feltdb/src/transactions.rs +0 -643
  229. package/dist/create/server-source/crates/feltdb/src/trigger.rs +0 -390
  230. package/dist/create/server-source/crates/feltdb/src/trigger_contract.rs +0 -749
  231. package/dist/create/server-source/crates/feltdb/src/versioned_object_substrate.rs +0 -708
  232. package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +0 -1133
  233. package/dist/create/server-source/crates/feltdb/src/workflow.rs +0 -713
  234. package/dist/create/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +0 -510
  235. package/dist/create/server-source/crates/feltdb/src/workflow_integration.rs +0 -354
  236. package/dist/create/server-source/crates/feltdb/src/workflow_runtime.rs +0 -594
  237. package/dist/create/server-source/crates/feltdb/src/workload.rs +0 -2886
  238. package/dist/create/server-source/crates/feltdb/src/workload_diagnostics.rs +0 -456
  239. package/dist/create/server-source/crates/feltdb/tests/agent_state_native.rs +0 -1188
  240. package/dist/create/server-source/crates/feltdb/tests/agent_transition_contract_conformance.rs +0 -2884
  241. package/dist/create/server-source/crates/feltdb/tests/authority_process.rs +0 -297
  242. package/dist/create/server-source/crates/feltdb/tests/authority_transaction_identity.rs +0 -534
  243. package/dist/create/server-source/crates/feltdb/tests/bounded_read_contract.rs +0 -132
  244. package/dist/create/server-source/crates/feltdb/tests/branching_evidence.rs +0 -299
  245. package/dist/create/server-source/crates/feltdb/tests/common/mod.rs +0 -96
  246. package/dist/create/server-source/crates/feltdb/tests/compaction_stall_contract.rs +0 -272
  247. package/dist/create/server-source/crates/feltdb/tests/crash_durability_contract.rs +0 -467
  248. package/dist/create/server-source/crates/feltdb/tests/current_revision_authority_evidence.rs +0 -309
  249. package/dist/create/server-source/crates/feltdb/tests/durable_backup_contract.rs +0 -445
  250. package/dist/create/server-source/crates/feltdb/tests/durable_corruption_contract.rs +0 -518
  251. package/dist/create/server-source/crates/feltdb/tests/durable_format_compatibility.rs +0 -392
  252. package/dist/create/server-source/crates/feltdb/tests/feltdb_state_boundary_tests.rs +0 -850
  253. package/dist/create/server-source/crates/feltdb/tests/fixtures/agent_transition_corpus.json +0 -23340
  254. package/dist/create/server-source/crates/feltdb/tests/fixtures/state_conflict_contract_corpus.json +0 -1916
  255. package/dist/create/server-source/crates/feltdb/tests/fixtures/state_diff_contract_corpus.json +0 -1878
  256. package/dist/create/server-source/crates/feltdb/tests/fixtures/trigger_contract_corpus.json +0 -1862
  257. package/dist/create/server-source/crates/feltdb/tests/generalized_version_control_evidence.rs +0 -123
  258. package/dist/create/server-source/crates/feltdb/tests/generalized_version_control_substrate_completion.rs +0 -299
  259. package/dist/create/server-source/crates/feltdb/tests/local_process_ownership.rs +0 -69
  260. package/dist/create/server-source/crates/feltdb/tests/managed_incident_regression.rs +0 -191
  261. package/dist/create/server-source/crates/feltdb/tests/operational_health_contract.rs +0 -278
  262. package/dist/create/server-source/crates/feltdb/tests/pr34_query_collection.rs +0 -234
  263. package/dist/create/server-source/crates/feltdb/tests/pr35_equality_index.rs +0 -947
  264. package/dist/create/server-source/crates/feltdb/tests/pr7_self_authorization_proof.rs +0 -404
  265. package/dist/create/server-source/crates/feltdb/tests/pr8_vocabulary_assessment.rs +0 -916
  266. package/dist/create/server-source/crates/feltdb/tests/pr9_phase2_boundary_tests.rs +0 -1045
  267. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3a_path_a_tests.rs +0 -347
  268. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_authorized_mutations.rs +0 -361
  269. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_role_based_authorization.rs +0 -330
  270. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_simple_auth_delete.rs +0 -93
  271. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_team_delete_role_authorization.rs +0 -622
  272. package/dist/create/server-source/crates/feltdb/tests/pr9_teams_role_based_access.rs +0 -517
  273. package/dist/create/server-source/crates/feltdb/tests/production_certification.rs +0 -1153
  274. package/dist/create/server-source/crates/feltdb/tests/production_contract.rs +0 -771
  275. package/dist/create/server-source/crates/feltdb/tests/production_readiness_contract.rs +0 -1383
  276. package/dist/create/server-source/crates/feltdb/tests/reconciliation_application.rs +0 -868
  277. package/dist/create/server-source/crates/feltdb/tests/reconciliation_wire_format_evidence.rs +0 -221
  278. package/dist/create/server-source/crates/feltdb/tests/replicated_history_contract.rs +0 -417
  279. package/dist/create/server-source/crates/feltdb/tests/resource_scoped_revisions.rs +0 -338
  280. package/dist/create/server-source/crates/feltdb/tests/revision_identity_contract.rs +0 -1039
  281. package/dist/create/server-source/crates/feltdb/tests/revision_model_decision.rs +0 -739
  282. package/dist/create/server-source/crates/feltdb/tests/revision_retention_boundary_evidence.rs +0 -452
  283. package/dist/create/server-source/crates/feltdb/tests/saas_authorization_integration.rs +0 -81
  284. package/dist/create/server-source/crates/feltdb/tests/saas_invitation_lifecycle.rs +0 -438
  285. package/dist/create/server-source/crates/feltdb/tests/semantic_decision.rs +0 -1165
  286. package/dist/create/server-source/crates/feltdb/tests/semantic_query.rs +0 -767
  287. package/dist/create/server-source/crates/feltdb/tests/semantic_query_contract.rs +0 -363
  288. package/dist/create/server-source/crates/feltdb/tests/state_conflict_contract_conformance.rs +0 -1799
  289. package/dist/create/server-source/crates/feltdb/tests/state_diff_contract_conformance.rs +0 -1316
  290. package/dist/create/server-source/crates/feltdb/tests/state_model_integration.rs +0 -358
  291. package/dist/create/server-source/crates/feltdb/tests/state_persistence_integration.rs +0 -365
  292. package/dist/create/server-source/crates/feltdb/tests/state_ref_authority.rs +0 -918
  293. package/dist/create/server-source/crates/feltdb/tests/state_store_boundary_evidence.rs +0 -299
  294. package/dist/create/server-source/crates/feltdb/tests/storage_independent_versioned_object_substrate.rs +0 -328
  295. package/dist/create/server-source/crates/feltdb/tests/sync_divergence_evidence.rs +0 -255
  296. package/dist/create/server-source/crates/feltdb/tests/three_way_input_boundary_evidence.rs +0 -249
  297. package/dist/create/server-source/crates/feltdb/tests/trigger_contract_conformance.rs +0 -994
  298. package/dist/create/server-source/crates/feltdb/tests/workload_envelope_contract.rs +0 -484
  299. package/dist/studio-app/assets/feltdb_wasm_bg-CFQT4gCy.wasm +0 -0
  300. package/dist/studio-app/assets/index-Dql1hS5m.js +0 -30
@@ -1,739 +0,0 @@
1
- //! The revision model decision experiment.
2
- //!
3
- //! This file **implements nothing in the product**. It builds three tiny probes
4
- //! of what a `StateRevision` could *be*, runs the same seven scenarios against
5
- //! each, and fills in a decision matrix by execution rather than by preference.
6
- //!
7
- //! It is the executable half of `docs/architecture/revision-model-decision.md`.
8
- //!
9
- //! # The question
10
- //!
11
- //! The [identity and ancestry contract](../../../docs/architecture/revision-identity-and-ancestry.md)
12
- //! established that content-only identity cannot survive automatic minting, and
13
- //! that `base` as "the previous state of resource X" is unanswerable because a
14
- //! `StateRevision` has no resource. So the decision is not which fix to apply.
15
- //! It is:
16
- //!
17
- //! > **What is a `StateRevision` a revision *of*?**
18
- //!
19
- //! Three answers are consistent with the evidence:
20
- //!
21
- //! | model | a revision is | identity |
22
- //! | --- | --- | --- |
23
- //! | **A — State** | a durable content | content alone; ancestry lives outside the revision |
24
- //! | **B — Historical transition** | a particular occurrence in history | content + parent + a discriminator |
25
- //! | **C — Resource transition** | a transition belonging to a resource | resource + content + parent + a discriminator |
26
- //!
27
- //! # Two invariants, asserted against every model
28
- //!
29
- //! These are not model choices. They are the boundary the T5 and T6 findings
30
- //! draw, and a model that cannot hold them is not a revision model:
31
- //!
32
- //! 1. **Once committed, a revision's identity and ancestry are immutable.** A
33
- //! record whose historical parent can change after commit is not a durable
34
- //! historical object; it is a mutable record that happens to contain
35
- //! historical fields.
36
- //! 2. **A `parent_id` is either a reference to an authoritative revision, or it
37
- //! is not a parent.** Parent existence is part of what makes a revision
38
- //! valid, not a lookup applied afterwards.
39
- //!
40
- //! The probes are deliberately small and their identities are readable strings
41
- //! rather than hashes: what is under test is the *structure* of identity, not
42
- //! its encoding.
43
- //!
44
- //! Storage cost, compaction economics and copy-on-write are **deliberately
45
- //! absent**. Measuring them before the object is defined would optimise
46
- //! something that does not yet exist.
47
-
48
- use feltdb::state_model::{StateRevision, StateStore};
49
- use feltdb::FeltDb;
50
- use std::collections::BTreeMap;
51
- use std::sync::Arc;
52
- use tempfile::TempDir;
53
-
54
- type Rid = String;
55
-
56
- #[derive(Debug, PartialEq, Eq)]
57
- enum MintError {
58
- /// Invariant 2: the named parent is not an authoritative revision.
59
- UnknownParent,
60
- }
61
-
62
- /// The model has no way to express the question, as opposed to answering "no".
63
- #[derive(Debug, PartialEq, Eq)]
64
- struct Unsupported(&'static str);
65
-
66
- /// What every candidate model must be able to do.
67
- trait Model {
68
- fn name(&self) -> &'static str;
69
-
70
- /// Mint a revision of `content` for `resource`, descending from `parent`.
71
- fn mint(
72
- &mut self,
73
- resource: &str,
74
- content: &str,
75
- parent: Option<&Rid>,
76
- ) -> Result<Rid, MintError>;
77
-
78
- /// The parent of `id` as seen from `resource`.
79
- fn parent_of(&self, resource: &str, id: &Rid) -> Option<Rid>;
80
-
81
- /// The revisions of one resource, oldest first.
82
- fn history_of(&self, resource: &str) -> Result<Vec<Rid>, Unsupported>;
83
-
84
- /// Retain only the newest `keep` revisions of one resource.
85
- fn retain_last(&mut self, resource: &str, keep: usize) -> Result<usize, Unsupported>;
86
-
87
- /// Every durable record, for immutability checking.
88
- fn records(&self) -> BTreeMap<Rid, String>;
89
- }
90
-
91
- // ---------------------------------------------------------------------------
92
- // Model A — a revision is a durable state
93
- // ---------------------------------------------------------------------------
94
-
95
- /// Identity is content. Ancestry is **not a field of the revision** — it is a
96
- /// separate edge set, so the same state recurring in history is one object
97
- /// referenced twice rather than one object rewritten twice.
98
- #[derive(Default)]
99
- struct StateModel {
100
- contents: BTreeMap<Rid, String>,
101
- edges: Vec<Edge>,
102
- }
103
-
104
- struct Edge {
105
- resource: String,
106
- from: Option<Rid>,
107
- to: Rid,
108
- }
109
-
110
- impl Model for StateModel {
111
- fn name(&self) -> &'static str {
112
- "A state"
113
- }
114
-
115
- fn mint(
116
- &mut self,
117
- resource: &str,
118
- content: &str,
119
- parent: Option<&Rid>,
120
- ) -> Result<Rid, MintError> {
121
- if let Some(parent) = parent {
122
- if !self.contents.contains_key(parent) {
123
- return Err(MintError::UnknownParent);
124
- }
125
- }
126
- let id = format!("state:{content}");
127
- // Idempotent by construction: the same content is the same bytes.
128
- self.contents.insert(id.clone(), content.to_string());
129
- self.edges.push(Edge {
130
- resource: resource.to_string(),
131
- from: parent.cloned(),
132
- to: id.clone(),
133
- });
134
- Ok(id)
135
- }
136
-
137
- fn parent_of(&self, resource: &str, id: &Rid) -> Option<Rid> {
138
- // The last time this state was reached on this resource.
139
- self.edges
140
- .iter()
141
- .rev()
142
- .find(|edge| edge.resource == resource && &edge.to == id)
143
- .and_then(|edge| edge.from.clone())
144
- }
145
-
146
- fn history_of(&self, resource: &str) -> Result<Vec<Rid>, Unsupported> {
147
- Ok(self
148
- .edges
149
- .iter()
150
- .filter(|edge| edge.resource == resource)
151
- .map(|edge| edge.to.clone())
152
- .collect())
153
- }
154
-
155
- fn retain_last(&mut self, resource: &str, keep: usize) -> Result<usize, Unsupported> {
156
- let mine: Vec<usize> = self
157
- .edges
158
- .iter()
159
- .enumerate()
160
- .filter(|(_, edge)| edge.resource == resource)
161
- .map(|(index, _)| index)
162
- .collect();
163
- let drop_count = mine.len().saturating_sub(keep);
164
- let dropped: Vec<usize> = mine.into_iter().take(drop_count).collect();
165
- self.edges = std::mem::take(&mut self.edges)
166
- .into_iter()
167
- .enumerate()
168
- .filter(|(index, _)| !dropped.contains(index))
169
- .map(|(_, edge)| edge)
170
- .collect();
171
- // Contents stay: they are shared, and another resource may reference them.
172
- Ok(drop_count)
173
- }
174
-
175
- fn records(&self) -> BTreeMap<Rid, String> {
176
- self.contents.clone()
177
- }
178
- }
179
-
180
- // ---------------------------------------------------------------------------
181
- // Model B — a revision is a historical transition
182
- // ---------------------------------------------------------------------------
183
-
184
- /// Identity is content plus parent plus a monotonic discriminator, so the same
185
- /// content occurring twice is two revisions. There is **no resource**: a
186
- /// revision is an occurrence in history, and history is not divided up.
187
- #[derive(Default)]
188
- struct TransitionModel {
189
- revisions: BTreeMap<Rid, (String, Option<Rid>)>,
190
- sequence: u64,
191
- }
192
-
193
- impl Model for TransitionModel {
194
- fn name(&self) -> &'static str {
195
- "B transition"
196
- }
197
-
198
- fn mint(
199
- &mut self,
200
- _resource: &str,
201
- content: &str,
202
- parent: Option<&Rid>,
203
- ) -> Result<Rid, MintError> {
204
- if let Some(parent) = parent {
205
- if !self.revisions.contains_key(parent) {
206
- return Err(MintError::UnknownParent);
207
- }
208
- }
209
- self.sequence += 1;
210
- let id = format!(
211
- "occurrence:{}:{}:{content}",
212
- self.sequence,
213
- parent.map(String::as_str).unwrap_or("root")
214
- );
215
- self.revisions
216
- .insert(id.clone(), (content.to_string(), parent.cloned()));
217
- Ok(id)
218
- }
219
-
220
- fn parent_of(&self, _resource: &str, id: &Rid) -> Option<Rid> {
221
- self.revisions
222
- .get(id)
223
- .and_then(|(_, parent)| parent.clone())
224
- }
225
-
226
- fn history_of(&self, _resource: &str) -> Result<Vec<Rid>, Unsupported> {
227
- Err(Unsupported(
228
- "a transition belongs to no resource, so a resource has no history",
229
- ))
230
- }
231
-
232
- fn retain_last(&mut self, _resource: &str, _keep: usize) -> Result<usize, Unsupported> {
233
- Err(Unsupported(
234
- "retention cannot be scoped to a resource the model cannot name",
235
- ))
236
- }
237
-
238
- fn records(&self) -> BTreeMap<Rid, String> {
239
- self.revisions
240
- .iter()
241
- .map(|(id, (content, parent))| (id.clone(), format!("{content}|{parent:?}")))
242
- .collect()
243
- }
244
- }
245
-
246
- // ---------------------------------------------------------------------------
247
- // Model C — a revision is a transition of a resource
248
- // ---------------------------------------------------------------------------
249
-
250
- /// Identity is resource plus content plus parent plus a discriminator. A
251
- /// revision knows what it is a revision *of*.
252
- #[derive(Default)]
253
- struct ResourceTransitionModel {
254
- revisions: BTreeMap<Rid, (String, String, Option<Rid>)>,
255
- sequence: u64,
256
- }
257
-
258
- impl Model for ResourceTransitionModel {
259
- fn name(&self) -> &'static str {
260
- "C resource transition"
261
- }
262
-
263
- fn mint(
264
- &mut self,
265
- resource: &str,
266
- content: &str,
267
- parent: Option<&Rid>,
268
- ) -> Result<Rid, MintError> {
269
- if let Some(parent) = parent {
270
- if !self.revisions.contains_key(parent) {
271
- return Err(MintError::UnknownParent);
272
- }
273
- }
274
- self.sequence += 1;
275
- let id = format!(
276
- "{resource}@{}:{}:{content}",
277
- self.sequence,
278
- parent.map(String::as_str).unwrap_or("root")
279
- );
280
- self.revisions.insert(
281
- id.clone(),
282
- (resource.to_string(), content.to_string(), parent.cloned()),
283
- );
284
- Ok(id)
285
- }
286
-
287
- fn parent_of(&self, _resource: &str, id: &Rid) -> Option<Rid> {
288
- self.revisions
289
- .get(id)
290
- .and_then(|(_, _, parent)| parent.clone())
291
- }
292
-
293
- fn history_of(&self, resource: &str) -> Result<Vec<Rid>, Unsupported> {
294
- Ok(self
295
- .revisions
296
- .iter()
297
- .filter(|(_, (owner, _, _))| owner == resource)
298
- .map(|(id, _)| id.clone())
299
- .collect())
300
- }
301
-
302
- fn retain_last(&mut self, resource: &str, keep: usize) -> Result<usize, Unsupported> {
303
- let mine = self.history_of(resource)?;
304
- let drop_count = mine.len().saturating_sub(keep);
305
- for id in mine.into_iter().take(drop_count) {
306
- self.revisions.remove(&id);
307
- }
308
- Ok(drop_count)
309
- }
310
-
311
- fn records(&self) -> BTreeMap<Rid, String> {
312
- self.revisions
313
- .iter()
314
- .map(|(id, (owner, content, parent))| {
315
- (id.clone(), format!("{owner}|{content}|{parent:?}"))
316
- })
317
- .collect()
318
- }
319
- }
320
-
321
- fn models() -> Vec<Box<dyn Model>> {
322
- vec![
323
- Box::<StateModel>::default(),
324
- Box::<TransitionModel>::default(),
325
- Box::<ResourceTransitionModel>::default(),
326
- ]
327
- }
328
-
329
- const X: &str = r#"{"title":"X"}"#;
330
- const Y: &str = r#"{"title":"Y"}"#;
331
-
332
- // ---------------------------------------------------------------------------
333
- // The two invariants, asserted against every model
334
- // ---------------------------------------------------------------------------
335
-
336
- /// **Invariant 1 — a committed revision's identity and ancestry are immutable.**
337
- ///
338
- /// Run every scenario that rewrote history under today's implementation, and
339
- /// assert that no already-stored record changed. All three models hold, by
340
- /// different means: A because a revision has no ancestry to rewrite, B and C
341
- /// because the rewrite would have a different identity.
342
- #[test]
343
- fn every_model_holds_committed_revisions_immutable() {
344
- for mut model in models() {
345
- let name = model.name();
346
- let first = model.mint("tasks:1", X, None).unwrap();
347
- let second = model.mint("tasks:1", Y, Some(&first)).unwrap();
348
- let before = model.records();
349
-
350
- // The three sequences that corrupt history today.
351
- model.mint("tasks:1", X, Some(&second)).unwrap(); // revert
352
- model.mint("tasks:1", Y, None).unwrap(); // re-mint a child as a root
353
- model.mint("tasks:2", X, None).unwrap(); // same content, other resource
354
-
355
- let after = model.records();
356
- for (id, record) in &before {
357
- assert_eq!(
358
- after.get(id),
359
- Some(record),
360
- "{name}: the record for {id} changed after commit"
361
- );
362
- }
363
- }
364
- }
365
-
366
- /// **Invariant 2 — a `parent_id` references an authoritative revision, or it is
367
- /// not a parent.**
368
- ///
369
- /// Model-independent: all three can enforce it at the mint, and it costs a
370
- /// containment check. This is the clause T5 should be discharged by — a rule in
371
- /// the definition of a valid revision, not a lookup bolted on afterwards.
372
- #[test]
373
- fn every_model_rejects_a_parent_it_does_not_hold() {
374
- for mut model in models() {
375
- let name = model.name();
376
- let foreign = "state:{\"never\":\"stored\"}".to_string();
377
- assert_eq!(
378
- model.mint("tasks:1", X, Some(&foreign)),
379
- Err(MintError::UnknownParent),
380
- "{name}: accepted a parent it does not hold"
381
- );
382
- }
383
- }
384
-
385
- /// **The real store now holds both — this is what the experiment decided.**
386
- ///
387
- /// This test asserted the opposite when the experiment was run: `StateStore`
388
- /// accepted an unheld parent, and re-minting a child's content as a root erased
389
- /// the parent that child had. Model C was adopted and implemented, and the same
390
- /// two sequences are now refused at the mint.
391
- ///
392
- /// It is kept in the experiment file rather than moved because the experiment's
393
- /// claim was that both invariants are *model-independent and cheap*. This is
394
- /// that claim, checked against the real store instead of a probe.
395
- #[test]
396
- fn the_real_store_now_holds_both_invariants() {
397
- let directory = TempDir::new().unwrap();
398
- let db = Arc::new(FeltDb::open(directory.path().join("today.log")).unwrap());
399
- let store = StateStore::with_feltdb(db).unwrap();
400
-
401
- let first = store
402
- .create("tasks:1", X.into(), "decision".into())
403
- .unwrap();
404
- let second = store.commit(Y.into(), &first, "decision".into()).unwrap();
405
- assert_eq!(
406
- store.get(&second.id).unwrap().parent_id,
407
- Some(first.id.clone())
408
- );
409
-
410
- // Invariant 1: beginning the resource again is refused, and a further
411
- // commit of the same content is a new revision rather than a rewrite.
412
- assert!(
413
- store
414
- .create("tasks:1", Y.into(), "decision".into())
415
- .is_err(),
416
- "a resource has one beginning"
417
- );
418
- let third = store.commit(Y.into(), &second, "decision".into()).unwrap();
419
- assert_ne!(
420
- third.id, second.id,
421
- "the same state again is a new revision"
422
- );
423
- assert_eq!(
424
- store.get(&second.id).unwrap().parent_id,
425
- Some(first.id),
426
- "the committed revision kept the parent it was committed with"
427
- );
428
-
429
- // Invariant 2: a parent the store does not hold is refused.
430
- let unheld = StateRevision::at(
431
- "tasks:1".into(),
432
- r#"{"never":"stored"}"#.into(),
433
- None,
434
- 0,
435
- "decision".into(),
436
- );
437
- assert!(
438
- store.commit(X.into(), &unheld, "decision".into()).is_err(),
439
- "a parent must resolve to a held revision"
440
- );
441
- }
442
-
443
- // ---------------------------------------------------------------------------
444
- // The seven scenarios
445
- // ---------------------------------------------------------------------------
446
-
447
- /// Whether the two mints produce one identity or two.
448
- fn same_content_twice(model: &mut dyn Model) -> bool {
449
- let first = model.mint("tasks:1", X, None).unwrap();
450
- let second = model.mint("tasks:1", X, None).unwrap();
451
- first == second
452
- }
453
-
454
- /// Whether a revert lands back on the identity it started from.
455
- fn revert_reuses_the_original_identity(model: &mut dyn Model) -> bool {
456
- let first = model.mint("tasks:1", X, None).unwrap();
457
- let second = model.mint("tasks:1", Y, Some(&first)).unwrap();
458
- let third = model.mint("tasks:1", X, Some(&second)).unwrap();
459
- first == third
460
- }
461
-
462
- /// Whether two resources holding the same content share one identity.
463
- fn two_resources_share_an_identity(model: &mut dyn Model) -> bool {
464
- let one = model.mint("tasks:1", X, None).unwrap();
465
- let two = model.mint("tasks:2", X, None).unwrap();
466
- one == two
467
- }
468
-
469
- /// Whether re-minting a child's content as a root can disturb the child.
470
- fn re_minting_a_child_as_a_root_disturbs_it(model: &mut dyn Model) -> bool {
471
- let first = model.mint("tasks:1", X, None).unwrap();
472
- let second = model.mint("tasks:1", Y, Some(&first)).unwrap();
473
- let before = model.parent_of("tasks:1", &second);
474
- model.mint("tasks:1", Y, None).unwrap();
475
- model.parent_of("tasks:1", &second) != before
476
- }
477
-
478
- /// Whether a foreign parent is refused.
479
- fn foreign_parent_refused(model: &mut dyn Model) -> bool {
480
- model.mint("tasks:1", X, Some(&"nothing:here".to_string())) == Err(MintError::UnknownParent)
481
- }
482
-
483
- /// Whether the history of one resource can be listed.
484
- fn resource_history_addressable(model: &mut dyn Model) -> bool {
485
- model.mint("tasks:1", X, None).unwrap();
486
- model.mint("tasks:2", Y, None).unwrap();
487
- matches!(model.history_of("tasks:1"), Ok(history) if history.len() == 1)
488
- }
489
-
490
- /// Whether a retention policy can be *stated* — "keep the last k of this
491
- /// resource" — as opposed to being applied to everything at once.
492
- fn retention_expressible(model: &mut dyn Model) -> bool {
493
- let mut previous = model.mint("tasks:1", X, None).unwrap();
494
- for n in 0..4 {
495
- previous = model
496
- .mint("tasks:1", &format!(r#"{{"n":{n}}}"#), Some(&previous))
497
- .unwrap();
498
- }
499
- model.retain_last("tasks:1", 2).is_ok()
500
- }
501
-
502
- /// Whether following parents from the newest revision terminates.
503
- fn topology_terminates(model: &mut dyn Model) -> bool {
504
- let first = model.mint("tasks:1", X, None).unwrap();
505
- let second = model.mint("tasks:1", Y, Some(&first)).unwrap();
506
- let third = model.mint("tasks:1", X, Some(&second)).unwrap();
507
-
508
- let mut seen: Vec<Rid> = Vec::new();
509
- let mut current = third;
510
- for _ in 0..32 {
511
- if seen.contains(&current) {
512
- return false;
513
- }
514
- seen.push(current.clone());
515
- match model.parent_of("tasks:1", &current) {
516
- Some(parent) => current = parent,
517
- None => return true,
518
- }
519
- }
520
- false
521
- }
522
-
523
- // ---------------------------------------------------------------------------
524
- // The decision matrix
525
- // ---------------------------------------------------------------------------
526
-
527
- /// One row of the matrix: a requirement, and what each model does about it.
528
- struct Row {
529
- requirement: &'static str,
530
- /// Evaluated per model, in the order A, B, C.
531
- evaluate: fn(&mut dyn Model) -> bool,
532
- expected: [bool; 3],
533
- }
534
-
535
- /// The matrix, filled by execution.
536
- ///
537
- /// `expected` is what the probes actually do. Changing a probe without changing
538
- /// this table fails the suite.
539
- const MATRIX: &[Row] = &[
540
- Row {
541
- requirement: "the same content can recur without reusing an identity",
542
- evaluate: |m| !same_content_twice(m),
543
- expected: [false, true, true],
544
- },
545
- Row {
546
- requirement: "a revert is distinguishable from the state it returns to",
547
- evaluate: |m| !revert_reuses_the_original_identity(m),
548
- expected: [false, true, true],
549
- },
550
- Row {
551
- requirement: "two resources at the same value are distinguishable",
552
- evaluate: |m| !two_resources_share_an_identity(m),
553
- expected: [false, true, true],
554
- },
555
- Row {
556
- requirement: "a committed revision's parent is undisturbed by later mints",
557
- evaluate: |m| !re_minting_a_child_as_a_root_disturbs_it(m),
558
- // A fails this for the same reason it deduplicates: parentage is not a
559
- // property of a revision there, so "the parent of R" has no stable
560
- // answer. See `model_a_is_sound_only_when_history_is_walked_over_edges`.
561
- expected: [false, true, true],
562
- },
563
- Row {
564
- requirement: "a parent must resolve to a held revision",
565
- evaluate: foreign_parent_refused,
566
- expected: [true, true, true],
567
- },
568
- Row {
569
- requirement: "the history of one resource is addressable",
570
- evaluate: resource_history_addressable,
571
- expected: [true, false, true],
572
- },
573
- Row {
574
- requirement: "a per-resource retention policy is expressible",
575
- evaluate: retention_expressible,
576
- expected: [true, false, true],
577
- },
578
- Row {
579
- requirement: "following parents terminates",
580
- evaluate: topology_terminates,
581
- // A cycles exactly as today's implementation does, and for the same
582
- // reason: resolving a parent by *identity* collapses the two occasions
583
- // one state was reached.
584
- expected: [false, true, true],
585
- },
586
- ];
587
-
588
- #[test]
589
- fn the_decision_matrix_is_exactly_this() {
590
- let mut drifted = Vec::new();
591
- for row in MATRIX {
592
- for (index, mut model) in models().into_iter().enumerate() {
593
- let actual = (row.evaluate)(model.as_mut());
594
- if actual != row.expected[index] {
595
- drifted.push(format!(
596
- " {} / {}: expected {}, observed {}",
597
- row.requirement,
598
- model.name(),
599
- row.expected[index],
600
- actual
601
- ));
602
- }
603
- }
604
- }
605
- assert!(
606
- drifted.is_empty(),
607
- "the decision matrix has drifted from the probes:\n{}\n\n\
608
- Update docs/architecture/revision-model-decision.md and this table together.",
609
- drifted.join("\n")
610
- );
611
- }
612
-
613
- /// **What the matrix forces.**
614
- ///
615
- /// A passes 3 of 8, B passes 6 of 8, C passes 8 of 8.
616
- ///
617
- /// B fails exactly the two rows that need a resource, and no discriminator added
618
- /// to its identity can fix that: those rows are unanswerable because the model
619
- /// has no resource to name, not because its identity is too coarse. Giving B a
620
- /// resource dimension **is** model C.
621
- ///
622
- /// A fails the three identity rows by design — a recurring state is one object
623
- /// referenced twice — and then fails two more as a consequence, because once
624
- /// identity is shared, "the parent of this revision" stops having one answer.
625
- /// That is not a defect in the probe; it is what moving ancestry out of the
626
- /// revision costs, and it is only recoverable under the discipline the next
627
- /// test describes.
628
- #[test]
629
- fn the_matrix_scores_a_three_b_six_c_eight() {
630
- let mut scores = [0usize; 3];
631
- for row in MATRIX {
632
- for (index, mut model) in models().into_iter().enumerate() {
633
- if (row.evaluate)(model.as_mut()) {
634
- scores[index] += 1;
635
- }
636
- }
637
- }
638
- assert_eq!(scores, [3, 6, 8], "A, B, C");
639
- }
640
-
641
- /// **B's failures are the two rows that need a resource, and only those.**
642
- #[test]
643
- fn model_b_fails_exactly_the_resource_rows() {
644
- let failed: Vec<&str> = MATRIX
645
- .iter()
646
- .filter(|row| !row.expected[1])
647
- .map(|row| row.requirement)
648
- .collect();
649
- assert_eq!(
650
- failed,
651
- vec![
652
- "the history of one resource is addressable",
653
- "a per-resource retention policy is expressible",
654
- ]
655
- );
656
- }
657
-
658
- /// **Model A is sound — but only if the addressable unit of history is the
659
- /// edge, not the revision.**
660
- ///
661
- /// The matrix shows A cycling and losing parentage when ancestry is resolved by
662
- /// revision identity. That is the tempting reading of "ancestry lives outside
663
- /// the revision", and it does not work: two occasions of one state are one
664
- /// identity, so the question has two answers and the walk closes a loop.
665
- ///
666
- /// Walked over the *edge list* instead — where each edge is a distinct,
667
- /// ordered occurrence — A is well behaved: the walk strictly decreases in index
668
- /// and therefore terminates, and no edge is ever rewritten.
669
- ///
670
- /// So A is not disqualified. It is conditional, and the condition is a real
671
- /// constraint on every consumer: `base` in model A is an edge lookup, and
672
- /// `revision.parent` does not exist.
673
- #[test]
674
- fn model_a_is_sound_only_when_history_is_walked_over_edges() {
675
- let mut model = StateModel::default();
676
- let first = model.mint("tasks:1", X, None).unwrap();
677
- let second = model.mint("tasks:1", Y, Some(&first)).unwrap();
678
- let third = model.mint("tasks:1", X, Some(&second)).unwrap();
679
- assert_eq!(first, third, "one object, reached twice");
680
-
681
- // Walk backwards over the edges of this resource, by position.
682
- let positions: Vec<usize> = model
683
- .edges
684
- .iter()
685
- .enumerate()
686
- .filter(|(_, edge)| edge.resource == "tasks:1")
687
- .map(|(index, _)| index)
688
- .collect();
689
-
690
- let mut walked = Vec::new();
691
- let mut cursor = Some(*positions.last().unwrap());
692
- while let Some(position) = cursor {
693
- walked.push(model.edges[position].to.clone());
694
- let from = model.edges[position].from.clone();
695
- cursor = match from {
696
- None => None,
697
- Some(parent) => positions
698
- .iter()
699
- .rev()
700
- .find(|candidate| **candidate < position && model.edges[**candidate].to == parent)
701
- .copied(),
702
- };
703
- assert!(walked.len() <= 8, "the edge walk must terminate");
704
- }
705
-
706
- assert_eq!(
707
- walked,
708
- vec![third, second, first],
709
- "three occasions, in order, from one deduplicated pair of states"
710
- );
711
- }
712
-
713
- /// **Why A behaves that way**, stated where it cannot be missed.
714
- ///
715
- /// A keeps deduplication — the only thing currently bounding storage growth —
716
- /// but it pays for it by moving ancestry out of the revision. A revision can no
717
- /// longer be asked for its parent: the question only has an answer relative to a
718
- /// resource, and if a state recurs on one resource it has more than one answer.
719
- #[test]
720
- fn model_a_has_no_well_formed_parent_for_a_revision() {
721
- let mut model = StateModel::default();
722
- let first = model.mint("tasks:1", X, None).unwrap();
723
- let second = model.mint("tasks:1", Y, Some(&first)).unwrap();
724
- let third = model.mint("tasks:1", X, Some(&second)).unwrap();
725
- assert_eq!(first, third, "one object, reached twice");
726
-
727
- // The same identity has two parents on one resource, depending on when.
728
- let parents: Vec<Option<Rid>> = model
729
- .edges
730
- .iter()
731
- .filter(|edge| edge.to == first)
732
- .map(|edge| edge.from.clone())
733
- .collect();
734
- assert_eq!(
735
- parents,
736
- vec![None, Some(second)],
737
- "'the parent of this revision' is not a well-formed question in model A"
738
- );
739
- }