@feltdb/core 0.8.4 → 0.8.6

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 (160) hide show
  1. package/dist/create/package-versions.js +1 -1
  2. package/dist/create/server-source/Cargo.lock +165 -0
  3. package/dist/create/server-source/Cargo.toml +9 -0
  4. package/dist/create/server-source/crates/feltdb/Cargo.toml +3 -0
  5. package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +44 -44
  6. package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +12 -24
  7. package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +7 -13
  8. package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +13 -10
  9. package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +12 -9
  10. package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +78 -25
  11. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +16 -13
  12. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +13 -5
  13. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +41 -22
  14. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +33 -15
  15. package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +100 -33
  16. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +56 -20
  17. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +116 -41
  18. package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +186 -55
  19. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +64 -26
  20. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +46 -15
  21. package/dist/create/server-source/crates/feltdb/src/admission.rs +8 -15
  22. package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +43 -13
  23. package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +15 -42
  24. package/dist/create/server-source/crates/feltdb/src/analytics.rs +65 -19
  25. package/dist/create/server-source/crates/feltdb/src/application.rs +113 -30
  26. package/dist/create/server-source/crates/feltdb/src/authorization_security_tests.rs +475 -140
  27. package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +17 -15
  28. package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +0 -1
  29. package/dist/create/server-source/crates/feltdb/src/causal_backlog_bound.rs +59 -15
  30. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +266 -114
  31. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +25 -7
  32. package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +10 -15
  33. package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +3 -11
  34. package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +14 -5
  35. package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +21 -25
  36. package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +14 -11
  37. package/dist/create/server-source/crates/feltdb/src/dedup_bound_investigation.rs +103 -22
  38. package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +18 -15
  39. package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +12 -8
  40. package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +1 -5
  41. package/dist/create/server-source/crates/feltdb/src/durable_operation_identity.rs +87 -23
  42. package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +3 -7
  43. package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +10 -9
  44. package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +1 -6
  45. package/dist/create/server-source/crates/feltdb/src/indexing.rs +35 -38
  46. package/dist/create/server-source/crates/feltdb/src/lib.rs +1648 -46
  47. package/dist/create/server-source/crates/feltdb/src/managed_cas_tests.rs +4 -1
  48. package/dist/create/server-source/crates/feltdb/src/metrics.rs +0 -1
  49. package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +1 -2
  50. package/dist/create/server-source/crates/feltdb/src/multi_operation_transaction.rs +107 -30
  51. package/dist/create/server-source/crates/feltdb/src/observability.rs +19 -6
  52. package/dist/create/server-source/crates/feltdb/src/operation.rs +39 -0
  53. package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +12 -11
  54. package/dist/create/server-source/crates/feltdb/src/operation_log.rs +9 -4
  55. package/dist/create/server-source/crates/feltdb/src/p1_application_atomicity.rs +65 -18
  56. package/dist/create/server-source/crates/feltdb/src/p1_atomicity_acceptance.rs +193 -57
  57. package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +37 -27
  58. package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +38 -10
  59. package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +20 -14
  60. package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +394 -229
  61. package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +8 -6
  62. package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +11 -13
  63. package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +79 -70
  64. package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +3 -3
  65. package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +33 -11
  66. package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +6 -6
  67. package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +14 -56
  68. package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +29 -27
  69. package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +35 -17
  70. package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +8 -2
  71. package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +59 -15
  72. package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +70 -17
  73. package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +23 -6
  74. package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +12 -3
  75. package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +41 -11
  76. package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +56 -25
  77. package/dist/create/server-source/crates/feltdb/src/policy_evaluation.rs +701 -245
  78. package/dist/create/server-source/crates/feltdb/src/production_api.rs +31 -13
  79. package/dist/create/server-source/crates/feltdb/src/query_performance.rs +6 -8
  80. package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +5 -5
  81. package/dist/create/server-source/crates/feltdb/src/replica_acknowledgements.rs +48 -18
  82. package/dist/create/server-source/crates/feltdb/src/replica_membership.rs +30 -11
  83. package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +6 -3
  84. package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +4 -3
  85. package/dist/create/server-source/crates/feltdb/src/sharding.rs +36 -10
  86. package/dist/create/server-source/crates/feltdb/src/state_conflict_contract.rs +516 -0
  87. package/dist/create/server-source/crates/feltdb/src/state_contract.rs +13 -4
  88. package/dist/create/server-source/crates/feltdb/src/state_diff_contract.rs +222 -0
  89. package/dist/create/server-source/crates/feltdb/src/state_facade.rs +82 -54
  90. package/dist/create/server-source/crates/feltdb/src/state_hash.rs +2 -2
  91. package/dist/create/server-source/crates/feltdb/src/state_model.rs +1565 -536
  92. package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +6 -3
  93. package/dist/create/server-source/crates/feltdb/src/state_trigger.rs +672 -0
  94. package/dist/create/server-source/crates/feltdb/src/storage.rs +9 -3
  95. package/dist/create/server-source/crates/feltdb/src/submission.rs +5 -11
  96. package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +6 -8
  97. package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +24 -35
  98. package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +24 -8
  99. package/dist/create/server-source/crates/feltdb/src/transaction_preconditions.rs +248 -59
  100. package/dist/create/server-source/crates/feltdb/src/transactions.rs +17 -20
  101. package/dist/create/server-source/crates/feltdb/src/trigger_contract.rs +749 -0
  102. package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +1 -0
  103. package/dist/create/server-source/crates/feltdb/src/workload.rs +512 -4
  104. package/dist/create/server-source/crates/feltdb/src/workload_diagnostics.rs +3 -4
  105. package/dist/create/server-source/crates/feltdb/tests/bounded_read_contract.rs +132 -0
  106. package/dist/create/server-source/crates/feltdb/tests/branching_evidence.rs +299 -0
  107. package/dist/create/server-source/crates/feltdb/tests/compaction_stall_contract.rs +272 -0
  108. package/dist/create/server-source/crates/feltdb/tests/crash_durability_contract.rs +467 -0
  109. package/dist/create/server-source/crates/feltdb/tests/current_revision_authority_evidence.rs +309 -0
  110. package/dist/create/server-source/crates/feltdb/tests/durable_backup_contract.rs +445 -0
  111. package/dist/create/server-source/crates/feltdb/tests/durable_corruption_contract.rs +518 -0
  112. package/dist/create/server-source/crates/feltdb/tests/durable_format_compatibility.rs +392 -0
  113. package/dist/create/server-source/crates/feltdb/tests/feltdb_state_boundary_tests.rs +436 -220
  114. package/dist/create/server-source/crates/feltdb/tests/fixtures/state_conflict_contract_corpus.json +1916 -0
  115. package/dist/create/server-source/crates/feltdb/tests/fixtures/state_diff_contract_corpus.json +1878 -0
  116. package/dist/create/server-source/crates/feltdb/tests/fixtures/trigger_contract_corpus.json +1862 -0
  117. package/dist/create/server-source/crates/feltdb/tests/operational_health_contract.rs +278 -0
  118. package/dist/create/server-source/crates/feltdb/tests/pr34_query_collection.rs +2 -1
  119. package/dist/create/server-source/crates/feltdb/tests/pr35_equality_index.rs +80 -25
  120. package/dist/create/server-source/crates/feltdb/tests/pr7_self_authorization_proof.rs +5 -8
  121. package/dist/create/server-source/crates/feltdb/tests/pr8_vocabulary_assessment.rs +52 -44
  122. package/dist/create/server-source/crates/feltdb/tests/pr9_phase2_boundary_tests.rs +33 -16
  123. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3a_path_a_tests.rs +22 -7
  124. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_authorized_mutations.rs +41 -22
  125. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_role_based_authorization.rs +25 -8
  126. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_simple_auth_delete.rs +9 -6
  127. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_team_delete_role_authorization.rs +120 -69
  128. package/dist/create/server-source/crates/feltdb/tests/pr9_teams_role_based_access.rs +21 -10
  129. package/dist/create/server-source/crates/feltdb/tests/production_readiness_contract.rs +1365 -0
  130. package/dist/create/server-source/crates/feltdb/tests/reconciliation_application.rs +868 -0
  131. package/dist/create/server-source/crates/feltdb/tests/reconciliation_wire_format_evidence.rs +221 -0
  132. package/dist/create/server-source/crates/feltdb/tests/replicated_history_contract.rs +417 -0
  133. package/dist/create/server-source/crates/feltdb/tests/resource_scoped_revisions.rs +338 -0
  134. package/dist/create/server-source/crates/feltdb/tests/revision_identity_contract.rs +1039 -0
  135. package/dist/create/server-source/crates/feltdb/tests/revision_model_decision.rs +739 -0
  136. package/dist/create/server-source/crates/feltdb/tests/revision_retention_boundary_evidence.rs +427 -0
  137. package/dist/create/server-source/crates/feltdb/tests/saas_authorization_integration.rs +3 -3
  138. package/dist/create/server-source/crates/feltdb/tests/saas_invitation_lifecycle.rs +25 -22
  139. package/dist/create/server-source/crates/feltdb/tests/state_conflict_contract_conformance.rs +1799 -0
  140. package/dist/create/server-source/crates/feltdb/tests/state_diff_contract_conformance.rs +1316 -0
  141. package/dist/create/server-source/crates/feltdb/tests/state_model_integration.rs +53 -61
  142. package/dist/create/server-source/crates/feltdb/tests/state_persistence_integration.rs +156 -61
  143. package/dist/create/server-source/crates/feltdb/tests/state_store_boundary_evidence.rs +299 -0
  144. package/dist/create/server-source/crates/feltdb/tests/sync_divergence_evidence.rs +255 -0
  145. package/dist/create/server-source/crates/feltdb/tests/three_way_input_boundary_evidence.rs +249 -0
  146. package/dist/create/server-source/crates/feltdb/tests/trigger_contract_conformance.rs +994 -0
  147. package/dist/create/server-source/crates/feltdb/tests/workload_envelope_contract.rs +442 -0
  148. package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +16 -1
  149. package/dist/create/server-source/crates/feltdb-server/src/auth.rs +164 -13
  150. package/dist/create/server-source/crates/feltdb-server/src/main.rs +695 -47
  151. package/dist/create/server-source/crates/feltdb-server/src/metrics.rs +21 -0
  152. package/dist/studio-app/assets/{feltdb_wasm-CVQWgXO-.js → feltdb_wasm-C1VhI-U5.js} +1 -1
  153. package/dist/studio-app/assets/feltdb_wasm_bg-C8HXbAXb.wasm +0 -0
  154. package/dist/studio-app/assets/{index-DwgNAIIX.js → index-Bbos1m2U.js} +1 -1
  155. package/dist/studio-app/index.html +1 -1
  156. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  157. package/dist/workload.d.ts +2 -1
  158. package/dist/workload.d.ts.map +1 -1
  159. package/package.json +1 -1
  160. package/dist/studio-app/assets/feltdb_wasm_bg-CNVpvaZV.wasm +0 -0
