hecks 3.14.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (427) hide show
  1. checksums.yaml +4 -4
  2. data/examples/pizzas/adapters/fake_processor.rb +34 -0
  3. data/examples/pizzas/adapters/payment_signature.rb +66 -0
  4. data/examples/pizzas/adapters/payment_webhook.rb +87 -0
  5. data/examples/pizzas/bluebook/pizzas.behaviors +33 -0
  6. data/examples/pizzas/bluebook/pizzas.hecksagon +5 -3
  7. data/examples/pizzas/config.ru +22 -0
  8. data/exe/hecks +1 -1
  9. data/lib/hecks/adapters/driven/prism.rb +0 -2
  10. data/lib/hecks/adapters/driven.rb +0 -2
  11. data/lib/hecks/adapters/driving/json.rb +9 -16
  12. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -2
  13. data/lib/hecks/bluebook/dsl/derivation_words.rb +58 -0
  14. data/lib/hecks/bluebook/dsl/translation_builder.rb +6 -37
  15. data/lib/hecks/bluebook/expression/ast_json.rb +0 -9
  16. data/lib/hecks/bluebook/hecksagon.rb +1 -1
  17. data/lib/hecks/bluebook/meta_validator/translation_judge/rules.rb +7 -10
  18. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +4 -8
  19. data/lib/hecks/bluebook/meta_validator.rb +0 -11
  20. data/lib/hecks/bluebook/translation.rb +18 -10
  21. data/lib/hecks/bluebook/translation_expression/evaluator.rb +63 -0
  22. data/lib/hecks/bluebook/translation_expression/parser.rb +127 -0
  23. data/lib/hecks/bluebook/translation_expression.rb +39 -0
  24. data/lib/hecks/bluebook/translation_plan.rb +70 -0
  25. data/lib/hecks/bluebook.rb +2 -0
  26. data/lib/hecks/chapters.rb +3 -3
  27. data/lib/hecks/cli/project_cli/launcher_source.rb +1 -1
  28. data/lib/hecks/composer/adapters/claude_composer.adapter +3 -0
  29. data/lib/hecks/composer/adapters/claude_composer.rb +83 -0
  30. data/lib/hecks/composer/adapters/fake_agent.adapter +3 -0
  31. data/lib/hecks/composer/adapters/fake_agent.rb +55 -0
  32. data/lib/hecks/composer/adapters/jev.adapter +3 -0
  33. data/lib/hecks/composer/adapters/jev.rb +66 -0
  34. data/lib/hecks/composer/agent.rb +113 -0
  35. data/lib/hecks/composer/assistant.rb +110 -0
  36. data/lib/hecks/composer/behavior_run.rb +53 -0
  37. data/lib/hecks/composer/bluebook/composer.bluebook +178 -0
  38. data/lib/hecks/composer/bluebook/composer.hecksagon +16 -0
  39. data/lib/hecks/composer/board.rb +65 -0
  40. data/lib/hecks/composer/board_edit/command_text.rb +39 -0
  41. data/lib/hecks/composer/board_edit/source.rb +84 -0
  42. data/lib/hecks/composer/board_edit.rb +144 -0
  43. data/lib/hecks/composer/check.rb +89 -0
  44. data/lib/hecks/composer/domains.rb +81 -0
  45. data/lib/hecks/composer/jobs.rb +134 -0
  46. data/lib/hecks/composer/layout.rb +37 -0
  47. data/lib/hecks/composer/live.rb +150 -0
  48. data/lib/hecks/composer/outline.rb +48 -0
  49. data/lib/hecks/composer/page.html +989 -0
  50. data/lib/hecks/composer/panels.rb +142 -0
  51. data/lib/hecks/composer/parse.rb +83 -0
  52. data/lib/hecks/composer/plain.rb +28 -0
  53. data/lib/hecks/composer/ports/composer_agent.port +7 -0
  54. data/lib/hecks/composer/session.rb +141 -0
  55. data/lib/hecks/composer/toolbox.rb +166 -0
  56. data/lib/hecks/composer/web.rb +156 -0
  57. data/lib/hecks/composer/workbench.rb +51 -0
  58. data/lib/hecks/composer/workspace.rb +81 -0
  59. data/lib/hecks/composer.rb +17 -0
  60. data/lib/hecks/corpus/adapters.rb +22 -0
  61. data/lib/hecks/corpus/rust.rb +1 -1
  62. data/lib/hecks/corpus/worlds.rb +19 -0
  63. data/lib/hecks/corpus.rb +5 -0
  64. data/lib/hecks/forms/app/commands.rb +2 -3
  65. data/lib/hecks/forms/app/queries.rb +2 -3
  66. data/lib/hecks/forms/app/records.rb +17 -5
  67. data/lib/hecks/forms/app/responses.rb +3 -1
  68. data/lib/hecks/forms/command_form_renderer.rb +42 -16
  69. data/lib/hecks/forms/field_controls.rb +2 -2
  70. data/lib/hecks/forms/field_renderer.rb +1 -1
  71. data/lib/hecks/forms/field_shape.rb +36 -17
  72. data/lib/hecks/forms/index_renderer.rb +2 -1
  73. data/lib/hecks/forms/page.rb +1 -1
  74. data/lib/hecks/forms/params.rb +0 -13
  75. data/lib/hecks/forms/query_form_renderer.rb +7 -6
  76. data/lib/hecks/forms/record_renderer.rb +11 -7
  77. data/lib/hecks/forms/rule_words.rb +100 -0
  78. data/lib/hecks/forms/value_object_shape.rb +2 -1
  79. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -3
  80. data/lib/hecks/fuzzing/isolated_boot/worlds.rb +3 -6
  81. data/lib/hecks/fuzzing/replay/filters.rb +2 -6
  82. data/lib/hecks/gate/stages.yml +25 -0
  83. data/lib/hecks/grammar/evolve/seeds.rb +0 -6
  84. data/lib/hecks/grammar/evolve.rb +0 -3
  85. data/lib/hecks/grammar/translation.bluebook +1 -1
  86. data/lib/hecks/hecks/adapters/codebase/composing.rb +56 -0
  87. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +3 -1
  88. data/lib/hecks/hecks/adapters/first_admin.rb +3 -3
  89. data/lib/hecks/hecks/adapters/journal_store/changes.rb +0 -26
  90. data/lib/hecks/hecks/adapters/journal_store/examination.rb +2 -23
  91. data/lib/hecks/hecks/adapters/journal_store/readings.rb +3 -11
  92. data/lib/hecks/hecks/adapters/journal_store.rb +0 -11
  93. data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +4 -11
  94. data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +0 -9
  95. data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +0 -4
  96. data/lib/hecks/hecks/codebase.behaviors +6 -0
  97. data/lib/hecks/hecks/codebase.bluebook +21 -0
  98. data/lib/hecks/hecks/composer.behaviors +68 -0
  99. data/lib/hecks/hecks/context_map.hecksagon +1 -1
  100. data/lib/hecks/hecks/custodian.behaviors +0 -6
  101. data/lib/hecks/hecks/custodian.bluebook +3 -80
  102. data/lib/hecks/hecks/hecks.hecksagon +2 -2
  103. data/lib/hecks/hecks/hecks.world +1 -1
  104. data/lib/hecks/hecks/rehearsal.bluebook +7 -13
  105. data/lib/hecks/kernel_capabilities/templates.rb +4 -4
  106. data/lib/hecks/kernel_capabilities.rb +1 -1
  107. data/lib/hecks/language/bluebook/vocabulary.bluebook +2 -3
  108. data/lib/hecks/language/translation/translation_aggregate.bluebook +21 -24
  109. data/lib/hecks/ports/access_control.rb +2 -2
  110. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +3 -41
  111. data/lib/hecks/ports/persistence/plugins/era/lineage/coverage.rb +7 -7
  112. data/lib/hecks/ports/persistence/plugins/era/lineage/rewrite.rb +25 -2
  113. data/lib/hecks/ports/persistence/plugins/era/lineage/rules.rb +4 -4
  114. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +17 -25
  115. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/base_sql.rb +0 -12
  116. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/domain_rename.rb +1 -1
  117. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +2 -22
  118. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +0 -1
  119. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +9 -3
  120. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +3 -29
  121. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/refusals.rb +2 -26
  122. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +6 -33
  123. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -3
  124. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +2 -4
  125. data/lib/hecks/ports/persistence/plugins/era/translation/expression_sql.rb +52 -0
  126. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +23 -29
  127. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +1 -1
  128. data/lib/hecks/ports/persistence/plugins/era/translation.rb +0 -1
  129. data/lib/hecks/ports/persistence/plugins/era.rb +3 -6
  130. data/lib/hecks/ports.rb +0 -1
  131. data/lib/hecks/projection_files.rb +3 -1
  132. data/lib/hecks/projections/deploy/templates/lambda/nat_comment_oauth.tmpl +1 -1
  133. data/lib/hecks/projections/glossary/entries.rb +10 -4
  134. data/lib/hecks/projections/glossary/groups.rb +42 -0
  135. data/lib/hecks/projections/glossary/html/page.rb +7 -2
  136. data/lib/hecks/projections/glossary/html/parser.rb +1 -1
  137. data/lib/hecks/projections/glossary/html/sections.rb +31 -11
  138. data/lib/hecks/projections/glossary/html.rb +1 -2
  139. data/lib/hecks/projections/glossary/markdown.rb +31 -28
  140. data/lib/hecks/projections/glossary/mermaid.rb +3 -0
  141. data/lib/hecks/projections/glossary/page.css +143 -153
  142. data/lib/hecks/projections/glossary/page.js +63 -3
  143. data/lib/hecks/projections/glossary/sentences/actions.rb +88 -0
  144. data/lib/hecks/projections/glossary/sentences/paths.rb +77 -0
  145. data/lib/hecks/projections/glossary/sentences/queries.rb +90 -0
  146. data/lib/hecks/projections/glossary/sentences/value_objects.rb +32 -5
  147. data/lib/hecks/projections/glossary/sentences.rb +13 -3
  148. data/lib/hecks/projections/glossary/slugs.rb +4 -1
  149. data/lib/hecks/projections/glossary.rb +2 -1
  150. data/lib/hecks/projections/plain_english.rb +97 -0
  151. data/lib/hecks/projections/rust_vocabulary/arguments.rb +2 -2
  152. data/lib/hecks/projections/rust_vocabulary/enum_body.rb +20 -25
  153. data/lib/hecks/projections/rust_vocabulary/tests.rb +2 -2
  154. data/lib/hecks/projections/rust_vocabulary.rb +14 -6
  155. data/lib/hecks/projections/site/cms_editor/color.rb +0 -6
  156. data/lib/hecks/projections/site/cms_editor/templates/src/host.ts.tmpl +7 -2
  157. data/lib/hecks/projections/statements/actions.rb +99 -0
  158. data/lib/hecks/projections/statements/relationships.rb +86 -0
  159. data/lib/hecks/projections/statements.rb +15 -24
  160. data/lib/hecks/projector/exporter/adapters.rb +112 -0
  161. data/lib/hecks/projector/exporter/translations.rb +18 -35
  162. data/lib/hecks/projector/exporter/worlds.rb +103 -0
  163. data/lib/hecks/projector/exporter.rb +5 -1
  164. data/lib/hecks/quality_control/adapters/agent.rb +6 -7
  165. data/lib/hecks/quality_control/adapters/agent_profile.rb +16 -114
  166. data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +1 -1
  167. data/lib/hecks/runtime/loader/boot_steps.rb +0 -20
  168. data/lib/hecks/runtime/outbox.rb +2 -9
  169. data/lib/hecks/runtime/port_operation_interpreter.rb +1 -9
  170. data/lib/hecks/runtime/remote_dispatcher.rb +2 -2
  171. data/lib/hecks/runtime/value/unwrapping.rb +60 -0
  172. data/lib/hecks/runtime/value.rb +10 -21
  173. data/lib/hecks/rust_build/project_rust/target_ir.rb +23 -4
  174. data/lib/hecks/rust_build/wasm.rb +0 -12
  175. data/lib/hecks/rust_build/write_if_changed.rb +12 -12
  176. data/lib/hecks/rust_format.rb +77 -0
  177. data/lib/hecks/tools/fuzz_sweep/findings.rb +3 -9
  178. data/lib/hecks/tools/fuzz_sweep.rb +1 -3
  179. data/lib/hecks/tools/translation_audit/verdicts.rb +3 -28
  180. data/lib/hecks/tools/translation_audit.rb +8 -10
  181. data/lib/hecks/tools/translation_scaffold/reporting.rb +1 -1
  182. data/lib/hecks/version.rb +1 -1
  183. data/lib/hecks/vocabulary.rb +2 -1
  184. data/lib/hecks.rb +3 -0
  185. data/prebuilt/{1a6f596be124228be93eba1d86dbc9d2933190fa389b284331241cb9f27115a0.marshal → ad68f9e06c8068c2a4176b57abf3083d591d5d8980c2b3e897b97331f965b643.marshal} +0 -0
  186. data/prebuilt/{a883a7e568667aa5ac904c82daff356bdf9e996252a36af6def4a4a43efb967e.marshal → ee22ec8642c4006717ba2b80f46e5efb81de459eef9dfec043e838c0ad4fd720.marshal} +0 -0
  187. data/prebuilt/{verdicts-872993b1aa26d73fe48f28251374b8585fed145d02aab42be0f00de386b6ff80.json → verdicts-b69f5dcbba79c20daa0493476fa7c317004a30aa2bc3d3dc6a722ea70ae2b43b.json} +1 -1
  188. data/rust/Cargo.toml +40 -0
  189. data/rust/build/Cargo.toml +36 -0
  190. data/rust/build/clippy.toml +4 -0
  191. data/rust/build/src/adapters_pass.rs +196 -0
  192. data/rust/build/src/binding_pass.rs +54 -13
  193. data/rust/build/src/build_artifact.rs +23 -5
  194. data/rust/build/src/cargo_sync.rs +69 -26
  195. data/rust/build/src/lineage_pass.rs +101 -87
  196. data/rust/build/src/main.rs +11 -2
  197. data/rust/build/src/pipeline.rs +80 -19
  198. data/rust/build/src/reserved_names.rs +6 -50
  199. data/rust/build/src/resolve.rs +82 -35
  200. data/rust/build/src/rustfmt.rs +100 -0
  201. data/rust/build/src/seams_pass.rs +85 -16
  202. data/rust/build/src/subprocess.rs +30 -6
  203. data/rust/build/src/tmp.rs +5 -2
  204. data/rust/build/src/translation_pass.rs +72 -22
  205. data/rust/build/src/world_pass.rs +109 -0
  206. data/rust/clippy.toml +4 -0
  207. data/rust/codegen/Cargo.toml +36 -0
  208. data/rust/codegen/clippy.toml +4 -0
  209. data/rust/codegen/src/asks.rs +40 -14
  210. data/rust/codegen/src/attr.rs +2 -2
  211. data/rust/codegen/src/bridging.rs +676 -117
  212. data/rust/codegen/src/commands.rs +979 -373
  213. data/rust/codegen/src/constraints.rs +88 -25
  214. data/rust/codegen/src/dependency_planning.rs +128 -34
  215. data/rust/codegen/src/domain_generator.rs +306 -170
  216. data/rust/codegen/src/exemplar.rs +87 -32
  217. data/rust/codegen/src/expr_emitter.rs +54 -6
  218. data/rust/codegen/src/fielded.rs +193 -41
  219. data/rust/codegen/src/hecks_naming.rs +124 -16
  220. data/rust/codegen/src/hecks_naming_tests.rs +81 -0
  221. data/rust/codegen/src/json.rs +80 -44
  222. data/rust/codegen/src/json_codec.rs +585 -149
  223. data/rust/codegen/src/literal.rs +104 -138
  224. data/rust/codegen/src/main.rs +151 -52
  225. data/rust/codegen/src/manifest.rs +76 -14
  226. data/rust/codegen/src/mutations.rs +1212 -239
  227. data/rust/codegen/src/naming.rs +111 -60
  228. data/rust/codegen/src/optional_pass.rs +90 -28
  229. data/rust/codegen/src/ports.rs +5 -4
  230. data/rust/codegen/src/prelude.rs +139 -49
  231. data/rust/codegen/src/presenters.rs +335 -0
  232. data/rust/codegen/src/queries.rs +601 -226
  233. data/rust/codegen/src/reactions.rs +268 -74
  234. data/rust/codegen/src/read_models.rs +574 -229
  235. data/rust/codegen/src/reference_specs.rs +16 -3
  236. data/rust/codegen/src/registry.rs +128 -79
  237. data/rust/codegen/src/reserved_names.rs +6 -50
  238. data/rust/codegen/src/shared.rs +71 -22
  239. data/rust/codegen/src/sidecars.rs +15 -5
  240. data/rust/codegen/src/skip_reason.rs +8 -2
  241. data/rust/codegen/src/types.rs +306 -108
  242. data/rust/host/Cargo.lock +1 -0
  243. data/rust/host/Cargo.toml +40 -4
  244. data/rust/host/HECKS_RELEASE +1 -1
  245. data/rust/host/clippy.toml +4 -0
  246. data/rust/host/src/api.rs +698 -218
  247. data/rust/host/src/auth.rs +491 -214
  248. data/rust/host/src/b64.rs +91 -0
  249. data/rust/host/src/bin/expr_harness.rs +6 -2
  250. data/rust/host/src/bin/lineage_harness.rs +47 -11
  251. data/rust/host/src/bin/mint_harness.rs +70 -37
  252. data/rust/host/src/bin/validate_harness.rs +16 -8
  253. data/rust/host/src/boot.rs +144 -68
  254. data/rust/host/src/boundary_fuzz/api.rs +130 -32
  255. data/rust/host/src/boundary_fuzz/auth.rs +108 -23
  256. data/rust/host/src/boundary_fuzz/expr_json.rs +85 -11
  257. data/rust/host/src/boundary_fuzz/ir.rs +164 -12
  258. data/rust/host/src/boundary_fuzz/server.rs +283 -36
  259. data/rust/host/src/boundary_fuzz/web.rs +56 -8
  260. data/rust/host/src/checkout.rs +78 -32
  261. data/rust/host/src/clock.rs +8 -0
  262. data/rust/host/src/commerce_ir.rs +333 -95
  263. data/rust/host/src/crypto.rs +33 -0
  264. data/rust/host/src/dispatch.rs +1037 -331
  265. data/rust/host/src/expr_json.rs +1021 -273
  266. data/rust/host/src/extension.rs +24 -4
  267. data/rust/host/src/field_hints.rs +11 -7
  268. data/rust/host/src/fuzz_support.rs +85 -13
  269. data/rust/host/src/host.rs +100 -0
  270. data/rust/host/src/http.rs +22 -0
  271. data/rust/host/src/ir.rs +326 -16
  272. data/rust/host/src/journal.rs +277 -176
  273. data/rust/host/src/lambda_client.rs +219 -53
  274. data/rust/host/src/lib.rs +16 -4
  275. data/rust/host/src/log.rs +62 -11
  276. data/rust/host/src/mint.rs +1153 -326
  277. data/rust/host/src/needs.rs +185 -44
  278. data/rust/host/src/payments/keystore.rs +197 -45
  279. data/rust/host/src/payments/roles.rs +39 -7
  280. data/rust/host/src/payments/tests.rs +1427 -282
  281. data/rust/host/src/payments.rs +391 -112
  282. data/rust/host/src/platform_signin/attack_tests.rs +5 -5
  283. data/rust/host/src/platform_signin/config.rs +11 -11
  284. data/rust/host/src/platform_signin/cookie.rs +2 -2
  285. data/rust/host/src/platform_signin/extension.rs +2 -1
  286. data/rust/host/src/platform_signin/handler.rs +9 -8
  287. data/rust/host/src/platform_signin/jti.rs +4 -2
  288. data/rust/host/src/platform_signin/jwks.rs +2 -1
  289. data/rust/host/src/platform_signin/jws.rs +2 -37
  290. data/rust/host/src/platform_signin/known_answer_tests.rs +5 -1
  291. data/rust/host/src/platform_signin/mode_tests.rs +5 -3
  292. data/rust/host/src/platform_signin/pages.rs +20 -20
  293. data/rust/host/src/platform_signin/session.rs +8 -1
  294. data/rust/host/src/platform_signin/settings.rs +6 -6
  295. data/rust/host/src/platform_signin/strict_json.rs +12 -9
  296. data/rust/host/src/platform_signin/verify.rs +41 -41
  297. data/rust/host/src/platform_signin/wiring_support.rs +13 -18
  298. data/rust/host/src/presentation.rs +207 -63
  299. data/rust/host/src/presentation_write.rs +502 -187
  300. data/rust/host/src/query_step.rs +69 -18
  301. data/rust/host/src/rate_limit.rs +541 -142
  302. data/rust/host/src/reference_transform.rs +77 -25
  303. data/rust/host/src/reference_validate.rs +443 -104
  304. data/rust/host/src/resend.rs +190 -55
  305. data/rust/host/src/secrets.rs +116 -21
  306. data/rust/host/src/server.rs +555 -104
  307. data/rust/host/src/storage_shape.rs +88 -21
  308. data/rust/host/src/test_pg.rs +17 -7
  309. data/rust/host/src/ui_schema.rs +495 -207
  310. data/rust/host/src/wasm_runner.rs +21 -6
  311. data/rust/host/src/web/commerce.rs +101 -23
  312. data/rust/host/src/web/newsletter/cooldown.rs +10 -3
  313. data/rust/host/src/web/newsletter/template.rs +26 -7
  314. data/rust/host/src/web/newsletter/tests.rs +112 -23
  315. data/rust/host/src/web/newsletter.rs +209 -59
  316. data/rust/host/src/web/newsletter_send.rs +251 -79
  317. data/rust/host/src/web/registration_receipt/tests.rs +16 -4
  318. data/rust/host/src/web/registration_receipt.rs +100 -24
  319. data/rust/host/src/web/registrations.rs +1384 -332
  320. data/rust/host/src/web/resend_webhook.rs +138 -80
  321. data/rust/host/src/web.rs +2416 -508
  322. data/rust/lsp/Cargo.toml +36 -0
  323. data/rust/lsp/clippy.toml +4 -0
  324. data/rust/lsp/src/json.rs +29 -22
  325. data/rust/lsp/src/main.rs +81 -31
  326. data/rust/lsp/src/outline.rs +23 -7
  327. data/rust/lsp/src/rpc.rs +17 -4
  328. data/rust/parser/Cargo.toml +36 -0
  329. data/rust/parser/clippy.toml +4 -0
  330. data/rust/parser/src/build/closed_sets.rs +6 -1
  331. data/rust/parser/src/build/identity.rs +4 -3
  332. data/rust/parser/src/build/mod.rs +1 -1
  333. data/rust/parser/src/build/named_pattern.rs +4 -1
  334. data/rust/parser/src/build/naming.rs +2 -80
  335. data/rust/parser/src/build/pattern_subset.rs +6 -8
  336. data/rust/parser/src/build/query_derive.rs +3 -1
  337. data/rust/parser/src/build/query_inference.rs +14 -5
  338. data/rust/parser/src/build/read_model.rs +4 -1
  339. data/rust/parser/src/build/references.rs +4 -3
  340. data/rust/parser/src/canonical.rs +34 -15
  341. data/rust/parser/src/emit.rs +187 -105
  342. data/rust/parser/src/expr/ast_json.rs +134 -42
  343. data/rust/parser/src/expr/evaluator.rs +27 -9
  344. data/rust/parser/src/expr/mod.rs +54 -13
  345. data/rust/parser/src/expr/resolver.rs +299 -92
  346. data/rust/parser/src/ir.rs +35 -3
  347. data/rust/parser/src/keywords.rs +7168 -516
  348. data/rust/parser/src/lex.rs +11 -25
  349. data/rust/parser/src/lib.rs +1 -0
  350. data/rust/parser/src/main.rs +65 -6
  351. data/rust/parser/src/parse/adapter.rs +157 -0
  352. data/rust/parser/src/parse/aggregate.rs +19 -10
  353. data/rust/parser/src/parse/chapter.rs +16 -17
  354. data/rust/parser/src/parse/command.rs +35 -16
  355. data/rust/parser/src/parse/domain_port.rs +4 -7
  356. data/rust/parser/src/parse/entity.rs +21 -11
  357. data/rust/parser/src/parse/hecksagon.rs +10 -4
  358. data/rust/parser/src/parse/lifecycle.rs +9 -5
  359. data/rust/parser/src/parse/mod.rs +22 -91
  360. data/rust/parser/src/parse/needs.rs +21 -12
  361. data/rust/parser/src/parse/policy.rs +2 -2
  362. data/rust/parser/src/parse/process_manager.rs +9 -11
  363. data/rust/parser/src/parse/query.rs +8 -4
  364. data/rust/parser/src/parse/read_model.rs +57 -16
  365. data/rust/parser/src/parse/value_object.rs +7 -2
  366. data/rust/parser/src/parse/world.rs +322 -0
  367. data/rust/parser/src/ruby_value.rs +7 -6
  368. data/rust/src/exemplar/json.rs +4 -4
  369. data/rust/src/exemplar/mutations.rs +18 -0
  370. data/rust/src/exemplar/read_models.rs +1 -10
  371. data/rust/src/kernel/attribute_shapes/composite.rs +54 -14
  372. data/rust/src/kernel/attribute_shapes/list.rs +2 -2
  373. data/rust/src/kernel/attribute_shapes/mod.rs +8 -8
  374. data/rust/src/kernel/attribute_shapes/scalar.rs +2 -2
  375. data/rust/src/kernel/cli.rs +244 -114
  376. data/rust/src/kernel/dispatch.rs +323 -115
  377. data/rust/src/kernel/dispatch_guard_tests.rs +327 -65
  378. data/rust/src/kernel/expr.rs +203 -86
  379. data/rust/src/kernel/expression_operators/arithmetic.rs +138 -25
  380. data/rust/src/kernel/expression_operators/comparison.rs +87 -2
  381. data/rust/src/kernel/expression_operators/enumeration.rs +106 -22
  382. data/rust/src/kernel/expression_operators/logical.rs +9 -3
  383. data/rust/src/kernel/expression_operators/membership.rs +3 -1
  384. data/rust/src/kernel/expression_operators/mod.rs +34 -21
  385. data/rust/src/kernel/expression_operators/pattern_match.rs +46 -11
  386. data/rust/src/kernel/expression_operators/positional.rs +84 -30
  387. data/rust/src/kernel/expression_operators/presence.rs +52 -13
  388. data/rust/src/kernel/expression_operators/sign_test.rs +3 -1
  389. data/rust/src/kernel/expression_operators/sized.rs +24 -8
  390. data/rust/src/kernel/expression_operators/text.rs +120 -27
  391. data/rust/src/kernel/expression_operators/to_string.rs +10 -4
  392. data/rust/src/kernel/json.rs +244 -148
  393. data/rust/src/kernel/mod.rs +47 -33
  394. data/rust/src/kernel/named_query.rs +63 -15
  395. data/rust/src/kernel/needs.rs +112 -25
  396. data/rust/src/kernel/orchestrate.rs +980 -581
  397. data/rust/src/kernel/orchestrate_guard_tests.rs +538 -140
  398. data/rust/src/kernel/pattern.rs +107 -34
  399. data/rust/src/kernel/present.rs +261 -0
  400. data/rust/src/kernel/query_comparators.rs +118 -41
  401. data/rust/src/kernel/query_ordering.rs +13 -5
  402. data/rust/src/kernel/read_model.rs +479 -181
  403. data/rust/src/kernel/reference_lookup.rs +122 -26
  404. data/rust/src/kernel/repository.rs +293 -66
  405. data/rust/src/kernel/routing.rs +58 -42
  406. data/rust/src/kernel/ruby_float.rs +139 -0
  407. data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +57 -57
  408. data/rust/src/kernel/vocab/entity_dispatch_order.rs +54 -54
  409. data/rust/src/kernel/vocab/field_hint.rs +19 -25
  410. data/rust/src/kernel/vocab/mod.rs +6 -6
  411. data/rust/src/kernel/vocab/query_comparator.rs +23 -24
  412. data/rust/src/kernel/vocab/refusal_template.rs +501 -297
  413. data/rust/src/lib.rs +50 -0
  414. data/rust/src/main.rs +4 -1
  415. data/rust/web/Cargo.toml +36 -0
  416. data/rust/web/clippy.toml +4 -0
  417. metadata +85 -15
  418. data/examples/pizzas/bluebook/hecksagon/mock_stripe_payment_adapter.rb +0 -36
  419. data/lib/hecks/adapters/driven/google_authentication.adapter +0 -3
  420. data/lib/hecks/adapters/driven/google_authentication.rb +0 -99
  421. data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +0 -3
  422. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +0 -32
  423. data/lib/hecks/ports/authentication.port +0 -6
  424. data/lib/hecks/ports/authentication.rb +0 -67
  425. data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +0 -255
  426. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +0 -22
  427. data/rust/host/src/approval.rs +0 -652
