hecks 3.13.0 → 4.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 (440) 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.bluebook +4 -4
  7. data/examples/pizzas/bluebook/pizzas.hecksagon +5 -3
  8. data/examples/pizzas/config.ru +22 -0
  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 +1 -7
  12. data/lib/hecks/bluebook/dsl/attribute_collector.rb +15 -5
  13. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -2
  14. data/lib/hecks/bluebook/dsl/derivation_words.rb +58 -0
  15. data/lib/hecks/bluebook/dsl/translation_builder.rb +6 -37
  16. data/lib/hecks/bluebook/expression/ast_json.rb +0 -9
  17. data/lib/hecks/bluebook/hecksagon.rb +1 -1
  18. data/lib/hecks/bluebook/meta_validator/translation_judge/rules.rb +7 -10
  19. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +4 -8
  20. data/lib/hecks/bluebook/meta_validator.rb +0 -11
  21. data/lib/hecks/bluebook/named_pattern.rb +33 -0
  22. data/lib/hecks/bluebook/translation.rb +18 -10
  23. data/lib/hecks/bluebook/translation_expression/evaluator.rb +63 -0
  24. data/lib/hecks/bluebook/translation_expression/parser.rb +127 -0
  25. data/lib/hecks/bluebook/translation_expression.rb +39 -0
  26. data/lib/hecks/bluebook/translation_plan.rb +70 -0
  27. data/lib/hecks/bluebook.rb +3 -0
  28. data/lib/hecks/chapters.rb +3 -3
  29. data/lib/hecks/cli/domain_stub.rb +1 -1
  30. data/lib/hecks/cli/interview_aggregate.rb +4 -4
  31. data/lib/hecks/composer/adapters/claude_composer.adapter +3 -0
  32. data/lib/hecks/composer/adapters/claude_composer.rb +83 -0
  33. data/lib/hecks/composer/adapters/fake_agent.adapter +3 -0
  34. data/lib/hecks/composer/adapters/fake_agent.rb +55 -0
  35. data/lib/hecks/composer/adapters/jev.adapter +3 -0
  36. data/lib/hecks/composer/adapters/jev.rb +66 -0
  37. data/lib/hecks/composer/agent.rb +113 -0
  38. data/lib/hecks/composer/assistant.rb +110 -0
  39. data/lib/hecks/composer/behavior_run.rb +53 -0
  40. data/lib/hecks/composer/bluebook/composer.bluebook +178 -0
  41. data/lib/hecks/composer/bluebook/composer.hecksagon +16 -0
  42. data/lib/hecks/composer/board.rb +65 -0
  43. data/lib/hecks/composer/board_edit/command_text.rb +39 -0
  44. data/lib/hecks/composer/board_edit/source.rb +84 -0
  45. data/lib/hecks/composer/board_edit.rb +144 -0
  46. data/lib/hecks/composer/check.rb +89 -0
  47. data/lib/hecks/composer/domains.rb +81 -0
  48. data/lib/hecks/composer/jobs.rb +134 -0
  49. data/lib/hecks/composer/layout.rb +37 -0
  50. data/lib/hecks/composer/live.rb +150 -0
  51. data/lib/hecks/composer/outline.rb +48 -0
  52. data/lib/hecks/composer/page.html +989 -0
  53. data/lib/hecks/composer/panels.rb +142 -0
  54. data/lib/hecks/composer/parse.rb +83 -0
  55. data/lib/hecks/composer/plain.rb +28 -0
  56. data/lib/hecks/composer/ports/composer_agent.port +7 -0
  57. data/lib/hecks/composer/session.rb +141 -0
  58. data/lib/hecks/composer/toolbox.rb +166 -0
  59. data/lib/hecks/composer/web.rb +156 -0
  60. data/lib/hecks/composer/workbench.rb +51 -0
  61. data/lib/hecks/composer/workspace.rb +81 -0
  62. data/lib/hecks/composer.rb +17 -0
  63. data/lib/hecks/corpus/adapters.rb +22 -0
  64. data/lib/hecks/corpus/rust.rb +1 -1
  65. data/lib/hecks/corpus/worlds.rb +19 -0
  66. data/lib/hecks/corpus.rb +5 -0
  67. data/lib/hecks/deploy/bluebook/deploy.bluebook +34 -34
  68. data/lib/hecks/forms/app/commands.rb +2 -3
  69. data/lib/hecks/forms/app/queries.rb +2 -3
  70. data/lib/hecks/forms/app/records.rb +17 -5
  71. data/lib/hecks/forms/command_form_renderer.rb +42 -16
  72. data/lib/hecks/forms/field_controls.rb +2 -2
  73. data/lib/hecks/forms/field_renderer.rb +1 -1
  74. data/lib/hecks/forms/field_shape.rb +36 -17
  75. data/lib/hecks/forms/index_renderer.rb +2 -1
  76. data/lib/hecks/forms/page.rb +1 -1
  77. data/lib/hecks/forms/params.rb +0 -13
  78. data/lib/hecks/forms/query_form_renderer.rb +7 -6
  79. data/lib/hecks/forms/record_renderer.rb +11 -7
  80. data/lib/hecks/forms/rule_words.rb +100 -0
  81. data/lib/hecks/forms/value_object_shape.rb +2 -1
  82. data/lib/hecks/framework/bluebook/change.bluebook +2 -2
  83. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -3
  84. data/lib/hecks/fuzzing/domain_generator/block_rendering.rb +1 -1
  85. data/lib/hecks/fuzzing/isolated_boot/worlds.rb +3 -6
  86. data/lib/hecks/fuzzing/replay/filters.rb +2 -6
  87. data/lib/hecks/gate/stages.yml +25 -0
  88. data/lib/hecks/grammar/evolve/seeds.rb +0 -6
  89. data/lib/hecks/grammar/evolve.rb +0 -3
  90. data/lib/hecks/grammar/translation.bluebook +1 -1
  91. data/lib/hecks/hecks/adapters/codebase/composing.rb +56 -0
  92. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +3 -1
  93. data/lib/hecks/hecks/adapters/journal_store/changes.rb +0 -26
  94. data/lib/hecks/hecks/adapters/journal_store/examination.rb +2 -23
  95. data/lib/hecks/hecks/adapters/journal_store/readings.rb +3 -11
  96. data/lib/hecks/hecks/adapters/journal_store.rb +0 -11
  97. data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +4 -11
  98. data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +0 -9
  99. data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +0 -4
  100. data/lib/hecks/hecks/codebase.behaviors +6 -0
  101. data/lib/hecks/hecks/codebase.bluebook +58 -37
  102. data/lib/hecks/hecks/composer.behaviors +68 -0
  103. data/lib/hecks/hecks/context_map.hecksagon +1 -1
  104. data/lib/hecks/hecks/custodian.behaviors +0 -6
  105. data/lib/hecks/hecks/custodian.bluebook +15 -92
  106. data/lib/hecks/hecks/hecks.bluebook +2 -2
  107. data/lib/hecks/hecks/hecks.hecksagon +2 -2
  108. data/lib/hecks/hecks/hecks.world +1 -1
  109. data/lib/hecks/hecks/rehearsal.bluebook +10 -16
  110. data/lib/hecks/hecks/tooling.bluebook +22 -22
  111. data/lib/hecks/kernel_capabilities/templates.rb +4 -4
  112. data/lib/hecks/kernel_capabilities.rb +1 -1
  113. data/lib/hecks/language/bluebook/aggregate.bluebook +1 -0
  114. data/lib/hecks/language/bluebook/command.bluebook +1 -0
  115. data/lib/hecks/language/bluebook/entity.bluebook +1 -0
  116. data/lib/hecks/language/bluebook/query.bluebook +1 -0
  117. data/lib/hecks/language/bluebook/shape.bluebook +8 -7
  118. data/lib/hecks/language/bluebook/vocabulary.bluebook +2 -3
  119. data/lib/hecks/language/hecksagon/port_operation.bluebook +1 -0
  120. data/lib/hecks/language/translation/translation_aggregate.bluebook +21 -24
  121. data/lib/hecks/ports/access_control.rb +2 -2
  122. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +3 -41
  123. data/lib/hecks/ports/persistence/plugins/era/lineage/coverage.rb +7 -7
  124. data/lib/hecks/ports/persistence/plugins/era/lineage/rewrite.rb +25 -2
  125. data/lib/hecks/ports/persistence/plugins/era/lineage/rules.rb +4 -4
  126. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +17 -25
  127. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/base_sql.rb +0 -12
  128. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/domain_rename.rb +1 -1
  129. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +2 -22
  130. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +0 -1
  131. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +9 -3
  132. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +3 -29
  133. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/refusals.rb +2 -26
  134. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +6 -33
  135. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -3
  136. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +2 -4
  137. data/lib/hecks/ports/persistence/plugins/era/translation/expression_sql.rb +52 -0
  138. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +23 -29
  139. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +1 -1
  140. data/lib/hecks/ports/persistence/plugins/era/translation.rb +0 -1
  141. data/lib/hecks/ports/persistence/plugins/era.rb +3 -6
  142. data/lib/hecks/ports.rb +0 -1
  143. data/lib/hecks/projection_files.rb +3 -1
  144. data/lib/hecks/projections/deploy/templates/lambda/nat_comment_oauth.tmpl +1 -1
  145. data/lib/hecks/projections/glossary/entries.rb +10 -4
  146. data/lib/hecks/projections/glossary/groups.rb +42 -0
  147. data/lib/hecks/projections/glossary/html/page.rb +7 -2
  148. data/lib/hecks/projections/glossary/html/parser.rb +1 -1
  149. data/lib/hecks/projections/glossary/html/sections.rb +31 -11
  150. data/lib/hecks/projections/glossary/html.rb +1 -2
  151. data/lib/hecks/projections/glossary/markdown.rb +31 -28
  152. data/lib/hecks/projections/glossary/mermaid.rb +3 -0
  153. data/lib/hecks/projections/glossary/page.css +143 -153
  154. data/lib/hecks/projections/glossary/page.js +63 -3
  155. data/lib/hecks/projections/glossary/sentences/actions.rb +88 -0
  156. data/lib/hecks/projections/glossary/sentences/paths.rb +77 -0
  157. data/lib/hecks/projections/glossary/sentences/queries.rb +90 -0
  158. data/lib/hecks/projections/glossary/sentences/value_objects.rb +32 -5
  159. data/lib/hecks/projections/glossary/sentences.rb +13 -3
  160. data/lib/hecks/projections/glossary/slugs.rb +4 -1
  161. data/lib/hecks/projections/glossary.rb +2 -1
  162. data/lib/hecks/projections/plain_english.rb +97 -0
  163. data/lib/hecks/projections/rust_vocabulary/arguments.rb +2 -2
  164. data/lib/hecks/projections/rust_vocabulary/enum_body.rb +20 -25
  165. data/lib/hecks/projections/rust_vocabulary/tests.rb +2 -2
  166. data/lib/hecks/projections/rust_vocabulary.rb +14 -6
  167. data/lib/hecks/projections/site/cms_editor/color.rb +0 -6
  168. data/lib/hecks/projections/statements/actions.rb +99 -0
  169. data/lib/hecks/projections/statements/relationships.rb +86 -0
  170. data/lib/hecks/projections/statements.rb +15 -24
  171. data/lib/hecks/projector/exporter/adapters.rb +112 -0
  172. data/lib/hecks/projector/exporter/translations.rb +18 -35
  173. data/lib/hecks/projector/exporter/worlds.rb +103 -0
  174. data/lib/hecks/projector/exporter.rb +5 -1
  175. data/lib/hecks/quality_control/adapters/agent.rb +6 -7
  176. data/lib/hecks/quality_control/adapters/agent_profile.rb +16 -114
  177. data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +1 -1
  178. data/lib/hecks/quality_control/quality_control.bluebook +51 -51
  179. data/lib/hecks/runtime/loader/boot_steps.rb +0 -20
  180. data/lib/hecks/runtime/outbox.rb +2 -9
  181. data/lib/hecks/runtime/port_operation_interpreter.rb +1 -9
  182. data/lib/hecks/runtime/remote_dispatcher.rb +2 -2
  183. data/lib/hecks/runtime/value.rb +13 -0
  184. data/lib/hecks/rust_build/project_rust/target_ir.rb +23 -4
  185. data/lib/hecks/rust_build/wasm.rb +0 -12
  186. data/lib/hecks/rust_build/write_if_changed.rb +12 -12
  187. data/lib/hecks/rust_format.rb +77 -0
  188. data/lib/hecks/site/bluebook/site.bluebook +5 -5
  189. data/lib/hecks/sme/bluebook/sme.bluebook +12 -12
  190. data/lib/hecks/tickets/bluebook/tickets.bluebook +3 -3
  191. data/lib/hecks/tools/fuzz_sweep/findings.rb +3 -9
  192. data/lib/hecks/tools/fuzz_sweep.rb +1 -3
  193. data/lib/hecks/tools/translation_audit/verdicts.rb +3 -28
  194. data/lib/hecks/tools/translation_audit.rb +8 -10
  195. data/lib/hecks/tools/translation_scaffold/reporting.rb +1 -1
  196. data/lib/hecks/version.rb +1 -1
  197. data/lib/hecks/vocabulary.rb +2 -1
  198. data/lib/hecks.rb +3 -0
  199. data/prebuilt/{58208399bada10b0db99928c48e38789288fc58f7b71a72b21bfa386680e32ed.marshal → 02c09c73b272c1fb5a9ae6d87bb5e5e529208e00f6b4b597dc2c0fd70a9c0964.marshal} +0 -0
  200. data/prebuilt/{2b59737fbdbd5f44edda0fddce2611f45d76087b3a7c782d1f1a17ea58c77948.marshal → bb84a835cf6a15136bad5ca03aa5bf93a5b92f5f72444618d3ef2412b987fb32.marshal} +0 -0
  201. data/prebuilt/verdicts-f1f10da14c8e8f01b4c9b7e3e2d74be8cd2bf4676364ed17fa16975d2a076d75.json +1 -0
  202. data/rust/Cargo.toml +40 -0
  203. data/rust/build/Cargo.toml +36 -0
  204. data/rust/build/clippy.toml +4 -0
  205. data/rust/build/src/adapters_pass.rs +196 -0
  206. data/rust/build/src/binding_pass.rs +54 -13
  207. data/rust/build/src/build_artifact.rs +23 -5
  208. data/rust/build/src/cargo_sync.rs +69 -26
  209. data/rust/build/src/lineage_pass.rs +101 -87
  210. data/rust/build/src/main.rs +11 -2
  211. data/rust/build/src/pipeline.rs +80 -19
  212. data/rust/build/src/reserved_names.rs +6 -50
  213. data/rust/build/src/resolve.rs +82 -35
  214. data/rust/build/src/rustfmt.rs +100 -0
  215. data/rust/build/src/seams_pass.rs +85 -16
  216. data/rust/build/src/subprocess.rs +30 -6
  217. data/rust/build/src/tmp.rs +5 -2
  218. data/rust/build/src/translation_pass.rs +72 -22
  219. data/rust/build/src/world_pass.rs +109 -0
  220. data/rust/clippy.toml +4 -0
  221. data/rust/codegen/Cargo.toml +36 -0
  222. data/rust/codegen/clippy.toml +4 -0
  223. data/rust/codegen/src/asks.rs +40 -14
  224. data/rust/codegen/src/attr.rs +2 -2
  225. data/rust/codegen/src/bridging.rs +676 -117
  226. data/rust/codegen/src/commands.rs +979 -373
  227. data/rust/codegen/src/constraints.rs +88 -25
  228. data/rust/codegen/src/dependency_planning.rs +128 -34
  229. data/rust/codegen/src/domain_generator.rs +300 -170
  230. data/rust/codegen/src/exemplar.rs +87 -32
  231. data/rust/codegen/src/expr_emitter.rs +54 -6
  232. data/rust/codegen/src/fielded.rs +193 -41
  233. data/rust/codegen/src/hecks_naming.rs +124 -16
  234. data/rust/codegen/src/hecks_naming_tests.rs +81 -0
  235. data/rust/codegen/src/json.rs +80 -44
  236. data/rust/codegen/src/json_codec.rs +585 -149
  237. data/rust/codegen/src/literal.rs +104 -138
  238. data/rust/codegen/src/main.rs +145 -52
  239. data/rust/codegen/src/manifest.rs +76 -14
  240. data/rust/codegen/src/mutations.rs +1212 -239
  241. data/rust/codegen/src/naming.rs +111 -60
  242. data/rust/codegen/src/optional_pass.rs +90 -28
  243. data/rust/codegen/src/ports.rs +5 -4
  244. data/rust/codegen/src/prelude.rs +139 -49
  245. data/rust/codegen/src/queries.rs +601 -226
  246. data/rust/codegen/src/reactions.rs +268 -74
  247. data/rust/codegen/src/read_models.rs +606 -205
  248. data/rust/codegen/src/reference_specs.rs +16 -3
  249. data/rust/codegen/src/registry.rs +128 -79
  250. data/rust/codegen/src/reserved_names.rs +6 -50
  251. data/rust/codegen/src/shared.rs +71 -22
  252. data/rust/codegen/src/sidecars.rs +15 -5
  253. data/rust/codegen/src/skip_reason.rs +8 -2
  254. data/rust/codegen/src/types.rs +306 -108
  255. data/rust/host/Cargo.lock +1 -0
  256. data/rust/host/Cargo.toml +40 -4
  257. data/rust/host/HECKS_RELEASE +1 -1
  258. data/rust/host/clippy.toml +4 -0
  259. data/rust/host/src/api.rs +698 -218
  260. data/rust/host/src/auth.rs +491 -214
  261. data/rust/host/src/b64.rs +91 -0
  262. data/rust/host/src/bin/expr_harness.rs +6 -2
  263. data/rust/host/src/bin/lineage_harness.rs +47 -11
  264. data/rust/host/src/bin/mint_harness.rs +70 -37
  265. data/rust/host/src/bin/validate_harness.rs +16 -8
  266. data/rust/host/src/boot.rs +144 -68
  267. data/rust/host/src/boundary_fuzz/api.rs +130 -32
  268. data/rust/host/src/boundary_fuzz/auth.rs +108 -23
  269. data/rust/host/src/boundary_fuzz/expr_json.rs +85 -11
  270. data/rust/host/src/boundary_fuzz/ir.rs +164 -12
  271. data/rust/host/src/boundary_fuzz/server.rs +283 -36
  272. data/rust/host/src/boundary_fuzz/web.rs +56 -8
  273. data/rust/host/src/checkout.rs +78 -32
  274. data/rust/host/src/clock.rs +8 -0
  275. data/rust/host/src/commerce_ir.rs +333 -95
  276. data/rust/host/src/crypto.rs +33 -0
  277. data/rust/host/src/dispatch.rs +990 -331
  278. data/rust/host/src/expr_json.rs +1021 -273
  279. data/rust/host/src/extension.rs +24 -4
  280. data/rust/host/src/field_hints.rs +11 -7
  281. data/rust/host/src/fuzz_support.rs +85 -13
  282. data/rust/host/src/host.rs +100 -0
  283. data/rust/host/src/http.rs +22 -0
  284. data/rust/host/src/ir.rs +326 -16
  285. data/rust/host/src/journal.rs +277 -176
  286. data/rust/host/src/lambda_client.rs +219 -53
  287. data/rust/host/src/lib.rs +16 -4
  288. data/rust/host/src/log.rs +62 -11
  289. data/rust/host/src/mint.rs +1153 -326
  290. data/rust/host/src/needs.rs +185 -44
  291. data/rust/host/src/payments/keystore.rs +197 -45
  292. data/rust/host/src/payments/roles.rs +191 -0
  293. data/rust/host/src/payments/tests.rs +1445 -275
  294. data/rust/host/src/payments.rs +409 -121
  295. data/rust/host/src/platform_signin/attack_tests.rs +5 -5
  296. data/rust/host/src/platform_signin/config.rs +11 -11
  297. data/rust/host/src/platform_signin/cookie.rs +2 -2
  298. data/rust/host/src/platform_signin/extension.rs +2 -1
  299. data/rust/host/src/platform_signin/handler.rs +9 -8
  300. data/rust/host/src/platform_signin/jti.rs +4 -2
  301. data/rust/host/src/platform_signin/jwks.rs +2 -1
  302. data/rust/host/src/platform_signin/jws.rs +2 -37
  303. data/rust/host/src/platform_signin/known_answer_tests.rs +5 -1
  304. data/rust/host/src/platform_signin/mode_tests.rs +5 -3
  305. data/rust/host/src/platform_signin/pages.rs +20 -20
  306. data/rust/host/src/platform_signin/session.rs +8 -1
  307. data/rust/host/src/platform_signin/settings.rs +6 -6
  308. data/rust/host/src/platform_signin/strict_json.rs +12 -9
  309. data/rust/host/src/platform_signin/verify.rs +41 -41
  310. data/rust/host/src/platform_signin/wiring_support.rs +13 -18
  311. data/rust/host/src/presentation.rs +207 -63
  312. data/rust/host/src/presentation_write.rs +502 -187
  313. data/rust/host/src/query_step.rs +69 -18
  314. data/rust/host/src/rate_limit.rs +541 -142
  315. data/rust/host/src/reference_transform.rs +77 -25
  316. data/rust/host/src/reference_validate.rs +443 -104
  317. data/rust/host/src/resend.rs +190 -55
  318. data/rust/host/src/secrets.rs +116 -21
  319. data/rust/host/src/server.rs +483 -104
  320. data/rust/host/src/storage_shape.rs +88 -21
  321. data/rust/host/src/test_pg.rs +17 -7
  322. data/rust/host/src/ui_schema.rs +495 -207
  323. data/rust/host/src/wasm_runner.rs +21 -6
  324. data/rust/host/src/web/commerce.rs +101 -23
  325. data/rust/host/src/web/newsletter/cooldown.rs +10 -3
  326. data/rust/host/src/web/newsletter/template.rs +26 -7
  327. data/rust/host/src/web/newsletter/tests.rs +112 -23
  328. data/rust/host/src/web/newsletter.rs +209 -59
  329. data/rust/host/src/web/newsletter_send.rs +251 -79
  330. data/rust/host/src/web/registration_receipt/tests.rs +16 -4
  331. data/rust/host/src/web/registration_receipt.rs +100 -24
  332. data/rust/host/src/web/registrations.rs +1384 -332
  333. data/rust/host/src/web/resend_webhook.rs +138 -80
  334. data/rust/host/src/web.rs +2416 -508
  335. data/rust/lsp/Cargo.toml +36 -0
  336. data/rust/lsp/clippy.toml +4 -0
  337. data/rust/lsp/src/json.rs +29 -22
  338. data/rust/lsp/src/main.rs +81 -31
  339. data/rust/lsp/src/outline.rs +23 -7
  340. data/rust/lsp/src/rpc.rs +17 -4
  341. data/rust/parser/Cargo.toml +36 -0
  342. data/rust/parser/clippy.toml +4 -0
  343. data/rust/parser/src/build/closed_sets.rs +6 -1
  344. data/rust/parser/src/build/identity.rs +4 -3
  345. data/rust/parser/src/build/mod.rs +1 -0
  346. data/rust/parser/src/build/named_pattern.rs +26 -0
  347. data/rust/parser/src/build/naming.rs +2 -80
  348. data/rust/parser/src/build/pattern_subset.rs +6 -8
  349. data/rust/parser/src/build/query_derive.rs +3 -1
  350. data/rust/parser/src/build/query_inference.rs +14 -5
  351. data/rust/parser/src/build/read_model.rs +4 -1
  352. data/rust/parser/src/build/references.rs +4 -3
  353. data/rust/parser/src/canonical.rs +34 -15
  354. data/rust/parser/src/emit.rs +187 -105
  355. data/rust/parser/src/expr/ast_json.rs +134 -42
  356. data/rust/parser/src/expr/evaluator.rs +27 -9
  357. data/rust/parser/src/expr/mod.rs +54 -13
  358. data/rust/parser/src/expr/resolver.rs +299 -92
  359. data/rust/parser/src/ir.rs +35 -3
  360. data/rust/parser/src/keywords.rs +7168 -510
  361. data/rust/parser/src/lex.rs +11 -25
  362. data/rust/parser/src/lib.rs +1 -0
  363. data/rust/parser/src/main.rs +65 -6
  364. data/rust/parser/src/parse/adapter.rs +157 -0
  365. data/rust/parser/src/parse/aggregate.rs +19 -10
  366. data/rust/parser/src/parse/chapter.rs +16 -17
  367. data/rust/parser/src/parse/command.rs +35 -16
  368. data/rust/parser/src/parse/domain_port.rs +4 -7
  369. data/rust/parser/src/parse/entity.rs +21 -11
  370. data/rust/parser/src/parse/hecksagon.rs +10 -4
  371. data/rust/parser/src/parse/lifecycle.rs +9 -5
  372. data/rust/parser/src/parse/mod.rs +43 -91
  373. data/rust/parser/src/parse/needs.rs +21 -12
  374. data/rust/parser/src/parse/policy.rs +2 -2
  375. data/rust/parser/src/parse/process_manager.rs +9 -11
  376. data/rust/parser/src/parse/query.rs +8 -4
  377. data/rust/parser/src/parse/read_model.rs +57 -16
  378. data/rust/parser/src/parse/value_object.rs +7 -2
  379. data/rust/parser/src/parse/world.rs +322 -0
  380. data/rust/parser/src/ruby_value.rs +7 -6
  381. data/rust/src/exemplar/json.rs +4 -4
  382. data/rust/src/exemplar/mutations.rs +18 -0
  383. data/rust/src/exemplar/read_models.rs +1 -10
  384. data/rust/src/kernel/attribute_shapes/composite.rs +54 -14
  385. data/rust/src/kernel/attribute_shapes/list.rs +2 -2
  386. data/rust/src/kernel/attribute_shapes/mod.rs +8 -8
  387. data/rust/src/kernel/attribute_shapes/scalar.rs +2 -2
  388. data/rust/src/kernel/cli.rs +229 -112
  389. data/rust/src/kernel/dispatch.rs +323 -115
  390. data/rust/src/kernel/dispatch_guard_tests.rs +327 -65
  391. data/rust/src/kernel/expr.rs +203 -86
  392. data/rust/src/kernel/expression_operators/arithmetic.rs +138 -25
  393. data/rust/src/kernel/expression_operators/comparison.rs +87 -2
  394. data/rust/src/kernel/expression_operators/enumeration.rs +106 -22
  395. data/rust/src/kernel/expression_operators/logical.rs +9 -3
  396. data/rust/src/kernel/expression_operators/membership.rs +3 -1
  397. data/rust/src/kernel/expression_operators/mod.rs +34 -21
  398. data/rust/src/kernel/expression_operators/pattern_match.rs +46 -11
  399. data/rust/src/kernel/expression_operators/positional.rs +84 -30
  400. data/rust/src/kernel/expression_operators/presence.rs +52 -13
  401. data/rust/src/kernel/expression_operators/sign_test.rs +3 -1
  402. data/rust/src/kernel/expression_operators/sized.rs +24 -8
  403. data/rust/src/kernel/expression_operators/text.rs +120 -27
  404. data/rust/src/kernel/expression_operators/to_string.rs +10 -4
  405. data/rust/src/kernel/json.rs +230 -148
  406. data/rust/src/kernel/mod.rs +46 -33
  407. data/rust/src/kernel/named_query.rs +63 -15
  408. data/rust/src/kernel/needs.rs +112 -25
  409. data/rust/src/kernel/orchestrate.rs +980 -581
  410. data/rust/src/kernel/orchestrate_guard_tests.rs +538 -140
  411. data/rust/src/kernel/pattern.rs +107 -34
  412. data/rust/src/kernel/query_comparators.rs +118 -41
  413. data/rust/src/kernel/query_ordering.rs +13 -5
  414. data/rust/src/kernel/read_model.rs +479 -181
  415. data/rust/src/kernel/reference_lookup.rs +122 -26
  416. data/rust/src/kernel/repository.rs +293 -66
  417. data/rust/src/kernel/routing.rs +58 -42
  418. data/rust/src/kernel/ruby_float.rs +139 -0
  419. data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +57 -57
  420. data/rust/src/kernel/vocab/entity_dispatch_order.rs +54 -54
  421. data/rust/src/kernel/vocab/field_hint.rs +19 -25
  422. data/rust/src/kernel/vocab/mod.rs +6 -6
  423. data/rust/src/kernel/vocab/query_comparator.rs +23 -24
  424. data/rust/src/kernel/vocab/refusal_template.rs +501 -297
  425. data/rust/src/lib.rs +50 -0
  426. data/rust/src/main.rs +4 -1
  427. data/rust/web/Cargo.toml +36 -0
  428. data/rust/web/clippy.toml +4 -0
  429. metadata +85 -15
  430. data/examples/pizzas/bluebook/hecksagon/mock_stripe_payment_adapter.rb +0 -36
  431. data/lib/hecks/adapters/driven/google_authentication.adapter +0 -3
  432. data/lib/hecks/adapters/driven/google_authentication.rb +0 -99
  433. data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +0 -3
  434. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +0 -32
  435. data/lib/hecks/ports/authentication.port +0 -6
  436. data/lib/hecks/ports/authentication.rb +0 -67
  437. data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +0 -255
  438. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +0 -22
  439. data/prebuilt/verdicts-48318ca172edd21443b1ad02801c697fff100b746e828f09db987647641a5df2.json +0 -1
  440. data/rust/host/src/approval.rs +0 -652
