@feltdb/core 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/dist/agent-state.d.ts +20 -0
  2. package/dist/agent-state.d.ts.map +1 -1
  3. package/dist/agent-state.js +36 -0
  4. package/dist/build-identity.json +12 -4
  5. package/dist/cli/commands.js +187 -4
  6. package/dist/cli/publish-engine.js +116 -16
  7. package/dist/collection.d.ts.map +1 -1
  8. package/dist/collection.js +3 -0
  9. package/dist/create/build-identity.json +12 -4
  10. package/dist/create/managed-account.js +93 -35
  11. package/dist/create/package-versions.js +1 -1
  12. package/dist/create/server-source/Cargo.lock +6 -509
  13. package/dist/create/server-source/Cargo.toml +2 -13
  14. package/dist/create/server-source/crates/feltdb-client/Cargo.toml +1 -1
  15. package/dist/create/server-source/crates/feltdb-server/Cargo.toml +1 -1
  16. package/dist/create/server-source/crates/feltdb-server/src/main.rs +255 -12
  17. package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +1 -1
  18. package/dist/db.d.ts +11 -1
  19. package/dist/db.d.ts.map +1 -1
  20. package/dist/db.js +15 -2
  21. package/dist/error-codes.d.ts +5 -0
  22. package/dist/error-codes.d.ts.map +1 -1
  23. package/dist/error-codes.js +9 -1
  24. package/dist/http-db.d.ts +16 -0
  25. package/dist/http-db.d.ts.map +1 -1
  26. package/dist/http-db.js +36 -6
  27. package/dist/managed-recovery.d.ts +6 -0
  28. package/dist/managed-recovery.d.ts.map +1 -1
  29. package/dist/managed-recovery.js +9 -0
  30. package/dist/studio-app/assets/{feltdb_wasm-BjM1ylL3.js → feltdb_wasm-DtybUY0q.js} +1 -1
  31. package/dist/studio-app/assets/feltdb_wasm_bg-DsgIUwaB.wasm +0 -0
  32. package/dist/studio-app/assets/index-C4OffsZl.js +37 -0
  33. package/dist/studio-app/index.html +1 -1
  34. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  35. package/dist/wasm/package.json +1 -1
  36. package/dist/workload.d.ts +55 -3
  37. package/dist/workload.d.ts.map +1 -1
  38. package/dist/workload.js +23 -0
  39. package/dist/workspace/workspace-connection.d.ts.map +1 -1
  40. package/dist/workspace/workspace-connection.js +14 -3
  41. package/package.json +1 -1
  42. package/dist/create/server-source/crates/feltdb/Cargo.lock +0 -175
  43. package/dist/create/server-source/crates/feltdb/Cargo.toml +0 -102
  44. package/dist/create/server-source/crates/feltdb/LICENSE +0 -21
  45. package/dist/create/server-source/crates/feltdb/README.md +0 -75
  46. package/dist/create/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +0 -370
  47. package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +0 -589
  48. package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +0 -247
  49. package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +0 -440
  50. package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +0 -275
  51. package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +0 -381
  52. package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +0 -467
  53. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +0 -489
  54. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +0 -281
  55. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +0 -606
  56. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +0 -531
  57. package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +0 -462
  58. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +0 -505
  59. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +0 -484
  60. package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +0 -758
  61. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +0 -421
  62. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +0 -329
  63. package/dist/create/server-source/crates/feltdb/src/acceptance_tests.rs +0 -1705
  64. package/dist/create/server-source/crates/feltdb/src/acquisition.rs +0 -286
  65. package/dist/create/server-source/crates/feltdb/src/admission.rs +0 -185
  66. package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +0 -507
  67. package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +0 -539
  68. package/dist/create/server-source/crates/feltdb/src/agent_state.rs +0 -320
  69. package/dist/create/server-source/crates/feltdb/src/agent_transition_contract.rs +0 -1545
  70. package/dist/create/server-source/crates/feltdb/src/analytics.rs +0 -521
  71. package/dist/create/server-source/crates/feltdb/src/application.rs +0 -2674
  72. package/dist/create/server-source/crates/feltdb/src/application_runtime.rs +0 -1070
  73. package/dist/create/server-source/crates/feltdb/src/authority.rs +0 -479
  74. package/dist/create/server-source/crates/feltdb/src/authority_failover.rs +0 -847
  75. package/dist/create/server-source/crates/feltdb/src/authorization.rs +0 -1030
  76. package/dist/create/server-source/crates/feltdb/src/authorization_security_tests.rs +0 -1122
  77. package/dist/create/server-source/crates/feltdb/src/bin/feltdb-authority-client.rs +0 -32
  78. package/dist/create/server-source/crates/feltdb/src/bin/feltdb-authority.rs +0 -19
  79. package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +0 -1474
  80. package/dist/create/server-source/crates/feltdb/src/capabilities/mod.rs +0 -8
  81. package/dist/create/server-source/crates/feltdb/src/capabilities/search.rs +0 -418
  82. package/dist/create/server-source/crates/feltdb/src/capabilities/vector.rs +0 -482
  83. package/dist/create/server-source/crates/feltdb/src/capability.rs +0 -903
  84. package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +0 -263
  85. package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +0 -77
  86. package/dist/create/server-source/crates/feltdb/src/causal_backlog_bound.rs +0 -496
  87. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +0 -2574
  88. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +0 -212
  89. package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +0 -422
  90. package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +0 -445
  91. package/dist/create/server-source/crates/feltdb/src/content_distribution.rs +0 -465
  92. package/dist/create/server-source/crates/feltdb/src/convergence.rs +0 -634
  93. package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +0 -427
  94. package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +0 -376
  95. package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +0 -365
  96. package/dist/create/server-source/crates/feltdb/src/cron.rs +0 -294
  97. package/dist/create/server-source/crates/feltdb/src/dedup_bound_investigation.rs +0 -483
  98. package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +0 -477
  99. package/dist/create/server-source/crates/feltdb/src/distributed_tests.rs +0 -1003
  100. package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +0 -1334
  101. package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +0 -368
  102. package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +0 -231
  103. package/dist/create/server-source/crates/feltdb/src/durable_operation_identity.rs +0 -482
  104. package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +0 -203
  105. package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +0 -317
  106. package/dist/create/server-source/crates/feltdb/src/equality_index.rs +0 -595
  107. package/dist/create/server-source/crates/feltdb/src/execution.rs +0 -426
  108. package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +0 -214
  109. package/dist/create/server-source/crates/feltdb/src/indexing.rs +0 -776
  110. package/dist/create/server-source/crates/feltdb/src/lib.rs +0 -7365
  111. package/dist/create/server-source/crates/feltdb/src/managed_cas_tests.rs +0 -234
  112. package/dist/create/server-source/crates/feltdb/src/materialization.rs +0 -184
  113. package/dist/create/server-source/crates/feltdb/src/metrics.rs +0 -266
  114. package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +0 -310
  115. package/dist/create/server-source/crates/feltdb/src/multi_operation_transaction.rs +0 -736
  116. package/dist/create/server-source/crates/feltdb/src/observability.rs +0 -379
  117. package/dist/create/server-source/crates/feltdb/src/operation.rs +0 -290
  118. package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +0 -439
  119. package/dist/create/server-source/crates/feltdb/src/operation_log.rs +0 -349
  120. package/dist/create/server-source/crates/feltdb/src/p1_application_atomicity.rs +0 -332
  121. package/dist/create/server-source/crates/feltdb/src/p1_atomicity_acceptance.rs +0 -718
  122. package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +0 -487
  123. package/dist/create/server-source/crates/feltdb/src/peer_registry.rs +0 -166
  124. package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +0 -289
  125. package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +0 -566
  126. package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +0 -3391
  127. package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +0 -203
  128. package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +0 -261
  129. package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +0 -502
  130. package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +0 -216
  131. package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +0 -303
  132. package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +0 -323
  133. package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +0 -531
  134. package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +0 -406
  135. package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +0 -436
  136. package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +0 -387
  137. package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +0 -378
  138. package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +0 -359
  139. package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +0 -372
  140. package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +0 -404
  141. package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +0 -376
  142. package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +0 -461
  143. package/dist/create/server-source/crates/feltdb/src/policy_evaluation.rs +0 -2125
  144. package/dist/create/server-source/crates/feltdb/src/production_api.rs +0 -418
  145. package/dist/create/server-source/crates/feltdb/src/provenance.rs +0 -207
  146. package/dist/create/server-source/crates/feltdb/src/query_execution_diagnostics.rs +0 -126
  147. package/dist/create/server-source/crates/feltdb/src/query_performance.rs +0 -218
  148. package/dist/create/server-source/crates/feltdb/src/read_basis.rs +0 -257
  149. package/dist/create/server-source/crates/feltdb/src/references.rs +0 -404
  150. package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +0 -401
  151. package/dist/create/server-source/crates/feltdb/src/replica_acknowledgements.rs +0 -501
  152. package/dist/create/server-source/crates/feltdb/src/replica_membership.rs +0 -680
  153. package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +0 -163
  154. package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +0 -133
  155. package/dist/create/server-source/crates/feltdb/src/routing.rs +0 -409
  156. package/dist/create/server-source/crates/feltdb/src/semantic_decision.rs +0 -2029
  157. package/dist/create/server-source/crates/feltdb/src/semantic_query.rs +0 -599
  158. package/dist/create/server-source/crates/feltdb/src/sharding.rs +0 -549
  159. package/dist/create/server-source/crates/feltdb/src/state_conflict_contract.rs +0 -516
  160. package/dist/create/server-source/crates/feltdb/src/state_contract.rs +0 -6003
  161. package/dist/create/server-source/crates/feltdb/src/state_diff_contract.rs +0 -222
  162. package/dist/create/server-source/crates/feltdb/src/state_facade.rs +0 -320
  163. package/dist/create/server-source/crates/feltdb/src/state_hash.rs +0 -291
  164. package/dist/create/server-source/crates/feltdb/src/state_model.rs +0 -4158
  165. package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +0 -379
  166. package/dist/create/server-source/crates/feltdb/src/state_trigger.rs +0 -673
  167. package/dist/create/server-source/crates/feltdb/src/storage.rs +0 -273
  168. package/dist/create/server-source/crates/feltdb/src/submission.rs +0 -471
  169. package/dist/create/server-source/crates/feltdb/src/sync.rs +0 -495
  170. package/dist/create/server-source/crates/feltdb/src/sync_contract.rs +0 -822
  171. package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +0 -433
  172. package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +0 -462
  173. package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +0 -965
  174. package/dist/create/server-source/crates/feltdb/src/transaction_preconditions.rs +0 -1120
  175. package/dist/create/server-source/crates/feltdb/src/transactions.rs +0 -643
  176. package/dist/create/server-source/crates/feltdb/src/trigger.rs +0 -390
  177. package/dist/create/server-source/crates/feltdb/src/trigger_contract.rs +0 -749
  178. package/dist/create/server-source/crates/feltdb/src/versioned_object_substrate.rs +0 -708
  179. package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +0 -1269
  180. package/dist/create/server-source/crates/feltdb/src/workflow.rs +0 -713
  181. package/dist/create/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +0 -510
  182. package/dist/create/server-source/crates/feltdb/src/workflow_integration.rs +0 -354
  183. package/dist/create/server-source/crates/feltdb/src/workflow_runtime.rs +0 -594
  184. package/dist/create/server-source/crates/feltdb/src/workload.rs +0 -4222
  185. package/dist/create/server-source/crates/feltdb/src/workload_diagnostics.rs +0 -456
  186. package/dist/create/server-source/crates/feltdb/tests/agent_state_native.rs +0 -1188
  187. package/dist/create/server-source/crates/feltdb/tests/agent_transition_contract_conformance.rs +0 -2884
  188. package/dist/create/server-source/crates/feltdb/tests/authority_process.rs +0 -297
  189. package/dist/create/server-source/crates/feltdb/tests/authority_transaction_identity.rs +0 -534
  190. package/dist/create/server-source/crates/feltdb/tests/bounded_read_contract.rs +0 -132
  191. package/dist/create/server-source/crates/feltdb/tests/branching_evidence.rs +0 -299
  192. package/dist/create/server-source/crates/feltdb/tests/common/mod.rs +0 -96
  193. package/dist/create/server-source/crates/feltdb/tests/compaction_stall_contract.rs +0 -272
  194. package/dist/create/server-source/crates/feltdb/tests/crash_durability_contract.rs +0 -467
  195. package/dist/create/server-source/crates/feltdb/tests/current_revision_authority_evidence.rs +0 -309
  196. package/dist/create/server-source/crates/feltdb/tests/durable_backup_contract.rs +0 -445
  197. package/dist/create/server-source/crates/feltdb/tests/durable_corruption_contract.rs +0 -518
  198. package/dist/create/server-source/crates/feltdb/tests/durable_format_compatibility.rs +0 -392
  199. package/dist/create/server-source/crates/feltdb/tests/feltdb_state_boundary_tests.rs +0 -850
  200. package/dist/create/server-source/crates/feltdb/tests/fixtures/agent_transition_corpus.json +0 -23340
  201. package/dist/create/server-source/crates/feltdb/tests/fixtures/state_conflict_contract_corpus.json +0 -1916
  202. package/dist/create/server-source/crates/feltdb/tests/fixtures/state_diff_contract_corpus.json +0 -1878
  203. package/dist/create/server-source/crates/feltdb/tests/fixtures/trigger_contract_corpus.json +0 -1862
  204. package/dist/create/server-source/crates/feltdb/tests/generalized_version_control_evidence.rs +0 -123
  205. package/dist/create/server-source/crates/feltdb/tests/generalized_version_control_substrate_completion.rs +0 -299
  206. package/dist/create/server-source/crates/feltdb/tests/local_process_ownership.rs +0 -69
  207. package/dist/create/server-source/crates/feltdb/tests/managed_incident_regression.rs +0 -191
  208. package/dist/create/server-source/crates/feltdb/tests/operational_health_contract.rs +0 -278
  209. package/dist/create/server-source/crates/feltdb/tests/pr34_query_collection.rs +0 -234
  210. package/dist/create/server-source/crates/feltdb/tests/pr35_equality_index.rs +0 -947
  211. package/dist/create/server-source/crates/feltdb/tests/pr7_self_authorization_proof.rs +0 -404
  212. package/dist/create/server-source/crates/feltdb/tests/pr8_vocabulary_assessment.rs +0 -916
  213. package/dist/create/server-source/crates/feltdb/tests/pr9_phase2_boundary_tests.rs +0 -1045
  214. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3a_path_a_tests.rs +0 -347
  215. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_authorized_mutations.rs +0 -361
  216. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_role_based_authorization.rs +0 -330
  217. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_simple_auth_delete.rs +0 -93
  218. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_team_delete_role_authorization.rs +0 -622
  219. package/dist/create/server-source/crates/feltdb/tests/pr9_teams_role_based_access.rs +0 -517
  220. package/dist/create/server-source/crates/feltdb/tests/production_certification.rs +0 -1153
  221. package/dist/create/server-source/crates/feltdb/tests/production_contract.rs +0 -771
  222. package/dist/create/server-source/crates/feltdb/tests/production_readiness_contract.rs +0 -1383
  223. package/dist/create/server-source/crates/feltdb/tests/reconciliation_application.rs +0 -868
  224. package/dist/create/server-source/crates/feltdb/tests/reconciliation_wire_format_evidence.rs +0 -221
  225. package/dist/create/server-source/crates/feltdb/tests/replicated_history_contract.rs +0 -417
  226. package/dist/create/server-source/crates/feltdb/tests/resource_scoped_revisions.rs +0 -338
  227. package/dist/create/server-source/crates/feltdb/tests/revision_identity_contract.rs +0 -1039
  228. package/dist/create/server-source/crates/feltdb/tests/revision_model_decision.rs +0 -739
  229. package/dist/create/server-source/crates/feltdb/tests/revision_retention_boundary_evidence.rs +0 -452
  230. package/dist/create/server-source/crates/feltdb/tests/saas_authorization_integration.rs +0 -81
  231. package/dist/create/server-source/crates/feltdb/tests/saas_invitation_lifecycle.rs +0 -438
  232. package/dist/create/server-source/crates/feltdb/tests/semantic_decision.rs +0 -1165
  233. package/dist/create/server-source/crates/feltdb/tests/semantic_query.rs +0 -767
  234. package/dist/create/server-source/crates/feltdb/tests/semantic_query_contract.rs +0 -363
  235. package/dist/create/server-source/crates/feltdb/tests/state_conflict_contract_conformance.rs +0 -1799
  236. package/dist/create/server-source/crates/feltdb/tests/state_diff_contract_conformance.rs +0 -1316
  237. package/dist/create/server-source/crates/feltdb/tests/state_model_integration.rs +0 -358
  238. package/dist/create/server-source/crates/feltdb/tests/state_persistence_integration.rs +0 -365
  239. package/dist/create/server-source/crates/feltdb/tests/state_ref_authority.rs +0 -918
  240. package/dist/create/server-source/crates/feltdb/tests/state_store_boundary_evidence.rs +0 -299
  241. package/dist/create/server-source/crates/feltdb/tests/storage_independent_versioned_object_substrate.rs +0 -328
  242. package/dist/create/server-source/crates/feltdb/tests/sync_divergence_evidence.rs +0 -255
  243. package/dist/create/server-source/crates/feltdb/tests/three_way_input_boundary_evidence.rs +0 -249
  244. package/dist/create/server-source/crates/feltdb/tests/trigger_contract_conformance.rs +0 -994
  245. package/dist/create/server-source/crates/feltdb/tests/workload_envelope_contract.rs +0 -484
  246. package/dist/studio-app/assets/feltdb_wasm_bg-TseJn2Ax.wasm +0 -0
  247. package/dist/studio-app/assets/index-1wd0uKua.js +0 -30