@@ -10,12 +10,24 @@ struct Bus {
10
10
 
11
11
  impl AggregateScan for Bus {
12
12
  fn scan(&self, aggregate: &str) -> Option<Vec<(String, Json)>> {
13
- (aggregate == "D::Order").then(|| vec![("o1".to_string(), Json::obj(vec![])), ("o2".to_string(), Json::obj(vec![]))])
13
+ (aggregate == "D::Order").then(|| {
14
+ vec![
15
+ ("o1".to_string(), Json::obj(vec![])),
16
+ ("o2".to_string(), Json::obj(vec![])),
17
+ ]
18
+ })
14
19
  }
15
20
  }
16
21
 
17
22
  fn event(name: &str, aggregate: &str, id: &str, payload: Json) -> Event {
18
- Event { name: name.to_string(), aggregate: aggregate.to_string(), id: id.to_string(), payload, occurred_at: None, correlation: None }
23
+ Event {
24
+ name: name.to_string(),
25
+ aggregate: aggregate.to_string(),
26
+ id: id.to_string(),
27
+ payload,
28
+ occurred_at: None,
29
+ correlation: None,
30
+ }
19
31
  }
20
32
 
21
33
  // `D::Xfer.<Name>` emits an event called `<Name>` correlated on `ref: x1`; a verb ending in
@@ -33,10 +45,20 @@ fn script(
33
45
  return Err(Refusal::GivenNotMet("refused".to_string()));
34
46
  }
35
47
  if let Some(name) = verb.strip_prefix("D::Xfer.") {
36
- return Ok(vec![event(name, "D::Xfer", "x1", Json::obj(vec![("ref", Json::str("x1"))]))]);
48
+ return Ok(vec![event(
49
+ name,
50
+ "D::Xfer",
51
+ "x1",
52
+ Json::obj(vec![("ref", Json::str("x1"))]),
53
+ )]);
37
54
  }
38
55
  match verb {
39
- "D::Order.Place" => Ok(vec![event("Placed", "D::Order", "o1", Json::obj(vec![("amount", Json::int(5))]))]),
56
+ "D::Order.Place" => Ok(vec![event(
57
+ "Placed",
58
+ "D::Order",
59
+ "o1",
60
+ Json::obj(vec![("amount", Json::int(5))]),
61
+ )]),
40
62
  "D::Order.Ping" => Ok(vec![event("Ping", "D::Order", "o1", Json::obj(vec![]))]),
41
63
  _ => Ok(vec![]),
42
64
  }
@@ -65,26 +87,64 @@ const fn policy(name: &'static str, event_name: &'static str, target: &'static s
65
87
  }
66
88
 
67
89
  const fn cross(name: &'static str, event_name: &'static str) -> CrossDomainPolicyRule {
68
- CrossDomainPolicyRule { policy_name: name, event_name, event_qualifier: None, where_expr: None, target_domain: "Other", target_verb: "Other::Do" }
90
+ CrossDomainPolicyRule {
91
+ policy_name: name,
92
+ event_name,
93
+ event_qualifier: None,
94
+ where_expr: None,
95
+ target_domain: "Other",
96
+ target_verb: "Other::Do",
97
+ }
69
98
  }
70
99
 
71
100
  static POLICIES: [PolicyRule; 8] = [
72
101
  policy("NotifyOnPlaced", "Placed", "D::Order.Notify"),
73
- PolicyRule { event_qualifier: Some("Other"), ..policy("QualWrong", "Qual", "D::Order.Wrong") },
74
- PolicyRule { event_qualifier: Some("Order"), ..policy("QualRight", "Qual", "D::Order.Right") },
75
- PolicyRule { where_expr: Some(off), ..policy("GuardedOff", "Guard", "D::Order.Off") },
76
- PolicyRule { where_expr: Some(on), ..policy("GuardedOn", "Guard", "D::Order.On") },
102
+ PolicyRule {
103
+ event_qualifier: Some("Other"),
104
+ ..policy("QualWrong", "Qual", "D::Order.Wrong")
105
+ },
106
+ PolicyRule {
107
+ event_qualifier: Some("Order"),
108
+ ..policy("QualRight", "Qual", "D::Order.Right")
109
+ },
110
+ PolicyRule {
111
+ where_expr: Some(off),
112
+ ..policy("GuardedOff", "Guard", "D::Order.Off")
113
+ },
114
+ PolicyRule {
115
+ where_expr: Some(on),
116
+ ..policy("GuardedOn", "Guard", "D::Order.On")
117
+ },
77
118
  policy("Pinger", "Ping", "D::Order.Ping"),
78
- PolicyRule { for_each: Some("D::Order.Open"), for_each_key: Some("order_id"), ..policy("FanPing", "Fan", "D::Order.Ping") },
79
- PolicyRule { for_each: Some("D::Order.Missing"), ..policy("FanMissing", "FanMissing", "D::Order.Ping") },
119
+ PolicyRule {
120
+ for_each: Some("D::Order.Open"),
121
+ for_each_key: Some("order_id"),
122
+ ..policy("FanPing", "Fan", "D::Order.Ping")
123
+ },
124
+ PolicyRule {
125
+ for_each: Some("D::Order.Missing"),
126
+ ..policy("FanMissing", "FanMissing", "D::Order.Ping")
127
+ },
80
128
  ];
81
129
 
82
130
  static CROSS_POLICIES: [CrossDomainPolicyRule; 5] = [
83
131
  cross("XPlain", "XEvt"),
84
- CrossDomainPolicyRule { event_qualifier: Some("Nope"), ..cross("XQualWrong", "XQual") },
85
- CrossDomainPolicyRule { event_qualifier: Some("Order"), ..cross("XQualRight", "XQual") },
86
- CrossDomainPolicyRule { where_expr: Some(off), ..cross("XWhereOff", "XGuard") },
87
- CrossDomainPolicyRule { where_expr: Some(on), ..cross("XWhereOn", "XGuard") },
132
+ CrossDomainPolicyRule {
133
+ event_qualifier: Some("Nope"),
134
+ ..cross("XQualWrong", "XQual")
135
+ },
136
+ CrossDomainPolicyRule {
137
+ event_qualifier: Some("Order"),
138
+ ..cross("XQualRight", "XQual")
139
+ },
140
+ CrossDomainPolicyRule {
141
+ where_expr: Some(off),
142
+ ..cross("XWhereOff", "XGuard")
143
+ },
144
+ CrossDomainPolicyRule {
145
+ where_expr: Some(on),
146
+ ..cross("XWhereOn", "XGuard")
147
+ },
88
148
  ];
89
149
 
90
150
  static QUERIES: [crate::kernel::QueryDef; 1] = [crate::kernel::QueryDef {
@@ -98,9 +158,17 @@ static QUERIES: [crate::kernel::QueryDef; 1] = [crate::kernel::QueryDef {
98
158
  authorization: None,
99
159
  }];
100
160
 
101
- static UNDO: DispatchSpec = DispatchSpec { command_name: "Ship.Undo", with: &[("ref", WithValue::Ref("ref"))], compensates: None };
161
+ static UNDO: DispatchSpec = DispatchSpec {
162
+ command_name: "Ship.Undo",
163
+ with: &[("ref", WithValue::Ref("ref"))],
164
+ compensates: None,
165
+ };
102
166
 
103
- static PING_SPEC: DispatchSpec = DispatchSpec { command_name: "Order.Ping", with: &[], compensates: None };
167
+ static PING_SPEC: DispatchSpec = DispatchSpec {
168
+ command_name: "Order.Ping",
169
+ with: &[],
170
+ compensates: None,
171
+ };
104
172
 
105
173
  static PROCESS_MANAGERS: [ProcessManagerDef; 3] = [
106
174
  ProcessManagerDef {
@@ -113,7 +181,11 @@ static PROCESS_MANAGERS: [ProcessManagerDef; 3] = [
113
181
  event_type: "Funded",
114
182
  from_state: "start",
115
183
  to_state: "mid",
116
- dispatches: &[DispatchSpec { command_name: "Ship.Go", with: &[("ref", WithValue::Ref("ref"))], compensates: Some(&UNDO) }],
184
+ dispatches: &[DispatchSpec {
185
+ command_name: "Ship.Go",
186
+ with: &[("ref", WithValue::Ref("ref"))],
187
+ compensates: Some(&UNDO),
188
+ }],
117
189
  }],
118
190
  },
119
191
  ProcessManagerDef {
@@ -128,11 +200,24 @@ static PROCESS_MANAGERS: [ProcessManagerDef; 3] = [
128
200
  from_state: "start",
129
201
  to_state: "mid",
130
202
  dispatches: &[
131
- DispatchSpec { command_name: "Ship.Go", with: &[("ref", WithValue::Ref("ref"))], compensates: Some(&UNDO) },
132
- DispatchSpec { command_name: "Ship.Refuse", with: &[("ref", WithValue::Ref("ref"))], compensates: None },
203
+ DispatchSpec {
204
+ command_name: "Ship.Go",
205
+ with: &[("ref", WithValue::Ref("ref"))],
206
+ compensates: Some(&UNDO),
207
+ },
208
+ DispatchSpec {
209
+ command_name: "Ship.Refuse",
210
+ with: &[("ref", WithValue::Ref("ref"))],
211
+ compensates: None,
212
+ },
133
213
  ],
134
214
  },
135
- Handler { event_type: REFUSED, from_state: "mid", to_state: "undone", dispatches: &[] },
215
+ Handler {
216
+ event_type: REFUSED,
217
+ from_state: "mid",
218
+ to_state: "undone",
219
+ dispatches: &[],
220
+ },
136
221
  ],
137
222
  },
138
223
  ProcessManagerDef {
@@ -145,7 +230,11 @@ static PROCESS_MANAGERS: [ProcessManagerDef; 3] = [
145
230
  event_type: "PlainFunded",
146
231
  from_state: "start",
147
232
  to_state: "mid",
148
- dispatches: &[DispatchSpec { command_name: "Ship.Refuse", with: &[("ref", WithValue::Ref("ref"))], compensates: None }],
233
+ dispatches: &[DispatchSpec {
234
+ command_name: "Ship.Refuse",
235
+ with: &[("ref", WithValue::Ref("ref"))],
236
+ compensates: None,
237
+ }],
149
238
  }],
150
239
  },
151
240
  ];