@@ -32,11 +32,20 @@ struct Acct {
32
32
  }
33
33
 
34
34
  fn item(state: &str, qty: i64) -> Item {
35
- Item { qty, state: state.to_string(), ok: true }
35
+ Item {
36
+ qty,
37
+ state: state.to_string(),
38
+ ok: true,
39
+ }
36
40
  }
37
41
 
38
42
  fn acct() -> Acct {
39
- Acct { balance: 10, status: "open".to_string(), ok: true, items: vec![item("a", 1), item("b", 2)] }
43
+ Acct {
44
+ balance: 10,
45
+ status: "open".to_string(),
46
+ ok: true,
47
+ items: vec![item("a", 1), item("b", 2)],
48
+ }
40
49
  }
41
50
 
42
51
  impl Fielded for Acct {
@@ -49,13 +58,21 @@ impl Fielded for Acct {
49
58
  }
50
59
  }
51
60
  fn items(&self, name: &str) -> Option<Vec<Field<'_>>> {
52
- (name == "items").then(|| self.items.iter().map(|i| Field::Nested(i as &dyn Fielded)).collect())
61
+ (name == "items").then(|| {
62
+ self.items
63
+ .iter()
64
+ .map(|i| Field::Nested(i as &dyn Fielded))
65
+ .collect()
66
+ })
53
67
  }
