@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,994 +0,0 @@
1
- //! Conformance, determinism and capability proofs for the
2
- //! `feltdb.trigger.match` deterministic contract.
3
- //!
4
- //! The architectural invariant under test is:
5
- //!
6
- //! ```text
7
- //! Contract semantics are authoritative.
8
- //! Runtime implementation is replaceable.
9
- //!
10
- //! NativeContract(input) == WasmContract(input) for every fixture
11
- //! ```
12
- //!
13
- //! The corpus in `tests/fixtures/trigger_contract_corpus.json` is committed
14
- //! rather than generated, and carries the canonical output each case must
15
- //! produce. Three comparisons run over it:
16
- //!
17
- //! 1. native output == committed expectation (runs everywhere);
18
- //! 2. WASM output == committed expectation (needs `wasm32-unknown-unknown`);
19
- //! 3. native output == WASM output, byte for byte.
20
- //!
21
- //! The first makes the suite meaningful even where the WASM toolchain is
22
- //! absent: a change in native semantics is caught by the same bytes the WASM
23
- //! implementation was measured against.
24
-
25
- use feltdb::trigger_contract::{
26
- canonical_input_bytes, evaluate_canonical, TriggerMatchInput, TRIGGER_MATCH_CONTRACT_ID,
27
- TRIGGER_MATCH_CONTRACT_VERSION,
28
- };
29
- use serde::Deserialize;
30
- use serde_json::Value;
31
- use std::path::{Path, PathBuf};
32
- use std::process::Command;
33
- use std::sync::OnceLock;
34
-
35
- // ---------------------------------------------------------------------------
36
- // Corpus
37
- // ---------------------------------------------------------------------------
38
-
39
- #[derive(Debug, Deserialize)]
40
- struct Corpus {
41
- corpus_version: u32,
42
- contract: String,
43
- contract_version: u32,
44
- #[allow(dead_code)]
45
- about: String,
46
- cases: Vec<Case>,
47
- }
48
-
49
- #[derive(Debug, Deserialize)]
50
- struct Case {
51
- name: String,
52
- #[allow(dead_code)]
53
- why: String,
54
- /// A well-formed contract input, canonically encoded by the harness.
55
- #[serde(default)]
56
- input: Option<TriggerMatchInput>,
57
- /// Bytes fed to the contract verbatim, for malformed and non-canonical
58
- /// encodings that a typed value cannot express.
59
- #[serde(default)]
60
- raw_input: Option<String>,
61
- /// The canonical encoding of `input`, recorded so that every consumer of
62
- /// the corpus presents the same bytes.
63
- ///
64
- /// A consumer in another language cannot always reproduce it: JavaScript
65
- /// has one number type, so it cannot encode the difference between `42` and
66
- /// `42.0` that this contract's value equality depends on. Recording the
67
- /// bytes makes the corpus self-describing instead of requiring every reader
68
- /// to own a canonical encoder.
69
- #[serde(default)]
70
- canonical_input: Option<String>,
71
- /// The canonical output both implementations must produce.
72
- #[serde(default)]
73
- expected_output: Option<String>,
74
- }
75
-
76
- impl Case {
77
- /// The exact bytes this case presents to a contract implementation.
78
- fn bytes(&self) -> Vec<u8> {
79
- match (&self.input, &self.raw_input) {
80
- (Some(input), None) => canonical_input_bytes(input),
81
- (None, Some(raw)) => raw.as_bytes().to_vec(),
82
- _ => panic!(
83
- "case {} must have exactly one of input/raw_input",
84
- self.name
85
- ),
86
- }
87
- }
88
-
89
- fn expected(&self) -> &str {
90
- self.expected_output.as_deref().unwrap_or_else(|| {
91
- panic!(
92
- "case {} has no expected_output; regenerate the corpus with \
93
- FELTDB_TRIGGER_CONTRACT_BLESS=1",
94
- self.name
95
- )
96
- })
97
- }
98
- }
99
-
100
- fn corpus_path() -> PathBuf {
101
- Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/trigger_contract_corpus.json")
102
- }
103
-
104
- fn corpus() -> &'static Corpus {
105
- static CORPUS: OnceLock<Corpus> = OnceLock::new();
106
- CORPUS.get_or_init(|| {
107
- let bytes = std::fs::read(corpus_path()).expect("conformance corpus is committed");
108
- serde_json::from_slice(&bytes).expect("conformance corpus is well formed")
109
- })
110
- }
111
-
112
- #[test]
113
- fn corpus_addresses_this_contract_at_this_version() {
114
- let corpus = corpus();
115
- assert_eq!(corpus.corpus_version, 1);
116
- assert_eq!(corpus.contract, TRIGGER_MATCH_CONTRACT_ID);
117
- assert_eq!(corpus.contract_version, TRIGGER_MATCH_CONTRACT_VERSION);
118
- assert!(
119
- corpus.cases.len() >= 90,
120
- "the corpus is the proof; it should not shrink silently"
121
- );
122
- let mut names: Vec<&str> = corpus.cases.iter().map(|case| case.name.as_str()).collect();
123
- names.sort_unstable();
124
- let unique = names.len();
125
- names.dedup();
126
- assert_eq!(unique, names.len(), "case names identify cases");
127
- }
128
-
129
- /// Every required category of behaviour is represented by at least one case.
130
- ///
131
- /// This is a guard against the corpus quietly losing a dimension it was built
132
- /// to cover, not a substitute for reading it.
133
- #[test]
134
- fn corpus_covers_every_required_category() {
135
- let names: Vec<&str> = corpus().cases.iter().map(|c| c.name.as_str()).collect();
136
- for required in [
137
- "collection_matches",
138
- "collection_differs",
139
- "change_kind_update_matches",
140
- "change_kind_insert_against_update_trigger",
141
- "disabled_trigger_rejects_matching_change",
142
- "predicate_matches_string",
143
- "predicate_value_mismatch",
144
- "predicate_absent_matches_any_value",
145
- "value_null_present_with_whole_record_predicate",
146
- "nested_path_matches",
147
- "array_equality_matches",
148
- "integer_equality_matches",
149
- "fanout_first_trigger_matches",
150
- "malformed_not_json",
151
- "empty_object_record",
152
- ] {
153
- assert!(
154
- names.contains(&required),
155
- "corpus lost coverage: {required}"
156
- );
157
- }
158
- }
159
-
160
- /// The committed canonical bytes are what this crate's encoder produces.
161
- ///
162
- /// Consumers outside Rust read `canonical_input` rather than re-canonicalizing,
163
- /// so this is the check that keeps those bytes honest: if canonicalization
164
- /// changed, every other reader of the corpus would silently be testing an
165
- /// encoding FeltDB no longer emits.
166
- #[test]
167
- fn committed_canonical_bytes_match_the_encoder() {
168
- for case in &corpus().cases {
169
- match (&case.input, &case.raw_input) {
170
- (Some(input), None) => assert_eq!(
171
- case.canonical_input.as_deref(),
172
- Some(
173
- String::from_utf8(canonical_input_bytes(input))
174
- .unwrap()
175
- .as_str()
176
- ),
177
- "{} has a stale canonical_input",
178
- case.name
179
- ),
180
- (None, Some(_)) => assert!(
181
- case.canonical_input.is_none(),
182
- "{} is a raw case and must not also record canonical_input",
183
- case.name
184
- ),
185
- _ => panic!(
186
- "case {} must have exactly one of input/raw_input",
187
- case.name
188
- ),
189
- }
190
- }
191
- }
192
-
193
- // ---------------------------------------------------------------------------
194
- // WASM host
195
- // ---------------------------------------------------------------------------
196
-
197
- const WASM_CRATE: &str = "crates/feltdb-trigger-contract-wasm";
198
- const WASM_ARTIFACT: &str =
199
- "target/wasm32-unknown-unknown/release/feltdb_trigger_contract_wasm.wasm";
200
-
201
- fn repository_root() -> &'static Path {
202
- Path::new(env!("CARGO_MANIFEST_DIR"))
203
- .parent()
204
- .and_then(Path::parent)
205
- .expect("the crate lives at <root>/crates/feltdb")
206
- }
207
-
208
- /// Whether this machine can compile the contract to WebAssembly at all.
209
- fn wasm_target_installed() -> bool {
210
- Command::new("rustc")
211
- .args([
212
- "--print",
213
- "target-libdir",
214
- "--target",
215
- "wasm32-unknown-unknown",
216
- ])
217
- .output()
218
- .is_ok_and(|output| output.status.success())
219
- }
220
-
221
- /// Compiles a WASM contract crate and returns the module bytes.
222
- ///
223
- /// A build failure is a defect and panics. A missing `wasm32-unknown-unknown`
224
- /// target is an environment fact, reported by the caller as a skip.
225
- fn build_module(manifest_dir: &Path) -> Vec<u8> {
226
- let output = Command::new(std::env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
227
- .args(["build", "--release", "--target", "wasm32-unknown-unknown"])
228
- .current_dir(manifest_dir)
229
- // The contract crate is its own workspace; inheriting the outer
230
- // build's target directory or profile would defeat that.
231
- .env_remove("CARGO_TARGET_DIR")
232
- .env_remove("RUSTFLAGS")
233
- .output()
234
- .expect("cargo is runnable");
235
- assert!(
236
- output.status.success(),
237
- "building the WASM contract at {} failed:\n{}",
238
- manifest_dir.display(),
239
- String::from_utf8_lossy(&output.stderr)
240
- );
241
- std::fs::read(manifest_dir.join(WASM_ARTIFACT)).expect("the build emits one module")
242
- }
243
-
244
- /// The committed WASM contract, compiled once for the whole suite.
245
- fn contract_module() -> Option<&'static [u8]> {
246
- static MODULE: OnceLock<Option<Vec<u8>>> = OnceLock::new();
247
- MODULE
248
- .get_or_init(|| {
249
- if let Ok(path) = std::env::var("FELTDB_TRIGGER_CONTRACT_WASM") {
250
- return Some(
251
- std::fs::read(path).expect("FELTDB_TRIGGER_CONTRACT_WASM is readable"),
252
- );
253
- }
254
- if !wasm_target_installed() {
255
- return None;
256
- }
257
- Some(build_module(&repository_root().join(WASM_CRATE)))
258
- })
259
- .as_deref()
260
- }
261
-
262
- /// Announces a skip loudly, so an absent toolchain is never a silent pass.
263
- fn skipped(test: &str) {
264
- eprintln!(
265
- "SKIPPED {test}: the wasm32-unknown-unknown target is not installed, so the WASM \
266
- contract implementation could not be built. Native conformance against the committed \
267
- expectations still ran. Install the target, or set FELTDB_TRIGGER_CONTRACT_WASM to a \
268
- prebuilt module, to execute the cross-runtime proof."
269
- );
270
- }
271
-
272
- /// One instantiation of the WASM contract.
273
- ///
274
- /// The linker is empty and stays empty: the module declares no imports, so
275
- /// there is nothing to satisfy and nothing to grant.
276
- struct WasmContract {
277
- store: wasmi::Store<()>,
278
- memory: wasmi::Memory,
279
- alloc: wasmi::TypedFunc<u32, u32>,
280
- evaluate: wasmi::TypedFunc<(u32, u32), u64>,
281
- free: wasmi::TypedFunc<(u32, u32), ()>,
282
- }
283
-
284
- impl WasmContract {
285
- fn instantiate(bytes: &[u8]) -> Self {
286
- let engine = wasmi::Engine::default();
287
- let module = wasmi::Module::new(&engine, bytes).expect("the module validates");
288
- let mut store = wasmi::Store::new(&engine, ());
289
- let instance = wasmi::Linker::<()>::new(&engine)
290
- .instantiate_and_start(&mut store, &module)
291
- .expect("an empty linker satisfies a module with no imports");
292
- Self {
293
- memory: instance
294
- .get_memory(&store, "memory")
295
- .expect("the module exports its memory"),
296
- alloc: instance
297
- .get_typed_func(&store, "contract_alloc")
298
- .expect("contract_alloc"),
299
- evaluate: instance
300
- .get_typed_func(&store, "contract_evaluate")
301
- .expect("contract_evaluate"),
302
- free: instance
303
- .get_typed_func(&store, "contract_free")
304
- .expect("contract_free"),
305
- store,
306
- }
307
- }
308
-
309
- fn version(bytes: &[u8]) -> u32 {
310
- let engine = wasmi::Engine::default();
311
- let module = wasmi::Module::new(&engine, bytes).unwrap();
312
- let mut store = wasmi::Store::new(&engine, ());
313
- let instance = wasmi::Linker::<()>::new(&engine)
314
- .instantiate_and_start(&mut store, &module)
315
- .unwrap();
316
- instance
317
- .get_typed_func::<(), u32>(&store, "contract_version")
318
- .expect("contract_version")
319
- .call(&mut store, ())
320
- .expect("contract_version is total")
321
- }
322
-
323
- fn evaluate(&mut self, input: &[u8]) -> Vec<u8> {
324
- let len = input.len() as u32;
325
- let ptr = self.alloc.call(&mut self.store, len).expect("allocation");
326
- self.memory
327
- .write(&mut self.store, ptr as usize, input)
328
- .expect("input fits in linear memory");
329
- let packed = self
330
- .evaluate
331
- .call(&mut self.store, (ptr, len))
332
- .expect("the contract never traps on any input");
333
- let out_ptr = (packed >> 32) as usize;
334
- let out_len = (packed & 0xffff_ffff) as usize;
335
- let mut output = vec![0u8; out_len];
336
- self.memory
337
- .read(&self.store, out_ptr, &mut output)
338
- .expect("the output buffer is inside linear memory");
339
- self.free.call(&mut self.store, (ptr, len)).expect("free");
340
- self.free
341
- .call(&mut self.store, (out_ptr as u32, out_len as u32))
342
- .expect("free");
343
- output
344
- }
345
- }
346
-
347
- // ---------------------------------------------------------------------------
348
- // Conformance
349
- // ---------------------------------------------------------------------------
350
-
351
- /// Native evaluation reproduces the committed canonical output for every case.
352
- ///
353
- /// The expectations were recorded from a run in which the native and the WASM
354
- /// implementation already agreed, so this is a full-strength check of native
355
- /// semantics even on a machine with no WASM toolchain.
356
- #[test]
357
- fn native_matches_the_committed_expectations() {
358
- let mut divergent = Vec::new();
359
- for case in &corpus().cases {
360
- let produced = String::from_utf8(evaluate_canonical(&case.bytes())).unwrap();
361
- if produced != case.expected() {
362
- divergent.push(format!(
363
- "{}\n expected: {}\n native: {}",
364
- case.name,
365
- case.expected(),
366
- produced
367
- ));
368
- }
369
- }
370
- assert!(
371
- divergent.is_empty(),
372
- "native contract diverged from the committed expectations:\n{}",
373
- divergent.join("\n")
374
- );
375
- }
376
-
377
- /// The proof: one corpus, two implementations, byte-identical canonical output.
378
- #[test]
379
- fn native_and_wasm_agree_on_every_fixture() {
380
- let Some(bytes) = contract_module() else {
381
- return skipped("native_and_wasm_agree_on_every_fixture");
382
- };
383
- let mut wasm = WasmContract::instantiate(bytes);
384
-
385
- println!(
386
- "{:<52} {:<7} {:<7} {}",
387
- "fixture", "native", "wasm", "equal"
388
- );
389
- let mut divergent = Vec::new();
390
- for case in &corpus().cases {
391
- let input = case.bytes();
392
- let native = evaluate_canonical(&input);
393
- let produced = wasm.evaluate(&input);
394
- let equal = native == produced;
395
- println!(
396
- "{:<52} {:<7} {:<7} {}",
397
- case.name,
398
- summarize(&native),
399
- summarize(&produced),
400
- if equal { "yes" } else { "NO" }
401
- );
402
- if !equal {
403
- divergent.push(format!(
404
- "{}\n input: {}\n native: {}\n wasm: {}",
405
- case.name,
406
- String::from_utf8_lossy(&input),
407
- String::from_utf8_lossy(&native),
408
- String::from_utf8_lossy(&produced)
409
- ));
410
- }
411
- }
412
- assert!(
413
- divergent.is_empty(),
414
- "native and WASM contract implementations diverged:\n{}",
415
- divergent.join("\n")
416
- );
417
- }
418
-
419
- /// The WASM implementation reproduces the committed canonical output too.
420
- ///
421
- /// Separate from the pairwise comparison on purpose: two implementations can
422
- /// agree with each other while both having moved.
423
- #[test]
424
- fn wasm_matches_the_committed_expectations() {
425
- let Some(bytes) = contract_module() else {
426
- return skipped("wasm_matches_the_committed_expectations");
427
- };
428
- let mut wasm = WasmContract::instantiate(bytes);
429
- for case in &corpus().cases {
430
- assert_eq!(
431
- String::from_utf8(wasm.evaluate(&case.bytes())).unwrap(),
432
- case.expected(),
433
- "WASM contract diverged from the committed expectation for {}",
434
- case.name
435
- );
436
- }
437
- }
438
-
439
- /// Both implementations answer for the same contract at the same version.
440
- #[test]
441
- fn both_implementations_declare_the_same_contract_version() {
442
- let Some(bytes) = contract_module() else {
443
- return skipped("both_implementations_declare_the_same_contract_version");
444
- };
445
- assert_eq!(WasmContract::version(bytes), TRIGGER_MATCH_CONTRACT_VERSION);
446
- for case in &corpus().cases {
447
- let output: Value = serde_json::from_slice(&evaluate_canonical(&case.bytes())).unwrap();
448
- assert_eq!(output["contract"], TRIGGER_MATCH_CONTRACT_ID);
449
- assert_eq!(output["version"], TRIGGER_MATCH_CONTRACT_VERSION);
450
- }
451
- }
452
-
453
- /// A short rendering of an output, for the printed conformance table.
454
- fn summarize(output: &[u8]) -> String {
455
- let parsed: Value = match serde_json::from_slice(output) {
456
- Ok(value) => value,
457
- Err(_) => return "?".into(),
458
- };
459
- if let Some(matched) = parsed["outcome"]["matched"].as_bool() {
460
- return if matched { "match" } else { "no-match" }.into();
461
- }
462
- "error".into()
463
- }
464
-
465
- // ---------------------------------------------------------------------------
466
- // Determinism
467
- // ---------------------------------------------------------------------------
468
-
469
- /// The same input, in the same instance, produces the same output every time.
470
- #[test]
471
- fn wasm_is_deterministic_across_repeated_calls() {
472
- let Some(bytes) = contract_module() else {
473
- return skipped("wasm_is_deterministic_across_repeated_calls");
474
- };
475
- let mut wasm = WasmContract::instantiate(bytes);
476
- for case in &corpus().cases {
477
- let input = case.bytes();
478
- let first = wasm.evaluate(&input);
479
- for round in 1..16 {
480
- assert_eq!(
481
- wasm.evaluate(&input),
482
- first,
483
- "{} changed answer on repeat {round} within one instance",
484
- case.name
485
- );
486
- }
487
- }
488
- }
489
-
490
- /// The same input produces the same output in a fresh instance.
491
- ///
492
- /// Each instance gets its own `Store`, so its linear memory, allocator state
493
- /// and call history all start over. An implementation that carried state
494
- /// between decisions would show it here.
495
- #[test]
496
- fn wasm_is_deterministic_across_fresh_instances() {
497
- let Some(bytes) = contract_module() else {
498
- return skipped("wasm_is_deterministic_across_fresh_instances");
499
- };
500
- let mut baseline = WasmContract::instantiate(bytes);
501
- let expected: Vec<Vec<u8>> = corpus()
502
- .cases
503
- .iter()
504
- .map(|case| baseline.evaluate(&case.bytes()))
505
- .collect();
506
-
507
- for round in 0..4 {
508
- let mut fresh = WasmContract::instantiate(bytes);
509
- for (case, want) in corpus().cases.iter().zip(&expected) {
510
- assert_eq!(
511
- &fresh.evaluate(&case.bytes()),
512
- want,
513
- "{} changed answer in fresh instance {round}",
514
- case.name
515
- );
516
- }
517
- }
518
- }
519
-
520
- /// Order of evaluation does not affect any answer.
521
- ///
522
- /// The corpus is replayed forwards and backwards through one instance. A
523
- /// decision that depended on what had been evaluated before would differ.
524
- #[test]
525
- fn wasm_answers_do_not_depend_on_evaluation_order() {
526
- let Some(bytes) = contract_module() else {
527
- return skipped("wasm_answers_do_not_depend_on_evaluation_order");
528
- };
529
- let mut forwards = WasmContract::instantiate(bytes);
530
- let ordered: Vec<Vec<u8>> = corpus()
531
- .cases
532
- .iter()
533
- .map(|case| forwards.evaluate(&case.bytes()))
534
- .collect();
535
-
536
- let mut backwards = WasmContract::instantiate(bytes);
537
- for (index, case) in corpus().cases.iter().enumerate().rev() {
538
- assert_eq!(
539
- backwards.evaluate(&case.bytes()),
540
- ordered[index],
541
- "{} answered differently when the corpus ran in reverse",
542
- case.name
543
- );
544
- }
545
- }
546
-
547
- /// The same input produces the same output in a separate OS process.
548
- ///
549
- /// `cargo test` may run the tests above in one process on one thread pool.
550
- /// This re-runs the corpus in a child process with an independently created
551
- /// engine, which is the strongest process boundary this harness can establish
552
- /// without shipping a second binary.
553
- #[test]
554
- fn wasm_is_deterministic_across_process_boundaries() {
555
- let Some(bytes) = contract_module() else {
556
- return skipped("wasm_is_deterministic_across_process_boundaries");
557
- };
558
- let mut here = WasmContract::instantiate(bytes);
559
- let mine: Vec<Vec<u8>> = corpus()
560
- .cases
561
- .iter()
562
- .map(|case| here.evaluate(&case.bytes()))
563
- .collect();
564
-
565
- let executable = std::env::current_exe().expect("the test binary has a path");
566
- let output = Command::new(executable)
567
- .args([
568
- "--exact",
569
- "wasm_is_deterministic_across_fresh_instances",
570
- "--nocapture",
571
- ])
572
- .output()
573
- .expect("the test binary re-runs");
574
- assert!(
575
- output.status.success(),
576
- "the corpus did not reproduce in a separate process:\n{}",
577
- String::from_utf8_lossy(&output.stdout)
578
- );
579
-
580
- // And the parent's own answers still match the committed expectations, so
581
- // the child agreeing with itself is not the whole claim.
582
- for (case, produced) in corpus().cases.iter().zip(&mine) {
583
- assert_eq!(String::from_utf8_lossy(produced), case.expected());
584
- }
585
- }
586
-
587
- // ---------------------------------------------------------------------------
588
- // Runtime restrictions
589
- // ---------------------------------------------------------------------------
590
-
591
- /// The module imports nothing.
592
- ///
593
- /// This is the whole capability argument and it is deliberately narrow. A
594
- /// WebAssembly module reaches the outside world only through its imports.
595
- /// With an empty import section there is no clock, no filesystem handle, no
596
- /// socket and no entropy source in scope — not because they were denied at
597
- /// call time, but because no such function is linked. It says nothing about
598
- /// hostile modules, which is a different claim this suite does not make.
599
- #[test]
600
- fn wasm_module_declares_no_imports() {
601
- let Some(bytes) = contract_module() else {
602
- return skipped("wasm_module_declares_no_imports");
603
- };
604
- let engine = wasmi::Engine::default();
605
- let module = wasmi::Module::new(&engine, bytes).expect("the module validates");
606
- let imports: Vec<String> = module
607
- .imports()
608
- .map(|import: wasmi::ImportType| format!("{}::{}", import.module(), import.name()))
609
- .collect();
610
- assert!(
611
- imports.is_empty(),
612
- "the contract module must import nothing; it imports {imports:?}"
613
- );
614
- }
615
-
616
- /// An empty linker instantiates the module.
617
- ///
618
- /// The companion to the import check, from the host's side: nothing is
619
- /// provided, and instantiation still succeeds, so no capability is being
620
- /// supplied implicitly by the runtime.
621
- #[test]
622
- fn wasm_module_instantiates_with_no_host_functions() {
623
- let Some(bytes) = contract_module() else {
624
- return skipped("wasm_module_instantiates_with_no_host_functions");
625
- };
626
- let engine = wasmi::Engine::default();
627
- let module = wasmi::Module::new(&engine, bytes).unwrap();
628
- let mut store = wasmi::Store::new(&engine, ());
629
- wasmi::Linker::<()>::new(&engine)
630
- .instantiate_and_start(&mut store, &module)
631
- .expect("no host function is required");
632
- }
633
-
634
- /// The module exports the contract ABI and nothing that could act on FeltDB.
635
- ///
636
- /// The exported surface is memory plus four functions. There is no export that
637
- /// writes state, creates work, or names a FeltDB concept: the module's only
638
- /// possible effect on FeltDB is the bytes it returns.
639
- #[test]
640
- fn wasm_module_exports_only_the_contract_abi() {
641
- let Some(bytes) = contract_module() else {
642
- return skipped("wasm_module_exports_only_the_contract_abi");
643
- };
644
- let engine = wasmi::Engine::default();
645
- let module = wasmi::Module::new(&engine, bytes).unwrap();
646
- let mut functions: Vec<String> = module
647
- .exports()
648
- .filter(|export| export.ty().func().is_some())
649
- .map(|export| export.name().to_string())
650
- .collect();
651
- functions.sort();
652
- assert_eq!(
653
- functions,
654
- vec![
655
- "contract_alloc".to_string(),
656
- "contract_evaluate".to_string(),
657
- "contract_free".to_string(),
658
- "contract_version".to_string(),
659
- ]
660
- );
661
- }
662
-
663
- /// WASI is not present, under any of the names a runtime would look for.
664
- #[test]
665
- fn wasm_module_requires_no_wasi() {
666
- let Some(bytes) = contract_module() else {
667
- return skipped("wasm_module_requires_no_wasi");
668
- };
669
- let text = String::from_utf8_lossy(bytes);
670
- for forbidden in [
671
- "wasi_snapshot_preview1",
672
- "wasi_unstable",
673
- "clock_time_get",
674
- "random_get",
675
- "fd_read",
676
- "fd_write",
677
- "sock_recv",
678
- "path_open",
679
- ] {
680
- assert!(
681
- !text.contains(forbidden),
682
- "the contract module names {forbidden}, which it has no reason to"
683
- );
684
- }
685
- }
686
-
687
- /// The contract never traps, on any corpus input.
688
- ///
689
- /// A trap would be a runtime-specific outcome rather than a contract decision,
690
- /// and the two implementations could not be compared through it.
691
- #[test]
692
- fn wasm_contract_returns_a_decision_for_every_input_including_malformed() {
693
- let Some(bytes) = contract_module() else {
694
- return skipped("wasm_contract_returns_a_decision_for_every_input_including_malformed");
695
- };
696
- let mut wasm = WasmContract::instantiate(bytes);
697
- for case in &corpus().cases {
698
- let output = wasm.evaluate(&case.bytes());
699
- let parsed: Value =
700
- serde_json::from_slice(&output).expect("every output is canonical JSON");
701
- assert_eq!(parsed["contract"], TRIGGER_MATCH_CONTRACT_ID);
702
- assert!(
703
- parsed.get("outcome").is_some() ^ parsed.get("error").is_some(),
704
- "{} produced neither or both of outcome and error",
705
- case.name
706
- );
707
- }
708
- // Inputs no fixture would contain, to show the trap-freedom is not a
709
- // property of the corpus.
710
- for hostile in [
711
- vec![0u8; 0],
712
- vec![0xff; 64],
713
- b"{".repeat(4096),
714
- b"[".repeat(4096),
715
- vec![b'"'; 1024],
716
- ] {
717
- let output = wasm.evaluate(&hostile);
718
- assert!(serde_json::from_slice::<Value>(&output).is_ok());
719
- }
720
- }
721
-
722
- // ---------------------------------------------------------------------------
723
- // Mutation: does the suite actually detect divergence?
724
- // ---------------------------------------------------------------------------
725
-
726
- /// A deliberate change to the WASM implementation's source.
727
- struct Mutation {
728
- name: &'static str,
729
- file: &'static str,
730
- from: &'static str,
731
- to: &'static str,
732
- }
733
-
734
- const MUTATIONS: &[Mutation] = &[
735
- Mutation {
736
- name: "predicate comparison always succeeds",
737
- file: "src/lib.rs",
738
- from: " if !resolved.equals(predicate.equals) {",
739
- to: " if false {",
740
- },
741
- Mutation {
742
- name: "collection comparison is case-insensitive",
743
- file: "src/lib.rs",
744
- from: " if change.collection != trigger.source_collection {",
745
- to: " if !change.collection.eq_ignore_ascii_case(trigger.source_collection) {",
746
- },
747
- Mutation {
748
- name: "disabled triggers are accepted",
749
- file: "src/lib.rs",
750
- from: " if !trigger.enabled {",
751
- to: " if false {",
752
- },
753
- Mutation {
754
- name: "a null record value counts as absent",
755
- file: "src/lib.rs",
756
- from: " let Some(value) = change.value else {",
757
- to: " let Some(value) = change.value.filter(|value| **value != Json::Null) else {",
758
- },
759
- Mutation {
760
- name: "change kind is never compared",
761
- file: "src/lib.rs",
762
- from: " if change.change_kind != trigger.change_kind {",
763
- to: " if false {",
764
- },
765
- Mutation {
766
- name: "output encoding renames a member",
767
- file: "src/lib.rs",
768
- from: r#"out.extend_from_slice(b"\",\"outcome\":{\"matched\":");"#,
769
- to: r#"out.extend_from_slice(b"\",\"result\":{\"matched\":");"#,
770
- },
771
- Mutation {
772
- name: "integers and floats compare equal",
773
- file: "src/json.rs",
774
- from: " (Json::Float(left), Json::Float(right)) => left == right,",
775
- to: " (Json::Float(left), Json::Float(right)) => left == right,\n (Json::PosInt(left), Json::Float(right)) => *left as f64 == *right,\n (Json::Float(left), Json::PosInt(right)) => *left == *right as f64,",
776
- },
777
- ];
778
-
779
- /// Every deliberate mutation of the WASM contract is caught by the corpus.
780
- ///
781
- /// Without this the conformance suite proves only that two implementations
782
- /// agree, not that agreement was ever in question. Each mutant is built from a
783
- /// copy of the real source with one edit applied, and must fail against the
784
- /// committed expectations.
785
- #[test]
786
- fn deliberate_wasm_mutations_are_detected() {
787
- if contract_module().is_none() {
788
- return skipped("deliberate_wasm_mutations_are_detected");
789
- }
790
- let source = repository_root().join(WASM_CRATE);
791
- let scratch = tempfile::tempdir().expect("a scratch directory");
792
-
793
- let mut undetected = Vec::new();
794
- for mutation in MUTATIONS {
795
- let root = scratch.path().join(mutation.name.replace(' ', "-"));
796
- copy_crate(&source, &root);
797
- let target = root.join(mutation.file);
798
- let original = std::fs::read_to_string(&target).expect("the mutated file exists");
799
- assert!(
800
- original.matches(mutation.from).count() == 1,
801
- "mutation {:?} no longer applies: its anchor is not present exactly once in {}. \
802
- The mutation suite must be updated with the implementation it mutates.",
803
- mutation.name,
804
- mutation.file
805
- );
806
- std::fs::write(&target, original.replace(mutation.from, mutation.to)).unwrap();
807
-
808
- let mut mutant = WasmContract::instantiate(&build_module(&root));
809
- let caught: Vec<&str> = corpus()
810
- .cases
811
- .iter()
812
- .filter(|case| {
813
- String::from_utf8_lossy(&mutant.evaluate(&case.bytes())) != case.expected()
814
- })
815
- .map(|case| case.name.as_str())
816
- .collect();
817
- match caught.first() {
818
- Some(first) => println!(
819
- "mutation {:?} caught by {} fixtures, first: {first}",
820
- mutation.name,
821
- caught.len()
822
- ),
823
- None => undetected.push(mutation.name),
824
- }
825
- }
826
- assert!(
827
- undetected.is_empty(),
828
- "the corpus does not distinguish these mutations from correct behaviour: {undetected:?}"
829
- );
830
- }
831
-
832
- /// Copies the contract crate's source, without its build directory.
833
- fn copy_crate(from: &Path, to: &Path) {
834
- std::fs::create_dir_all(to.join("src")).unwrap();
835
- std::fs::copy(from.join("Cargo.toml"), to.join("Cargo.toml")).unwrap();
836
- for entry in std::fs::read_dir(from.join("src")).unwrap() {
837
- let entry = entry.unwrap();
838
- std::fs::copy(entry.path(), to.join("src").join(entry.file_name())).unwrap();
839
- }
840
- }
841
-
842
- /// Mutating the canonical encoding is detected where the encoding is
843
- /// semantically load-bearing, and not where it is not.
844
- ///
845
- /// This is the honest shape of the result. Three encoder mutations are applied
846
- /// to well-formed cases and fed to both implementations:
847
- ///
848
- /// - conflating an absent record value with `null` changes a decision, and
849
- /// both implementations change it together, so only the committed
850
- /// expectations catch it;
851
- /// - dropping the contract identity turns every case into an input error,
852
- /// likewise caught by the expectations; and
853
- /// - emitting members in non-sorted order changes nothing, because JSON object
854
- /// equality is by member and both parsers agree. The suite correctly does
855
- /// not flag it, and the contract does not claim byte-canonical input.
856
- #[test]
857
- fn canonicalization_mutations_are_detected_where_they_matter() {
858
- let cases: Vec<(&Case, Value)> = corpus()
859
- .cases
860
- .iter()
861
- .filter_map(|case| {
862
- let input = case.input.as_ref()?;
863
- Some((case, serde_json::to_value(input).unwrap()))
864
- })
865
- .collect();
866
- assert!(cases.len() > 40, "most of the corpus is typed input");
867
-
868
- // 1. Absence conflated with null.
869
- let mut changed = 0;
870
- for (case, encoded) in &cases {
871
- let mut mutated = encoded.clone();
872
- if mutated["change"].get("value").is_none() {
873
- mutated["change"]["value"] = Value::Null;
874
- }
875
- let produced = String::from_utf8(evaluate_canonical(
876
- serde_json::to_vec(&mutated).unwrap().as_slice(),
877
- ))
878
- .unwrap();
879
- if produced != case.expected() {
880
- changed += 1;
881
- }
882
- }
883
- assert!(
884
- changed > 0,
885
- "an encoder that writes null for an absent record value must change a decision"
886
- );
887
-
888
- // 2. Contract identity dropped.
889
- for (case, encoded) in cases.iter().take(1) {
890
- let mut mutated = encoded.clone();
891
- mutated.as_object_mut().unwrap().remove("contract");
892
- let produced = String::from_utf8(evaluate_canonical(
893
- serde_json::to_vec(&mutated).unwrap().as_slice(),
894
- ))
895
- .unwrap();
896
- assert_ne!(produced, case.expected());
897
- assert!(produced.contains("CONTRACT_INPUT_INVALID"));
898
- }
899
-
900
- // 3. Member order, which carries no meaning.
901
- for (case, encoded) in &cases {
902
- let produced =
903
- String::from_utf8(evaluate_canonical(encode_reversed(encoded).as_bytes())).unwrap();
904
- assert_eq!(
905
- produced,
906
- case.expected(),
907
- "{} changed answer under a reordered encoding; object member order is \
908
- not part of this contract's semantics",
909
- case.name
910
- );
911
- }
912
- }
913
-
914
- /// Encodes a value with every object's members in reverse sorted order.
915
- ///
916
- /// `serde_json::Map` re-sorts on insert, so a non-canonical member order has to
917
- /// be produced as text rather than as a value.
918
- fn encode_reversed(value: &Value) -> String {
919
- match value {
920
- Value::Object(members) => {
921
- let mut parts: Vec<String> = members
922
- .iter()
923
- .map(|(key, value)| {
924
- format!(
925
- "{}:{}",
926
- serde_json::to_string(key).unwrap(),
927
- encode_reversed(value)
928
- )
929
- })
930
- .collect();
931
- parts.reverse();
932
- format!("{{{}}}", parts.join(","))
933
- }
934
- Value::Array(items) => format!(
935
- "[{}]",
936
- items
937
- .iter()
938
- .map(encode_reversed)
939
- .collect::<Vec<_>>()
940
- .join(",")
941
- ),
942
- other => serde_json::to_string(other).unwrap(),
943
- }
944
- }
945
-
946
- // ---------------------------------------------------------------------------
947
- // Corpus maintenance
948
- // ---------------------------------------------------------------------------
949
-
950
- /// Records the canonical output of every case, after both implementations agree.
951
- ///
952
- /// Ignored by default: it writes the corpus. Run it deliberately with
953
- /// `FELTDB_TRIGGER_CONTRACT_BLESS=1 cargo test -p feltdb --test
954
- /// trigger_contract_conformance -- bless --ignored`. It refuses to record
955
- /// anything unless the WASM implementation is available and agrees, so an
956
- /// expectation can never be blessed from one implementation alone.
957
- #[test]
958
- #[ignore = "rewrites the committed corpus"]
959
- fn bless() {
960
- assert_eq!(
961
- std::env::var("FELTDB_TRIGGER_CONTRACT_BLESS").as_deref(),
962
- Ok("1"),
963
- "set FELTDB_TRIGGER_CONTRACT_BLESS=1 to rewrite the corpus"
964
- );
965
- let bytes = contract_module().expect(
966
- "blessing requires the WASM implementation: an expectation recorded from the native \
967
- implementation alone would prove nothing",
968
- );
969
- let mut wasm = WasmContract::instantiate(bytes);
970
-
971
- let mut document: Value =
972
- serde_json::from_slice(&std::fs::read(corpus_path()).unwrap()).unwrap();
973
- for (index, case) in corpus().cases.iter().enumerate() {
974
- let input = case.bytes();
975
- let native = evaluate_canonical(&input);
976
- let produced = wasm.evaluate(&input);
977
- assert_eq!(
978
- String::from_utf8_lossy(&native),
979
- String::from_utf8_lossy(&produced),
980
- "refusing to record {}: the implementations disagree",
981
- case.name
982
- );
983
- if case.input.is_some() {
984
- document["cases"][index]["canonical_input"] =
985
- Value::String(String::from_utf8(input).unwrap());
986
- }
987
- document["cases"][index]["expected_output"] =
988
- Value::String(String::from_utf8(native).unwrap());
989
- }
990
- let mut text = serde_json::to_string_pretty(&document).unwrap();
991
- text.push('\n');
992
- std::fs::write(corpus_path(), text).unwrap();
993
- println!("recorded {} expectations", corpus().cases.len());
994
- }