@@ -160,7 +249,9 @@ fn identity_head(aggregate: &str) -> Option<&'static str> {
160
249
  (aggregate == "D::Order").then_some("order_id")
161
250
  }
162
251
  fn declared(_verb: &str) -> &'static [&'static str] {
163
- &["amount", "note", "tag", "order_id", "reason", "ref", "line_id", "to", "with"]
252
+ &[
253
+ "amount", "note", "tag", "order_id", "reason", "ref", "line_id", "to", "with",
254
+ ]
164
255
  }
165
256
  fn entity_head(qualified: &str) -> Option<&'static str> {
166
257
  (qualified == "D::Order.Line").then_some("line_id")
@@ -180,6 +271,14 @@ fn tables() -> Tables<'static> {
180
271
  }
181
272
  }
182
273
 
274
+ fn ping_leg() -> SagaLeg<'static> {
275
+ SagaLeg {
276
+ pm: &PROCESS_MANAGERS[0],
277
+ correlation: "x1",
278
+ domain_name: "D",
279
+ }
280
+ }
281
+
183
282
  struct World {
184
283
  bus: Bus,
185
284
  sagas: HashMap<(String, String), SagaInstance>,
@@ -224,74 +323,62 @@ impl World {
224
323
  )
225
324
  }
226
325
 