@@ -0,0 +1,1862 @@
1
+ {
2
+ "about": "Deterministic conformance corpus for the feltdb.trigger.match contract. Every case is executed by both the native and the WASM implementation and their canonical output bytes must be identical to each other and to expected_output. Cases with 'input' are canonically encoded by the harness; cases with 'raw_input' are fed to the contract verbatim so that malformed and non-canonical encodings are testable. Regenerate expected_output with FELTDB_TRIGGER_CONTRACT_BLESS=1 cargo test -p feltdb --test trigger_contract_conformance -- bless --ignored",
3
+ "cases": [
4
+ {
5
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"orders\"},\"version\":1}",
6
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
7
+ "input": {
8
+ "change": {
9
+ "change_kind": "insert",
10
+ "collection": "orders",
11
+ "value": {
12
+ "status": "paid"
13
+ }
14
+ },
15
+ "contract": "feltdb.trigger.match",
16
+ "trigger": {
17
+ "change_kind": "insert",
18
+ "enabled": true,
19
+ "source_collection": "orders"
20
+ },
21
+ "version": 1
22
+ },
23
+ "name": "collection_matches",
24
+ "why": "the change is in the trigger's source collection"
25
+ },
26
+ {
27
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"customers\",\"value\":{\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"orders\"},\"version\":1}",
28
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"collection_mismatch\"},\"version\":1}",
29
+ "input": {
30
+ "change": {
31
+ "change_kind": "insert",
32
+ "collection": "customers",
33
+ "value": {
34
+ "status": "paid"
35
+ }
36
+ },
37
+ "contract": "feltdb.trigger.match",
38
+ "trigger": {
39
+ "change_kind": "insert",
40
+ "enabled": true,
41
+ "source_collection": "orders"
42
+ },
43
+ "version": 1
44
+ },
45
+ "name": "collection_differs",
46
+ "why": "a change in another collection is not this trigger's"
47
+ },
48
+ {
49
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"Orders\",\"value\":{\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"orders\"},\"version\":1}",
50
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"collection_mismatch\"},\"version\":1}",
51
+ "input": {
52
+ "change": {
53
+ "change_kind": "insert",
54
+ "collection": "Orders",
55
+ "value": {
56
+ "status": "paid"
57
+ }
58
+ },
59
+ "contract": "feltdb.trigger.match",
60
+ "trigger": {
61
+ "change_kind": "insert",
62
+ "enabled": true,
63
+ "source_collection": "orders"
64
+ },
65
+ "version": 1
66
+ },
67
+ "name": "collection_differs_by_case",
68
+ "why": "collection comparison is exact, not case-folded"
69
+ },
70
+ {
71
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"order\",\"value\":{\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"orders\"},\"version\":1}",
72
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"collection_mismatch\"},\"version\":1}",
73
+ "input": {
74
+ "change": {
75
+ "change_kind": "insert",
76
+ "collection": "order",
77
+ "value": {
78
+ "status": "paid"
79
+ }
80
+ },
81
+ "contract": "feltdb.trigger.match",
82
+ "trigger": {
83
+ "change_kind": "insert",
84
+ "enabled": true,
85
+ "source_collection": "orders"
86
+ },
87
+ "version": 1
88
+ },
89
+ "name": "collection_differs_by_prefix",
90
+ "why": "a prefix of the source collection is not the source collection"
91
+ },
92
+ {
93
+ "canonical_input": "{\"change\":{\"change_kind\":\"update\",\"collection\":\"orders\",\"value\":{\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"update\",\"enabled\":true,\"source_collection\":\"orders\"},\"version\":1}",
94
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
95
+ "input": {
96
+ "change": {
97
+ "change_kind": "update",
98
+ "collection": "orders",
99
+ "value": {
100
+ "status": "paid"
101
+ }
102
+ },
103
+ "contract": "feltdb.trigger.match",
104
+ "trigger": {
105
+ "change_kind": "update",
106
+ "enabled": true,
107
+ "source_collection": "orders"
108
+ },
109
+ "version": 1
110
+ },
111
+ "name": "change_kind_update_matches",
112
+ "why": "an update trigger accepts an update"
113
+ },
114
+ {
115
+ "canonical_input": "{\"change\":{\"change_kind\":\"delete\",\"collection\":\"orders\"},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"delete\",\"enabled\":true,\"source_collection\":\"orders\"},\"version\":1}",
116
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
117
+ "input": {
118
+ "change": {
119
+ "change_kind": "delete",
120
+ "collection": "orders"
121
+ },
122
+ "contract": "feltdb.trigger.match",
123
+ "trigger": {
124
+ "change_kind": "delete",
125
+ "enabled": true,
126
+ "source_collection": "orders"
127
+ },
128
+ "version": 1
129
+ },
130
+ "name": "change_kind_delete_matches",
131
+ "why": "a delete trigger accepts a delete with no value"
132
+ },
133
+ {
134
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"update\",\"enabled\":true,\"source_collection\":\"orders\"},\"version\":1}",
135
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"change_kind_mismatch\"},\"version\":1}",
136
+ "input": {
137
+ "change": {
138
+ "change_kind": "insert",
139
+ "collection": "orders",
140
+ "value": {
141
+ "status": "paid"
142
+ }
143
+ },
144
+ "contract": "feltdb.trigger.match",
145
+ "trigger": {
146
+ "change_kind": "update",
147
+ "enabled": true,
148
+ "source_collection": "orders"
149
+ },
150
+ "version": 1
151
+ },
152
+ "name": "change_kind_insert_against_update_trigger",
153
+ "why": "an insert is not an update"
154
+ },
155
+ {
156
+ "canonical_input": "{\"change\":{\"change_kind\":\"delete\",\"collection\":\"orders\"},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"orders\"},\"version\":1}",
157
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"change_kind_mismatch\"},\"version\":1}",
158
+ "input": {
159
+ "change": {
160
+ "change_kind": "delete",
161
+ "collection": "orders"
162
+ },
163
+ "contract": "feltdb.trigger.match",
164
+ "trigger": {
165
+ "change_kind": "insert",
166
+ "enabled": true,
167
+ "source_collection": "orders"
168
+ },
169
+ "version": 1
170
+ },
171
+ "name": "change_kind_delete_against_insert_trigger",
172
+ "why": "a delete is not an insert"
173
+ },
174
+ {
175
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":false,\"predicate\":{\"equals\":\"paid\",\"field\":\"status\"},\"source_collection\":\"orders\"},\"version\":1}",
176
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"trigger_disabled\"},\"version\":1}",
177
+ "input": {
178
+ "change": {
179
+ "change_kind": "insert",
180
+ "collection": "orders",
181
+ "value": {
182
+ "status": "paid"
183
+ }
184
+ },
185
+ "contract": "feltdb.trigger.match",
186
+ "trigger": {
187
+ "change_kind": "insert",
188
+ "enabled": false,
189
+ "predicate": {
190
+ "equals": "paid",
191
+ "field": "status"
192
+ },
193
+ "source_collection": "orders"
194
+ },
195
+ "version": 1
196
+ },
197
+ "name": "disabled_trigger_rejects_matching_change",
198
+ "why": "a disabled trigger never matches, even when everything else agrees"
199
+ },
200
+ {
201
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"customers\",\"value\":{\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":false,\"source_collection\":\"orders\"},\"version\":1}",
202
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"trigger_disabled\"},\"version\":1}",
203
+ "input": {
204
+ "change": {
205
+ "change_kind": "insert",
206
+ "collection": "customers",
207
+ "value": {
208
+ "status": "paid"
209
+ }
210
+ },
211
+ "contract": "feltdb.trigger.match",
212
+ "trigger": {
213
+ "change_kind": "insert",
214
+ "enabled": false,
215
+ "source_collection": "orders"
216
+ },
217
+ "version": 1
218
+ },
219
+ "name": "disabled_trigger_outranks_collection_mismatch",
220
+ "why": "disabled is checked before collection, so the reason is stable"
221
+ },
222
+ {
223
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"anything\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"orders\"},\"version\":1}",
224
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
225
+ "input": {
226
+ "change": {
227
+ "change_kind": "insert",
228
+ "collection": "orders",
229
+ "value": {
230
+ "status": "anything"
231
+ }
232
+ },
233
+ "contract": "feltdb.trigger.match",
234
+ "trigger": {
235
+ "change_kind": "insert",
236
+ "enabled": true,
237
+ "source_collection": "orders"
238
+ },
239
+ "version": 1
240
+ },
241
+ "name": "predicate_absent_matches_any_value",
242
+ "why": "no predicate means collection and kind decide alone"
243
+ },
244
+ {
245
+ "canonical_input": "{\"change\":{\"change_kind\":\"delete\",\"collection\":\"orders\"},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"delete\",\"enabled\":true,\"source_collection\":\"orders\"},\"version\":1}",
246
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
247
+ "input": {
248
+ "change": {
249
+ "change_kind": "delete",
250
+ "collection": "orders"
251
+ },
252
+ "contract": "feltdb.trigger.match",
253
+ "trigger": {
254
+ "change_kind": "delete",
255
+ "enabled": true,
256
+ "source_collection": "orders"
257
+ },
258
+ "version": 1
259
+ },
260
+ "name": "predicate_absent_matches_absent_value",
261
+ "why": "no predicate means a valueless change still matches"
262
+ },
263
+ {
264
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"paid\",\"field\":\"status\"},\"source_collection\":\"orders\"},\"version\":1}",
265
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
266
+ "input": {
267
+ "change": {
268
+ "change_kind": "insert",
269
+ "collection": "orders",
270
+ "value": {
271
+ "status": "paid"
272
+ }
273
+ },
274
+ "contract": "feltdb.trigger.match",
275
+ "trigger": {
276
+ "change_kind": "insert",
277
+ "enabled": true,
278
+ "predicate": {
279
+ "equals": "paid",
280
+ "field": "status"
281
+ },
282
+ "source_collection": "orders"
283
+ },
284
+ "version": 1
285
+ },
286
+ "name": "predicate_matches_string",
287
+ "why": "the field resolves and equals the expected value"
288
+ },
289
+ {
290
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"draft\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"paid\",\"field\":\"status\"},\"source_collection\":\"orders\"},\"version\":1}",
291
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
292
+ "input": {
293
+ "change": {
294
+ "change_kind": "insert",
295
+ "collection": "orders",
296
+ "value": {
297
+ "status": "draft"
298
+ }
299
+ },
300
+ "contract": "feltdb.trigger.match",
301
+ "trigger": {
302
+ "change_kind": "insert",
303
+ "enabled": true,
304
+ "predicate": {
305
+ "equals": "paid",
306
+ "field": "status"
307
+ },
308
+ "source_collection": "orders"
309
+ },
310
+ "version": 1
311
+ },
312
+ "name": "predicate_value_mismatch",
313
+ "why": "the field resolves to a different value"
314
+ },
315
+ {
316
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"state\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"paid\",\"field\":\"status\"},\"source_collection\":\"orders\"},\"version\":1}",
317
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_field_absent\"},\"version\":1}",
318
+ "input": {
319
+ "change": {
320
+ "change_kind": "insert",
321
+ "collection": "orders",
322
+ "value": {
323
+ "state": "paid"
324
+ }
325
+ },
326
+ "contract": "feltdb.trigger.match",
327
+ "trigger": {
328
+ "change_kind": "insert",
329
+ "enabled": true,
330
+ "predicate": {
331
+ "equals": "paid",
332
+ "field": "status"
333
+ },
334
+ "source_collection": "orders"
335
+ },
336
+ "version": 1
337
+ },
338
+ "name": "predicate_field_absent",
339
+ "why": "the field path does not resolve"
340
+ },
341
+ {
342
+ "canonical_input": "{\"change\":{\"change_kind\":\"delete\",\"collection\":\"orders\"},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"delete\",\"enabled\":true,\"predicate\":{\"equals\":\"paid\",\"field\":\"status\"},\"source_collection\":\"orders\"},\"version\":1}",
343
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"change_value_absent\"},\"version\":1}",
344
+ "input": {
345
+ "change": {
346
+ "change_kind": "delete",
347
+ "collection": "orders"
348
+ },
349
+ "contract": "feltdb.trigger.match",
350
+ "trigger": {
351
+ "change_kind": "delete",
352
+ "enabled": true,
353
+ "predicate": {
354
+ "equals": "paid",
355
+ "field": "status"
356
+ },
357
+ "source_collection": "orders"
358
+ },
359
+ "version": 1
360
+ },
361
+ "name": "predicate_against_absent_value",
362
+ "why": "a predicate cannot be evaluated against a change that carried no record"
363
+ },
364
+ {
365
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":{\"status\":\"paid\"},\"field\":\"\"},\"source_collection\":\"orders\"},\"version\":1}",
366
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
367
+ "input": {
368
+ "change": {
369
+ "change_kind": "insert",
370
+ "collection": "orders",
371
+ "value": {
372
+ "status": "paid"
373
+ }
374
+ },
375
+ "contract": "feltdb.trigger.match",
376
+ "trigger": {
377
+ "change_kind": "insert",
378
+ "enabled": true,
379
+ "predicate": {
380
+ "equals": {
381
+ "status": "paid"
382
+ },
383
+ "field": ""
384
+ },
385
+ "source_collection": "orders"
386
+ },
387
+ "version": 1
388
+ },
389
+ "name": "predicate_empty_field_path_selects_whole_value",
390
+ "why": "an empty path compares the whole record"
391
+ },
392
+ {
393
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":{\"status\":\"draft\"},\"field\":\"\"},\"source_collection\":\"orders\"},\"version\":1}",
394
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
395
+ "input": {
396
+ "change": {
397
+ "change_kind": "insert",
398
+ "collection": "orders",
399
+ "value": {
400
+ "status": "paid"
401
+ }
402
+ },
403
+ "contract": "feltdb.trigger.match",
404
+ "trigger": {
405
+ "change_kind": "insert",
406
+ "enabled": true,
407
+ "predicate": {
408
+ "equals": {
409
+ "status": "draft"
410
+ },
411
+ "field": ""
412
+ },
413
+ "source_collection": "orders"
414
+ },
415
+ "version": 1
416
+ },
417
+ "name": "predicate_empty_field_path_mismatch",
418
+ "why": "an empty path comparing an unequal record"
419
+ },
420
+ {
421
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":\"paid\"},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"paid\",\"field\":\"status\"},\"source_collection\":\"orders\"},\"version\":1}",
422
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_field_absent\"},\"version\":1}",
423
+ "input": {
424
+ "change": {
425
+ "change_kind": "insert",
426
+ "collection": "orders",
427
+ "value": "paid"
428
+ },
429
+ "contract": "feltdb.trigger.match",
430
+ "trigger": {
431
+ "change_kind": "insert",
432
+ "enabled": true,
433
+ "predicate": {
434
+ "equals": "paid",
435
+ "field": "status"
436
+ },
437
+ "source_collection": "orders"
438
+ },
439
+ "version": 1
440
+ },
441
+ "name": "predicate_field_on_scalar_value",
442
+ "why": "a scalar record has no members to address"
443
+ },
444
+ {
445
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"a.b\":1}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":1,\"field\":\"a.b\"},\"source_collection\":\"orders\"},\"version\":1}",
446
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_field_absent\"},\"version\":1}",
447
+ "input": {
448
+ "change": {
449
+ "change_kind": "insert",
450
+ "collection": "orders",
451
+ "value": {
452
+ "a.b": 1
453
+ }
454
+ },
455
+ "contract": "feltdb.trigger.match",
456
+ "trigger": {
457
+ "change_kind": "insert",
458
+ "enabled": true,
459
+ "predicate": {
460
+ "equals": 1,
461
+ "field": "a.b"
462
+ },
463
+ "source_collection": "orders"
464
+ },
465
+ "version": 1
466
+ },
467
+ "name": "predicate_dotted_key_is_a_path_not_a_key",
468
+ "why": "a literal dotted key is not addressable, because the path splits first"
469
+ },
470
+ {
471
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":null},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":null,\"field\":\"\"},\"source_collection\":\"orders\"},\"version\":1}",
472
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
473
+ "input": {
474
+ "change": {
475
+ "change_kind": "insert",
476
+ "collection": "orders",
477
+ "value": null
478
+ },
479
+ "contract": "feltdb.trigger.match",
480
+ "trigger": {
481
+ "change_kind": "insert",
482
+ "enabled": true,
483
+ "predicate": {
484
+ "equals": null,
485
+ "field": ""
486
+ },
487
+ "source_collection": "orders"
488
+ },
489
+ "version": 1
490
+ },
491
+ "name": "value_null_present_with_whole_record_predicate",
492
+ "why": "a record that is JSON null is present and comparable"
493
+ },
494
+ {
495
+ "canonical_input": "{\"change\":{\"change_kind\":\"delete\",\"collection\":\"orders\"},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"delete\",\"enabled\":true,\"predicate\":{\"equals\":null,\"field\":\"\"},\"source_collection\":\"orders\"},\"version\":1}",
496
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"change_value_absent\"},\"version\":1}",
497
+ "input": {
498
+ "change": {
499
+ "change_kind": "delete",
500
+ "collection": "orders"
501
+ },
502
+ "contract": "feltdb.trigger.match",
503
+ "trigger": {
504
+ "change_kind": "delete",
505
+ "enabled": true,
506
+ "predicate": {
507
+ "equals": null,
508
+ "field": ""
509
+ },
510
+ "source_collection": "orders"
511
+ },
512
+ "version": 1
513
+ },
514
+ "name": "value_absent_with_whole_record_predicate",
515
+ "why": "an absent record is not JSON null, so the same predicate rejects"
516
+ },
517
+ {
518
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"cancelled_at\":null}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":null,\"field\":\"cancelled_at\"},\"source_collection\":\"orders\"},\"version\":1}",
519
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
520
+ "input": {
521
+ "change": {
522
+ "change_kind": "insert",
523
+ "collection": "orders",
524
+ "value": {
525
+ "cancelled_at": null
526
+ }
527
+ },
528
+ "contract": "feltdb.trigger.match",
529
+ "trigger": {
530
+ "change_kind": "insert",
531
+ "enabled": true,
532
+ "predicate": {
533
+ "equals": null,
534
+ "field": "cancelled_at"
535
+ },
536
+ "source_collection": "orders"
537
+ },
538
+ "version": 1
539
+ },
540
+ "name": "predicate_matches_null_field",
541
+ "why": "a field whose value is null equals a null expectation"
542
+ },
543
+ {
544
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"cancelled_at\":null}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"never\",\"field\":\"cancelled_at\"},\"source_collection\":\"orders\"},\"version\":1}",
545
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
546
+ "input": {
547
+ "change": {
548
+ "change_kind": "insert",
549
+ "collection": "orders",
550
+ "value": {
551
+ "cancelled_at": null
552
+ }
553
+ },
554
+ "contract": "feltdb.trigger.match",
555
+ "trigger": {
556
+ "change_kind": "insert",
557
+ "enabled": true,
558
+ "predicate": {
559
+ "equals": "never",
560
+ "field": "cancelled_at"
561
+ },
562
+ "source_collection": "orders"
563
+ },
564
+ "version": 1
565
+ },
566
+ "name": "null_field_is_not_a_missing_field",
567
+ "why": "a present null field resolves; it is not the absent case"
568
+ },
569
+ {
570
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":null,\"field\":\"cancelled_at\"},\"source_collection\":\"orders\"},\"version\":1}",
571
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_field_absent\"},\"version\":1}",
572
+ "input": {
573
+ "change": {
574
+ "change_kind": "insert",
575
+ "collection": "orders",
576
+ "value": {
577
+ "status": "paid"
578
+ }
579
+ },
580
+ "contract": "feltdb.trigger.match",
581
+ "trigger": {
582
+ "change_kind": "insert",
583
+ "enabled": true,
584
+ "predicate": {
585
+ "equals": null,
586
+ "field": "cancelled_at"
587
+ },
588
+ "source_collection": "orders"
589
+ },
590
+ "version": 1
591
+ },
592
+ "name": "missing_field_does_not_equal_null",
593
+ "why": "an absent field never equals null"
594
+ },
595
+ {
596
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"flag\":null}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":false,\"field\":\"flag\"},\"source_collection\":\"orders\"},\"version\":1}",
597
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
598
+ "input": {
599
+ "change": {
600
+ "change_kind": "insert",
601
+ "collection": "orders",
602
+ "value": {
603
+ "flag": null
604
+ }
605
+ },
606
+ "contract": "feltdb.trigger.match",
607
+ "trigger": {
608
+ "change_kind": "insert",
609
+ "enabled": true,
610
+ "predicate": {
611
+ "equals": false,
612
+ "field": "flag"
613
+ },
614
+ "source_collection": "orders"
615
+ },
616
+ "version": 1
617
+ },
618
+ "name": "null_is_not_false",
619
+ "why": "JSON null and false are different values"
620
+ },
621
+ {
622
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"customer\":{\"billing\":{\"country\":\"NL\"}}}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"NL\",\"field\":\"customer.billing.country\"},\"source_collection\":\"orders\"},\"version\":1}",
623
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
624
+ "input": {
625
+ "change": {
626
+ "change_kind": "insert",
627
+ "collection": "orders",
628
+ "value": {
629
+ "customer": {
630
+ "billing": {
631
+ "country": "NL"
632
+ }
633
+ }
634
+ }
635
+ },
636
+ "contract": "feltdb.trigger.match",
637
+ "trigger": {
638
+ "change_kind": "insert",
639
+ "enabled": true,
640
+ "predicate": {
641
+ "equals": "NL",
642
+ "field": "customer.billing.country"
643
+ },
644
+ "source_collection": "orders"
645
+ },
646
+ "version": 1
647
+ },
648
+ "name": "nested_path_matches",
649
+ "why": "a dotted path descends through nested objects"
650
+ },
651
+ {
652
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"customer\":{\"billing\":{\"country\":\"BE\"}}}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"NL\",\"field\":\"customer.billing.country\"},\"source_collection\":\"orders\"},\"version\":1}",
653
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
654
+ "input": {
655
+ "change": {
656
+ "change_kind": "insert",
657
+ "collection": "orders",
658
+ "value": {
659
+ "customer": {
660
+ "billing": {
661
+ "country": "BE"
662
+ }
663
+ }
664
+ }
665
+ },
666
+ "contract": "feltdb.trigger.match",
667
+ "trigger": {
668
+ "change_kind": "insert",
669
+ "enabled": true,
670
+ "predicate": {
671
+ "equals": "NL",
672
+ "field": "customer.billing.country"
673
+ },
674
+ "source_collection": "orders"
675
+ },
676
+ "version": 1
677
+ },
678
+ "name": "nested_path_mismatch",
679
+ "why": "a nested path that resolves to another value"
680
+ },
681
+ {
682
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"customer\":{\"shipping\":{\"country\":\"NL\"}}}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"NL\",\"field\":\"customer.billing.country\"},\"source_collection\":\"orders\"},\"version\":1}",
683
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_field_absent\"},\"version\":1}",
684
+ "input": {
685
+ "change": {
686
+ "change_kind": "insert",
687
+ "collection": "orders",
688
+ "value": {
689
+ "customer": {
690
+ "shipping": {
691
+ "country": "NL"
692
+ }
693
+ }
694
+ }
695
+ },
696
+ "contract": "feltdb.trigger.match",
697
+ "trigger": {
698
+ "change_kind": "insert",
699
+ "enabled": true,
700
+ "predicate": {
701
+ "equals": "NL",
702
+ "field": "customer.billing.country"
703
+ },
704
+ "source_collection": "orders"
705
+ },
706
+ "version": 1
707
+ },
708
+ "name": "nested_path_stops_at_missing_segment",
709
+ "why": "an intermediate segment that does not exist stops the walk"
710
+ },
711
+ {
712
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"customer\":{\"alpha\":2,\"zeta\":1}}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":{\"alpha\":2,\"zeta\":1},\"field\":\"customer\"},\"source_collection\":\"orders\"},\"version\":1}",
713
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
714
+ "input": {
715
+ "change": {
716
+ "change_kind": "insert",
717
+ "collection": "orders",
718
+ "value": {
719
+ "customer": {
720
+ "alpha": 2,
721
+ "zeta": 1
722
+ }
723
+ }
724
+ },
725
+ "contract": "feltdb.trigger.match",
726
+ "trigger": {
727
+ "change_kind": "insert",
728
+ "enabled": true,
729
+ "predicate": {
730
+ "equals": {
731
+ "alpha": 2,
732
+ "zeta": 1
733
+ },
734
+ "field": "customer"
735
+ },
736
+ "source_collection": "orders"
737
+ },
738
+ "version": 1
739
+ },
740
+ "name": "nested_object_equality_ignores_key_order",
741
+ "why": "objects compare as maps, so the encoded key order cannot decide"
742
+ },
743
+ {
744
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"customer\":{\"alpha\":2,\"zeta\":1}}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":{\"alpha\":2},\"field\":\"customer\"},\"source_collection\":\"orders\"},\"version\":1}",
745
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
746
+ "input": {
747
+ "change": {
748
+ "change_kind": "insert",
749
+ "collection": "orders",
750
+ "value": {
751
+ "customer": {
752
+ "alpha": 2,
753
+ "zeta": 1
754
+ }
755
+ }
756
+ },
757
+ "contract": "feltdb.trigger.match",
758
+ "trigger": {
759
+ "change_kind": "insert",
760
+ "enabled": true,
761
+ "predicate": {
762
+ "equals": {
763
+ "alpha": 2
764
+ },
765
+ "field": "customer"
766
+ },
767
+ "source_collection": "orders"
768
+ },
769
+ "version": 1
770
+ },
771
+ "name": "nested_object_equality_rejects_extra_key",
772
+ "why": "an object with an extra member is a different object"
773
+ },
774
+ {
775
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"a\":{\"b\":{\"c\":{\"d\":{\"e\":{\"f\":{\"g\":{\"h\":{\"i\":{\"j\":\"deep\"}}}}}}}}}}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"deep\",\"field\":\"a.b.c.d.e.f.g.h.i.j\"},\"source_collection\":\"orders\"},\"version\":1}",
776
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
777
+ "input": {
778
+ "change": {
779
+ "change_kind": "insert",
780
+ "collection": "orders",
781
+ "value": {
782
+ "a": {
783
+ "b": {
784
+ "c": {
785
+ "d": {
786
+ "e": {
787
+ "f": {
788
+ "g": {
789
+ "h": {
790
+ "i": {
791
+ "j": "deep"
792
+ }
793
+ }
794
+ }
795
+ }
796
+ }
797
+ }
798
+ }
799
+ }
800
+ }
801
+ }
802
+ },
803
+ "contract": "feltdb.trigger.match",
804
+ "trigger": {
805
+ "change_kind": "insert",
806
+ "enabled": true,
807
+ "predicate": {
808
+ "equals": "deep",
809
+ "field": "a.b.c.d.e.f.g.h.i.j"
810
+ },
811
+ "source_collection": "orders"
812
+ },
813
+ "version": 1
814
+ },
815
+ "name": "deeply_nested_value",
816
+ "why": "nesting well inside the shared recursion bound"
817
+ },
818
+ {
819
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"tags\":[\"a\",\"b\",\"c\"]}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":[\"a\",\"b\",\"c\"],\"field\":\"tags\"},\"source_collection\":\"orders\"},\"version\":1}",
820
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
821
+ "input": {
822
+ "change": {
823
+ "change_kind": "insert",
824
+ "collection": "orders",
825
+ "value": {
826
+ "tags": [
827
+ "a",
828
+ "b",
829
+ "c"
830
+ ]
831
+ }
832
+ },
833
+ "contract": "feltdb.trigger.match",
834
+ "trigger": {
835
+ "change_kind": "insert",
836
+ "enabled": true,
837
+ "predicate": {
838
+ "equals": [
839
+ "a",
840
+ "b",
841
+ "c"
842
+ ],
843
+ "field": "tags"
844
+ },
845
+ "source_collection": "orders"
846
+ },
847
+ "version": 1
848
+ },
849
+ "name": "array_equality_matches",
850
+ "why": "arrays compare elementwise and in order"
851
+ },
852
+ {
853
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"tags\":[\"c\",\"b\",\"a\"]}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":[\"a\",\"b\",\"c\"],\"field\":\"tags\"},\"source_collection\":\"orders\"},\"version\":1}",
854
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
855
+ "input": {
856
+ "change": {
857
+ "change_kind": "insert",
858
+ "collection": "orders",
859
+ "value": {
860
+ "tags": [
861
+ "c",
862
+ "b",
863
+ "a"
864
+ ]
865
+ }
866
+ },
867
+ "contract": "feltdb.trigger.match",
868
+ "trigger": {
869
+ "change_kind": "insert",
870
+ "enabled": true,
871
+ "predicate": {
872
+ "equals": [
873
+ "a",
874
+ "b",
875
+ "c"
876
+ ],
877
+ "field": "tags"
878
+ },
879
+ "source_collection": "orders"
880
+ },
881
+ "version": 1
882
+ },
883
+ "name": "array_order_is_significant",
884
+ "why": "the same members in another order are a different array"
885
+ },
886
+ {
887
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"tags\":[\"a\",\"b\"]}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":[\"a\",\"b\",\"c\"],\"field\":\"tags\"},\"source_collection\":\"orders\"},\"version\":1}",
888
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
889
+ "input": {
890
+ "change": {
891
+ "change_kind": "insert",
892
+ "collection": "orders",
893
+ "value": {
894
+ "tags": [
895
+ "a",
896
+ "b"
897
+ ]
898
+ }
899
+ },
900
+ "contract": "feltdb.trigger.match",
901
+ "trigger": {
902
+ "change_kind": "insert",
903
+ "enabled": true,
904
+ "predicate": {
905
+ "equals": [
906
+ "a",
907
+ "b",
908
+ "c"
909
+ ],
910
+ "field": "tags"
911
+ },
912
+ "source_collection": "orders"
913
+ },
914
+ "version": 1
915
+ },
916
+ "name": "array_length_is_significant",
917
+ "why": "a prefix is not the array"
918
+ },
919
+ {
920
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"tags\":[\"a\",\"b\"]}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"a\",\"field\":\"tags.0\"},\"source_collection\":\"orders\"},\"version\":1}",
921
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_field_absent\"},\"version\":1}",
922
+ "input": {
923
+ "change": {
924
+ "change_kind": "insert",
925
+ "collection": "orders",
926
+ "value": {
927
+ "tags": [
928
+ "a",
929
+ "b"
930
+ ]
931
+ }
932
+ },
933
+ "contract": "feltdb.trigger.match",
934
+ "trigger": {
935
+ "change_kind": "insert",
936
+ "enabled": true,
937
+ "predicate": {
938
+ "equals": "a",
939
+ "field": "tags.0"
940
+ },
941
+ "source_collection": "orders"
942
+ },
943
+ "version": 1
944
+ },
945
+ "name": "array_elements_are_not_addressable",
946
+ "why": "a numeric path segment does not index an array"
947
+ },
948
+ {
949
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"lines\":[{\"qty\":2,\"sku\":\"x\"},{\"qty\":1,\"sku\":\"y\"}]}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":[{\"qty\":2,\"sku\":\"x\"},{\"qty\":1,\"sku\":\"y\"}],\"field\":\"lines\"},\"source_collection\":\"orders\"},\"version\":1}",
950
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
951
+ "input": {
952
+ "change": {
953
+ "change_kind": "insert",
954
+ "collection": "orders",
955
+ "value": {
956
+ "lines": [
957
+ {
958
+ "qty": 2,
959
+ "sku": "x"
960
+ },
961
+ {
962
+ "qty": 1,
963
+ "sku": "y"
964
+ }
965
+ ]
966
+ }
967
+ },
968
+ "contract": "feltdb.trigger.match",
969
+ "trigger": {
970
+ "change_kind": "insert",
971
+ "enabled": true,
972
+ "predicate": {
973
+ "equals": [
974
+ {
975
+ "qty": 2,
976
+ "sku": "x"
977
+ },
978
+ {
979
+ "qty": 1,
980
+ "sku": "y"
981
+ }
982
+ ],
983
+ "field": "lines"
984
+ },
985
+ "source_collection": "orders"
986
+ },
987
+ "version": 1
988
+ },
989
+ "name": "array_of_objects_equality",
990
+ "why": "nested structure inside array elements participates"
991
+ },
992
+ {
993
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"tags\":[]}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":[],\"field\":\"tags\"},\"source_collection\":\"orders\"},\"version\":1}",
994
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
995
+ "input": {
996
+ "change": {
997
+ "change_kind": "insert",
998
+ "collection": "orders",
999
+ "value": {
1000
+ "tags": []
1001
+ }
1002
+ },
1003
+ "contract": "feltdb.trigger.match",
1004
+ "trigger": {
1005
+ "change_kind": "insert",
1006
+ "enabled": true,
1007
+ "predicate": {
1008
+ "equals": [],
1009
+ "field": "tags"
1010
+ },
1011
+ "source_collection": "orders"
1012
+ },
1013
+ "version": 1
1014
+ },
1015
+ "name": "empty_array_matches_empty_array",
1016
+ "why": "an empty array is a value"
1017
+ },
1018
+ {
1019
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"tags\":[]}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":{},\"field\":\"tags\"},\"source_collection\":\"orders\"},\"version\":1}",
1020
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
1021
+ "input": {
1022
+ "change": {
1023
+ "change_kind": "insert",
1024
+ "collection": "orders",
1025
+ "value": {
1026
+ "tags": []
1027
+ }
1028
+ },
1029
+ "contract": "feltdb.trigger.match",
1030
+ "trigger": {
1031
+ "change_kind": "insert",
1032
+ "enabled": true,
1033
+ "predicate": {
1034
+ "equals": {},
1035
+ "field": "tags"
1036
+ },
1037
+ "source_collection": "orders"
1038
+ },
1039
+ "version": 1
1040
+ },
1041
+ "name": "empty_array_is_not_empty_object",
1042
+ "why": "an empty array and an empty object are different values"
1043
+ },
1044
+ {
1045
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"total\":42}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":42,\"field\":\"total\"},\"source_collection\":\"orders\"},\"version\":1}",
1046
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1047
+ "input": {
1048
+ "change": {
1049
+ "change_kind": "insert",
1050
+ "collection": "orders",
1051
+ "value": {
1052
+ "total": 42
1053
+ }
1054
+ },
1055
+ "contract": "feltdb.trigger.match",
1056
+ "trigger": {
1057
+ "change_kind": "insert",
1058
+ "enabled": true,
1059
+ "predicate": {
1060
+ "equals": 42,
1061
+ "field": "total"
1062
+ },
1063
+ "source_collection": "orders"
1064
+ },
1065
+ "version": 1
1066
+ },
1067
+ "name": "integer_equality_matches",
1068
+ "why": "integers compare by value"
1069
+ },
1070
+ {
1071
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"total\":42}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":42.0,\"field\":\"total\"},\"source_collection\":\"orders\"},\"version\":1}",
1072
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
1073
+ "input": {
1074
+ "change": {
1075
+ "change_kind": "insert",
1076
+ "collection": "orders",
1077
+ "value": {
1078
+ "total": 42
1079
+ }
1080
+ },
1081
+ "contract": "feltdb.trigger.match",
1082
+ "trigger": {
1083
+ "change_kind": "insert",
1084
+ "enabled": true,
1085
+ "predicate": {
1086
+ "equals": 42.0,
1087
+ "field": "total"
1088
+ },
1089
+ "source_collection": "orders"
1090
+ },
1091
+ "version": 1
1092
+ },
1093
+ "name": "integer_and_float_are_different_values",
1094
+ "why": "42 is not 42.0 under JSON value equality"
1095
+ },
1096
+ {
1097
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"total\":42.0}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":42,\"field\":\"total\"},\"source_collection\":\"orders\"},\"version\":1}",
1098
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
1099
+ "input": {
1100
+ "change": {
1101
+ "change_kind": "insert",
1102
+ "collection": "orders",
1103
+ "value": {
1104
+ "total": 42.0
1105
+ }
1106
+ },
1107
+ "contract": "feltdb.trigger.match",
1108
+ "trigger": {
1109
+ "change_kind": "insert",
1110
+ "enabled": true,
1111
+ "predicate": {
1112
+ "equals": 42,
1113
+ "field": "total"
1114
+ },
1115
+ "source_collection": "orders"
1116
+ },
1117
+ "version": 1
1118
+ },
1119
+ "name": "float_and_integer_are_different_values",
1120
+ "why": "and the comparison is symmetric"
1121
+ },
1122
+ {
1123
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"rate\":0.125}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":0.125,\"field\":\"rate\"},\"source_collection\":\"orders\"},\"version\":1}",
1124
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1125
+ "input": {
1126
+ "change": {
1127
+ "change_kind": "insert",
1128
+ "collection": "orders",
1129
+ "value": {
1130
+ "rate": 0.125
1131
+ }
1132
+ },
1133
+ "contract": "feltdb.trigger.match",
1134
+ "trigger": {
1135
+ "change_kind": "insert",
1136
+ "enabled": true,
1137
+ "predicate": {
1138
+ "equals": 0.125,
1139
+ "field": "rate"
1140
+ },
1141
+ "source_collection": "orders"
1142
+ },
1143
+ "version": 1
1144
+ },
1145
+ "name": "float_equality_matches",
1146
+ "why": "floats compare by value"
1147
+ },
1148
+ {
1149
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"delta\":-7}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":-7,\"field\":\"delta\"},\"source_collection\":\"orders\"},\"version\":1}",
1150
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1151
+ "input": {
1152
+ "change": {
1153
+ "change_kind": "insert",
1154
+ "collection": "orders",
1155
+ "value": {
1156
+ "delta": -7
1157
+ }
1158
+ },
1159
+ "contract": "feltdb.trigger.match",
1160
+ "trigger": {
1161
+ "change_kind": "insert",
1162
+ "enabled": true,
1163
+ "predicate": {
1164
+ "equals": -7,
1165
+ "field": "delta"
1166
+ },
1167
+ "source_collection": "orders"
1168
+ },
1169
+ "version": 1
1170
+ },
1171
+ "name": "negative_integer_matches",
1172
+ "why": "negative integers are their own variant"
1173
+ },
1174
+ {
1175
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
1176
+ "name": "negative_zero_is_not_integer_zero",
1177
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"delta\":-0}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":0,\"field\":\"delta\"},\"source_collection\":\"orders\"},\"version\":1}",
1178
+ "why": "the literal -0 carries a sign no integer can hold, so it decodes as a float and never equals the integer 0"
1179
+ },
1180
+ {
1181
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"counter\":18446744073709551615}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":18446744073709551615,\"field\":\"counter\"},\"source_collection\":\"orders\"},\"version\":1}",
1182
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1183
+ "input": {
1184
+ "change": {
1185
+ "change_kind": "insert",
1186
+ "collection": "orders",
1187
+ "value": {
1188
+ "counter": 18446744073709551615
1189
+ }
1190
+ },
1191
+ "contract": "feltdb.trigger.match",
1192
+ "trigger": {
1193
+ "change_kind": "insert",
1194
+ "enabled": true,
1195
+ "predicate": {
1196
+ "equals": 18446744073709551615,
1197
+ "field": "counter"
1198
+ },
1199
+ "source_collection": "orders"
1200
+ },
1201
+ "version": 1
1202
+ },
1203
+ "name": "large_unsigned_integer_matches",
1204
+ "why": "a u64 near the top of the range stays an integer"
1205
+ },
1206
+ {
1207
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"floor\":-9223372036854775808}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":-9223372036854775808,\"field\":\"floor\"},\"source_collection\":\"orders\"},\"version\":1}",
1208
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1209
+ "input": {
1210
+ "change": {
1211
+ "change_kind": "insert",
1212
+ "collection": "orders",
1213
+ "value": {
1214
+ "floor": -9223372036854775808
1215
+ }
1216
+ },
1217
+ "contract": "feltdb.trigger.match",
1218
+ "trigger": {
1219
+ "change_kind": "insert",
1220
+ "enabled": true,
1221
+ "predicate": {
1222
+ "equals": -9223372036854775808,
1223
+ "field": "floor"
1224
+ },
1225
+ "source_collection": "orders"
1226
+ },
1227
+ "version": 1
1228
+ },
1229
+ "name": "smallest_signed_integer_matches",
1230
+ "why": "i64::MIN stays an integer"
1231
+ },
1232
+ {
1233
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"total\":0}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":0,\"field\":\"total\"},\"source_collection\":\"orders\"},\"version\":1}",
1234
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1235
+ "input": {
1236
+ "change": {
1237
+ "change_kind": "insert",
1238
+ "collection": "orders",
1239
+ "value": {
1240
+ "total": 0
1241
+ }
1242
+ },
1243
+ "contract": "feltdb.trigger.match",
1244
+ "trigger": {
1245
+ "change_kind": "insert",
1246
+ "enabled": true,
1247
+ "predicate": {
1248
+ "equals": 0,
1249
+ "field": "total"
1250
+ },
1251
+ "source_collection": "orders"
1252
+ },
1253
+ "version": 1
1254
+ },
1255
+ "name": "zero_matches_zero",
1256
+ "why": "zero is an ordinary value"
1257
+ },
1258
+ {
1259
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"flag\":0}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":false,\"field\":\"flag\"},\"source_collection\":\"orders\"},\"version\":1}",
1260
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
1261
+ "input": {
1262
+ "change": {
1263
+ "change_kind": "insert",
1264
+ "collection": "orders",
1265
+ "value": {
1266
+ "flag": 0
1267
+ }
1268
+ },
1269
+ "contract": "feltdb.trigger.match",
1270
+ "trigger": {
1271
+ "change_kind": "insert",
1272
+ "enabled": true,
1273
+ "predicate": {
1274
+ "equals": false,
1275
+ "field": "flag"
1276
+ },
1277
+ "source_collection": "orders"
1278
+ },
1279
+ "version": 1
1280
+ },
1281
+ "name": "zero_is_not_false",
1282
+ "why": "a number and a boolean are different values"
1283
+ },
1284
+ {
1285
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"total\":\"42\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":42,\"field\":\"total\"},\"source_collection\":\"orders\"},\"version\":1}",
1286
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
1287
+ "input": {
1288
+ "change": {
1289
+ "change_kind": "insert",
1290
+ "collection": "orders",
1291
+ "value": {
1292
+ "total": "42"
1293
+ }
1294
+ },
1295
+ "contract": "feltdb.trigger.match",
1296
+ "trigger": {
1297
+ "change_kind": "insert",
1298
+ "enabled": true,
1299
+ "predicate": {
1300
+ "equals": 42,
1301
+ "field": "total"
1302
+ },
1303
+ "source_collection": "orders"
1304
+ },
1305
+ "version": 1
1306
+ },
1307
+ "name": "numeric_string_is_not_a_number",
1308
+ "why": "\"42\" is not 42"
1309
+ },
1310
+ {
1311
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"\",\"value\":{\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"\"},\"version\":1}",
1312
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1313
+ "input": {
1314
+ "change": {
1315
+ "change_kind": "insert",
1316
+ "collection": "",
1317
+ "value": {
1318
+ "status": "paid"
1319
+ }
1320
+ },
1321
+ "contract": "feltdb.trigger.match",
1322
+ "trigger": {
1323
+ "change_kind": "insert",
1324
+ "enabled": true,
1325
+ "source_collection": ""
1326
+ },
1327
+ "version": 1
1328
+ },
1329
+ "name": "empty_collection_names_match",
1330
+ "why": "an empty collection name is compared like any other"
1331
+ },
1332
+ {
1333
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"\",\"value\":{\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"orders\"},\"version\":1}",
1334
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"collection_mismatch\"},\"version\":1}",
1335
+ "input": {
1336
+ "change": {
1337
+ "change_kind": "insert",
1338
+ "collection": "",
1339
+ "value": {
1340
+ "status": "paid"
1341
+ }
1342
+ },
1343
+ "contract": "feltdb.trigger.match",
1344
+ "trigger": {
1345
+ "change_kind": "insert",
1346
+ "enabled": true,
1347
+ "source_collection": "orders"
1348
+ },
1349
+ "version": 1
1350
+ },
1351
+ "name": "empty_collection_against_named_trigger",
1352
+ "why": "an empty collection name is not a wildcard"
1353
+ },
1354
+ {
1355
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":{},\"field\":\"\"},\"source_collection\":\"orders\"},\"version\":1}",
1356
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1357
+ "input": {
1358
+ "change": {
1359
+ "change_kind": "insert",
1360
+ "collection": "orders",
1361
+ "value": {}
1362
+ },
1363
+ "contract": "feltdb.trigger.match",
1364
+ "trigger": {
1365
+ "change_kind": "insert",
1366
+ "enabled": true,
1367
+ "predicate": {
1368
+ "equals": {},
1369
+ "field": ""
1370
+ },
1371
+ "source_collection": "orders"
1372
+ },
1373
+ "version": 1
1374
+ },
1375
+ "name": "empty_object_record",
1376
+ "why": "a record with no members"
1377
+ },
1378
+ {
1379
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"\",\"field\":\"status\"},\"source_collection\":\"orders\"},\"version\":1}",
1380
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1381
+ "input": {
1382
+ "change": {
1383
+ "change_kind": "insert",
1384
+ "collection": "orders",
1385
+ "value": {
1386
+ "status": ""
1387
+ }
1388
+ },
1389
+ "contract": "feltdb.trigger.match",
1390
+ "trigger": {
1391
+ "change_kind": "insert",
1392
+ "enabled": true,
1393
+ "predicate": {
1394
+ "equals": "",
1395
+ "field": "status"
1396
+ },
1397
+ "source_collection": "orders"
1398
+ },
1399
+ "version": 1
1400
+ },
1401
+ "name": "empty_string_field_value",
1402
+ "why": "an empty string is a value, not an absence"
1403
+ },
1404
+ {
1405
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"paid\",\"field\":\"status\"},\"source_collection\":\"orders\"},\"version\":1}",
1406
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
1407
+ "input": {
1408
+ "change": {
1409
+ "change_kind": "insert",
1410
+ "collection": "orders",
1411
+ "value": {
1412
+ "status": ""
1413
+ }
1414
+ },
1415
+ "contract": "feltdb.trigger.match",
1416
+ "trigger": {
1417
+ "change_kind": "insert",
1418
+ "enabled": true,
1419
+ "predicate": {
1420
+ "equals": "paid",
1421
+ "field": "status"
1422
+ },
1423
+ "source_collection": "orders"
1424
+ },
1425
+ "version": 1
1426
+ },
1427
+ "name": "empty_string_is_not_missing",
1428
+ "why": "an empty string does not satisfy a non-empty expectation"
1429
+ },
1430
+ {
1431
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"\":{\"status\":\"paid\"}}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"paid\",\"field\":\".status\"},\"source_collection\":\"orders\"},\"version\":1}",
1432
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1433
+ "input": {
1434
+ "change": {
1435
+ "change_kind": "insert",
1436
+ "collection": "orders",
1437
+ "value": {
1438
+ "": {
1439
+ "status": "paid"
1440
+ }
1441
+ }
1442
+ },
1443
+ "contract": "feltdb.trigger.match",
1444
+ "trigger": {
1445
+ "change_kind": "insert",
1446
+ "enabled": true,
1447
+ "predicate": {
1448
+ "equals": "paid",
1449
+ "field": ".status"
1450
+ },
1451
+ "source_collection": "orders"
1452
+ },
1453
+ "version": 1
1454
+ },
1455
+ "name": "empty_key_segment_in_path",
1456
+ "why": "a leading dot addresses a member whose name is the empty string"
1457
+ },
1458
+ {
1459
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"naïve\":\"café ☕\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"café ☕\",\"field\":\"naïve\"},\"source_collection\":\"orders\"},\"version\":1}",
1460
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1461
+ "input": {
1462
+ "change": {
1463
+ "change_kind": "insert",
1464
+ "collection": "orders",
1465
+ "value": {
1466
+ "naïve": "café ☕"
1467
+ }
1468
+ },
1469
+ "contract": "feltdb.trigger.match",
1470
+ "trigger": {
1471
+ "change_kind": "insert",
1472
+ "enabled": true,
1473
+ "predicate": {
1474
+ "equals": "café ☕",
1475
+ "field": "naïve"
1476
+ },
1477
+ "source_collection": "orders"
1478
+ },
1479
+ "version": 1
1480
+ },
1481
+ "name": "unicode_field_and_value",
1482
+ "why": "non-ASCII keys and values survive canonical encoding on both sides"
1483
+ },
1484
+ {
1485
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"note\":\"line\\nbreak\\ttab\\\"quote\\\\slash\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"line\\nbreak\\ttab\\\"quote\\\\slash\",\"field\":\"note\"},\"source_collection\":\"orders\"},\"version\":1}",
1486
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1487
+ "input": {
1488
+ "change": {
1489
+ "change_kind": "insert",
1490
+ "collection": "orders",
1491
+ "value": {
1492
+ "note": "line\nbreak\ttab\"quote\\slash"
1493
+ }
1494
+ },
1495
+ "contract": "feltdb.trigger.match",
1496
+ "trigger": {
1497
+ "change_kind": "insert",
1498
+ "enabled": true,
1499
+ "predicate": {
1500
+ "equals": "line\nbreak\ttab\"quote\\slash",
1501
+ "field": "note"
1502
+ },
1503
+ "source_collection": "orders"
1504
+ },
1505
+ "version": 1
1506
+ },
1507
+ "name": "escaped_control_characters_in_value",
1508
+ "why": "a value containing characters the encoder must escape"
1509
+ },
1510
+ {
1511
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"paid\",\"total\":42}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"paid\",\"field\":\"status\"},\"source_collection\":\"orders\"},\"version\":1}",
1512
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1513
+ "input": {
1514
+ "change": {
1515
+ "change_kind": "insert",
1516
+ "collection": "orders",
1517
+ "value": {
1518
+ "status": "paid",
1519
+ "total": 42
1520
+ }
1521
+ },
1522
+ "contract": "feltdb.trigger.match",
1523
+ "trigger": {
1524
+ "change_kind": "insert",
1525
+ "enabled": true,
1526
+ "predicate": {
1527
+ "equals": "paid",
1528
+ "field": "status"
1529
+ },
1530
+ "source_collection": "orders"
1531
+ },
1532
+ "version": 1
1533
+ },
1534
+ "name": "fanout_first_trigger_matches",
1535
+ "why": "one change against the first of several triggers"
1536
+ },
1537
+ {
1538
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"paid\",\"total\":42}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":42,\"field\":\"total\"},\"source_collection\":\"orders\"},\"version\":1}",
1539
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1540
+ "input": {
1541
+ "change": {
1542
+ "change_kind": "insert",
1543
+ "collection": "orders",
1544
+ "value": {
1545
+ "status": "paid",
1546
+ "total": 42
1547
+ }
1548
+ },
1549
+ "contract": "feltdb.trigger.match",
1550
+ "trigger": {
1551
+ "change_kind": "insert",
1552
+ "enabled": true,
1553
+ "predicate": {
1554
+ "equals": 42,
1555
+ "field": "total"
1556
+ },
1557
+ "source_collection": "orders"
1558
+ },
1559
+ "version": 1
1560
+ },
1561
+ "name": "fanout_second_trigger_matches",
1562
+ "why": "the same change against a second, differently-predicated trigger"
1563
+ },
1564
+ {
1565
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"paid\",\"total\":42}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"shipped\",\"field\":\"status\"},\"source_collection\":\"orders\"},\"version\":1}",
1566
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
1567
+ "input": {
1568
+ "change": {
1569
+ "change_kind": "insert",
1570
+ "collection": "orders",
1571
+ "value": {
1572
+ "status": "paid",
1573
+ "total": 42
1574
+ }
1575
+ },
1576
+ "contract": "feltdb.trigger.match",
1577
+ "trigger": {
1578
+ "change_kind": "insert",
1579
+ "enabled": true,
1580
+ "predicate": {
1581
+ "equals": "shipped",
1582
+ "field": "status"
1583
+ },
1584
+ "source_collection": "orders"
1585
+ },
1586
+ "version": 1
1587
+ },
1588
+ "name": "fanout_third_trigger_rejects",
1589
+ "why": "the same change against a third trigger that does not match"
1590
+ },
1591
+ {
1592
+ "canonical_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"paid\",\"total\":42}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":false,\"predicate\":{\"equals\":\"paid\",\"field\":\"status\"},\"source_collection\":\"orders\"},\"version\":1}",
1593
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"trigger_disabled\"},\"version\":1}",
1594
+ "input": {
1595
+ "change": {
1596
+ "change_kind": "insert",
1597
+ "collection": "orders",
1598
+ "value": {
1599
+ "status": "paid",
1600
+ "total": 42
1601
+ }
1602
+ },
1603
+ "contract": "feltdb.trigger.match",
1604
+ "trigger": {
1605
+ "change_kind": "insert",
1606
+ "enabled": false,
1607
+ "predicate": {
1608
+ "equals": "paid",
1609
+ "field": "status"
1610
+ },
1611
+ "source_collection": "orders"
1612
+ },
1613
+ "version": 1
1614
+ },
1615
+ "name": "fanout_fourth_trigger_disabled",
1616
+ "why": "the same change against a disabled trigger"
1617
+ },
1618
+ {
1619
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1620
+ "name": "malformed_not_json",
1621
+ "raw_input": "not json at all",
1622
+ "why": "bytes that are not JSON at all"
1623
+ },
1624
+ {
1625
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1626
+ "name": "malformed_empty_input",
1627
+ "raw_input": "",
1628
+ "why": "zero bytes"
1629
+ },
1630
+ {
1631
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1632
+ "name": "malformed_truncated_object",
1633
+ "raw_input": "{\"change\":",
1634
+ "why": "a JSON document that ends mid-value"
1635
+ },
1636
+ {
1637
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1638
+ "name": "malformed_trailing_content",
1639
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\"},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":1} trailing",
1640
+ "why": "a complete document followed by more bytes"
1641
+ },
1642
+ {
1643
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1644
+ "name": "malformed_trailing_comma",
1645
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\",},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":1}",
1646
+ "why": "a trailing comma is not JSON"
1647
+ },
1648
+ {
1649
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1650
+ "name": "malformed_single_quotes",
1651
+ "raw_input": "{'contract':'feltdb.trigger.match'}",
1652
+ "why": "single-quoted strings are not JSON"
1653
+ },
1654
+ {
1655
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1656
+ "name": "malformed_top_level_array",
1657
+ "raw_input": "[]",
1658
+ "why": "the input must be an object"
1659
+ },
1660
+ {
1661
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1662
+ "name": "malformed_top_level_string",
1663
+ "raw_input": "\"feltdb.trigger.match\"",
1664
+ "why": "the input must be an object"
1665
+ },
1666
+ {
1667
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1668
+ "name": "malformed_missing_change",
1669
+ "raw_input": "{\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":1}",
1670
+ "why": "a required member is absent"
1671
+ },
1672
+ {
1673
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1674
+ "name": "malformed_missing_trigger",
1675
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\"},\"contract\":\"feltdb.trigger.match\",\"version\":1}",
1676
+ "why": "a required member is absent"
1677
+ },
1678
+ {
1679
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1680
+ "name": "malformed_unknown_top_level_field",
1681
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\"},\"contract\":\"feltdb.trigger.match\",\"extra\":true,\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":1}",
1682
+ "why": "the contract denies unknown members"
1683
+ },
1684
+ {
1685
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1686
+ "name": "malformed_unknown_trigger_field",
1687
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\"},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\",\"target_capability\":\"identity\"},\"version\":1}",
1688
+ "why": "the contract denies unknown members in nested objects"
1689
+ },
1690
+ {
1691
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1692
+ "name": "malformed_duplicate_field",
1693
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\"},\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\"},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":1}",
1694
+ "why": "a repeated contract member is rejected"
1695
+ },
1696
+ {
1697
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1698
+ "name": "malformed_change_kind_value",
1699
+ "raw_input": "{\"change\":{\"change_kind\":\"upsert\",\"collection\":\"o\"},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":1}",
1700
+ "why": "change_kind is a closed set"
1701
+ },
1702
+ {
1703
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1704
+ "name": "malformed_enabled_is_not_bool",
1705
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\"},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":1,\"source_collection\":\"o\"},\"version\":1}",
1706
+ "why": "enabled must be a boolean, not a truthy value"
1707
+ },
1708
+ {
1709
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1710
+ "name": "malformed_collection_is_not_string",
1711
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":7},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":1}",
1712
+ "why": "collection must be a string"
1713
+ },
1714
+ {
1715
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1716
+ "name": "malformed_predicate_missing_field",
1717
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\"},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"x\"},\"source_collection\":\"o\"},\"version\":1}",
1718
+ "why": "a predicate needs both members"
1719
+ },
1720
+ {
1721
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1722
+ "name": "malformed_version_is_float",
1723
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\"},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":1.0}",
1724
+ "why": "version is an integer"
1725
+ },
1726
+ {
1727
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1728
+ "name": "malformed_version_is_negative",
1729
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\"},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":-1}",
1730
+ "why": "version is unsigned"
1731
+ },
1732
+ {
1733
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_ID_MISMATCH\"},\"version\":1}",
1734
+ "name": "contract_id_mismatch",
1735
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\"},\"contract\":\"feltdb.trigger.other\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":1}",
1736
+ "why": "a well-formed input addressed to another contract"
1737
+ },
1738
+ {
1739
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_VERSION_UNSUPPORTED\"},\"version\":1}",
1740
+ "name": "contract_version_unsupported",
1741
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\"},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":2}",
1742
+ "why": "a well-formed input at a version this implementation does not implement"
1743
+ },
1744
+ {
1745
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1746
+ "name": "malformed_and_misaddressed",
1747
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\"},\"contract\":\"feltdb.trigger.other\",\"extra\":1,\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":1}",
1748
+ "why": "shape is validated before identity, so this is an input error"
1749
+ },
1750
+ {
1751
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1752
+ "name": "null_predicate_is_no_predicate",
1753
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\",\"value\":{\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":null,\"source_collection\":\"o\"},\"version\":1}",
1754
+ "why": "an explicit null predicate is the absent predicate"
1755
+ },
1756
+ {
1757
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1758
+ "name": "whitespace_around_document",
1759
+ "raw_input": " {\"change\" : {\"change_kind\":\"insert\",\"collection\":\"o\"} , \"contract\":\"feltdb.trigger.match\", \"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"}, \"version\":1} ",
1760
+ "why": "insignificant whitespace does not change the decision"
1761
+ },
1762
+ {
1763
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1764
+ "name": "unsorted_input_keys_are_still_valid_input",
1765
+ "raw_input": "{\"version\":1,\"trigger\":{\"source_collection\":\"o\",\"enabled\":true,\"change_kind\":\"insert\"},\"contract\":\"feltdb.trigger.match\",\"change\":{\"collection\":\"o\",\"change_kind\":\"insert\"}}",
1766
+ "why": "canonical ordering is how FeltDB emits input, not a parsing requirement"
1767
+ },
1768
+ {
1769
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1770
+ "name": "unsorted_nested_keys_still_compare_equal",
1771
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"customer\":{\"zeta\":1,\"alpha\":2}}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":{\"alpha\":2,\"zeta\":1},\"field\":\"customer\"},\"source_collection\":\"orders\"},\"version\":1}",
1772
+ "why": "object equality is by member, so a record encoded with unsorted keys still equals a sorted expectation"
1773
+ },
1774
+ {
1775
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1776
+ "name": "duplicate_key_inside_record_resolves_last_wins",
1777
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"status\":\"draft\",\"status\":\"paid\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"paid\",\"field\":\"status\"},\"source_collection\":\"orders\"},\"version\":1}",
1778
+ "why": "a repeated member inside an opaque record collapses to its last value, as a map-backed decoder does"
1779
+ },
1780
+ {
1781
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1782
+ "name": "escaped_unicode_equals_literal_unicode",
1783
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"note\":\"caf\\u00e9\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"café\",\"field\":\"note\"},\"source_collection\":\"orders\"},\"version\":1}",
1784
+ "why": "\\u escapes and literal UTF-8 decode to the same string, so the encoding of the input cannot decide"
1785
+ },
1786
+ {
1787
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1788
+ "name": "surrogate_pair_escape_decodes",
1789
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"note\":\"\\ud83d\\udd25\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":\"🔥\",\"field\":\"note\"},\"source_collection\":\"orders\"},\"version\":1}",
1790
+ "why": "an astral character written as a surrogate pair equals the same character written literally"
1791
+ },
1792
+ {
1793
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
1794
+ "name": "exponent_notation_is_a_float",
1795
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"total\":1e2}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":100,\"field\":\"total\"},\"source_collection\":\"orders\"},\"version\":1}",
1796
+ "why": "1e2 is a float and 100 is an integer, so they are different values"
1797
+ },
1798
+ {
1799
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1800
+ "name": "exponent_notation_equals_decimal_float",
1801
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"total\":1e2}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":100.0,\"field\":\"total\"},\"source_collection\":\"orders\"},\"version\":1}",
1802
+ "why": "1e2 and 100.0 are the same float"
1803
+ },
1804
+ {
1805
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
1806
+ "name": "integer_beyond_u64_becomes_a_float",
1807
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"counter\":18446744073709551616}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":18446744073709551615,\"field\":\"counter\"},\"source_collection\":\"orders\"},\"version\":1}",
1808
+ "why": "an integer literal too large for u64 is a float on both sides, so it cannot equal an integer"
1809
+ },
1810
+ {
1811
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1812
+ "name": "high_precision_float_round_trips",
1813
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"rate\":3.141592653589793}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":3.141592653589793,\"field\":\"rate\"},\"source_collection\":\"orders\"},\"version\":1}",
1814
+ "why": "a float needing full precision decodes identically on both sides"
1815
+ },
1816
+ {
1817
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1818
+ "name": "malformed_leading_zero_number",
1819
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\",\"value\":{\"total\":01}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":1}",
1820
+ "why": "01 is not a JSON number"
1821
+ },
1822
+ {
1823
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1824
+ "name": "malformed_nan_literal",
1825
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\",\"value\":{\"total\":NaN}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":1}",
1826
+ "why": "NaN is not a JSON value, and a contract that accepted it would admit a value with no equality"
1827
+ },
1828
+ {
1829
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1830
+ "name": "malformed_raw_control_character_in_string",
1831
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\",\"value\":{\"note\":\"a\nb\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":1}",
1832
+ "why": "an unescaped control character is not legal inside a JSON string"
1833
+ },
1834
+ {
1835
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"error\":{\"code\":\"CONTRACT_INPUT_INVALID\"},\"version\":1}",
1836
+ "name": "malformed_lone_surrogate_escape",
1837
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"o\",\"value\":{\"note\":\"\\ud83d\"}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"source_collection\":\"o\"},\"version\":1}",
1838
+ "why": "an unpaired surrogate does not name a character"
1839
+ },
1840
+ {
1841
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1842
+ "name": "negative_zero_equals_negative_zero",
1843
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"delta\":-0}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":-0.0,\"field\":\"delta\"},\"source_collection\":\"orders\"},\"version\":1}",
1844
+ "why": "-0 and -0.0 decode to the same float"
1845
+ },
1846
+ {
1847
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":true,\"reason\":\"matched\"},\"version\":1}",
1848
+ "name": "negative_zero_float_equals_positive_zero_float",
1849
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"delta\":-0.0}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":0.0,\"field\":\"delta\"},\"source_collection\":\"orders\"},\"version\":1}",
1850
+ "why": "float equality is IEEE equality, under which -0.0 and 0.0 are equal"
1851
+ },
1852
+ {
1853
+ "expected_output": "{\"contract\":\"feltdb.trigger.match\",\"outcome\":{\"matched\":false,\"reason\":\"predicate_value_mismatch\"},\"version\":1}",
1854
+ "name": "negative_integer_beyond_i64_becomes_a_float",
1855
+ "raw_input": "{\"change\":{\"change_kind\":\"insert\",\"collection\":\"orders\",\"value\":{\"floor\":-9223372036854775809}},\"contract\":\"feltdb.trigger.match\",\"trigger\":{\"change_kind\":\"insert\",\"enabled\":true,\"predicate\":{\"equals\":-9223372036854775808,\"field\":\"floor\"},\"source_collection\":\"orders\"},\"version\":1}",
1856
+ "why": "a negative integer literal too small for i64 decodes as a float"
1857
+ }
1858
+ ],
1859
+ "contract": "feltdb.trigger.match",
1860
+ "contract_version": 1,
1861
+ "corpus_version": 1
1862
+ }