54
68
  }
55
69
 
56
70
  impl ToJson for Acct {
57
71
  fn to_json(&self) -> Json {
58
- Json::obj(vec![("balance", Json::int(self.balance)), ("status", Json::str(self.status.clone()))])
72
+ Json::obj(vec![
73
+ ("balance", Json::int(self.balance)),
74
+ ("status", Json::str(self.status.clone())),
75
+ ])
59
76
  }
60
77
  }
61
78
 
@@ -64,19 +81,33 @@ impl SetProjectedField for Acct {
64
81
  }
65
82
 
66
83
  fn rule(description: &'static str, field: &'static str) -> InvariantSpec {
67
- InvariantSpec { description, expr: Expr::Lookup(field) }
84
+ InvariantSpec {
85
+ description,
86
+ expr: Expr::Lookup(field),
87
+ }
68
88
  }
69
89
 
70
90
  fn given(description: &'static str, field: &'static str) -> GivenSpec {
71
- GivenSpec { description, expr: Expr::Lookup(field), corrects_event: None }
91
+ GivenSpec {
92
+ description,
93
+ expr: Expr::Lookup(field),
94
+ corrects_event: None,
95
+ }
72
96
  }
73
97
 
74
98
  fn corrects_given(event: &'static str, field: &'static str) -> GivenSpec {
75
- GivenSpec { description: "unused", expr: Expr::Lookup(field), corrects_event: Some(event) }
99
+ GivenSpec {
100
+ description: "unused",
101
+ expr: Expr::Lookup(field),
102
+ corrects_event: Some(event),
103
+ }
76
104
  }