326
+ fn cascade(&mut self) -> Cascade<'_, Bus> {
327
+ Cascade {
328
+ store: &mut self.bus,
329
+ dispatch_fn: script,
330
+ tables: tables(),
331
+ sagas: &mut self.sagas,
332
+ occurred_at: None,
333
+ all_events: &mut self.all_events,
334
+ mutations: &mut self.mutations,
335
+ cross_domain: &mut self.cross_domain,
336
+ reaction_log: &mut self.reaction_log,
337
+ saga_log: &mut self.saga_log,
338
+ }
339
+ }
340
+
227
341
  fn react(&mut self, event: &Event, depth: usize) {
228
- react_policies(
229
- &mut self.bus,
230
- script,
231
- tables(),
232
- &mut self.sagas,
233
- event,
234
- None,
235
- depth,
236
- &mut self.all_events,
237
- &mut self.mutations,
238
- &mut self.cross_domain,
239
- &mut self.reaction_log,
240
- &mut self.saga_log,
241
- );
342
+ self.cascade().react_policies(event, depth);
242
343
  }
243
344
 
244
345
  fn verbs(&self) -> Vec<&str> {
245
- self.bus.calls.iter().map(|(verb, _)| verb.as_str()).collect()
346
+ self.bus
347
+ .calls
348
+ .iter()
349
+ .map(|(verb, _)| verb.as_str())
350
+ .collect()
246
351
  }