@@ -1,1153 +0,0 @@
1
- //! The FeltDB production certification matrix.
2
- //!
3
- //! This file is the **authoritative** statement of what FeltDB can and cannot
4
- //! claim. Every count in `docs/architecture/production-certification.md` is
5
- //! derived from the table below; none is maintained by hand.
6
- //!
7
- //! # The certification principle
8
- //!
9
- //! > For every claim: **what exact evidence proves this today, and what does
10
- //! > that evidence not prove?**
11
- //!
12
- //! A claim is not `Proven` because an implementation exists, because another
13
- //! claim implies it, because an earlier change said so, because a related test
14
- //! passes, or because the wording sounds reasonable. Every `Proven` claim names
15
- //! a test that exists and runs now.
16
- //!
17
- //! # What this audit changed
18
- //!
19
- //! Recalculating rather than inheriting **downgraded two claims** that earlier
20
- //! work recorded as `Proven` (see `DOWNGRADES`), corrected two dangling
21
- //! evidence citations, and added the managed-incident remediation, which
22
- //! had shipped with tests but no matrix entry at all. Discovering that an
23
- //! earlier conclusion no longer holds is the point of the exercise, not a
24
- //! failure of it.
25
-
26
- use std::collections::BTreeMap;
27
-
28
- mod common;
29
-
30
- /// The status labels that withhold rather than grant. A table row carrying one
31
- /// of these is recording a gap, and is read as such by the prose tripwire.
32
- const WITHHELD_LABELS: &[&str] = &["Partially Proven", "Unproven", "Blocked", "Not Applicable"];
33
-
34
- /// The only statuses this certification recognises.
35
- #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
36
- enum Status {
37
- Proven,
38
- PartiallyProven,
39
- Unproven,
40
- Blocked,
41
- NotApplicable,
42
- }
43
-
44
- impl Status {
45
- /// Every status this certification recognises. Counts are derived over this
46
- /// list, so a bucket that happens to be empty is still published as zero.
47
- const ALL: [Status; 5] = [
48
- Status::Proven,
49
- Status::PartiallyProven,
50
- Status::Unproven,
51
- Status::Blocked,
52
- Status::NotApplicable,
53
- ];
54
-
55
- /// The enum variant's own name, which is how earlier ledgers spell it.
56
- fn variant(self) -> &'static str {
57
- match self {
58
- Status::Proven => "Proven",
59
- Status::PartiallyProven => "PartiallyProven",
60
- Status::Unproven => "Unproven",
61
- Status::Blocked => "Blocked",
62
- Status::NotApplicable => "NotApplicable",
63
- }
64
- }
65
-
66
- /// How much a status claims. Only used to assert that a divergence from an
67
- /// earlier ledger is a *weakening*; a strengthening needs new evidence and
68
- /// must not slip through as a declared downgrade.
69
- fn strength(self) -> u8 {
70
- match self {
71
- Status::Proven => 3,
72
- Status::PartiallyProven => 2,
73
- Status::Blocked => 1,
74
- Status::Unproven | Status::NotApplicable => 0,
75
- }
76
- }
77
-
78
- fn label(self) -> &'static str {
79
- match self {
80
- Status::Proven => "Proven",
81
- Status::PartiallyProven => "Partially Proven",
82
- Status::Unproven => "Unproven",
83
- Status::Blocked => "Blocked",
84
- Status::NotApplicable => "Not Applicable",
85
- }
86
- }
87
- }
88
-
89
- /// How a claim is established. The distinction matters: implementation
90
- /// inspection alone may not carry a *behavioural* guarantee.
91
- #[derive(Debug, Clone, Copy, PartialEq, Eq)]
92
- enum Evidence {
93
- /// A test that exercises the behaviour and asserts the outcome.
94
- ExecutableContract,
95
- /// A test that damages, truncates or kills something and asserts recovery.
96
- FailureInjection,
97
- /// A test that runs a fixed experiment and asserts a relationship.
98
- DeterministicExperiment,
99
- /// A measurement under a frozen workload.
100
- Benchmark,
101
- /// Reading the code. Sufficient only for structural claims.
102
- ImplementationInspection,
103
- /// No evidence exists.
104
- None,
105
- }
106
-
107
- impl Evidence {
108
- /// How the published document names this evidence type.
109
- fn label(self) -> &'static str {
110
- match self {
111
- Evidence::ExecutableContract => "Executable contract",
112
- Evidence::FailureInjection => "Failure injection",
113
- Evidence::DeterministicExperiment => "Deterministic experiment",
114
- Evidence::Benchmark => "Benchmark",
115
- Evidence::ImplementationInspection => "Implementation inspection",
116
- Evidence::None => "None",
117
- }
118
- }
119
- }
120
-
121
- struct Claim {
122
- id: &'static str,
123
- domain: &'static str,
124
- claim: &'static str,
125
- status: Status,
126
- /// The test function that establishes this claim, or "" when there is none.
127
- evidence: &'static str,
128
- kind: Evidence,
129
- /// What the evidence does **not** establish. Required for every claim that
130
- /// is not fully `Proven`, and used freely on `Proven` ones.
131
- limitation: &'static str,
132
- source: &'static str,
133
- }
134
-
135
- /// Where this audit disagrees with the ledger of the pull request that first
136
- /// recorded a claim.
137
- ///
138
- /// The earlier ledgers stay as they are: they are the record of what #307, #313
139
- /// and #314 concluded on the evidence they had, and rewriting them would erase
140
- /// the fact that the conclusion changed. But a disagreement must never be
141
- /// silent, so every one of them is declared here and checked in both
142
- /// directions — the earlier ledger must still say what this table claims it
143
- /// says, and the certification must still say the weaker thing.
144
- ///
145
- /// `(claim, what the earlier ledger records, what this audit records, why)`
146
- const DOWNGRADES: &[(&str, &str, &str, &str)] = &[
147
- (
148
- "E6",
149
- "Proven",
150
- "PartiallyProven",
151
- "the frozen workload is asserted by a test; the environment is only in prose",
152
- ),
153
- (
154
- "O2",
155
- "Proven",
156
- "PartiallyProven",
157
- "the library value and the status derivation are tested; the HTTP handler is not",
158
- ),
159
- ];
160
-
161
- /// The certification matrix.
162
- ///
163
- /// Laid out as a table on purpose: a claim is meant to be read across its row,
164
- /// and the fields line up so a missing limitation or an empty evidence cell is
165
- /// visible at a glance. `rustfmt` would expand each entry to nine lines and
166
- /// lose that.
167
- #[rustfmt::skip]
168
- const CERTIFICATION: &[Claim] = &[
169
- // ---------------------------------------------------------------- D
170
- Claim { id: "D1", domain: "Durability", claim: "committed mutations survive a clean restart",
171
- status: Status::Proven, evidence: "a_clean_restart_preserves_state_history_and_retention",
172
- kind: Evidence::ExecutableContract,
173
- limitation: "A clean, cooperative shutdown. Says nothing about an abrupt one.",
174
- source: "#307" },
175
- Claim { id: "D2", domain: "Durability", claim: "revision history survives a clean restart",
176
- status: Status::Proven, evidence: "a_clean_restart_preserves_state_history_and_retention",
177
- kind: Evidence::ExecutableContract, limitation: "As D1.", source: "#307" },
178
- Claim { id: "D3", domain: "Durability", claim: "retention policy and horizon survive a restart",
179
- status: Status::Proven, evidence: "a_clean_restart_preserves_state_history_and_retention",
180
- kind: Evidence::ExecutableContract, limitation: "As D1.", source: "#306" },
181
- Claim { id: "D4", domain: "Durability", claim: "a reopened database continues history rather than restarting it",
182
- status: Status::Proven, evidence: "a_clean_restart_preserves_state_history_and_retention",
183
- kind: Evidence::ExecutableContract, limitation: "As D1.", source: "#306" },
184
- Claim { id: "D5", domain: "Durability", claim: "a single write survives operating-system or power loss",
185
- status: Status::Unproven, evidence: "", kind: Evidence::None,
186
- limitation: "NOT PROVEN AND NOT PROVABLE HERE. The default mode flushes to the \
187
- operating system without fsync. `Synced` mode issues a barrier per write, \
188
- but whether the device honoured it is a property of the storage stack that \
189
- no test in this repository can observe. Settling this needs an experiment \
190
- that cuts power to real hardware.",
191
- source: "#312, #314" },
192
- Claim { id: "D6", domain: "Durability", claim: "every crash point leaves a clean prefix of the mutation sequence",
193
- status: Status::Proven, evidence: "every_crash_point_leaves_a_clean_prefix",
194
- kind: Evidence::FailureInjection,
195
- limitation: "Truncation models the durable bytes at every byte boundary of a \
196
- three-write log. It does not model a filesystem reordering writes or a \
197
- device returning stale data.",
198
- source: "#312" },
199
- Claim { id: "D7", domain: "Durability", claim: "a crash never produces a revision for a record that was not written",
200
- status: Status::Proven, evidence: "no_crash_point_produces_a_phantom_revision",
201
- kind: Evidence::FailureInjection,
202
- limitation: "Follows from record-before-revision ordering; verified over one workload.",
203
- source: "#312" },
204
- Claim { id: "D8", domain: "Durability", claim: "a committed write survives the process dying",
205
- status: Status::Proven, evidence: "a_committed_write_survives_process_death",
206
- kind: Evidence::FailureInjection,
207
- limitation: "A real SIGABRT. The process, not the machine.", source: "#312" },
208
- Claim { id: "D9", domain: "Durability", claim: "a transaction is all-or-nothing across a crash",
209
- status: Status::Proven, evidence: "a_transaction_is_all_or_nothing_at_every_crash_point",
210
- kind: Evidence::FailureInjection,
211
- limitation: "Every byte offset of one three-row transaction.", source: "#312" },
212
- Claim { id: "D10", domain: "Durability", claim: "a crash-recovered database replicates identically",
213
- status: Status::Proven, evidence: "a_crash_recovered_database_replicates_identically",
214
- kind: Evidence::FailureInjection,
215
- limitation: "Crash points sampled every 37 bytes, not exhaustively.", source: "#312" },
216
- // ---------------------------------------------------------------- A
217
- Claim { id: "A1", domain: "Atomicity", claim: "a stale fenced write is rejected and mints nothing",
218
- status: Status::Proven, evidence: "a_stale_fenced_write_is_rejected_and_mints_nothing",
219
- kind: Evidence::ExecutableContract, limitation: "Version conflict only.", source: "#307" },
220
- Claim { id: "A2", domain: "Atomicity", claim: "concurrent writes to distinct resources keep distinct chains",
221
- status: Status::Proven, evidence: "concurrent_writes_produce_correct_chains",
222
- kind: Evidence::ExecutableContract,
223
- limitation: "Four threads, twenty-five writes each, on one machine.", source: "#307" },
224
- Claim { id: "A3", domain: "Atomicity", claim: "concurrent writes to one resource form one correct chain",
225
- status: Status::Proven, evidence: "concurrent_writes_produce_correct_chains",
226
- kind: Evidence::ExecutableContract,
227
- limitation: "One hundred writes producing one hundred unique sequences. Not a \
228
- stress test.", source: "#307" },
229
- Claim { id: "A4", domain: "Atomicity", claim: "a duplicate remote operation is idempotent",
230
- status: Status::Proven, evidence: "replayed_and_gapped_remote_operations_are_handled_explicitly",
231
- kind: Evidence::ExecutableContract, limitation: "Whole-stream replay.", source: "#307" },
232
- Claim { id: "A5", domain: "Atomicity", claim: "a remote operation with a sequence gap is rejected",
233
- status: Status::Proven, evidence: "replayed_and_gapped_remote_operations_are_handled_explicitly",
234
- kind: Evidence::ExecutableContract, limitation: "One gap shape.", source: "#307" },
235
- Claim { id: "A6", domain: "Atomicity", claim: "a crash part-way through a mutation leaves consistent state",
236
- status: Status::Proven, evidence: "every_crash_point_leaves_a_clean_prefix",
237
- kind: Evidence::FailureInjection, limitation: "As D6.", source: "#312" },
238
- // ---------------------------------------------------------------- R
239
- Claim { id: "R1", domain: "Recovery", claim: "an incomplete final append is recovered and reported, not silently dropped",
240
- status: Status::Proven, evidence: "an_unterminated_final_record_is_recovered_and_reported",
241
- kind: Evidence::FailureInjection,
242
- limitation: "A KNOWN INCOMPLETE APPEND ONLY. This is not general recovery from \
243
- storage failure.", source: "#309" },
244
- Claim { id: "R2", domain: "Recovery", claim: "a complete but invalid record refuses the open, wherever it sits",
245
- status: Status::Proven, evidence: "a_complete_but_invalid_final_record_refuses_the_open",
246
- kind: Evidence::FailureInjection,
247
- limitation: "Detection and refusal. Damaged records are never repaired.", source: "#309" },
248
- Claim { id: "R3", domain: "Recovery", claim: "damaged ancestry is distinguishable from expired ancestry",
249
- status: Status::Proven, evidence: "damaged_ancestry_is_distinguishable_from_expired_ancestry",
250
- kind: Evidence::ExecutableContract,
251
- limitation: "On inspection of a named revision. See R4.", source: "#306, #307" },
252
- Claim { id: "R4", domain: "Recovery", claim: "ancestry damage is surfaced without being asked for",
253
- status: Status::Unproven, evidence: "", kind: Evidence::None,
254
- limitation: "`parent_of` distinguishes Expired from Missing when a caller asks about \
255
- a specific revision. NOTHING SCANS PROACTIVELY. Detection on inspection is \
256
- not monitoring.", source: "#307" },
257
- // ---------------------------------------------------------------- H
258
- Claim { id: "H1", domain: "History", claim: "history is bounded under a configured policy",
259
- status: Status::Proven, evidence: "repeated_mutation_has_bounded_history",
260
- kind: Evidence::ExecutableContract, limitation: "Count-based policy only.", source: "#306" },
261
- Claim { id: "H2", domain: "History", claim: "history is unbounded without one, by design",
262
- status: Status::Proven, evidence: "the_retention_envelope_behaves_in_both_directions",
263
- kind: Evidence::ExecutableContract,
264
- limitation: "A stated contract, not an omission.", source: "#306" },
265
- Claim { id: "H3", domain: "History", claim: "a policy change takes effect in both directions",
266
- status: Status::Proven, evidence: "the_retention_envelope_behaves_in_both_directions",
267
- kind: Evidence::ExecutableContract,
268
- limitation: "Loosening does not restore what was expired.", source: "#306" },
269
- Claim { id: "H4", domain: "History", claim: "maintenance never rewrites history",
270
- status: Status::Proven, evidence: "maintenance_never_rewrites_history_and_forks_survive",
271
- kind: Evidence::ExecutableContract,
272
- limitation: "Compaction, an unrelated write and a retention pass.", source: "#306" },
273
- Claim { id: "H5", domain: "History", claim: "forked history is preserved",
274
- status: Status::Proven, evidence: "maintenance_never_rewrites_history_and_forks_survive",
275
- kind: Evidence::ExecutableContract, limitation: "Two heads from one base.", source: "#306" },
276
- // ---------------------------------------------------------------- B
277
- Claim { id: "B1", domain: "Backup", claim: "a durable backup artifact is self-contained and independently verifiable",
278
- status: Status::Proven, evidence: "a_backup_is_self_contained_and_outlives_its_source",
279
- kind: Evidence::ExecutableContract,
280
- limitation: "Verified with the source database deleted.", source: "#310" },
281
- Claim { id: "B2", domain: "Backup", claim: "a restore proves the result means the same thing, not merely that it parsed",
282
- status: Status::Proven, evidence: "a_restore_preserves_state_history_forks_retention_and_provenance",
283
- kind: Evidence::ExecutableContract,
284
- limitation: "The meaning digest is recomputed from the restored live database.",
285
- source: "#310" },
286
- Claim { id: "B3", domain: "Backup", claim: "an altered or truncated backup is refused rather than restored",
287
- status: Status::Proven, evidence: "a_single_altered_byte_is_refused",
288
- kind: Evidence::FailureInjection,
289
- limitation: "One altered byte inside a value: still valid JSON, still a valid record.",
290
- source: "#310" },
291
- Claim { id: "B4", domain: "Backup", claim: "a restore will not overwrite an existing database",
292
- status: Status::Proven, evidence: "a_restore_will_not_overwrite_an_existing_database",
293
- kind: Evidence::ExecutableContract,
294
- limitation: "The occupied target is byte-identical afterwards.", source: "#310" },
295
- Claim { id: "B5", domain: "Backup", claim: "backup and restore are exposed as an operator command-line workflow",
296
- status: Status::Unproven, evidence: "", kind: Evidence::None,
297
- limitation: "THE PRIMITIVE WORKING IS NOT A WORKFLOW. `write_backup`, `verify_backup` \
298
- and `restore_backup` are library calls. There is no command, schedule, or \
299
- documented operator procedure. An operator without a Rust toolchain has no \
300
- backup.", source: "#310" },
301
- // ---------------------------------------------------------------- S
302
- Claim { id: "S1", domain: "Replication", claim: "current state replicates to a peer",
303
- status: Status::Proven, evidence: "replication_preserves_revision_history_and_ancestry",
304
- kind: Evidence::ExecutableContract,
305
- limitation: "STATE CONVERGENCE IS NOT HISTORY CONVERGENCE. See S4.", source: "#311" },
306
- Claim { id: "S2", domain: "Replication", claim: "revision history replicates to a peer with identical identities",
307
- status: Status::Proven, evidence: "replication_preserves_revision_history_and_ancestry",
308
- kind: Evidence::ExecutableContract,
309
- limitation: "Reconstructed from operation provenance, not re-minted. Requires the peer \
310
- to send provenance; see S5.", source: "#311" },
311
- Claim { id: "S3", domain: "Replication", claim: "replicated history preserves parents, sequences, forks and provenance",
312
- status: Status::Proven, evidence: "concurrent_authorities_produce_a_fork_that_survives_replication",
313
- kind: Evidence::ExecutableContract,
314
- limitation: "Two authorities, one fork.", source: "#311" },
315
- Claim { id: "S4", domain: "Replication", claim: "state equivalence and historical equivalence are checked separately",
316
- status: Status::Proven, evidence: "same_state_with_different_history_is_detected",
317
- kind: Evidence::ExecutableContract,
318
- limitation: "THE NEGATIVE CONTROL. Two databases with an identical state digest and a \
319
- different history digest. Without this, every other S claim could be \
320
- satisfied by values alone.", source: "#311" },
321
- Claim { id: "S5", domain: "Replication", claim: "a peer that sends no revision provenance contributes no history",
322
- status: Status::Proven, evidence: "an_operation_without_provenance_replicates_state_only",
323
- kind: Evidence::ExecutableContract,
324
- limitation: "A bounded, stated consequence of the field being additive.", source: "#311" },
325
- // ---------------------------------------------------------------- E
326
- Claim { id: "E1", domain: "Envelope", claim: "retention cost per write grows with the retention window",
327
- status: Status::Proven, evidence: "the_retention_envelope_has_the_measured_shape",
328
- kind: Evidence::DeterministicExperiment, limitation: "An ordering, not a number.", source: "#314" },
329
- Claim { id: "E2", domain: "Envelope", claim: "retention increases log size before compaction",
330
- status: Status::Proven, evidence: "the_retention_envelope_has_the_measured_shape",
331
- kind: Evidence::DeterministicExperiment, limitation: "Expiry tombstones. Before compaction only.",
332
- source: "#314" },
333
- Claim { id: "E3", domain: "Envelope", claim: "durability is a selectable contract, and each mode states its guarantee",
334
- status: Status::Proven, evidence: "every_durability_mode_states_its_own_guarantee",
335
- kind: Evidence::ExecutableContract,
336
- limitation: "The wording is asserted not to overstate. It does not make the guarantee true.",
337
- source: "#314" },
338
- Claim { id: "E4", domain: "Envelope", claim: "a stable-storage barrier per write has a measured cost",
339
- status: Status::Proven, evidence: "a_barrier_per_write_costs_more_than_none",
340
- kind: Evidence::DeterministicExperiment,
341
- limitation: "3-4x on the recorded environment. THE COST OF ASKING, NOT PROOF OF LANDING.",
342
- source: "#314" },
343
- Claim { id: "E5", domain: "Envelope", claim: "the durability mode changes the contract and not the stored database",
344
- status: Status::Proven, evidence: "the_durability_mode_does_not_change_what_is_stored",
345
- kind: Evidence::ExecutableContract,
346
- limitation: "Compared on one path, because authority identity is path-derived.",
347
- source: "#314" },
348
- Claim { id: "E6", domain: "Envelope", claim: "the workload envelope is recorded against a frozen workload and a named environment",
349
- status: Status::PartiallyProven, evidence: "a_measurement_carries_the_workload_that_produced_it",
350
- kind: Evidence::Benchmark,
351
- limitation: "DOWNGRADED BY THIS AUDIT. The test asserts the frozen workload half only. \
352
- The environment is recorded in prose in the envelope document and no test \
353
- asserts that a measurement carries it.", source: "#314" },
354
- Claim { id: "E7", domain: "Envelope", claim: "grouped durability is measurably cheaper than a barrier per write",
355
- status: Status::Unproven, evidence: "", kind: Evidence::None,
356
- limitation: "Grouped ran SLOWER than per-write fsync on one of four workloads and faster \
357
- on three. The proven property is that grouping reduces barrier frequency to \
358
- the configured interval, which is a contract, not a speed.", source: "#314" },
359
- // ---------------------------------------------------------------- U
360
- Claim { id: "U1", domain: "Format", claim: "an incompatible durable format is detected before any record is interpreted",
361
- status: Status::Proven, evidence: "pre_306_database_does_not_open_as_empty_history",
362
- kind: Evidence::FailureInjection,
363
- limitation: "A read-only probe runs before the open.", source: "#308" },
364
- Claim { id: "U2", domain: "Format", claim: "a pre-model database's revision history is losslessly migratable",
365
- status: Status::NotApplicable, evidence: "migration_is_refused_because_the_resource_was_never_recorded",
366
- kind: Evidence::ExecutableContract,
367
- limitation: "IMPOSSIBLE, NOT UNIMPLEMENTED. A legacy revision never recorded its \
368
- resource, so which history it belongs to is not in the data. Migration \
369
- would have to invent it.", source: "#308" },
370
- Claim { id: "U3", domain: "Format", claim: "a persisted durable format version exists and is checked on open",
371
- status: Status::Proven, evidence: "a_new_database_declares_its_format",
372
- kind: Evidence::ExecutableContract,
373
- limitation: "New logs and compaction headers. An unversioned database with no legacy \
374
- revisions opens by design.", source: "#308" },
375
- Claim { id: "U4", domain: "Format", claim: "a refused open leaves the database byte-identical",
376
- status: Status::Proven, evidence: "pre_306_database_does_not_open_as_empty_history",
377
- kind: Evidence::FailureInjection,
378
- limitation: "Bytes compared before and after. Made unconditional by making the log \
379
- reader read-only until replay succeeds.", source: "#308, #309" },
380
- Claim { id: "U5", domain: "Format", claim: "a durable format from a newer build is refused",
381
- status: Status::Proven, evidence: "a_newer_durable_format_is_refused",
382
- kind: Evidence::FailureInjection,
383
- limitation: "The rollback direction, exercised by a synthesised future version.",
384
- source: "#308" },
385
- Claim { id: "U6", domain: "Format", claim: "a snapshot from another format is refused",
386
- status: Status::Proven, evidence: "a_snapshot_from_another_format_is_refused",
387
- kind: Evidence::ExecutableContract,
388
- limitation: "Snapshots are a second durable ingress and carry their own version.",
389
- source: "#308" },
390
- // ---------------------------------------------------------------- O
391
- Claim { id: "O1", domain: "Observability", claim: "an operator can inspect history and retention state",
392
- status: Status::PartiallyProven, evidence: "revision_retention_bounds_a_resources_history",
393
- kind: Evidence::ExecutableContract,
394
- limitation: "Per resource only. Nothing aggregates, so \"is any ancestry anywhere \
395
- damaged?\" means walking every revision.", source: "#313" },
396
- Claim { id: "O2", domain: "Observability", claim: "reported health reflects actual storage state",
397
- status: Status::PartiallyProven, evidence: "a_clean_open_reports_clean_storage",
398
- kind: Evidence::ExecutableContract,
399
- limitation: "DOWNGRADED BY THIS AUDIT. The library value and the server's status \
400
- derivation are each tested, but no test exercises the HTTP endpoint. That \
401
- the handler composes them is established by inspection.", source: "#313" },
402
- Claim { id: "O3", domain: "Observability", claim: "a recovered open is distinguishable from a clean one in health",
403
- status: Status::Proven, evidence: "a_recovered_open_does_not_report_the_same_health_as_a_clean_one",
404
- kind: Evidence::ExecutableContract,
405
- limitation: "At the library boundary.", source: "#313" },
406
- Claim { id: "O4", domain: "Observability", claim: "health reports only conditions that were observed",
407
- status: Status::Proven, evidence: "health_reports_only_conditions_that_were_observed",
408
- kind: Evidence::ExecutableContract,
409
- limitation: "Asserts no storage label says `durable` or `healthy`.", source: "#313" },
410
- Claim { id: "O5", domain: "Observability", claim: "the remaining health fields are compile-time constants",
411
- status: Status::PartiallyProven, evidence: "crates/feltdb-server/src/main.rs:HealthResponse",
412
- kind: Evidence::ImplementationInspection,
413
- limitation: "`runtime`, `fabric`, `workflows` and `agents` are still constants. \
414
- Recorded, not fixed: each needs an operational contract first.",
415
- source: "#313" },
416
- // ---------------------------------------------------------------- M
417
- Claim { id: "M1", domain: "Managed incident", claim: "a timer-driven compaction defers the log rewrite",
418
- status: Status::Proven, evidence: "the_default_policy_does_not_rewrite_on_a_handful_of_operations",
419
- kind: Evidence::ExecutableContract,
420
- limitation: "Ten timer ticks over a small database cause zero rewrites. THIS DOES NOT \
421
- MAKE COMPACTION NON-BLOCKING; see M6.", source: "6b550ea" },
422
- Claim { id: "M2", domain: "Managed incident", claim: "an explicit compaction still rewrites immediately",
423
- status: Status::Proven, evidence: "an_explicit_compaction_still_rewrites_now",
424
- kind: Evidence::ExecutableContract,
425
- limitation: "The policy governs the timer, not a caller. Every prior call site keeps \
426
- its behaviour.", source: "6b550ea" },
427
- Claim { id: "M3", domain: "Managed incident", claim: "deferring the rewrite preserves state and history",
428
- status: Status::Proven, evidence: "deferring_the_rewrite_preserves_state_and_history",
429
- kind: Evidence::ExecutableContract,
430
- limitation: "State and history digests across a reopen. The log stays longer than \
431
- needed, which is the accepted cost.", source: "6b550ea" },
432
- Claim { id: "M4", domain: "Managed incident", claim: "an overload is refused with a status, a code and a retry hint",
433
- status: Status::Proven, evidence: "an_overload_is_an_explicit_refusal_with_a_retry_hint",
434
- kind: Evidence::ExecutableContract,
435
- limitation: "The refusal's shape is asserted. THAT THE BOUND AND DEADLINE FIRE UNDER \
436
- REAL LOAD IS NOT TESTED; there is no load harness.", source: "6b550ea" },
437
- Claim { id: "M5", domain: "Managed incident", claim: "a bounded search visits only as many rows as its limit",
438
- status: Status::Proven, evidence: "a_bounded_search_stops_at_the_limit_instead_of_scanning",
439
- kind: Evidence::ExecutableContract,
440
- limitation: "500 rows, limit 10, exactly 10 predicate visits. THIS BOUNDS THE SEARCH \
441
- AND PROVENANCE PATHS ONLY, not every read in the database.",
442
- source: "6b550ea" },
443
- Claim { id: "M6", domain: "Managed incident", claim: "compaction no longer blocks the database",
444
- status: Status::Unproven, evidence: "", kind: Evidence::None,
445
- limitation: "EXPLICITLY NOT CLAIMED. A rewrite still holds the global lock for its \
446
- duration; it merely happens rarely and off the runtime. A large enough \
447
- database will still stall while one runs. `the_rewrite_cost_grows_with_the_\
448
- database` measures that it grows.", source: "6b550ea" },
449
- Claim { id: "M7", domain: "Managed incident", claim: "readiness performs a real scoped storage probe",
450
- status: Status::PartiallyProven, evidence: "a_recovered_open_does_not_report_the_same_health_as_a_clean_one",
451
- kind: Evidence::ImplementationInspection,
452
- limitation: "The storage conditions it reports are tested at the library boundary. \
453
- THE `/health/ready` HANDLER ITSELF IS NOT EXERCISED BY A TEST, including \
454
- the STORAGE_STALLED path; there is no HTTP-level harness.",
455
- source: "6b550ea" },
456
- Claim { id: "M8", domain: "Managed incident", claim: "scoped reads stay correct and bounded while a compaction runs",
457
- status: Status::Proven, evidence: "scoped_reads_stay_correct_and_bounded_while_compaction_runs",
458
- kind: Evidence::ExecutableContract,
459
- limitation: "The composed shape, not the isolated fixes. NO LATENCY IS MEASURED, so \
460
- this is not evidence that the incident cannot recur; see M6.",
461
- source: "#315" },
462
- Claim { id: "M9", domain: "Managed incident", claim: "a compaction concurrent with traffic leaves the database intact",
463
- status: Status::Proven, evidence: "a_concurrent_compaction_leaves_the_database_intact",
464
- kind: Evidence::ExecutableContract,
465
- limitation: "Correctness under concurrency, including a forced rewrite and a reopen. \
466
- Says nothing about how long anything waited.",
467
- source: "#315" },
468
- ];
469
-
470
- fn matrix() -> BTreeMap<&'static str, &'static Claim> {
471
- CERTIFICATION.iter().map(|c| (c.id, c)).collect()
472
- }
473
-
474
- /// Every test named as evidence, gathered from the test sources on disk.
475
- /// Resolve a claim's `evidence` field to something that actually exists.
476
- ///
477
- /// Two citation forms are permitted, and the permitted form depends on the
478
- /// evidence *kind*:
479
- ///
480
- /// - a **test function name**, which must be a `fn` in this repository's test
481
- /// suites (or in the server crate, which holds its tests inline);
482
- /// - a **source location** of the form `path/to/file.rs:Symbol`, permitted only
483
- /// for `ImplementationInspection`, where there is by definition no test. The
484
- /// file must exist and must contain the named symbol.
485
- ///
486
- /// The restriction is the point: a claim may not dodge the test requirement by
487
- /// citing a source file. Only a claim that has already been marked as resting
488
- /// on inspection — and which `inspection_alone_never_proves_a_behavioural_claim`
489
- /// therefore forbids from being `Proven` — may cite one.
490
- fn evidence_resolves(claim: &Claim, known: &[String]) -> bool {
491
- match claim.evidence.split_once(".rs:") {
492
- Some((file, symbol)) if claim.kind == Evidence::ImplementationInspection => {
493
- let path = std::path::Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/../.."))
494
- .join(format!("{file}.rs"));
495
- match std::fs::read_to_string(path) {
496
- Ok(source) => source.contains(symbol),
497
- Err(_) => false,
498
- }
499
- }
500
- Some(_) => false,
501
- None => known.iter().any(|f| f == claim.evidence),
502
- }
503
- }
504
-
505
- /// A tripwire that cannot fire is decoration, so the mention/assertion rule has
506
- /// its own negative control.
507
- #[test]
508
- fn the_forbidden_phrase_rule_separates_assertion_from_mention() {
509
- // Asserted: flagged.
510
- assert!(common::asserts_phrase(
511
- "feltdb is power-loss safe.",
512
- "power-loss safe"
513
- ));
514
- assert!(common::asserts_phrase(
515
- "a mention of \"power-loss safe\" here, but the next line is not.\n\
516
- and feltdb is power-loss safe.",
517
- "power-loss safe"
518
- ));
519
-
520
- // Merely named: not flagged.
521
- assert!(!common::asserts_phrase(
522
- "a test asserts no mode's wording contains \"power-loss safe\".",
523
- "power-loss safe"
524
- ));
525
- assert!(!common::asserts_phrase(
526
- "the phrase `power-loss safe` appears nowhere in the api.",
527
- "power-loss safe"
528
- ));
529
-
530
- // An unbalanced delimiter must not silence the line it opens.
531
- assert!(common::asserts_phrase(
532
- "the \"mode is power-loss safe",
533
- "power-loss safe"
534
- ));
535
-
536
- // Absent: not flagged.
537
- assert!(!common::asserts_phrase(
538
- "flushed is not synced.",
539
- "power-loss safe"
540
- ));
541
- }
542
-
543
- /// The published document, read from disk.
544
- fn published_document() -> String {
545
- let path = concat!(
546
- env!("CARGO_MANIFEST_DIR"),
547
- "/../../docs/architecture/production-certification.md"
548
- );
549
- std::fs::read_to_string(path).expect("the certification document exists and is readable")
550
- }
551
-
552
- /// The status counts the document publishes, read out of its summary table.
553
- fn published_counts() -> BTreeMap<String, usize> {
554
- let mut counts = BTreeMap::new();
555
- for line in published_document().lines() {
556
- let Some(cells) = common::table_cells(line) else {
557
- continue;
558
- };
559
- if cells.len() != 2 {
560
- continue;
561
- }
562
- let label = cells[0].clone();
563
- if !Status::ALL.iter().any(|status| status.label() == label) {
564
- continue;
565
- }
566
- let Ok(count) = cells[1].parse::<usize>() else {
567
- continue;
568
- };
569
- assert!(
570
- counts.insert(label.clone(), count).is_none(),
571
- "the document publishes the count for `{label}` more than once"
572
- );
573
- }
574
- counts
575
- }
576
-
577
- /// One claim row as the document renders it.
578
- struct PublishedRow {
579
- status: String,
580
- evidence: String,
581
- kind: String,
582
- source: String,
583
- }
584
-
585
- /// Every claim row in the document, keyed by claim id.
586
- fn published_rows() -> BTreeMap<String, PublishedRow> {
587
- let mut rows = BTreeMap::new();
588
- for line in published_document().lines() {
589
- let Some(cells) = common::table_cells(line) else {
590
- continue;
591
- };
592
- // id | domain | claim | status | evidence | kind | limitation | source
593
- if cells.len() != 8 {
594
- continue;
595
- }
596
- let id = cells[0].clone();
597
- let looks_like_a_claim_id = id.len() >= 2
598
- && id.starts_with(|c: char| c.is_ascii_uppercase())
599
- && id[1..].chars().all(|c| c.is_ascii_digit());
600
- if !looks_like_a_claim_id {
601
- continue;
602
- }
603
- assert!(
604
- rows.insert(
605
- id.clone(),
606
- PublishedRow {
607
- status: cells[3].clone(),
608
- // An em dash is the document's rendering of "no evidence".
609
- evidence: if cells[4] == "—" {
610
- String::new()
611
- } else {
612
- cells[4].clone()
613
- },
614
- kind: cells[5].clone(),
615
- source: cells[7].clone(),
616
- },
617
- )
618
- .is_none(),
619
- "the document publishes claim `{id}` more than once"
620
- );
621
- }
622
- rows
623
- }
624
-
625
- fn known_test_functions() -> Vec<String> {
626
- let mut found = Vec::new();
627
- let root = concat!(env!("CARGO_MANIFEST_DIR"), "/tests");
628
- for entry in std::fs::read_dir(root).expect("the tests directory is readable") {
629
- let path = entry.expect("a readable entry").path();
630
- if path.extension().and_then(|e| e.to_str()) != Some("rs") {
631
- continue;
632
- }
633
- let source = std::fs::read_to_string(&path).expect("a readable test file");
634
- for line in source.lines() {
635
- if let Some(rest) = line.trim().strip_prefix("fn ") {
636
- if let Some(name) = rest.split('(').next() {
637
- found.push(name.to_string());
638
- }
639
- }
640
- }
641
- }
642
- // The server crate holds the admission and health-status tests.
643
- let server = concat!(env!("CARGO_MANIFEST_DIR"), "/../feltdb-server/src/main.rs");
644
- if let Ok(source) = std::fs::read_to_string(server) {
645
- for line in source.lines() {
646
- if let Some(rest) = line.trim().strip_prefix("fn ") {
647
- if let Some(name) = rest.split('(').next() {
648
- found.push(name.to_string());
649
- }
650
- }
651
- }
652
- }
653
- found
654
- }
655
-
656
- // ===========================================================================
657
- // Matrix integrity
658
- // ===========================================================================
659
-
660
- /// The statuses an earlier ledger records for the same claims.
661
- ///
662
- /// Parsed rather than duplicated, so this cannot drift from the file it reads.
663
- fn readiness_ledger() -> BTreeMap<String, String> {
664
- let readiness = include_str!("production_readiness_contract.rs");
665
- let start = readiness
666
- .find("const CLAIMS")
667
- .expect("the readiness contract declares CLAIMS");
668
- let end = start
669
- + readiness[start..]
670
- .find("];")
671
- .expect("the CLAIMS table terminates");
672
- let table = &readiness[start..end];
673
-
674
- let mut ledger = BTreeMap::new();
675
- let mut pending: Option<String> = None;
676
- for line in table.lines() {
677
- let trimmed = line.trim().trim_start_matches('(').trim();
678
- if let Some(rest) = trimmed.strip_prefix('"') {
679
- if let Some(id) = rest.split(' ').next() {
680
- if id.len() >= 2 {
681
- pending = Some(id.to_string());
682
- }
683
- }
684
- }
685
- if let Some(index) = line.find("Status::") {
686
- let status: String = line[index + "Status::".len()..]
687
- .chars()
688
- .take_while(|character| character.is_alphanumeric())
689
- .collect();
690
- if let Some(id) = pending.take() {
691
- ledger.insert(id, status);
692
- }
693
- }
694
- }
695
- ledger
696
- }
697
-
698
- /// **Every disagreement with an earlier ledger is declared.**
699
- ///
700
- /// This is the tripwire that makes recalculation safe. Re-deriving a claim from
701
- /// current evidence is only honest if a changed answer is visible; otherwise two
702
- /// files quietly assert different things and the reader believes whichever they
703
- /// opened first.
704
- ///
705
- /// It fails three ways. A claim whose status differs and is not in `DOWNGRADES`
706
- /// fails. A declared downgrade whose earlier ledger no longer records the prior
707
- /// status fails — so closing the gap for real forces this table to be updated
708
- /// rather than left as a stale accusation. And a declared change that makes a
709
- /// claim *stronger* fails, because new evidence is not a downgrade and must not
710
- /// be recorded as one.
711
- #[test]
712
- fn every_disagreement_with_an_earlier_ledger_is_declared() {
713
- let ledger = readiness_ledger();
714
- let certified = matrix();
715
- assert!(
716
- ledger.len() > 40,
717
- "the readiness ledger did not parse; it yielded {} entries",
718
- ledger.len()
719
- );
720
-
721
- let mut problems = Vec::new();
722
-
723
- for (id, earlier) in &ledger {
724
- let Some(claim) = certified.get(id.as_str()) else {
725
- continue;
726
- };
727
- let now = claim.status.variant();
728
- if now == earlier {
729
- continue;
730
- }
731
- match DOWNGRADES.iter().find(|(claim_id, ..)| claim_id == id) {
732
- None => problems.push(format!(
733
- "{id}: the readiness ledger records `{earlier}`, this audit records `{now}`, \
734
- and the disagreement is not declared"
735
- )),
736
- Some((_, from, to, _)) => {
737
- if from != earlier {
738
- problems.push(format!(
739
- "{id}: declared as a downgrade from `{from}`, but the readiness ledger \
740
- now records `{earlier}`"
741
- ));
742
- }
743
- if to != &now {
744
- problems.push(format!(
745
- "{id}: declared as a downgrade to `{to}`, but this audit records `{now}`"
746
- ));
747
- }
748
- }
749
- }
750
- }
751
-
752
- for (id, from, to, why) in DOWNGRADES {
753
- let claim = certified
754
- .get(id)
755
- .unwrap_or_else(|| panic!("{id} is declared as a downgrade and is not in the matrix"));
756
- assert_eq!(
757
- claim.status.variant(),
758
- *to,
759
- "{id} is declared as a downgrade to `{to}`"
760
- );
761
- assert_eq!(
762
- ledger.get(*id).map(String::as_str),
763
- Some(*from),
764
- "{id} is declared as a downgrade from `{from}`; the earlier ledger disagrees"
765
- );
766
- assert!(
767
- !why.trim().is_empty(),
768
- "{id} is declared as a downgrade with no reason"
769
- );
770
-
771
- let stronger = Status::ALL
772
- .iter()
773
- .find(|status| status.variant() == *from)
774
- .expect("a declared prior status is a real status");
775
- assert!(
776
- claim.status.strength() < stronger.strength(),
777
- "{id} is declared as a downgrade but `{to}` is not weaker than `{from}`"
778
- );
779
- }
780
-
781
- assert!(problems.is_empty(), "{}", problems.join("\n"));
782
- }
783
-
784
- /// Claim identifiers are unique.
785
- #[test]
786
- fn every_claim_has_a_unique_identifier() {
787
- assert_eq!(
788
- matrix().len(),
789
- CERTIFICATION.len(),
790
- "a claim identifier is used twice"
791
- );
792
- }
793
-
794
- /// **Every `Proven` claim names a test that exists.**
795
- ///
796
- /// The central tripwire. A claim cannot be `Proven` on the strength of an
797
- /// implementation existing, of another claim, or of a test that was renamed or
798
- /// deleted.
799
- #[test]
800
- fn every_proven_claim_names_a_test_that_exists() {
801
- let known = known_test_functions();
802
- let mut problems = Vec::new();
803
-
804
- for claim in CERTIFICATION {
805
- let proven = claim.status == Status::Proven;
806
- if proven && claim.evidence.is_empty() {
807
- problems.push(format!("{}: Proven with no named evidence", claim.id));
808
- continue;
809
- }
810
- if !claim.evidence.is_empty() && !evidence_resolves(claim, &known) {
811
- problems.push(format!(
812
- "{}: names `{}`, which resolves to nothing in this repository",
813
- claim.id, claim.evidence
814
- ));
815
- }
816
- if proven && claim.kind == Evidence::None {
817
- problems.push(format!("{}: Proven with evidence kind None", claim.id));
818
- }
819
- }
820
-
821
- assert!(problems.is_empty(), "{}", problems.join("\n"));
822
- }
823
-
824
- /// **Implementation inspection alone never carries a `Proven` behavioural
825
- /// claim.**
826
- ///
827
- /// Reading the code establishes what the code says, not what it does under a
828
- /// condition nobody has run.
829
- #[test]
830
- fn inspection_alone_never_proves_a_behavioural_claim() {
831
- for claim in CERTIFICATION {
832
- if claim.kind == Evidence::ImplementationInspection {
833
- assert_ne!(
834
- claim.status,
835
- Status::Proven,
836
- "{} is Proven on implementation inspection alone: {}",
837
- claim.id,
838
- claim.claim
839
- );
840
- }
841
- }
842
- }
843
-
844
- /// Every claim that is not fully `Proven` says what is missing, and every
845
- /// claim with no evidence has no evidence kind.
846
- #[test]
847
- fn every_claim_states_its_limitation() {
848
- for claim in CERTIFICATION {
849
- assert!(
850
- !claim.limitation.trim().is_empty(),
851
- "{} has no stated limitation",
852
- claim.id
853
- );
854
- if claim.evidence.is_empty() {
855
- assert_eq!(
856
- claim.kind,
857
- Evidence::None,
858
- "{} names no evidence but claims a kind",
859
- claim.id
860
- );
861
- }
862
- }
863
- }
864
-
865
- /// The certification covers every claim the readiness contract declares.
866
- ///
867
- /// The two files are kept in step mechanically rather than by memory: a claim
868
- /// added to one and forgotten in the other fails here.
869
- #[test]
870
- fn the_certification_covers_the_readiness_contract() {
871
- let readiness = include_str!("production_readiness_contract.rs");
872
- let start = readiness
873
- .find("const CLAIMS")
874
- .expect("the readiness contract declares CLAIMS");
875
- let end = readiness[start..]
876
- .find("];")
877
- .map(|offset| start + offset)
878
- .expect("the CLAIMS table terminates");
879
- let table = &readiness[start..end];
880
-
881
- let certified = matrix();
882
- let mut missing = Vec::new();
883
- for line in table.lines() {
884
- let trimmed = line.trim();
885
- let Some(rest) = trimmed.strip_prefix('"') else {
886
- continue;
887
- };
888
- let Some(id) = rest.split(' ').next() else {
889
- continue;
890
- };
891
- if id.len() >= 2 && !certified.contains_key(id) {
892
- missing.push(id.to_string());
893
- }
894
- }
895
- missing.sort();
896
- missing.dedup();
897
- assert!(
898
- missing.is_empty(),
899
- "declared in the readiness contract and absent from the certification: {missing:?}"
900
- );
901
- }
902
-
903
- // ===========================================================================
904
- // Claim-inflation tripwires
905
- // ===========================================================================
906
-
907
- /// **The substitutions this certification refuses to make.**
908
- ///
909
- /// Each pair is a real temptation, and each has been available at some point in
910
- /// this work. Encoding them means a future change cannot make the stronger
911
- /// claim by editing a status.
912
- #[test]
913
- fn no_claim_is_inflated_into_a_stronger_one() {
914
- let certified = matrix();
915
- let must_not_be_proven = [
916
- (
917
- "D5",
918
- "a barrier being issued is not the hardware preserving data",
919
- ),
920
- (
921
- "E7",
922
- "a configured grouping interval is not a measured speed advantage",
923
- ),
924
- (
925
- "B5",
926
- "a working library primitive is not an operator workflow",
927
- ),
928
- ("R4", "detection on inspection is not proactive monitoring"),
929
- ("M6", "a deferred rewrite is not a non-blocking compaction"),
930
- ];
931
-
932
- for (id, why) in must_not_be_proven {
933
- let claim = certified
934
- .get(id)
935
- .unwrap_or_else(|| panic!("{id} is missing"));
936
- assert_ne!(
937
- claim.status,
938
- Status::Proven,
939
- "{id} must not be Proven: {why}"
940
- );
941
- }
942
-
943
- // State convergence must never stand in for history convergence: the claim
944
- // that separates them has to remain Proven and independently evidenced.
945
- let separation = certified.get("S4").expect("S4 exists");
946
- assert_eq!(separation.status, Status::Proven);
947
- assert_eq!(
948
- separation.evidence, "same_state_with_different_history_is_detected",
949
- "the negative control is what keeps every other replication claim honest"
950
- );
951
- assert_ne!(
952
- certified.get("S1").unwrap().evidence,
953
- separation.evidence,
954
- "state convergence and history convergence must not rest on one test"
955
- );
956
- }
957
-
958
- /// **No document claims a guarantee the matrix does not permit.**
959
- ///
960
- /// Documentation drifts faster than tests. These phrases would each assert
961
- /// something the evidence does not support, so their absence is checked rather
962
- /// than trusted.
963
- #[test]
964
- fn no_document_asserts_a_guarantee_the_matrix_withholds() {
965
- let docs = concat!(env!("CARGO_MANIFEST_DIR"), "/../../docs/architecture");
966
- let forbidden = [
967
- "power-loss safe",
968
- "power loss safe",
969
- "guaranteed durable",
970
- "compaction is non-blocking",
971
- "compaction no longer blocks",
972
- "all reads are bounded",
973
- "supported capacity",
974
- ];
975
-
976
- let mut violations = Vec::new();
977
- for entry in std::fs::read_dir(docs).expect("the architecture docs are readable") {
978
- let path = entry.expect("a readable entry").path();
979
- if path.extension().and_then(|e| e.to_str()) != Some("md") {
980
- continue;
981
- }
982
- let document = std::fs::read_to_string(&path).expect("a readable document");
983
- let prose = common::prose_excluding_withheld_rows(&document, WITHHELD_LABELS);
984
- for phrase in forbidden {
985
- if common::asserts_phrase(&prose, phrase) {
986
- violations.push(format!(
987
- "{}: asserts \"{phrase}\"",
988
- path.file_name().unwrap().to_string_lossy()
989
- ));
990
- }
991
- }
992
- }
993
- assert!(violations.is_empty(), "{}", violations.join("\n"));
994
- }
995
-
996
- // ===========================================================================
997
- // Derived counts
998
- // ===========================================================================
999
-
1000
- /// Counts are computed from the matrix, never maintained by hand.
1001
- ///
1002
- /// The numbers below are the certification's published totals. They are
1003
- /// asserted so the document and the table cannot disagree.
1004
- #[test]
1005
- fn the_published_counts_are_derived_from_the_matrix() {
1006
- let mut derived: BTreeMap<&str, usize> = BTreeMap::new();
1007
- for status in Status::ALL {
1008
- derived.insert(status.label(), 0);
1009
- }
1010
- for claim in CERTIFICATION {
1011
- *derived.entry(claim.status.label()).or_default() += 1;
1012
- }
1013
-
1014
- let total: usize = derived.values().sum();
1015
- assert_eq!(
1016
- total,
1017
- CERTIFICATION.len(),
1018
- "every claim has exactly one status"
1019
- );
1020
-
1021
- // The document may not carry a total of its own. Each count it publishes is
1022
- // checked against the count computed here, and every status must appear —
1023
- // so a bucket cannot be quietly dropped from the published summary because
1024
- // it is inconvenient.
1025
- let published = published_counts();
1026
- for (label, count) in &derived {
1027
- let shown = published.get(*label).copied().unwrap_or_else(|| {
1028
- panic!("the certification document publishes no count for `{label}`")
1029
- });
1030
- assert_eq!(
1031
- shown, *count,
1032
- "the document publishes {shown} `{label}` claims; the matrix holds {count}"
1033
- );
1034
- }
1035
- assert_eq!(
1036
- published.len(),
1037
- derived.len(),
1038
- "the document publishes a status the matrix does not define"
1039
- );
1040
- }
1041
-
1042
- /// The published matrix is a rendering of the executable one, not a second
1043
- /// record of the same facts.
1044
- ///
1045
- /// Every claim must appear in the document with the same status, the same
1046
- /// evidence and the same source. A downgrade that lands in the test file and
1047
- /// not in the document — or the reverse — fails here.
1048
- #[test]
1049
- fn the_published_matrix_matches_the_executable_matrix() {
1050
- let rows = published_rows();
1051
- let mut problems = Vec::new();
1052
-
1053
- for claim in CERTIFICATION {
1054
- match rows.get(claim.id) {
1055
- None => problems.push(format!("{}: absent from the document", claim.id)),
1056
- Some(row) => {
1057
- if row.status != claim.status.label() {
1058
- problems.push(format!(
1059
- "{}: the document says `{}`, the matrix says `{}`",
1060
- claim.id,
1061
- row.status,
1062
- claim.status.label()
1063
- ));
1064
- }
1065
- if row.evidence != claim.evidence {
1066
- problems.push(format!(
1067
- "{}: the document cites `{}`, the matrix cites `{}`",
1068
- claim.id, row.evidence, claim.evidence
1069
- ));
1070
- }
1071
- if row.kind != claim.kind.label() {
1072
- problems.push(format!(
1073
- "{}: the document types the evidence `{}`, the matrix types it `{}`",
1074
- claim.id,
1075
- row.kind,
1076
- claim.kind.label()
1077
- ));
1078
- }
1079
- if row.source != claim.source {
1080
- problems.push(format!(
1081
- "{}: the document sources `{}`, the matrix sources `{}`",
1082
- claim.id, row.source, claim.source
1083
- ));
1084
- }
1085
- }
1086
- }
1087
- }
1088
-
1089
- for id in rows.keys() {
1090
- if !CERTIFICATION.iter().any(|claim| &claim.id == id) {
1091
- problems.push(format!("{id}: in the document, absent from the matrix"));
1092
- }
1093
- }
1094
-
1095
- assert!(problems.is_empty(), "{}", problems.join("\n"));
1096
- }
1097
-
1098
- /// Every domain the certification covers is represented, and the managed
1099
- /// incident is among them.
1100
- #[test]
1101
- fn every_domain_is_represented_including_the_managed_incident() {
1102
- let mut domains: BTreeMap<&str, usize> = BTreeMap::new();
1103
- for claim in CERTIFICATION {
1104
- *domains.entry(claim.domain).or_default() += 1;
1105
- }
1106
- for domain in [
1107
- "Durability",
1108
- "Atomicity",
1109
- "Recovery",
1110
- "History",
1111
- "Backup",
1112
- "Replication",
1113
- "Envelope",
1114
- "Format",
1115
- "Observability",
1116
- "Managed incident",
1117
- ] {
1118
- assert!(
1119
- domains.contains_key(domain),
1120
- "the certification has no {domain} claims"
1121
- );
1122
- }
1123
- assert_eq!(
1124
- domains.get("Managed incident").copied().unwrap_or(0),
1125
- 9,
1126
- "the incident remediation shipped with tests and no matrix entry; it has one now, \
1127
- plus the two composed-shape claims this audit added"
1128
- );
1129
- }
1130
-
1131
- /// The intentional gaps are still gaps.
1132
- ///
1133
- /// A certification whose Unproven claims quietly disappear is worse than one
1134
- /// that keeps them. Each of these must remain present and unproven until real
1135
- /// evidence exists.
1136
- #[test]
1137
- fn the_known_gaps_have_not_disappeared() {
1138
- let certified = matrix();
1139
- for id in ["D5", "E7", "B5", "R4", "M6"] {
1140
- let claim = certified
1141
- .get(id)
1142
- .unwrap_or_else(|| panic!("{id} was removed from the certification"));
1143
- assert_eq!(
1144
- claim.status,
1145
- Status::Unproven,
1146
- "{id} changed status without new evidence"
1147
- );
1148
- assert!(
1149
- claim.evidence.is_empty(),
1150
- "{id} names evidence but is still Unproven"
1151
- );
1152
- }
1153
- }