77
105
 
78
106
  fn no_invariants() -> InvariantSet {
79
- InvariantSet { aggregate: vec![], entities: vec![] }
107
+ InvariantSet {
108
+ aggregate: vec![],
109
+ entities: vec![],
110
+ }
80
111
  }
81
112
 
82
113
  fn refusal_of(result: Result<(), Refusal>) -> (&'static str, String) {
@@ -85,42 +116,73 @@ fn refusal_of(result: Result<(), Refusal>) -> (&'static str, String) {
85
116
  }
86
117
 
87
118
  fn closed() -> Acct {
88
- Acct { ok: false, ..acct() }
119
+ Acct {
120
+ ok: false,
121
+ ..acct()
122
+ }
89
123
  }
90
124
 
91
125
  #[test]
92
126
  fn an_aggregate_invariant_that_does_not_hold_refuses_naming_the_aggregate() {
93
- let set = InvariantSet { aggregate: vec![rule("never frozen", "ok")], entities: vec![] };
127
+ let set = InvariantSet {
128
+ aggregate: vec![rule("never frozen", "ok")],
129
+ entities: vec![],
130
+ };
94
131
 
95
- assert_eq!(refusal_of(enforce_invariants(&closed(), "Acct", &set)), ("InvariantViolation", "Acct refused — never frozen".to_string()));
132
+ assert_eq!(
133
+ refusal_of(enforce_invariants(&closed(), "Acct", &set)),
134
+ (
135
+ "InvariantViolation",
136
+ "Acct refused — never frozen".to_string()
137
+ )
138
+ );
96
139
  assert!(enforce_invariants(&acct(), "Acct", &set).is_ok());
97
140
  }
98
141
 
99
142
  #[test]
100
143
  fn the_first_failing_aggregate_invariant_is_the_one_named() {
101
- let set = InvariantSet { aggregate: vec![rule("first", "ok"), rule("second", "ok")], entities: vec![] };
144
+ let set = InvariantSet {
145
+ aggregate: vec![rule("first", "ok"), rule("second", "ok")],
146
+ entities: vec![],
147
+ };
102
148
 
103
- assert_eq!(refusal_of(enforce_invariants(&closed(), "Acct", &set)).1, "Acct refused — first");
149
+ assert_eq!(
150
+ refusal_of(enforce_invariants(&closed(), "Acct", &set)).1,
151
+ "Acct refused — first"
152
+ );
104
153
  }
105
154
 
106
155
  #[test]
107
156
  fn an_entity_invariant_refuses_the_element_that_breaks_it_and_names_the_entity() {
108
157
  let set = InvariantSet {
109
158
  aggregate: vec![],
110
- entities: vec![EntityInvariants { name: "Item", list_field: "items", specs: vec![rule("stays ok", "ok")], nested: vec![] }],
159
+ entities: vec![EntityInvariants {
160
+ name: "Item",
161
+ list_field: "items",
162
+ specs: vec![rule("stays ok", "ok")],
163
+ nested: vec![],
164
+ }],
111
165
  };
112
166
  let mut record = acct();
113
167
  assert!(enforce_invariants(&record, "Acct", &set).is_ok());
114
168
 
115
169
  record.items[1].ok = false;
116
- assert_eq!(refusal_of(enforce_invariants(&record, "Acct", &set)), ("InvariantViolation", "Item refused — stays ok".to_string()));
170
+ assert_eq!(
171
+ refusal_of(enforce_invariants(&record, "Acct", &set)),
172
+ ("InvariantViolation", "Item refused — stays ok".to_string())
173
+ );
117
174
  }
118
175
 
119
176
  #[test]
120
177
  fn an_entity_invariant_over_a_list_the_owner_does_not_have_passes() {
121
178
  let set = InvariantSet {
122
179
  aggregate: vec![],
123
- entities: vec![EntityInvariants { name: "Item", list_field: "no_such_list", specs: vec![rule("never read", "missing")], nested: vec![] }],
180
+ entities: vec![EntityInvariants {
181
+ name: "Item",
182
+ list_field: "no_such_list",
183
+ specs: vec![rule("never read", "missing")],
184
+ nested: vec![],
185
+ }],
124
186
  };
125
187
 
126
188
  assert!(enforce_invariants(&acct(), "Acct", &set).is_ok());
@@ -131,7 +193,14 @@ fn a_given_that_does_not_hold_refuses_with_its_description() {
131
193
  let givens = [given("must be open", "ok")];
132
194
 
133
195
  assert_eq!(
134
- refusal_of(enforce_givens(&closed(), &NoFields, &givens, "Close", "D::Acct", "a1")),
196
+ refusal_of(enforce_givens(
197
+ &closed(),
198
+ &NoFields,
199
+ &givens,
200
+ "Close",
201
+ "D::Acct",
202
+ "a1"
203
+ )),
135
204
  ("GivenNotMet", "Close refused — must be open".to_string())
136
205
  );
137
206
  assert!(enforce_givens(&acct(), &NoFields, &givens, "Close", "D::Acct", "a1").is_ok());
@@ -142,17 +211,33 @@ fn a_failing_corrects_given_refuses_as_nothing_to_correct_naming_the_record() {
142
211
  let givens = [corrects_given("Opened", "ok")];
143
212
 
144
213
  assert_eq!(
145
- refusal_of(enforce_givens(&closed(), &NoFields, &givens, "Fix", "D::Acct", "a1")),
146
- ("NothingToCorrect", "Fix refused — corrects Opened, but D::Acct #a1 has never emitted it".to_string())
214
+ refusal_of(enforce_givens(
215
+ &closed(),
216
+ &NoFields,
217
+ &givens,
218
+ "Fix",
219
+ "D::Acct",
220
+ "a1"
221
+ )),
222
+ (
223
+ "NothingToCorrect",
224
+ "Fix refused — corrects Opened, but D::Acct #a1 has never emitted it".to_string()
225
+ )
147
226
  );
148
227
  }
149
228
 
150
229
  #[test]
151
230
  fn a_transition_from_an_allowed_state_passes_and_from_any_other_refuses() {
152
- let check = TransitionCheck { field: "status", from_states: &["open", "held"] };
231
+ let check = TransitionCheck {
232
+ field: "status",
233
+ from_states: &["open", "held"],
234
+ };
153
235
 
154
236
  assert!(admissible_transition(&acct(), Some(&check), "Close").is_ok());
155
- let shut = Acct { status: "closed".to_string(), ..acct() };
237
+ let shut = Acct {
238
+ status: "closed".to_string(),
239
+ ..acct()
240
+ };
156
241
  let (kind, text) = refusal_of(admissible_transition(&shut, Some(&check), "Close"));
157
242
  assert_eq!(kind, "LifecycleRefused");
158
243
  assert!(text.contains("closed"), "{text}");
@@ -165,19 +250,40 @@ fn no_transition_declared_admits_anything() {
165
250
 
166
251
  #[test]
167
252
  fn a_lifecycle_field_that_is_missing_or_not_a_string_is_a_type_mismatch() {
168
- let numeric = TransitionCheck { field: "balance", from_states: &["open"] };
169
- let absent = TransitionCheck { field: "nope", from_states: &["open"] };
253
+ let numeric = TransitionCheck {
254
+ field: "balance",
255
+ from_states: &["open"],
256
+ };
257
+ let absent = TransitionCheck {
258
+ field: "nope",
259
+ from_states: &["open"],
260
+ };
170
261
 
171
- assert_eq!(refusal_of(admissible_transition(&acct(), Some(&numeric), "Close")).0, "TypeMismatch");
172
- assert_eq!(refusal_of(admissible_transition(&acct(), Some(&absent), "Close")).0, "TypeMismatch");
262
+ assert_eq!(
263
+ refusal_of(admissible_transition(&acct(), Some(&numeric), "Close")).0,
264
+ "TypeMismatch"
265
+ );
266
+ assert_eq!(
267
+ refusal_of(admissible_transition(&acct(), Some(&absent), "Close")).0,
268
+ "TypeMismatch"
269
+ );
173
270
  }
174
271
 
175
272
  #[test]
176
273
  fn an_ensures_that_does_not_hold_after_the_mutation_refuses() {
177
- let ensures = [EnsuresSpec { description: "stays ok", expr: Expr::Lookup("ok") }];
274
+ let ensures = [EnsuresSpec {
275
+ description: "stays ok",
276
+ expr: Expr::Lookup("ok"),
277
+ }];
178
278
 
179
279
  assert_eq!(
180
- refusal_of(enforce_ensures(&closed(), &acct(), &NoFields, &ensures, "Close")),
280
+ refusal_of(enforce_ensures(
281
+ &closed(),
282
+ &acct(),
283
+ &NoFields,
284
+ &ensures,
285
+ "Close"
286
+ )),
181
287
  ("EnsuresNotMet", "Close refused — stays ok".to_string())
182
288
  );
183
289
  assert!(enforce_ensures(&acct(), &acct(), &NoFields, &ensures, "Close").is_ok());
@@ -189,11 +295,18 @@ struct Run {
189
295
  }
190
296
 
191
297
  fn fresh() -> Run {
192
- Run { repo: InMemoryRepository::new(), mutations: vec![] }
298
+ Run {
299
+ repo: InMemoryRepository::new(),
300
+ mutations: vec![],
301
+ }
193
302
  }
194
303
 
195
304
  fn create(id: &str, state_independent: bool) -> Hydrate<'static, Acct> {
196
- Hydrate::Create { id: id.to_string(), build: Box::new(acct), state_independent }
305
+ Hydrate::Create {
306
+ id: id.to_string(),
307
+ build: Box::new(acct),
308
+ state_independent,
309
+ }
197
310
  }
198
311
 
199
312
  fn act(id: &str) -> Hydrate<'static, Acct> {
@@ -236,16 +349,33 @@ fn run_dispatch(
236
349
  fn a_creating_dispatch_saves_the_record_records_the_mutation_and_emits_in_declared_order() {
237
350
  let mut run = fresh();
238
351
 
239
- let (record, events) = run_dispatch(&mut run, create("a1", false), &[], None, &[], &no_invariants()).unwrap();
352
+ let (record, events) = run_dispatch(
353
+ &mut run,
354
+ create("a1", false),
355
+ &[],
356
+ None,
357
+ &[],
358
+ &no_invariants(),
359
+ )
360
+ .unwrap();
240
361
 
241
362
  assert_eq!(record.balance, 15);
242
363
  assert_eq!(run.repo.find("a1").unwrap().balance, 15);
243
364
  assert_eq!(run.mutations.len(), 1);
244
365
  let saved = &run.mutations[0];
245
- assert_eq!((saved.aggregate.as_str(), saved.id.as_str(), saved.operation), ("D::Acct", "a1", "save"));
366
+ assert_eq!(
367
+ (saved.aggregate.as_str(), saved.id.as_str(), saved.operation),
368
+ ("D::Acct", "a1", "save")
369
+ );
246
370
  assert_eq!(saved.state, record.to_json());
247
- let emitted: Vec<(&str, &str, &str)> = events.iter().map(|e| (e.name.as_str(), e.aggregate.as_str(), e.id.as_str())).collect();
248
- assert_eq!(emitted, [("Funded", "D::Acct", "a1"), ("Audited", "D::Acct", "a1")]);
371
+ let emitted: Vec<(&str, &str, &str)> = events
372
+ .iter()
373
+ .map(|e| (e.name.as_str(), e.aggregate.as_str(), e.id.as_str()))
374
+ .collect();
375
+ assert_eq!(
376
+ emitted,
377
+ [("Funded", "D::Acct", "a1"), ("Audited", "D::Acct", "a1")]
378
+ );
249
379
  assert_eq!(events[0].payload, Json::str("payload"));
250
380
  }
251
381
 
@@ -264,7 +394,8 @@ fn acting_on_an_existing_record_succeeds_and_does_not_trip_the_deferred_existenc
264
394
  fn acting_on_a_missing_record_is_not_found() {
265
395
  let mut run = fresh();
266
396
 
267
- let refusal = run_dispatch(&mut run, act("ghost"), &[], None, &[], &no_invariants()).unwrap_err();
397
+ let refusal =
398
+ run_dispatch(&mut run, act("ghost"), &[], None, &[], &no_invariants()).unwrap_err();
268
399
 
269
400
  assert_eq!(refusal.kind(), "NotFound");
270
401
  assert!(run.mutations.is_empty());
@@ -276,9 +407,21 @@ fn a_creating_dispatch_over_an_existing_identity_is_already_exists_in_both_check
276
407
  let mut run = fresh();
277
408
  run.repo.save("a1", acct());
278
409
 
279
- let refusal = run_dispatch(&mut run, create("a1", state_independent), &[], None, &[], &no_invariants()).unwrap_err();
280
-
281
- assert_eq!(refusal.kind(), "AlreadyExists", "state_independent={state_independent}");
410
+ let refusal = run_dispatch(
411
+ &mut run,
412
+ create("a1", state_independent),
413
+ &[],
414
+ None,
415
+ &[],
416
+ &no_invariants(),
417
+ )
418
+ .unwrap_err();
419
+
420
+ assert_eq!(
421
+ refusal.kind(),
422
+ "AlreadyExists",
423
+ "state_independent={state_independent}"
424
+ );
282
425
  assert!(run.mutations.is_empty(), "nothing saved when refused");
283
426
  }
284
427
  }
@@ -287,30 +430,81 @@ fn a_creating_dispatch_over_an_existing_identity_is_already_exists_in_both_check
287
430
  fn a_creating_dispatch_with_a_blank_identity_is_not_found() {
288
431
  let mut run = fresh();
289
432
 
290
- assert_eq!(run_dispatch(&mut run, create("", false), &[], None, &[], &no_invariants()).unwrap_err().kind(), "NotFound");
433
+ assert_eq!(
434
+ run_dispatch(
435
+ &mut run,
436
+ create("", false),
437
+ &[],
438
+ None,
439
+ &[],
440
+ &no_invariants()
441
+ )
442
+ .unwrap_err()
443
+ .kind(),
444
+ "NotFound"
445
+ );
291
446
  }
292
447
 
293
448
  // Each guard stored over a record that fails it, so the refusal is the guard's own.
294
- fn refused_by(run: &mut Run, givens: &[GivenSpec], transition: Option<TransitionCheck>, ensures: &[EnsuresSpec], invariants: &InvariantSet) -> &'static str {
449
+ fn refused_by(
450
+ run: &mut Run,
451
+ givens: &[GivenSpec],
452
+ transition: Option<TransitionCheck>,
453
+ ensures: &[EnsuresSpec],
454
+ invariants: &InvariantSet,
455
+ ) -> &'static str {
295
456
  run.repo.save("a1", closed());
296
- let kind = run_dispatch(run, act("a1"), givens, transition, ensures, invariants).unwrap_err().kind();
297
- assert_eq!(run.repo.find("a1").unwrap().balance, 10, "a refused dispatch leaves the stored record alone");
457
+ let kind = run_dispatch(run, act("a1"), givens, transition, ensures, invariants)
458
+ .unwrap_err()
459
+ .kind();
460
+ assert_eq!(
461
+ run.repo.find("a1").unwrap().balance,
462
+ 10,
463
+ "a refused dispatch leaves the stored record alone"
464
+ );
298
465
  assert!(run.mutations.is_empty());
299
466
  kind
300
467
  }
301
468
 
302
469
  #[test]
303
470
  fn dispatch_refuses_at_each_guard_before_saving() {
304
- assert_eq!(refused_by(&mut fresh(), &[given("open", "ok")], None, &[], &no_invariants()), "GivenNotMet");
471
+ assert_eq!(
472
+ refused_by(
473
+ &mut fresh(),
474
+ &[given("open", "ok")],
475
+ None,
476
+ &[],
477
+ &no_invariants()
478
+ ),
479
+ "GivenNotMet"
480
+ );
305
481
 
306
- let held_only = TransitionCheck { field: "status", from_states: &["held"] };
307
- assert_eq!(refused_by(&mut fresh(), &[], Some(held_only), &[], &no_invariants()), "LifecycleRefused");
482
+ let held_only = TransitionCheck {
483
+ field: "status",
484
+ from_states: &["held"],
485
+ };
486
+ assert_eq!(
487
+ refused_by(&mut fresh(), &[], Some(held_only), &[], &no_invariants()),
488
+ "LifecycleRefused"
489
+ );
308
490
 
309
- let ensures = [EnsuresSpec { description: "ok", expr: Expr::Lookup("ok") }];
310
- assert_eq!(refused_by(&mut fresh(), &[], None, &ensures, &no_invariants()), "EnsuresNotMet");
491
+ let ensures = [EnsuresSpec {
492
+ description: "ok",
493
+ expr: Expr::Lookup("ok"),
494
+ }];
495
+ assert_eq!(
496
+ refused_by(&mut fresh(), &[], None, &ensures, &no_invariants()),
497
+ "EnsuresNotMet"
498
+ );
311
499
 
312
- let invariants = InvariantSet { aggregate: vec![rule("ok", "ok")], entities: vec![] };
313
- assert_eq!(refused_by(&mut fresh(), &[], None, &[], &invariants), "InvariantViolation");
500
+ let invariants = InvariantSet {
501
+ aggregate: vec![rule("ok", "ok")],
502
+ entities: vec![],
503
+ };
504
+ assert_eq!(
505
+ refused_by(&mut fresh(), &[], None, &[], &invariants),
506
+ "InvariantViolation"
507
+ );
314
508
  }
315
509
 
316
510
  #[test]
@@ -386,15 +580,27 @@ fn an_entity_command_mutates_only_the_located_element() {
386
580
 
387
581
  entity_call(&mut record, is_b, &[], None, &[]).unwrap();
388
582
 
389
- assert_eq!((record.items[0].qty, record.items[0].state.as_str()), (1, "a"));
390
- assert_eq!((record.items[1].qty, record.items[1].state.as_str()), (102, "bumped"));
583
+ assert_eq!(
584
+ (record.items[0].qty, record.items[0].state.as_str()),
585
+ (1, "a")
586
+ );
587
+ assert_eq!(
588
+ (record.items[1].qty, record.items[1].state.as_str()),
589
+ (102, "bumped")
590
+ );
391
591
  }
392
592
 
393
593
  #[test]
394
594
  fn an_entity_command_naming_no_element_is_not_found_and_changes_nothing() {
395
595
  let mut record = acct();
396
596
 
397
- let (kind, _) = refusal_of(entity_call(&mut record, |i| i.state == "zzz", &[], None, &[]));
597
+ let (kind, _) = refusal_of(entity_call(
598
+ &mut record,
599
+ |i| i.state == "zzz",
600
+ &[],
601
+ None,
602
+ &[],
603
+ ));
398
604
 
399
605
  assert_eq!(kind, "NotFound");
400
606
  assert_eq!(record.items[1].qty, 2);
@@ -405,9 +611,18 @@ fn an_entity_given_is_read_off_the_element_and_refuses_when_it_fails() {
405
611
  let mut record = acct();
406
612
  record.items[1].ok = false;
407
613
 
408
- let (kind, text) = refusal_of(entity_call(&mut record, is_b, &[given("item ok", "ok")], None, &[]));
614
+ let (kind, text) = refusal_of(entity_call(
615
+ &mut record,
616
+ is_b,
617
+ &[given("item ok", "ok")],
618
+ None,
619
+ &[],
620
+ ));
409
621
 
410
- assert_eq!((kind, text.as_str()), ("GivenNotMet", "Bump refused — item ok"));
622
+ assert_eq!(
623
+ (kind, text.as_str()),
624
+ ("GivenNotMet", "Bump refused — item ok")
625
+ );
411
626
  assert_eq!(record.items[1].qty, 2, "refused before the mutation");
412
627
  }
413
628
 
@@ -418,44 +633,83 @@ fn an_entity_corrects_given_is_asked_of_the_parent_and_never_of_the_element() {
418
633
  let mut record = acct();
419
634
  record.items[1].ok = false;
420
635
  let givens = [corrects_given("Opened", "ok"), given("item ok", "ok")];
421
- assert_eq!(refusal_of(entity_call(&mut record, is_b, &givens, None, &[])).0, "GivenNotMet");
636
+ assert_eq!(
637
+ refusal_of(entity_call(&mut record, is_b, &givens, None, &[])).0,
638
+ "GivenNotMet"
639
+ );
422
640
 
423
641
  // Parent not ok: the corrects given refuses, naming the parent record.
424
642
  let mut record = closed();
425
- let (kind, text) = refusal_of(entity_call(&mut record, is_b, &[corrects_given("Opened", "ok")], None, &[]));
643
+ let (kind, text) = refusal_of(entity_call(
644
+ &mut record,
645
+ is_b,
646
+ &[corrects_given("Opened", "ok")],
647
+ None,
648
+ &[],
649
+ ));
426
650
  assert_eq!(kind, "NothingToCorrect");
427
- assert_eq!(text, "Bump refused — corrects Opened, but D::Acct #a1 has never emitted it");
651
+ assert_eq!(
652
+ text,
653
+ "Bump refused — corrects Opened, but D::Acct #a1 has never emitted it"
654
+ );
428
655
 
429
656
  // `balance` is on the parent only. Read off the element it would refuse, so passing proves
430
657
  // a corrects given is skipped by the element loop.
431
658
  let mut record = acct();
432
- assert!(entity_call(&mut record, is_b, &[corrects_given("Opened", "balance")], None, &[]).is_ok());
659
+ assert!(entity_call(
660
+ &mut record,
661
+ is_b,
662
+ &[corrects_given("Opened", "balance")],
663
+ None,
664
+ &[]
665
+ )
666
+ .is_ok());
433
667
  }
434
668
 
435
669
  #[test]
436
670
  fn an_entity_transition_checks_the_element_state() {
437
671
  let mut record = acct();
438
- let wrong = TransitionCheck { field: "state", from_states: &["a"] };
439
- assert_eq!(refusal_of(entity_call(&mut record, is_b, &[], Some(wrong), &[])).0, "LifecycleRefused");
672
+ let wrong = TransitionCheck {
673
+ field: "state",
674
+ from_states: &["a"],
675
+ };
676
+ assert_eq!(
677
+ refusal_of(entity_call(&mut record, is_b, &[], Some(wrong), &[])).0,
678
+ "LifecycleRefused"
679
+ );
440
680
 
441
- let right = TransitionCheck { field: "state", from_states: &["b"] };
681
+ let right = TransitionCheck {
682
+ field: "state",
683
+ from_states: &["b"],
684
+ };
442
685
  assert!(entity_call(&mut record, is_b, &[], Some(right), &[]).is_ok());
443
686
  }
444
687
 
445
688
  #[test]
446
689
  fn an_entity_ensures_sees_the_settled_element_and_refuses_when_it_fails() {
447
- let ensures = [EnsuresSpec { description: "ok", expr: Expr::Lookup("ok") }];
690
+ let ensures = [EnsuresSpec {
691
+ description: "ok",
692
+ expr: Expr::Lookup("ok"),
693
+ }];
448
694
  let mut record = acct();
449
695
  assert!(entity_call(&mut record, is_b, &[], None, &ensures).is_ok());
450
696
 
451
697
  let mut record = acct();
452
698
  record.items[1].ok = false;
453
699
  let (kind, text) = refusal_of(entity_call(&mut record, is_b, &[], None, &ensures));
454
- assert_eq!((kind, text.as_str()), ("EnsuresNotMet", "Bump refused — ok"));
700
+ assert_eq!(
701
+ (kind, text.as_str()),
702
+ ("EnsuresNotMet", "Bump refused — ok")
703
+ );
455
704
  }
456
705
 
457
706
  #[allow(clippy::too_many_arguments)]
458
- fn run_dispatch_entity(run: &mut Run, parent_id: &str, matches: impl Fn(&Item) -> bool, new_qty: i64) -> Result<(Acct, Vec<Event>), Refusal> {
707
+ fn run_dispatch_entity(
708
+ run: &mut Run,
709
+ parent_id: &str,
710
+ matches: impl Fn(&Item) -> bool,
711
+ new_qty: i64,
712
+ ) -> Result<(Acct, Vec<Event>), Refusal> {
459
713
  dispatch_entity(
460
714
  &mut run.repo,
461
715
  parent_id,
@@ -495,12 +749,20 @@ fn dispatch_entity_hydrates_the_parent_mutates_the_element_saves_and_emits() {
495
749
  assert_eq!(record.items[1].qty, 99);
496
750
  assert_eq!(run.repo.find("a1").unwrap().items[1].qty, 99);
497
751
  assert_eq!(run.mutations.len(), 1);
498
- assert_eq!(events.iter().map(|e| e.name.as_str()).collect::<Vec<_>>(), ["Bumped"]);
752
+ assert_eq!(
753
+ events.iter().map(|e| e.name.as_str()).collect::<Vec<_>>(),
754
+ ["Bumped"]
755
+ );
499
756
  }
500
757
 
501
758
  #[test]
502
759
  fn dispatch_entity_over_a_missing_parent_is_not_found() {
503
760
  let mut run = fresh();
504
761
 
505
- assert_eq!(run_dispatch_entity(&mut run, "ghost", is_b, 99).unwrap_err().kind(), "NotFound");
762
+ assert_eq!(
763
+ run_dispatch_entity(&mut run, "ghost", is_b, 99)
764
+ .unwrap_err()
765
+ .kind(),
766
+ "NotFound"
767
+ );
506
768
  }