247
352
 
248
353
  fn deliver_saga(&mut self, depth: usize) -> Option<bool> {
249
- deliver_saga_dispatch(
250
- &mut self.bus,
251
- script,
252
- tables(),
253
- &mut self.sagas,
254
- &PROCESS_MANAGERS[0],
354
+ self.cascade().deliver_saga_dispatch(
355
+ &ping_leg(),
255
356
  &PING_SPEC,
256
- "D",
257
357
  &Json::obj(vec![]),
258
- "x1",
259
- None,
260
358
  depth,
261
- &mut self.all_events,
262
- &mut self.mutations,
263
- &mut self.cross_domain,
264
- &mut self.reaction_log,
265
- &mut self.saga_log,
266
- &HashMap::new(),
267
359
  None,
268
360
  )
269
361
  }
270
362
 
271
363
  fn deliver_compensation(&mut self, depth: usize) {
272
- let entry = CompletedCompensation { command_name: "Order.Ping".to_string(), args: Json::obj(vec![]) };
273
- deliver_derived_compensation(
274
- &mut self.bus,
275
- script,
276
- tables(),
277
- &mut self.sagas,
278
- &PROCESS_MANAGERS[0],
279
- &entry,
280
- "D",
281
- "x1",
282
- None,
283
- depth,
284
- &mut self.all_events,
285
- &mut self.mutations,
286
- &mut self.cross_domain,
287
- &mut self.reaction_log,
288
- &mut self.saga_log,
289
- );
364
+ let entry = CompletedCompensation {
365
+ command_name: "Order.Ping".to_string(),
366
+ args: Json::obj(vec![]),
367
+ };
368
+ self.cascade()
369
+ .deliver_derived_compensation(&ping_leg(), &entry, depth);
290
370
  }
291
371
  }
292
372
 
293
373
  fn reaction(entry: &Json) -> (String, bool) {
294
- (entry.get("policy").and_then(Json::as_str).unwrap().to_string(), matches!(entry.get("delivered"), Some(Json::Bool(true))))
374
+ (
375
+ entry
376
+ .get("policy")
377
+ .and_then(Json::as_str)
378
+ .unwrap()
379
+ .to_string(),
380
+ matches!(entry.get("delivered"), Some(Json::Bool(true))),
381
+ )
295
382
  }
296
383
 
297
384
  fn reason(entry: &Json) -> Option<&str> {
@@ -310,7 +397,10 @@ fn a_policy_answers_only_the_event_it_names() {
310
397
  w.react(&event("Unrelated", "D::Order", "o1", Json::obj(vec![])), 0);
311
398
 
312
399
  assert_eq!(w.verbs(), ["D::Order.Notify"]);
313
- assert_eq!(w.reaction_log.iter().map(reaction).collect::<Vec<_>>(), [("NotifyOnPlaced".to_string(), true)]);
400
+ assert_eq!(
401
+ w.reaction_log.iter().map(reaction).collect::<Vec<_>>(),
402
+ [("NotifyOnPlaced".to_string(), true)]
403
+ );
314
404
  }
315
405
 
316
406
  #[test]
@@ -319,7 +409,11 @@ fn a_policy_with_an_event_qualifier_fires_only_for_that_emitting_aggregate() {
319
409
 
320
410
  w.react(&event("Qual", "D::Order", "o1", Json::obj(vec![])), 0);
321
411
 
322
- assert_eq!(w.verbs(), ["D::Order.Right"], "the qualifier `Other` skips, `Order` fires");
412
+ assert_eq!(
413
+ w.verbs(),
414
+ ["D::Order.Right"],
415
+ "the qualifier `Other` skips, `Order` fires"
416
+ );
323
417
  }
324
418
 
325
419
  #[test]
@@ -336,8 +430,18 @@ fn where_holds_reads_the_event_payload_and_defaults_to_true_with_no_clause() {
336
430
  fn go() -> Expr {
337
431
  Expr::Lookup("go")
338
432
  }
339
- let yes = event("E", "D::Order", "o1", Json::obj(vec![("go", Json::Bool(true))]));
340
- let no = event("E", "D::Order", "o1", Json::obj(vec![("go", Json::Bool(false))]));
433
+ let yes = event(
434
+ "E",
435
+ "D::Order",
436
+ "o1",
437
+ Json::obj(vec![("go", Json::Bool(true))]),
438
+ );
439
+ let no = event(
440
+ "E",
441
+ "D::Order",
442
+ "o1",
443
+ Json::obj(vec![("go", Json::Bool(false))]),
444
+ );
341
445
 
342
446
  assert!(where_holds(None, &no));
343
447
  assert!(where_holds(Some(go), &yes));
@@ -349,14 +453,28 @@ fn where_holds_reads_the_event_payload_and_defaults_to_true_with_no_clause() {
349
453
  fn a_cross_domain_policy_is_recorded_for_the_host_never_dispatched() {
350
454
  let mut w = world();
351
455
 
352
- w.react(&event("XEvt", "D::Order", "o1", Json::obj(vec![("k", Json::int(1))])), 0);
456
+ w.react(
457
+ &event(
458
+ "XEvt",
459
+ "D::Order",
460
+ "o1",
461
+ Json::obj(vec![("k", Json::int(1))]),
462
+ ),
463
+ 0,
464
+ );
353
465
 
354
466
  assert!(w.bus.calls.is_empty());
355
467
  assert!(w.reaction_log.is_empty());
356
468
  assert_eq!(w.cross_domain.len(), 1);
357
469
  let pending = &w.cross_domain[0];
358
- assert_eq!((pending.policy_name.as_str(), pending.event_name.as_str()), ("XPlain", "XEvt"));
359
- assert_eq!((pending.target_domain.as_str(), pending.target_verb.as_str()), ("Other", "Other::Do"));
470
+ assert_eq!(
471
+ (pending.policy_name.as_str(), pending.event_name.as_str()),
472
+ ("XPlain", "XEvt")
473
+ );
474
+ assert_eq!(
475
+ (pending.target_domain.as_str(), pending.target_verb.as_str()),
476
+ ("Other", "Other::Do")
477
+ );
360
478
  assert_eq!(pending.payload, Json::obj(vec![("k", Json::int(1))]));
361
479
  }
362
480
 
@@ -364,11 +482,23 @@ fn a_cross_domain_policy_is_recorded_for_the_host_never_dispatched() {
364
482
  fn a_cross_domain_policy_honours_its_event_qualifier_and_where_clause() {
365
483
  let mut w = world();
366
484
  w.react(&event("XQual", "D::Order", "o1", Json::obj(vec![])), 0);
367
- assert_eq!(w.cross_domain.iter().map(|p| p.policy_name.as_str()).collect::<Vec<_>>(), ["XQualRight"]);
485
+ assert_eq!(
486
+ w.cross_domain
487
+ .iter()
488
+ .map(|p| p.policy_name.as_str())
489
+ .collect::<Vec<_>>(),
490
+ ["XQualRight"]
491
+ );
368
492
 
369
493
  let mut w = world();
370
494
  w.react(&event("XGuard", "D::Order", "o1", Json::obj(vec![])), 0);
371
- assert_eq!(w.cross_domain.iter().map(|p| p.policy_name.as_str()).collect::<Vec<_>>(), ["XWhereOn"]);
495
+ assert_eq!(
496
+ w.cross_domain
497
+ .iter()
498
+ .map(|p| p.policy_name.as_str())
499
+ .collect::<Vec<_>>(),
500
+ ["XWhereOn"]
501
+ );
372
502
 
373
503
  let mut w = world();
374
504
  w.react(&event("Nothing", "D::Order", "o1", Json::obj(vec![])), 0);
@@ -385,7 +515,11 @@ fn a_reaction_below_the_depth_ceiling_is_delivered_and_one_at_it_is_logged_undel
385
515
  w.react(&event("Placed", "D::Order", "o1", Json::obj(vec![])), depth);
386
516
 
387
517
  assert_eq!(w.verbs().len(), usize::from(delivers), "depth {depth}");
388
- assert_eq!(w.reaction_log.iter().map(reaction).collect::<Vec<_>>(), [("NotifyOnPlaced".to_string(), delivers)], "depth {depth}");
518
+ assert_eq!(
519
+ w.reaction_log.iter().map(reaction).collect::<Vec<_>>(),
520
+ [("NotifyOnPlaced".to_string(), delivers)],
521
+ "depth {depth}"
522
+ );
389
523
  if !delivers {
390
524
  assert_eq!(reason(&w.reaction_log[0]), Some(DEPTH_REACHED));
391
525
  }
@@ -399,7 +533,11 @@ fn a_policy_that_re_triggers_itself_stops_after_five_dispatches() {
399
533
  w.orchestrate("D::Order.Ping", 0).unwrap();
400
534
 
401
535
  assert_eq!(w.verbs(), ["D::Order.Ping"; 5]);
402
- let delivered: Vec<bool> = w.reaction_log.iter().map(|entry| reaction(entry).1).collect();
536
+ let delivered: Vec<bool> = w
537
+ .reaction_log
538
+ .iter()
539
+ .map(|entry| reaction(entry).1)
540
+ .collect();
403
541
  // The innermost reaction is logged first: the ceiling, then the four that delivered.
404
542
  assert_eq!(delivered, [false, true, true, true, true]);
405
543
  assert_eq!(reason(&w.reaction_log[0]), Some(DEPTH_REACHED));
@@ -413,11 +551,20 @@ fn a_fan_out_dispatches_once_per_row_with_the_row_id_under_the_declared_key_one_
413
551
 
414
552
  // Each row dispatches `Ping` at depth 4, whose own `Pinger` reaction is stopped there.
415
553
  assert_eq!(w.verbs(), ["D::Order.Ping", "D::Order.Ping"]);
416
- assert_eq!(w.bus.calls[0].1, Json::obj(vec![("order_id", Json::str("o1"))]));
417
- assert_eq!(w.bus.calls[1].1, Json::obj(vec![("order_id", Json::str("o2"))]));
554
+ assert_eq!(
555
+ w.bus.calls[0].1,
556
+ Json::obj(vec![("order_id", Json::str("o1"))])
557
+ );
558
+ assert_eq!(
559
+ w.bus.calls[1].1,
560
+ Json::obj(vec![("order_id", Json::str("o2"))])
561
+ );
418
562
  let log: Vec<(String, bool)> = w.reaction_log.iter().map(reaction).collect();
419
563
  assert_eq!(log.iter().filter(|(name, _)| name == "Pinger").count(), 2);
420
- assert!(w.reaction_log.iter().any(|entry| entry.get("for_row").and_then(Json::as_str) == Some("o2")));
564
+ assert!(w
565
+ .reaction_log
566
+ .iter()
567
+ .any(|entry| entry.get("for_row").and_then(Json::as_str) == Some("o2")));
421
568
  }
422
569
 
423
570
  #[test]
@@ -427,7 +574,10 @@ fn a_fan_out_over_a_query_nothing_declares_logs_the_missing_query() {
427
574
  w.react(&event("FanMissing", "D::Order", "o1", Json::obj(vec![])), 0);
428
575
 
429
576
  assert!(w.bus.calls.is_empty());
430
- assert_eq!(reason(&w.reaction_log[0]), Some("no query D::Order.Missing"));
577
+ assert_eq!(
578
+ reason(&w.reaction_log[0]),
579
+ Some("no query D::Order.Missing")
580
+ );
431
581
  }
432
582
 
433
583
  #[test]
@@ -459,7 +609,10 @@ fn a_derived_compensation_stopped_at_the_ceiling_is_logged_failed_and_never_disp
459
609
 
460
610
  assert!(w.bus.calls.is_empty());
461
611
  assert_eq!(reason(&w.saga_log[0]), Some(DEPTH_REACHED));
462
- assert_eq!(w.saga_log[0].get("compensation_failed"), Some(&Json::Bool(true)));
612
+ assert_eq!(
613
+ w.saga_log[0].get("compensation_failed"),
614
+ Some(&Json::Bool(true))
615
+ );
463
616
  }
464
617
 
465
618
  #[test]
@@ -480,7 +633,11 @@ fn dispatch_log(w: &World) -> Vec<(String, bool, bool)> {
480
633
  .iter()
481
634
  .filter_map(|entry| {
482
635
  let dispatch = entry.get("dispatch")?.as_str()?.to_string();
483
- Some((dispatch, matches!(entry.get("delivered"), Some(Json::Bool(true))), matches!(entry.get("compensation"), Some(Json::Bool(true)))))
636
+ Some((
637
+ dispatch,
638
+ matches!(entry.get("delivered"), Some(Json::Bool(true))),
639
+ matches!(entry.get("compensation"), Some(Json::Bool(true))),
640
+ ))
484
641
  })
485
642
  .collect()
486
643
  }
@@ -496,15 +653,24 @@ fn a_saga_is_born_advances_and_ends_on_its_declared_events() {
496
653
 
497
654
  w.orchestrate("D::Xfer.Funded", 0).unwrap();
498
655
  assert_eq!(w.sagas[&key].state, "mid");
499
- assert_eq!(w.verbs(), ["D::Xfer.Started", "D::Xfer.Funded", "D::Ship.Go"]);
656
+ assert_eq!(
657
+ w.verbs(),
658
+ ["D::Xfer.Started", "D::Xfer.Funded", "D::Ship.Go"]
659
+ );
500
660
  assert_eq!(w.bus.calls[2].1, Json::obj(vec![("ref", Json::str("x1"))]));
501
661
  let ledger = &w.sagas[&key].completed_compensations;
502
662
  assert_eq!(ledger.len(), 1);
503
- assert_eq!((ledger[0].command_name.as_str(), &ledger[0].args), ("Ship.Undo", &Json::obj(vec![("ref", Json::str("x1"))])));
663
+ assert_eq!(
664
+ (ledger[0].command_name.as_str(), &ledger[0].args),
665
+ ("Ship.Undo", &Json::obj(vec![("ref", Json::str("x1"))]))
666
+ );
504
667
 
505
668
  w.orchestrate("D::Xfer.Ended", 0).unwrap();
506
669
  assert!(w.sagas.is_empty());
507
- assert_eq!(w.saga_log.last().unwrap().get("ended"), Some(&Json::Bool(true)));
670
+ assert_eq!(
671
+ w.saga_log.last().unwrap().get("ended"),
672
+ Some(&Json::Bool(true))
673
+ );
508
674
  }
509
675
 
510
676
  #[test]
@@ -515,14 +681,31 @@ fn a_leg_that_refuses_runs_the_refused_leg_and_fires_earlier_compensations() {
515
681
  w.orchestrate("D::Xfer.RiskyStarted", 0).unwrap();
516
682
  w.orchestrate("D::Xfer.RiskyFunded", 0).unwrap();
517
683
 
518
- assert_eq!(w.verbs(), ["D::Xfer.RiskyStarted", "D::Xfer.RiskyFunded", "D::Ship.Go", "D::Ship.Refuse", "D::Ship.Undo"]);
684
+ assert_eq!(
685
+ w.verbs(),
686
+ [
687
+ "D::Xfer.RiskyStarted",
688
+ "D::Xfer.RiskyFunded",
689
+ "D::Ship.Go",
690
+ "D::Ship.Refuse",
691
+ "D::Ship.Undo"
692
+ ]
693
+ );
519
694
  assert_eq!(w.sagas[&key].state, "undone");
520
695
  assert!(w.sagas[&key].completed_compensations.is_empty());
521
696
  assert_eq!(
522
697
  dispatch_log(&w),
523
- [("Ship.Go".to_string(), true, false), ("Ship.Refuse".to_string(), false, false), ("Ship.Undo".to_string(), true, true)]
698
+ [
699
+ ("Ship.Go".to_string(), true, false),
700
+ ("Ship.Refuse".to_string(), false, false),
701
+ ("Ship.Undo".to_string(), true, true)
702
+ ]
524
703
  );
525
- assert!(w.saga_log.iter().any(|e| e.get("on").and_then(Json::as_str) == Some("refused") && e.get("advanced") == Some(&Json::Bool(true))));
704
+ assert!(w
705
+ .saga_log
706
+ .iter()
707
+ .any(|e| e.get("on").and_then(Json::as_str) == Some("refused")
708
+ && e.get("advanced") == Some(&Json::Bool(true))));
526
709
  }
527
710
 
528
711
  #[test]
@@ -533,9 +716,22 @@ fn a_refusal_in_a_saga_with_no_refused_leg_compensates_nothing_and_logs_nothing(
533
716
  w.orchestrate("D::Xfer.PlainStarted", 0).unwrap();
534
717
  w.orchestrate("D::Xfer.PlainFunded", 0).unwrap();
535
718
 
536
- assert_eq!(w.verbs(), ["D::Xfer.PlainStarted", "D::Xfer.PlainFunded", "D::Ship.Refuse"]);
719
+ assert_eq!(
720
+ w.verbs(),
721
+ [
722
+ "D::Xfer.PlainStarted",
723
+ "D::Xfer.PlainFunded",
724
+ "D::Ship.Refuse"
725
+ ]
726
+ );
537
727
  assert_eq!(w.sagas[&key].state, "mid");
538
- assert!(!w.saga_log.iter().any(|e| e.get("on").and_then(Json::as_str) == Some("refused")), "{:?}", w.saga_log);
728
+ assert!(
729
+ !w.saga_log
730
+ .iter()
731
+ .any(|e| e.get("on").and_then(Json::as_str) == Some("refused")),
732
+ "{:?}",
733
+ w.saga_log
734
+ );
539
735
  }
540
736
 
541
737
  #[test]
@@ -546,13 +742,18 @@ fn a_leg_naming_an_unremembered_conversation_is_logged_not_advanced() {
546
742
 
547
743
  assert_eq!(w.verbs(), ["D::Xfer.Funded"]);
548
744
  assert_eq!(w.saga_log[0].get("advanced"), Some(&Json::Bool(false)));
549
- assert!(reason(&w.saga_log[0]).unwrap().contains("no conversation remembers"));
745
+ assert!(reason(&w.saga_log[0])
746
+ .unwrap()
747
+ .contains("no conversation remembers"));
550
748
  }
551
749
 
552
750
  // ---- argument assembly ----
553
751
 
554
752
  fn rule(target: &'static str, with_spec: &'static [(&'static str, &'static str)]) -> PolicyRule {
555
- PolicyRule { with_spec, ..policy("P", "E", target) }
753
+ PolicyRule {
754
+ with_spec,
755
+ ..policy("P", "E", target)
756
+ }
556
757
  }
557
758
 
558
759
  fn order_event(payload: Json) -> Event {
@@ -564,11 +765,24 @@ fn payload() -> Json {
564
765
  }
565
766
 
566
767
  #[test]
567
- fn an_empty_with_forwards_the_payload_and_lifts_the_event_id_to_the_receiver_of_a_non_creating_same_aggregate_target() {
568
- let args = trigger_args(&rule("D::Order.Close", NO_WITH), &order_event(payload()), None, "D::Order.Close", &tables());
768
+ fn an_empty_with_forwards_the_payload_and_lifts_the_event_id_to_the_receiver_of_a_non_creating_same_aggregate_target(
769
+ ) {
770
+ let args = trigger_args(
771
+ &rule("D::Order.Close", NO_WITH),
772
+ &order_event(payload()),
773
+ None,
774
+ "D::Order.Close",
775
+ &tables(),
776
+ );
569
777
 
570
778
  // The payload's own `to` is dropped; the lifted receiver replaces it.
571
- assert_eq!(args, Json::obj(vec![("to", Json::str("o1")), ("with", Json::obj(vec![("amount", Json::int(5))]))]));
779
+ assert_eq!(
780
+ args,
781
+ Json::obj(vec![
782
+ ("to", Json::str("o1")),
783
+ ("with", Json::obj(vec![("amount", Json::int(5))]))
784
+ ])
785
+ );
572
786
  }
573
787
 
574
788
  #[test]
@@ -576,24 +790,55 @@ fn an_empty_with_forwards_the_payload_verbatim_when_nothing_is_lifted() {
576
790
  let t = tables();
577
791
  // A creating target, a different aggregate, a fan-out row's own key, and a verb with no
578
792
  // aggregate each leave the payload as it came.
579
- for (verb, extra) in [("D::Order.Place", None), ("D::Ship.Close", None), ("Close", None)] {
580
- let args = trigger_args(&rule(verb, NO_WITH), &order_event(payload()), extra, verb, &t);
793
+ for (verb, extra) in [
794
+ ("D::Order.Place", None),
795
+ ("D::Ship.Close", None),
796
+ ("Close", None),
797
+ ] {
798
+ let args = trigger_args(
799
+ &rule(verb, NO_WITH),
800
+ &order_event(payload()),
801
+ extra,
802
+ verb,
803
+ &t,
804
+ );
581
805
  assert_eq!(args, payload(), "{verb}");
582
806
  }
583
807
  }
584
808
 
585
809
  #[test]
586
810
  fn a_fan_out_row_id_replaces_any_payload_field_of_the_same_name_and_is_never_lifted() {
587
- let with_old = Json::obj(vec![("order_id", Json::str("old")), ("amount", Json::int(5))]);
588
-
589
- let args = trigger_args(&rule("D::Order.Close", NO_WITH), &order_event(with_old), Some(("order_id", "row-1".to_string())), "D::Order.Close", &tables());
811
+ let with_old = Json::obj(vec![
812
+ ("order_id", Json::str("old")),
813
+ ("amount", Json::int(5)),
814
+ ]);
815
+
816
+ let args = trigger_args(
817
+ &rule("D::Order.Close", NO_WITH),
818
+ &order_event(with_old),
819
+ Some(("order_id", "row-1")),
820
+ "D::Order.Close",
821
+ &tables(),
822
+ );
590
823
 
591
- assert_eq!(args, Json::obj(vec![("amount", Json::int(5)), ("order_id", Json::str("row-1"))]));
824
+ assert_eq!(
825
+ args,
826
+ Json::obj(vec![
827
+ ("amount", Json::int(5)),
828
+ ("order_id", Json::str("row-1"))
829
+ ])
830
+ );
592
831
  }
593
832
 
594
833
  #[test]
595
834
  fn a_payload_that_is_not_an_object_forwards_as_an_empty_object() {
596
- let args = trigger_args(&rule("D::Order.Place", NO_WITH), &order_event(Json::Null), None, "D::Order.Place", &tables());
835
+ let args = trigger_args(
836
+ &rule("D::Order.Place", NO_WITH),
837
+ &order_event(Json::Null),
838
+ None,
839
+ "D::Order.Place",
840
+ &tables(),
841
+ );
597
842
 
598
843
  assert_eq!(args, Json::Object(vec![]));
599
844
  }
@@ -604,22 +849,51 @@ fn row_record() -> Json {
604
849
 
605
850
  #[test]
606
851
  fn an_explicit_with_may_read_a_fan_out_rows_fields_but_the_payload_wins() {
607
- const READ_ROW: &[(&str, &str)] = &[("note", ":charged"), ("amount", ":amount"), ("tag", ":id")];
852
+ const READ_ROW: &[(&str, &str)] =
853
+ &[("note", ":charged"), ("amount", ":amount"), ("tag", ":id")];
608
854
  let record = row_record();
609
855
 
610
- let args = trigger_args_with_row(&rule("D::Order.Place", READ_ROW), &order_event(payload()), None, Some(("r1", &record)), "D::Order.Place", &tables());
856
+ let args = trigger_args_with_row(
857
+ &rule("D::Order.Place", READ_ROW),
858
+ &order_event(payload()),
859
+ None,
860
+ Some(("r1", &record)),
861
+ "D::Order.Place",
862
+ &tables(),
863
+ );
611
864
 
612
- assert_eq!(args, Json::obj(vec![("note", Json::int(40)), ("amount", Json::int(5)), ("tag", Json::str("r1"))]));
865
+ assert_eq!(
866
+ args,
867
+ Json::obj(vec![
868
+ ("note", Json::int(40)),
869
+ ("amount", Json::int(5)),
870
+ ("tag", Json::str("r1"))
871
+ ])
872
+ );
613
873
  }
614
874
 
615
875
  #[test]
616
876
  fn an_undeclared_with_never_offers_a_fan_out_rows_fields() {
617
877
  let record = row_record();
618
- let extra = Some(("order_id", "r1".to_string()));
619
-
620
- let args = trigger_args_with_row(&rule("D::Order.Place", NO_WITH), &order_event(payload()), extra, Some(("r1", &record)), "D::Order.Place", &tables());
878
+ let extra = Some(("order_id", "r1"));
879
+
880
+ let args = trigger_args_with_row(
881
+ &rule("D::Order.Place", NO_WITH),
882
+ &order_event(payload()),
883
+ extra,
884
+ Some(("r1", &record)),
885
+ "D::Order.Place",
886
+ &tables(),
887
+ );
621
888
 
622
- assert_eq!(args, Json::obj(vec![("amount", Json::int(5)), ("to", Json::str("zzz")), ("order_id", Json::str("r1"))]));
889
+ assert_eq!(
890
+ args,
891
+ Json::obj(vec![
892
+ ("amount", Json::int(5)),
893
+ ("to", Json::str("zzz")),
894
+ ("order_id", Json::str("r1"))
895
+ ])
896
+ );
623
897
  }
624
898
 
625
899
  const READS_ORDER_ID: crate::kernel::QueryDef = crate::kernel::QueryDef {
@@ -646,7 +920,11 @@ fn a_for_each_query_is_lent_the_emitting_records_id_under_its_identity_head() {
646
920
 
647
921
  #[test]
648
922
  fn a_for_each_query_keeps_a_payload_value_over_the_lent_identity() {
649
- let args = for_each_query_args(&READS_ORDER_ID, &order_event(Json::obj(vec![("order_id", Json::str("mine"))])), &tables());
923
+ let args = for_each_query_args(
924
+ &READS_ORDER_ID,
925
+ &order_event(Json::obj(vec![("order_id", Json::str("mine"))])),
926
+ &tables(),
927
+ );
650
928
 
651
929
  assert_eq!(args, Json::obj(vec![("order_id", Json::str("mine"))]));
652
930
  }
@@ -660,18 +938,39 @@ fn a_for_each_query_that_does_not_read_the_head_is_lent_nothing() {
660
938
 
661
939
  #[test]
662
940
  fn a_for_each_query_is_lent_nothing_for_an_aggregate_without_a_single_head() {
663
- let args = for_each_query_args(&READS_ORDER_ID, &event("E", "D::Other", "x1", Json::obj(vec![])), &tables());
941
+ let args = for_each_query_args(
942
+ &READS_ORDER_ID,
943
+ &event("E", "D::Other", "x1", Json::obj(vec![])),
944
+ &tables(),
945
+ );
664
946
 
665
947
  assert_eq!(args, Json::obj(vec![]));
666
948
  }
667
949
 
668
- const PROJECT: &[(&str, &str)] = &[("amount", ":amount"), ("note", "\"hi\""), ("tag", ":absent")];
950
+ const PROJECT: &[(&str, &str)] = &[
951
+ ("amount", ":amount"),
952
+ ("note", "\"hi\""),
953
+ ("tag", ":absent"),
954
+ ];
669
955
 
670
956
  #[test]
671
957
  fn an_explicit_with_projects_source_fields_decodes_literals_and_nulls_what_is_absent() {
672
- let args = trigger_args(&rule("D::Order.Place", PROJECT), &order_event(payload()), None, "D::Order.Place", &tables());
958
+ let args = trigger_args(
959
+ &rule("D::Order.Place", PROJECT),
960
+ &order_event(payload()),
961
+ None,
962
+ "D::Order.Place",
963
+ &tables(),
964
+ );
673
965
 
674
- assert_eq!(args, Json::obj(vec![("amount", Json::int(5)), ("note", Json::str("hi")), ("tag", Json::Null)]));
966
+ assert_eq!(
967
+ args,
968
+ Json::obj(vec![
969
+ ("amount", Json::int(5)),
970
+ ("note", Json::str("hi")),
971
+ ("tag", Json::Null)
972
+ ])
973
+ );
675
974
  }
676
975
 
677
976
  #[test]
@@ -679,39 +978,97 @@ fn an_explicit_with_may_read_the_emitting_records_identity_unless_the_payload_ca
679
978
  const READ_ID: &[(&str, &str)] = &[("order_id", ":order_id")];
680
979
  let t = tables();
681
980
 
682
- let from_event = trigger_args(&rule("D::Order.Place", READ_ID), &order_event(payload()), None, "D::Order.Place", &t);
981
+ let from_event = trigger_args(
982
+ &rule("D::Order.Place", READ_ID),
983
+ &order_event(payload()),
984
+ None,
985
+ "D::Order.Place",
986
+ &t,
987
+ );
683
988
  assert_eq!(from_event, Json::obj(vec![("order_id", Json::str("o1"))]));
684
989
 
685
990
  let carried = Json::obj(vec![("order_id", Json::str("p9"))]);
686
- let from_payload = trigger_args(&rule("D::Order.Place", READ_ID), &order_event(carried), None, "D::Order.Place", &t);
991
+ let from_payload = trigger_args(
992
+ &rule("D::Order.Place", READ_ID),
993
+ &order_event(carried),
994
+ None,
995
+ "D::Order.Place",
996
+ &t,
997
+ );
687
998
  assert_eq!(from_payload, Json::obj(vec![("order_id", Json::str("p9"))]));
688
999
 
689
1000
  let blank = event("E", "D::Order", "", payload());
690
- let none = trigger_args(&rule("D::Order.Place", READ_ID), &blank, None, "D::Order.Place", &t);
1001
+ let none = trigger_args(
1002
+ &rule("D::Order.Place", READ_ID),
1003
+ &blank,
1004
+ None,
1005
+ "D::Order.Place",
1006
+ &t,
1007
+ );
691
1008
  assert_eq!(none, Json::obj(vec![("order_id", Json::Null)]));
692
1009
  }
693
1010
 
694
1011
  #[test]
695
- fn an_explicit_with_for_a_non_creating_target_names_the_receiver_from_the_projection_or_the_event() {
1012
+ fn an_explicit_with_for_a_non_creating_target_names_the_receiver_from_the_projection_or_the_event()
1013
+ {
696
1014
  const REASON: &[(&str, &str)] = &[("reason", "\"x\"")];
697
1015
  const BOTH: &[(&str, &str)] = &[("order_id", ":order_id"), ("reason", "\"x\"")];
698
1016
  let t = tables();
699
1017
 
700
1018
  // Nothing projected names the identity: the same-aggregate event's own id is the receiver.
701
- let fallback = trigger_args(&rule("D::Order.Close", REASON), &order_event(payload()), None, "D::Order.Close", &t);
702
- assert_eq!(fallback, Json::obj(vec![("to", Json::str("o1")), ("with", Json::obj(vec![("reason", Json::str("x"))]))]));
1019
+ let fallback = trigger_args(
1020
+ &rule("D::Order.Close", REASON),
1021
+ &order_event(payload()),
1022
+ None,
1023
+ "D::Order.Close",
1024
+ &t,
1025
+ );
1026
+ assert_eq!(
1027
+ fallback,
1028
+ Json::obj(vec![
1029
+ ("to", Json::str("o1")),
1030
+ ("with", Json::obj(vec![("reason", Json::str("x"))]))
1031
+ ])
1032
+ );
703
1033
 
704
1034
  // The projection names it: that wins and is not re-routed.
705
- let named = trigger_args(&rule("D::Order.Close", BOTH), &order_event(payload()), None, "D::Order.Close", &t);
1035
+ let named = trigger_args(
1036
+ &rule("D::Order.Close", BOTH),
1037
+ &order_event(payload()),
1038
+ None,
1039
+ "D::Order.Close",
1040
+ &t,
1041
+ );
706
1042
  assert_eq!(
707
1043
  named,
708
- Json::obj(vec![("to", Json::str("o1")), ("with", Json::obj(vec![("order_id", Json::str("o1")), ("reason", Json::str("x"))]))])
1044
+ Json::obj(vec![
1045
+ ("to", Json::str("o1")),
1046
+ (
1047
+ "with",
1048
+ Json::obj(vec![
1049
+ ("order_id", Json::str("o1")),
1050
+ ("reason", Json::str("x"))
1051
+ ])
1052
+ )
1053
+ ])
709
1054
  );
710
1055
 
711
1056
  // A different aggregate has no event identity to offer, and a fan-out row never falls back.
712
- let other = trigger_args(&rule("D::Ship.Close", REASON), &order_event(payload()), None, "D::Ship.Close", &t);
1057
+ let other = trigger_args(
1058
+ &rule("D::Ship.Close", REASON),
1059
+ &order_event(payload()),
1060
+ None,
1061
+ "D::Ship.Close",
1062
+ &t,
1063
+ );
713
1064
  assert_eq!(other, Json::obj(vec![("reason", Json::str("x"))]));
714
- let fan = trigger_args(&rule("D::Order.Close", REASON), &order_event(payload()), Some(("order_id", "r1".to_string())), "D::Order.Close", &t);
1065
+ let fan = trigger_args(
1066
+ &rule("D::Order.Close", REASON),
1067
+ &order_event(payload()),
1068
+ Some(("order_id", "r1")),
1069
+ "D::Order.Close",
1070
+ &t,
1071
+ );
715
1072
  assert_eq!(fan, Json::obj(vec![("reason", Json::str("x"))]));
716
1073
  }
717
1074
 
@@ -723,23 +1080,59 @@ fn a_projected_fact_named_to_or_with_alone_is_not_mistaken_for_an_already_routed
723
1080
  const JUST_WITH: &[(&str, &str)] = &[("with", "\"w\"")];
724
1081
  let t = tables();
725
1082
 
726
- let to = trigger_args(&rule("D::Order.Close", JUST_TO), &order_event(payload()), None, "D::Order.Close", &t);
727
- assert_eq!(to, Json::obj(vec![("to", Json::str("o1")), ("with", Json::obj(vec![("to", Json::str("somewhere"))]))]));
1083
+ let to = trigger_args(
1084
+ &rule("D::Order.Close", JUST_TO),
1085
+ &order_event(payload()),
1086
+ None,
1087
+ "D::Order.Close",
1088
+ &t,
1089
+ );
1090
+ assert_eq!(
1091
+ to,
1092
+ Json::obj(vec![
1093
+ ("to", Json::str("o1")),
1094
+ ("with", Json::obj(vec![("to", Json::str("somewhere"))]))
1095
+ ])
1096
+ );
728
1097
 
729
- let with = trigger_args(&rule("D::Order.Close", JUST_WITH), &order_event(payload()), None, "D::Order.Close", &t);
730
- assert_eq!(with, Json::obj(vec![("to", Json::str("o1")), ("with", Json::obj(vec![("with", Json::str("w"))]))]));
1098
+ let with = trigger_args(
1099
+ &rule("D::Order.Close", JUST_WITH),
1100
+ &order_event(payload()),
1101
+ None,
1102
+ "D::Order.Close",
1103
+ &t,
1104
+ );
1105
+ assert_eq!(
1106
+ with,
1107
+ Json::obj(vec![
1108
+ ("to", Json::str("o1")),
1109
+ ("with", Json::obj(vec![("with", Json::str("w"))]))
1110
+ ])
1111
+ );
731
1112
  }
732
1113
 
733
1114
  #[test]
734
- fn an_entity_command_is_routed_to_the_parent_named_by_the_event_when_the_projection_does_not_name_it() {
1115
+ fn an_entity_command_is_routed_to_the_parent_named_by_the_event_when_the_projection_does_not_name_it(
1116
+ ) {
735
1117
  let t = tables();
736
1118
  let projected = || Json::obj(vec![("line_id", Json::str("l1")), ("note", Json::str("n"))]);
737
1119
 
738
- let got = route_dispatch_args(projected(), "D::Order.Line.Add", &t, &order_event(payload()));
1120
+ let got = route_dispatch_args(
1121
+ &projected(),
1122
+ "D::Order.Line.Add",
1123
+ &t,
1124
+ &order_event(payload()),
1125
+ );
739
1126
  assert_eq!(
740
1127
  got,
741
1128
  Json::obj(vec![
742
- ("to", Json::obj(vec![("aggregate", Json::str("o1")), ("entities", Json::Array(vec![Json::str("l1")]))])),
1129
+ (
1130
+ "to",
1131
+ Json::obj(vec![
1132
+ ("aggregate", Json::str("o1")),
1133
+ ("entities", Json::Array(vec![Json::str("l1")]))
1134
+ ])
1135
+ ),
743
1136
  ("with", projected()),
744
1137
  ])
745
1138
  );
@@ -748,7 +1141,7 @@ fn an_entity_command_is_routed_to_the_parent_named_by_the_event_when_the_project
748
1141
  let other = event("E", "D::Other", "o1", payload());
749
1142
  let blank = event("E", "D::Order", "", payload());
750
1143
  for e in [other, blank] {
751
- let flat = route_dispatch_args(projected(), "D::Order.Line.Add", &t, &e);
1144
+ let flat = route_dispatch_args(&projected(), "D::Order.Line.Add", &t, &e);
752
1145
  assert!(flat.get("to").is_none(), "{flat:?}");
753
1146
  }
754
1147
  }
@@ -756,7 +1149,12 @@ fn an_entity_command_is_routed_to_the_parent_named_by_the_event_when_the_project
756
1149
  #[test]
757
1150
  fn resolve_with_reads_the_correlation_then_the_payload_then_the_memory_then_null() {
758
1151
  let pm = &PROCESS_MANAGERS[0];
759
- let e = event("E", "D::Xfer", "x1", Json::obj(vec![("from_event", Json::str("p"))]));
1152
+ let e = event(
1153
+ "E",
1154
+ "D::Xfer",
1155
+ "x1",
1156
+ Json::obj(vec![("from_event", Json::str("p"))]),
1157
+ );
760
1158
  let memory = Json::obj(vec![("from_memory", Json::str("m"))]);
761
1159
  let resolve = |name: &'static str| resolve_with(pm, &WithValue::Ref(name), &e, "corr", &memory);
762
1160