hecks 1.3.0 → 1.4.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 (355) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hecks/adapters/driven/claude_code.rb +7 -7
  3. data/lib/hecks/adapters/driven/d1.rb +187 -23
  4. data/lib/hecks/adapters/driven/folder.rb +10 -10
  5. data/lib/hecks/adapters/driven/google_authentication.rb +8 -8
  6. data/lib/hecks/adapters/driven/governance_authorization.rb +31 -13
  7. data/lib/hecks/adapters/driven/heki/journal.rb +5 -4
  8. data/lib/hecks/adapters/driven/heki/saga_store.rb +5 -5
  9. data/lib/hecks/adapters/driven/heki.rb +13 -7
  10. data/lib/hecks/adapters/driven/identity_registry.rb +2 -2
  11. data/lib/hecks/adapters/driven/in_memory_ordering.rb +3 -3
  12. data/lib/hecks/adapters/driven/lambda/client.rb +34 -9
  13. data/lib/hecks/adapters/driven/lambda.rb +39 -33
  14. data/lib/hecks/adapters/driven/local_storage.rb +17 -10
  15. data/lib/hecks/adapters/driven/memory.rb +205 -9
  16. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +1 -1
  17. data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
  18. data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
  19. data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
  20. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
  21. data/lib/hecks/adapters/driven/postgres.rb +175 -28
  22. data/lib/hecks/adapters/driven/prism.rb +4 -4
  23. data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
  24. data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
  25. data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
  26. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
  27. data/lib/hecks/adapters/driven/sqlite.rb +181 -21
  28. data/lib/hecks/adapters/driven.rb +4 -4
  29. data/lib/hecks/adapters/driving/github_webhook.rb +18 -18
  30. data/lib/hecks/behaviors/dsl.rb +2 -2
  31. data/lib/hecks/behaviors/expectations.rb +23 -23
  32. data/lib/hecks/behaviors/ir.rb +1 -1
  33. data/lib/hecks/behaviors/rspec.rb +1 -1
  34. data/lib/hecks/behaviors/runner.rb +2 -2
  35. data/lib/hecks/behaviors.rb +1 -1
  36. data/lib/hecks/bluebook/aggregate.rb +13 -13
  37. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +10 -10
  38. data/lib/hecks/bluebook/assembly/build.rb +1 -1
  39. data/lib/hecks/bluebook/assembly/contract.rb +39 -16
  40. data/lib/hecks/bluebook/assembly/contracts.rb +40 -38
  41. data/lib/hecks/bluebook/assembly/marks.rb +18 -18
  42. data/lib/hecks/bluebook/assembly/specializer.rb +19 -21
  43. data/lib/hecks/bluebook/assembly.rb +9 -9
  44. data/lib/hecks/bluebook/attribute.rb +9 -9
  45. data/lib/hecks/bluebook/behaviour/aggregate.rb +11 -11
  46. data/lib/hecks/bluebook/behaviour/attribute.rb +5 -5
  47. data/lib/hecks/bluebook/behaviour/chapter.rb +23 -5
  48. data/lib/hecks/bluebook/behaviour/command.rb +23 -23
  49. data/lib/hecks/bluebook/behaviour/domain_port.rb +7 -7
  50. data/lib/hecks/bluebook/behaviour/entity.rb +8 -8
  51. data/lib/hecks/bluebook/behaviour/hexagon.rb +4 -4
  52. data/lib/hecks/bluebook/behaviour/lifecycle.rb +5 -5
  53. data/lib/hecks/bluebook/behaviour/policy.rb +12 -12
  54. data/lib/hecks/bluebook/behaviour/process_manager.rb +7 -7
  55. data/lib/hecks/bluebook/behaviour/query.rb +1 -1
  56. data/lib/hecks/bluebook/behaviour/read_model.rb +8 -8
  57. data/lib/hecks/bluebook/behaviour/traits.rb +12 -12
  58. data/lib/hecks/bluebook/behaviour/value_object.rb +6 -6
  59. data/lib/hecks/bluebook/capabilities.rb +27 -0
  60. data/lib/hecks/bluebook/chapter.rb +28 -9
  61. data/lib/hecks/bluebook/command.rb +12 -12
  62. data/lib/hecks/bluebook/domain_port.rb +9 -9
  63. data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
  64. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
  65. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +96 -96
  66. data/lib/hecks/bluebook/dsl/attribute_collector.rb +41 -41
  67. data/lib/hecks/bluebook/dsl/binding_proxy.rb +22 -2
  68. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +111 -74
  69. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +48 -30
  70. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
  71. data/lib/hecks/bluebook/dsl/command_builder.rb +103 -103
  72. data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
  73. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
  74. data/lib/hecks/bluebook/dsl/entity_builder.rb +56 -56
  75. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
  76. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +89 -30
  77. data/lib/hecks/bluebook/dsl/identity_declaration.rb +17 -17
  78. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
  79. data/lib/hecks/bluebook/dsl/policy_builder.rb +30 -21
  80. data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
  81. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
  82. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +35 -35
  83. data/lib/hecks/bluebook/dsl/query_builder.rb +5 -5
  84. data/lib/hecks/bluebook/dsl/read_model_builder.rb +34 -34
  85. data/lib/hecks/bluebook/dsl/rule_reference.rb +41 -39
  86. data/lib/hecks/bluebook/dsl/translation_builder.rb +9 -9
  87. data/lib/hecks/bluebook/dsl/value_object_builder.rb +16 -16
  88. data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
  89. data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
  90. data/lib/hecks/bluebook/entity.rb +11 -11
  91. data/lib/hecks/bluebook/expression/ast_json.rb +20 -20
  92. data/lib/hecks/bluebook/expression/ast_reader.rb +3 -3
  93. data/lib/hecks/bluebook/expression/canonical_form.rb +9 -9
  94. data/lib/hecks/bluebook/expression/evaluator.rb +18 -18
  95. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +18 -18
  96. data/lib/hecks/bluebook/expression/resolver.rb +60 -62
  97. data/lib/hecks/bluebook/hexagon.rb +1 -1
  98. data/lib/hecks/bluebook/lifecycle.rb +1 -1
  99. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -1
  100. data/lib/hecks/bluebook/meta_validator/judge.rb +101 -87
  101. data/lib/hecks/bluebook/meta_validator/plan.rb +39 -39
  102. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -2
  103. data/lib/hecks/bluebook/meta_validator/readings.rb +43 -43
  104. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +44 -37
  105. data/lib/hecks/bluebook/meta_validator/shapes.rb +25 -21
  106. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +145 -31
  107. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +6 -6
  108. data/lib/hecks/bluebook/meta_validator/world_judge.rb +5 -5
  109. data/lib/hecks/bluebook/meta_validator.rb +70 -70
  110. data/lib/hecks/bluebook/model_check.rb +170 -84
  111. data/lib/hecks/bluebook/pattern_subset.rb +9 -9
  112. data/lib/hecks/bluebook/policy.rb +15 -13
  113. data/lib/hecks/bluebook/process_manager.rb +14 -14
  114. data/lib/hecks/bluebook/project_register.rb +6 -6
  115. data/lib/hecks/bluebook/query.rb +4 -4
  116. data/lib/hecks/bluebook/read_model.rb +14 -14
  117. data/lib/hecks/bluebook/reference.rb +8 -8
  118. data/lib/hecks/bluebook/smoke_test.rb +19 -19
  119. data/lib/hecks/bluebook/synthesizer.rb +12 -12
  120. data/lib/hecks/bluebook/translation.rb +4 -4
  121. data/lib/hecks/bluebook/value_object.rb +6 -6
  122. data/lib/hecks/bluebook.rb +2 -2
  123. data/lib/hecks/codemod/legacy_dispatch_args.rb +299 -0
  124. data/lib/hecks/codemod/legacy_dispatch_recorder.rb +186 -0
  125. data/lib/hecks/codemod.rb +36 -35
  126. data/lib/hecks/construct.rb +6 -6
  127. data/lib/hecks/corpus.rb +317 -0
  128. data/lib/hecks/deprecation.rb +95 -0
  129. data/lib/hecks/doc/reference.rb +19 -19
  130. data/lib/hecks/embryonaut_bluebook.rb +11 -11
  131. data/lib/hecks/facade/cli_door.rb +69 -10
  132. data/lib/hecks/facade/cli_runner.rb +105 -24
  133. data/lib/hecks/facade/command_request.rb +23 -0
  134. data/lib/hecks/facade/handle.rb +79 -32
  135. data/lib/hecks/facade/json_door.rb +106 -25
  136. data/lib/hecks/facade/surface/aggregate_door.rb +42 -27
  137. data/lib/hecks/facade/surface/chapter.rb +26 -17
  138. data/lib/hecks/facade/surface.rb +16 -3
  139. data/lib/hecks/facade.rb +15 -4
  140. data/lib/hecks/forms/app.rb +46 -30
  141. data/lib/hecks/forms/command_form_renderer.rb +70 -9
  142. data/lib/hecks/forms/field_renderer.rb +142 -6
  143. data/lib/hecks/forms/field_shape.rb +180 -19
  144. data/lib/hecks/forms/html.rb +51 -7
  145. data/lib/hecks/forms/index_renderer.rb +14 -2
  146. data/lib/hecks/forms/params.rb +120 -23
  147. data/lib/hecks/forms/port_argument.rb +2 -2
  148. data/lib/hecks/forms/query_form_renderer.rb +2 -2
  149. data/lib/hecks/forms/record_renderer.rb +2 -2
  150. data/lib/hecks/forms/record_table.rb +1 -1
  151. data/lib/hecks/forms/value_object_shape.rb +3 -3
  152. data/lib/hecks/forms.rb +24 -4
  153. data/lib/hecks/fqn.rb +1 -1
  154. data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
  155. data/lib/hecks/framework.rb +48 -17
  156. data/lib/hecks/freezer.rb +11 -11
  157. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +90 -90
  158. data/lib/hecks/fuzzing/combination_miner.rb +119 -0
  159. data/lib/hecks/fuzzing/concurrent_dispatch.rb +140 -45
  160. data/lib/hecks/fuzzing/coverage_campaign.rb +118 -0
  161. data/lib/hecks/fuzzing/differential.rb +158 -0
  162. data/lib/hecks/fuzzing/domain_generator.rb +694 -0
  163. data/lib/hecks/fuzzing/era_boundary.rb +37 -18
  164. data/lib/hecks/fuzzing/form_census.rb +35 -20
  165. data/lib/hecks/fuzzing/generated_domain_check.rb +95 -0
  166. data/lib/hecks/fuzzing/invalid_value_generator.rb +6 -6
  167. data/lib/hecks/fuzzing/isolated_boot.rb +62 -62
  168. data/lib/hecks/fuzzing/nondeterministic.rb +67 -0
  169. data/lib/hecks/fuzzing/persistence_parity.rb +19 -21
  170. data/lib/hecks/fuzzing/properties/corrections.rb +9 -9
  171. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +154 -49
  172. data/lib/hecks/fuzzing/properties/guards.rb +42 -42
  173. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +32 -32
  174. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +22 -35
  175. data/lib/hecks/fuzzing/properties/outbox.rb +24 -24
  176. data/lib/hecks/fuzzing/properties/querying.rb +17 -17
  177. data/lib/hecks/fuzzing/properties.rb +64 -40
  178. data/lib/hecks/fuzzing/qa_settings.rb +152 -0
  179. data/lib/hecks/fuzzing/replay.rb +114 -114
  180. data/lib/hecks/fuzzing/rotation_priority.rb +10 -10
  181. data/lib/hecks/fuzzing/rust_gap_manifest.rb +113 -0
  182. data/lib/hecks/fuzzing/self_consistency.rb +141 -112
  183. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +35 -35
  184. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +18 -11
  185. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +13 -12
  186. data/lib/hecks/fuzzing/sequence_generator/picker.rb +21 -12
  187. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +58 -31
  188. data/lib/hecks/fuzzing/sequence_generator.rb +111 -23
  189. data/lib/hecks/fuzzing/shrinker.rb +197 -0
  190. data/lib/hecks/fuzzing/structural_skips.rb +23 -130
  191. data/lib/hecks/fuzzing/sweep_depth.rb +4 -4
  192. data/lib/hecks/fuzzing/target_capabilities.rb +49 -18
  193. data/lib/hecks/fuzzing/value_generator.rb +14 -14
  194. data/lib/hecks/fuzzing.rb +5 -0
  195. data/lib/hecks/grammar/evolve.rb +10 -10
  196. data/lib/hecks/grammar.rb +7 -7
  197. data/lib/hecks/ir.rb +13 -13
  198. data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
  199. data/lib/hecks/language/bluebook/policy.bluebook +11 -1
  200. data/lib/hecks/language/bluebook/vocabulary.bluebook +348 -13
  201. data/lib/hecks/language/oidc.json +5 -0
  202. data/lib/hecks/literal.rb +9 -9
  203. data/lib/hecks/naming.rb +25 -25
  204. data/lib/hecks/ports/access_control.rb +58 -2
  205. data/lib/hecks/ports/agent/answers.rb +83 -6
  206. data/lib/hecks/ports/agent.rb +119 -35
  207. data/lib/hecks/ports/authentication.rb +44 -4
  208. data/lib/hecks/ports/authorization.rb +53 -11
  209. data/lib/hecks/ports/clock.rb +42 -23
  210. data/lib/hecks/ports/extraction.rb +16 -0
  211. data/lib/hecks/ports/identity_assignment.rb +24 -2
  212. data/lib/hecks/ports/identity_generation.rb +17 -3
  213. data/lib/hecks/ports/identity_resolution.rb +18 -1
  214. data/lib/hecks/ports/loading.rb +4 -0
  215. data/lib/hecks/ports/persistence/append_only.rb +172 -8
  216. data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
  217. data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
  218. data/lib/hecks/ports/persistence/execution.rb +4 -0
  219. data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
  220. data/lib/hecks/ports/persistence/plugin.rb +42 -4
  221. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
  222. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
  223. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
  224. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
  225. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
  226. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
  227. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
  228. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
  229. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
  230. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +118 -66
  231. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
  232. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +28 -5
  233. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
  234. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
  235. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
  236. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +33 -9
  237. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
  238. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +57 -4
  239. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +314 -90
  241. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
  242. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
  243. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
  244. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +42 -8
  245. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
  246. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
  247. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
  248. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -19
  249. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +5 -5
  250. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +1 -1
  251. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
  252. data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
  253. data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
  254. data/lib/hecks/ports/persistence/repository_factory.rb +23 -3
  255. data/lib/hecks/ports/persistence/state_codec.rb +319 -0
  256. data/lib/hecks/ports/persistence.rb +36 -1
  257. data/lib/hecks/ports/projection.rb +61 -7
  258. data/lib/hecks/ports/query/in_memory.rb +3 -3
  259. data/lib/hecks/ports/query/ordering.rb +6 -6
  260. data/lib/hecks/ports/query.rb +35 -0
  261. data/lib/hecks/projections/bootstrap_table.rb +112 -0
  262. data/lib/hecks/projections/diagrams.rb +75 -75
  263. data/lib/hecks/projections/glossary/html.rb +3 -3
  264. data/lib/hecks/projections/glossary/markdown.rb +3 -3
  265. data/lib/hecks/projections/glossary/mermaid.rb +1 -1
  266. data/lib/hecks/projections/glossary/sections.rb +1 -1
  267. data/lib/hecks/projections/glossary/sentences.rb +5 -5
  268. data/lib/hecks/projections/glossary.rb +15 -15
  269. data/lib/hecks/projections/ir.rb +1 -1
  270. data/lib/hecks/projections/model/deviations.rb +18 -17
  271. data/lib/hecks/projections/model.rb +25 -21
  272. data/lib/hecks/projections/oidc.rb +7 -7
  273. data/lib/hecks/projections/parser_table.rb +5 -5
  274. data/lib/hecks/projections/reference.rb +3 -3
  275. data/lib/hecks/projections/rust_vocabulary.rb +443 -0
  276. data/lib/hecks/projections/shape.rb +2 -2
  277. data/lib/hecks/projections/statements.rb +11 -11
  278. data/lib/hecks/projections/vocabulary.rb +9 -9
  279. data/lib/hecks/projections.rb +5 -3
  280. data/lib/hecks/projector/cli_projector.rb +29 -29
  281. data/lib/hecks/projector/docs_projector.rb +13 -13
  282. data/lib/hecks/projector/exporter.rb +42 -21
  283. data/lib/hecks/projector/ir_projector.rb +1 -1
  284. data/lib/hecks/projector/narrate_projector.rb +11 -11
  285. data/lib/hecks/projector/target.rb +13 -13
  286. data/lib/hecks/projector.rb +15 -15
  287. data/lib/hecks/query_ir.rb +47 -47
  288. data/lib/hecks/query_specification/common/comparators.rb +19 -3
  289. data/lib/hecks/query_specification/common/comparison.rb +109 -27
  290. data/lib/hecks/query_specification/common/dsl.rb +65 -9
  291. data/lib/hecks/query_specification/common/null_policy.rb +57 -13
  292. data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
  293. data/lib/hecks/query_specification/common/options.rb +25 -0
  294. data/lib/hecks/query_specification/field_path.rb +69 -15
  295. data/lib/hecks/query_specification/hop_path.rb +57 -20
  296. data/lib/hecks/query_specification/read_model/specification.rb +4 -0
  297. data/lib/hecks/rendering.rb +3 -3
  298. data/lib/hecks/router/namespace_installer.rb +3 -3
  299. data/lib/hecks/router.rb +1 -1
  300. data/lib/hecks/runtime/aggregate_lock.rb +11 -11
  301. data/lib/hecks/runtime/boot_gates.rb +3 -3
  302. data/lib/hecks/runtime/caller.rb +8 -8
  303. data/lib/hecks/runtime/capability_graph.rb +2 -2
  304. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +22 -25
  305. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +42 -63
  306. data/lib/hecks/runtime/command_interpreter.rb +159 -102
  307. data/lib/hecks/runtime/command_rules/admissibility.rb +69 -69
  308. data/lib/hecks/runtime/command_rules/arithmetic.rb +137 -91
  309. data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
  310. data/lib/hecks/runtime/command_rules/emission.rb +18 -1
  311. data/lib/hecks/runtime/command_rules/references.rb +35 -35
  312. data/lib/hecks/runtime/command_rules.rb +3 -0
  313. data/lib/hecks/runtime/dependency_planning.rb +11 -11
  314. data/lib/hecks/runtime/dispatcher.rb +283 -90
  315. data/lib/hecks/runtime/entity_element.rb +151 -67
  316. data/lib/hecks/runtime/entity_interpreter.rb +108 -82
  317. data/lib/hecks/runtime/errors.rb +19 -19
  318. data/lib/hecks/runtime/event.rb +6 -6
  319. data/lib/hecks/runtime/identity.rb +22 -22
  320. data/lib/hecks/runtime/instance.rb +39 -14
  321. data/lib/hecks/runtime/interpreting.rb +12 -12
  322. data/lib/hecks/runtime/invocation.rb +276 -0
  323. data/lib/hecks/runtime/loader.rb +14 -14
  324. data/lib/hecks/runtime/outbox.rb +23 -23
  325. data/lib/hecks/runtime/policy_interpreter.rb +54 -54
  326. data/lib/hecks/runtime/port_operation_interpreter.rb +22 -19
  327. data/lib/hecks/runtime/query_interpreter.rb +55 -64
  328. data/lib/hecks/runtime/reaction_invocation.rb +20 -20
  329. data/lib/hecks/runtime/read_model_interpreter.rb +40 -40
  330. data/lib/hecks/runtime/rebuild_sweep.rb +4 -4
  331. data/lib/hecks/runtime/reference_hop.rb +6 -6
  332. data/lib/hecks/runtime/refusal_wording.rb +92 -115
  333. data/lib/hecks/runtime/registry/saga_persistence.rb +21 -21
  334. data/lib/hecks/runtime/registry/verification.rb +36 -26
  335. data/lib/hecks/runtime/registry.rb +45 -28
  336. data/lib/hecks/runtime/remote_dispatcher.rb +38 -23
  337. data/lib/hecks/runtime/routing.rb +10 -153
  338. data/lib/hecks/runtime/saga_interpreter/correlation.rb +17 -17
  339. data/lib/hecks/runtime/saga_interpreter.rb +64 -64
  340. data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
  341. data/lib/hecks/runtime/tenant_check.rb +9 -9
  342. data/lib/hecks/runtime/tenant_scope.rb +5 -5
  343. data/lib/hecks/runtime/value/admission.rb +75 -30
  344. data/lib/hecks/runtime/value/coercion.rb +318 -127
  345. data/lib/hecks/runtime/value/entity_list_coercion.rb +34 -34
  346. data/lib/hecks/runtime/value.rb +21 -21
  347. data/lib/hecks/runtime.rb +7 -7
  348. data/lib/hecks/storehouse.rb +64 -64
  349. data/lib/hecks/version.rb +3 -3
  350. data/lib/hecks/vocabulary.rb +205 -4
  351. data/lib/hecks.rb +13 -11
  352. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +11 -11
  353. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +14 -12
  354. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +11 -11
  355. metadata +22 -2
@@ -20,14 +20,12 @@ module Hecks
20
20
  SIGN_TESTS = Hecks::Vocabulary.fetch("SignTest")
21
21
 
22
22
  # Which Comparison operator each sign test is sugar for, against the
23
- # literal 0 — declared the same way in Vocabulary::SignTest's
24
- # compares_via (language/bluebook/vocabulary.bluebook) ; spec/vocabulary_conformance_spec
25
- # holds the two tables equal.
26
- SIGN_TEST_OPERATORS = {
27
- "positive?" => ">",
28
- "negative?" => "<",
29
- "zero?" => "=="
30
- }.freeze
23
+ # literal 0 — Vocabulary::SignTest's own compares_via
24
+ # (language/bluebook/vocabulary.bluebook), read off the generated
25
+ # table rather than typed a second time.
26
+ SIGN_TEST_OPERATORS = Hecks::Vocabulary.rows("SignTest")
27
+ .to_h { |row| [row["name"], row["compares_via"]] }
28
+ .freeze
31
29
 
32
30
  # The leaf grammar an expression's dotted/arithmetic side parses into.
33
31
  # Which node a string produces is a pure function of the string, so
@@ -40,7 +38,7 @@ module Hecks
40
38
  StringLiteral = Struct.new(:value, keyword_init: true)
41
39
  BoolLiteral = Struct.new(:value, keyword_init: true)
42
40
  # `["active", "suspended"]` — a literal set, the haystack half of
43
- # an `.include?`. Vocabulary::IncludeHaystack has always ADMITTED
41
+ # an `.include?`. Vocabulary::IncludeHaystack has always admitted
44
42
  # Array (and Evaluator#includes? has always had a `when Array`
45
43
  # arm), but nothing could produce one: there was no array-literal
46
44
  # node, so `["a", "b"].include?(x)` fell through to Lookup and
@@ -66,18 +64,18 @@ module Hecks
66
64
  Size = Struct.new(:receiver, keyword_init: true)
67
65
  Lookup = Struct.new(:path, keyword_init: true)
68
66
 
69
- # UPDATE 2026-08-27: every "vendored addition, not (yet) upstream
67
+ # Update 2026-08-27: every "vendored addition, not (yet) upstream
70
68
  # hecks" comment on this file's own MatchesRegex/Presence/Split/
71
69
  # First/Last/StartsWith/EndsWith below (plus ArrayLiteral above)
72
- # described a REAL gap, found the hard way, in the history each
70
+ # described a real gap, found the hard way, in the history each
73
71
  # comment tells — and that history stays exactly as written,
74
- # on purpose. What changed is the PRESENT TENSE claim "not (yet)
72
+ # on purpose. What changed is the present tense claim "not (yet)
75
73
  # upstream": a review of this exact migration found these eight
76
- # symbols had working Ruby parse/interpret arms but had NEVER
74
+ # symbols had working Ruby parse/interpret arms but had never
77
75
  # gone through Propose -> Render -> Admit
78
76
  # (lib/hecks/grammar/expression_operators.json) the way every
79
77
  # other operator here has — a closed-vocabulary guard
80
- # (spec/operator_conformance_spec.rb) built entirely over TABLES
78
+ # (spec/operator_conformance_spec.rb) built entirely over tables
81
79
  # structurally could not see hand-coded Struct/parse/interpret
82
80
  # additions, so eight operators ran in Ruby, admitted nowhere,
83
81
  # invisible to the one guard whose whole job was "reads in every
@@ -88,13 +86,13 @@ module Hecks
88
86
  #
89
87
  # `receiver.match?(/pattern/)` -- vendored addition, not (yet)
90
88
  # upstream hecks (migration plan task 8): confirmed the
91
- # SINGLE most impactful corpus-wide dispatch-time gap of the
89
+ # single most impactful corpus-wide dispatch-time gap of the
92
90
  # whole migration -- `.match?(regex)` appears in nearly every
93
91
  # value_object's format-validation rule across every corpus
94
92
  # this migration touched (email/phone/ISO-8601-timestamp/zip
95
- # patterns, dozens of files), and had NO parse support at all:
93
+ # patterns, dozens of files), and had no parse support at all:
96
94
  # it fell all the way through to the `Lookup` catch-all below,
97
- # which tried to split the ENTIRE ".match?(/\A\d{5}\z/)" text
95
+ # which tried to split the entire ".match?(/\A\d{5}\z/)" text
98
96
  # on "." as if it were a dotted attribute path, and crashed with
99
97
  # an opaque "no implicit conversion of Symbol into Integer"
100
98
  # somewhere downstream -- confirmed live via a real dispatch,
@@ -118,13 +116,13 @@ module Hecks
118
116
  Presence = Struct.new(:receiver, :negated, keyword_init: true)
119
117
 
120
118
  # `.set?`/`.unset?` -- sibling of `.present?`/`.blank?` immediately
121
- # above, added for a DELIBERATELY narrower question, spelled out in
119
+ # above, added for a deliberately narrower question, spelled out in
122
120
  # the name so choosing between the two pairs is a choice, not a
123
121
  # trap: `.present?` means "not EMPTY" (Rails-standard -- nil/false,
124
- # and an EMPTY String/Array/Hash, are blank; nothing else is),
122
+ # and an empty String/Array/Hash, are blank; nothing else is),
125
123
  # which quietly answers "was this ever assigned" and "does the
126
- # assigned value happen to be empty" as the SAME question. For an
127
- # optional field whose only legitimate unset state IS nil, that
124
+ # assigned value happen to be empty" as the same question. For an
125
+ # optional field whose only legitimate unset state is nil, that
128
126
  # conflation is a real trap -- confirmed live: a corpus author
129
127
  # reaching for `superseded_by.blank?` to guard an optional
130
128
  # reference burned real time before landing on "just don't guard
@@ -144,7 +142,7 @@ module Hecks
144
142
  # `value.split("::").length == 4 && value.split("::").all? { |s|
145
143
  # s.length > 0 }` -- `.split(` matched none of this grammar's
146
144
  # known suffixes, so it fell through to the `Lookup` catch-all,
147
- # which split the RAW EXPRESSION TEXT on "." (not the runtime
145
+ # which split the raw expression text on "." (not the runtime
148
146
  # value) and crashed with `TypeError: no implicit conversion of
149
147
  # Symbol into Integer` the moment `String#[]` was handed a
150
148
  # Symbol segment -- meaning every command taking a Phrase was
@@ -213,13 +211,13 @@ module Hecks
213
211
  end
214
212
 
215
213
  # A grammar's own dispatch table — one `return Node.new(...) if
216
- # expr =~ /pattern/` per leaf production, in a FIXED precedence
214
+ # expr =~ /pattern/` per leaf production, in a fixed precedence
217
215
  # order (`.length` before the generic suffixes, sign tests before
218
216
  # the rest, etc. — see this file's own history comments on why
219
217
  # several of these were added in exactly this position). Each
220
218
  # branch is already one line; splitting the table into smaller
221
219
  # methods would not shrink any single check, only hide the
222
- # precedence order this method's own line-by-line sequence IS.
220
+ # precedence order this method's own line-by-line sequence is.
223
221
  # rubocop:disable-next Metrics/AbcSize
224
222
  # rubocop:disable-next Metrics/CyclomaticComplexity
225
223
  # rubocop:disable-next Metrics/MethodLength
@@ -299,7 +297,7 @@ module Hecks
299
297
  # `parse`'s own dispatch table, mirrored: one `when` per leaf node
300
298
  # type it can produce, each already delegating to a small named
301
299
  # helper (add, apply_sign_test, emptiness_of, ...) — the case
302
- # itself IS the closed, declared set this method exists to
300
+ # itself is the closed, declared set this method exists to
303
301
  # exhaust; the `else` backstop's own comment explains why a
304
302
  # missing arm is a bug this method is built to make loud, not
305
303
  # quiet.
@@ -365,8 +363,8 @@ module Hecks
365
363
 
366
364
  # `.present?`/`.blank?` -- vendored addition, see the
367
365
  # `Presence` struct's own comment above. `nil` and `false` are
368
- # blank ; a String/Array/Hash is blank when EMPTY, not merely
369
- # falsy -- a VO-wrapped field that IS assigned (`{value: "x"}`,
366
+ # blank ; a String/Array/Hash is blank when empty, not merely
367
+ # falsy -- a VO-wrapped field that is assigned (`{value: "x"}`,
370
368
  # `Value#to_h`'d first) is present regardless of what its own
371
369
  # inner value holds, matching how every VO-typed field in this
372
370
  # corpus is actually shaped once set at all.
@@ -389,7 +387,7 @@ module Hecks
389
387
  # `receiver.match?(/pattern/)` -- vendored addition, see the
390
388
  # `MatchesRegex` struct's own comment above. `receiver_value` is
391
389
  # coerced to a plain String first -- inlined here rather than
392
- # calling `Evaluator#string_of` (a DIFFERENT module_function
390
+ # calling `Evaluator#string_of` (a different module_function
393
391
  # module; not actually in scope from inside Resolver despite
394
392
  # `Modulo`'s own parse rule above calling a same-named
395
393
  # `match_call` that has the identical cross-module problem --
@@ -410,7 +408,7 @@ module Hecks
410
408
  Regexp.new(pattern, options).match?(text)
411
409
  rescue RegexpError => e
412
410
  # M9: a malformed pattern between the slashes (an unclosed
413
- # character class, say) is a defect in the EXPRESSION TEXT
411
+ # character class, say) is a defect in the expression text
414
412
  # itself, exactly the same category of author mistake an
415
413
  # unresolvable attribute name already refuses for — `Regexp.new`
416
414
  # raising a raw `RegexpError` crossed this sublanguage's own
@@ -420,7 +418,7 @@ module Hecks
420
418
  end
421
419
 
422
420
  # The elements of a bracketed literal, or nil if this isn't one.
423
- # Splits on TOP-LEVEL commas only — quote-aware and depth-aware,
421
+ # Splits on top-level commas only — quote-aware and depth-aware,
424
422
  # the same discipline `split_addition` already applies, so a
425
423
  # nested array or a comma inside a string element stays whole.
426
424
  def array_elements(expr)
@@ -455,9 +453,9 @@ module Hecks
455
453
  elements.reject(&:empty?)
456
454
  end
457
455
 
458
- # BRACES COUNT TOWARD DEPTH, exactly as parens do — a `+` inside a
456
+ # Braces count toward depth, exactly as parens do — a `+` inside a
459
457
  # block predicate's own `{ |x| ... }` body is not this expression's
460
- # own addition. `parse` tries addition BEFORE `parse_block_opener`,
458
+ # own addition. `parse` tries addition before `parse_block_opener`,
461
459
  # so a paren-only depth count split
462
460
  # kings.any? { |k| k.square.file == to.file + 1 && ... }
463
461
  # at that inner `+`, turning the whole expression into a nonsense
@@ -483,7 +481,7 @@ module Hecks
483
481
  # Phase 7 of the equivalence-gap plan): `ArrayLiteral` can
484
482
  # appear as a general sub-expression now, not only as
485
483
  # `.include?`'s own haystack, so an array element containing
486
- # its own top-level `+` (`[0, 0 + 0]`) used to read as THIS
484
+ # its own top-level `+` (`[0, 0 + 0]`) used to read as this
487
485
  # expression's own addition split point -- the whole
488
486
  # receiver before `.all?`/`.any?`/etc. torn in half before
489
487
  # `parse_block_opener` ever saw it as one atomic leaf.
@@ -629,48 +627,48 @@ module Hecks
629
627
  Evaluator.apply(node.operator, number, 0)
630
628
  end
631
629
 
632
- # FOUND LIVE via the type-directed bounded-exhaustive expression
630
+ # Found live via the type-directed bounded-exhaustive expression
633
631
  # generator (Phase 7, equivalence-gap plan — spec/
634
632
  # bounded_exhaustive_expression_spec.rb): `.modulo(`'s own
635
633
  # argument position accepts any numeric sub-expression, including
636
- # ANOTHER `.modulo(...)` call — `0.modulo(num_b.modulo(-1))` is
634
+ # another `.modulo(...)` call — `0.modulo(num_b.modulo(-1))` is
637
635
  # perfectly well-typed — but `expr.rindex(marker)` finds the
638
- # RIGHTMOST (innermost) `.modulo(` in the whole string, not the
639
- # OUTERMOST one a nested call needs split at. For that expression
640
- # it found the INNER `.modulo(` (inside `num_b.modulo(-1)`) and
636
+ # rightmost (innermost) `.modulo(` in the whole string, not the
637
+ # outermost one a nested call needs split at. For that expression
638
+ # it found the inner `.modulo(` (inside `num_b.modulo(-1)`) and
641
639
  # split there, producing a receiver of `"0.modulo(num_b"` and a
642
640
  # divisor of `"-1)"` — both garbage, both re-parsed as bogus
643
641
  # `Lookup` paths, both then refusing with "cannot resolve" — a
644
- # SILENT MISPARSE that happened to fail safe into a real
642
+ # silent misparse that happened to fail safe into a real
645
643
  # `EvaluationError` rather than a raw crash, which is exactly why
646
644
  # this had gone unnoticed: nothing before this generator existed
647
645
  # ever fed `.modulo` a nested `.modulo` call, random fuzzing
648
646
  # essentially never manufactures that specific shape by chance,
649
- # and the resulting refusal LOOKS like an ordinary, correct one
647
+ # and the resulting refusal looks like an ordinary, correct one
650
648
  # unless you already know every name this generator's own
651
649
  # synthetic state declares (real corpus authors would see this as
652
650
  # a mysterious "cannot resolve" on text they never wrote).
653
651
  #
654
652
  # Fixed the same way `split_addition`/`Evaluator.top_level_index`
655
653
  # already handle nested `(`/`{` elsewhere in this exact file:
656
- # find the FIRST (leftmost, outermost) occurrence of the marker,
657
- # then track paren/quote depth from there to find ITS OWN
654
+ # find the first (leftmost, outermost) occurrence of the marker,
655
+ # then track paren/quote depth from there to find its own
658
656
  # matching close — not just strip the string's own trailing `)`
659
657
  # and hope it belongs to this call.
660
- # Not just the FIRST occurrence, either — `.modulo` also CHAINS
661
- # (`x.modulo(a).modulo(b)`, the receiver of the OUTER call itself
658
+ # Not just the first occurrence, either — `.modulo` also chains
659
+ # (`x.modulo(a).modulo(b)`, the receiver of the outer call itself
662
660
  # ending in a `.modulo(...)` call), a second real shape the
663
661
  # leftmost-occurrence-only version of this fix still mis-parsed:
664
662
  # the first `.modulo(`'s own matching close paren lands mid-
665
663
  # string (right after `a)`, before the second `.modulo(b)`), so
666
664
  # it correctly fails the "reaches the end" check below and must
667
- # be tried again at the NEXT occurrence rather than giving up.
668
- # Trying occurrences strictly left to right and taking the FIRST
665
+ # be tried again at the next occurrence rather than giving up.
666
+ # Trying occurrences strictly left to right and taking the first
669
667
  # one whose matching close reaches the string's last character
670
- # handles both shapes with the same rule: for NESTING
668
+ # handles both shapes with the same rule: for nesting
671
669
  # (`.modulo(x.modulo(y))`), the leftmost (outer) occurrence's own
672
670
  # paren-depth tracking already walks straight through the inner
673
- # call to the true final `)`; for CHAINING, the leftmost
671
+ # call to the true final `)`; for chaining, the leftmost
674
672
  # occurrence's close lands short and is rejected, so the next
675
673
  # occurrence (the true outermost call) is tried instead.
676
674
  def match_call(expr, marker)
@@ -685,7 +683,7 @@ module Hecks
685
683
  end
686
684
 
687
685
  # `matching_brace` (resolver/block_predicates.rb)'s own twin, one
688
- # bracket pair over: `start` is the index just past the OPENING
686
+ # bracket pair over: `start` is the index just past the opening
689
687
  # `(` already consumed by the caller (depth starts at 1, not 0,
690
688
  # for the same reason).
691
689
  def matching_paren(expr, start)
@@ -709,12 +707,12 @@ module Hecks
709
707
  nil
710
708
  end
711
709
 
712
- # Both operands are coerced to a real Integer/Float BEFORE the
713
- # zero-check, and the check reads the COERCED divisor — not the
710
+ # Both operands are coerced to a real Integer/Float before the
711
+ # zero-check, and the check reads the coerced divisor — not the
714
712
  # raw `divisor_value` (which might not even respond to `.zero?`,
715
713
  # a String for instance) and not a `.to_i`-truncated stand-in for
716
714
  # it either. The old order checked a truncated `divisor.to_i`
717
- # AFTER already validating the untruncated value wasn't zero, so
715
+ # after already validating the untruncated value wasn't zero, so
718
716
  # a divisor merely small (`0.3`, truncating to `0`) sailed past
719
717
  # the guard and then blew up `Integer#%` with a raw
720
718
  # `ZeroDivisionError` the moment it reached zero anyway.
@@ -785,7 +783,7 @@ module Hecks
785
783
  # from_identifier`/`Value::Coercion#fields_for`'s own single-
786
784
  # field auto-unwrap already treats as "this VO IS its scalar"
787
785
  # everywhere else in this runtime) came back as the `Value`
788
- # wrapper itself, never unwrapped for READING -- so `Value#==`
786
+ # wrapper itself, never unwrapped for reading -- so `Value#==`
789
787
  # (which only ever equals another `Value` instance) silently
790
788
  # refused every `guarantees "..." do status == "active" end` /
791
789
  # `expects "..." do trash_day.present? end`-shaped bare
@@ -797,12 +795,12 @@ module Hecks
797
795
  # predicate. Scoped narrowly to the single-field `{value: X}`
798
796
  # shape only.
799
797
  #
800
- # UPDATE 2026-08-18: originally scoped to unwrap ONLY the bare
798
+ # Update 2026-08-18: originally scoped to unwrap only the bare
801
799
  # (undotted) case, on the belief that a dotted lookup only ever
802
- # reaches into a VO's OWN field (`field.value`, `field.sub_
800
+ # reaches into a VO's own field (`field.value`, `field.sub_
803
801
  # field`) and so should keep walking `#[]` untouched. That
804
802
  # belief held for the single-hop case but not for the general
805
- # one: a dotted lookup that NAVIGATES THROUGH an entity/list
803
+ # one: a dotted lookup that navigates through an entity/list
806
804
  # element to a nested field (`leg.voyage`, where `voyage` is
807
805
  # itself a single-field VO) landed on the very same unwrapped-
808
806
  # `Value` shape the bare case fixed, and hit the identical
@@ -810,26 +808,26 @@ module Hecks
810
808
  # literal or another unwrapped VO returned false for everything,
811
809
  # no error. The terminal value of a dotted walk deserves the
812
810
  # same "this VO IS its scalar" treatment as a bare lookup's
813
- # result; only the INTERMEDIATE hops need raw `#[]` addressing
811
+ # result; only the intermediate hops need raw `#[]` addressing
814
812
  # to keep navigating. `unwrap_scalar` is idempotent on an
815
813
  # already-raw scalar (a String/Integer doesn't respond to
816
814
  # `#to_h`), so this is safe for the existing `field.value`-
817
815
  # shaped dotted lookups too -- they already returned a raw
818
816
  # scalar and are unaffected.
819
- # UPDATE (single-element value objects strictly answer `.value`):
820
- # the unwrap used to gate on the sole key being literally NAMED
817
+ # Update (single-element value objects strictly answer `.value`):
818
+ # the unwrap used to gate on the sole key being literally named
821
819
  # `:value` — correct for the shorthand/closed-set shapes that
822
820
  # motivated it, but a lie of omission for `Money{amount}` and
823
821
  # every other single-field value object whose author picked a
824
- # domain name for the field: the SAME "this VO IS its scalar"
822
+ # domain name for the field: the same "this VO IS its scalar"
825
823
  # reading ([[feedback_name_the_scalar_field]], `Behaviour::
826
824
  # ValueObject#sole_attribute`) applies regardless of what the
827
825
  # sole field happens to be called, and the name gate made a bare
828
826
  # `balance > 0` work for a `Balance{value}` while silently
829
- # comparing a whole VO for a `Balance{amount}`. Now the COUNT is
827
+ # comparing a whole VO for a `Balance{amount}`. Now the count is
830
828
  # the gate, never the name. A declared `Runtime::Value` reads
831
829
  # its own `sole_attribute` (the declaration's answer, not the
832
- # stored hash's); any OTHER to_h-able (a Struct, a bespoke
830
+ # stored hash's); any other to_h-able (a Struct, a bespoke
833
831
  # wrapper with no declaration to consult) keeps the original
834
832
  # `{value: X}`-only unwrap, so nothing that never was a value
835
833
  # object gains a surprise unwrapping. `rust/src/kernel/json.rs`'s
@@ -48,7 +48,7 @@ module Hecks
48
48
 
49
49
  # The built form of a `.world` file, produced by `DSL::WorldBuilder` —
50
50
  # a domain's own `realm`/`latest` version markers and its adapter bind
51
- # SETTINGS (as opposed to `Hecksagon`'s own bind LIST, above).
51
+ # settings (as opposed to `Hecksagon`'s own bind list, above).
52
52
  # `Behaviour::World` supplies the settings lookups (`for_verb`/
53
53
  # `for_binding`); this class holds only the declared data.
54
54
  class World
@@ -3,7 +3,7 @@ require_relative "behaviour/lifecycle"
3
3
  module Hecks
4
4
  module Bluebook
5
5
  # One declared `transition` row — the state a command moves an
6
- # aggregate or entity TO, and, when guarded, the state(s) it must
6
+ # aggregate or entity to, and, when guarded, the state(s) it must
7
7
  # currently be in (`from:`) for the transition to apply. An unguarded
8
8
  # transition (`from: nil`) applies from any current state.
9
9
  class StateTransition
@@ -34,7 +34,7 @@ module Hecks
34
34
  end
35
35
 
36
36
  def send_to(verb, label, **payload)
37
- offer(label) { @runtime.dispatch(verb, **args(payload)) }
37
+ offer(label) { @runtime.dispatch_flat(verb, args(payload)) }
38
38
  end
39
39
 
40
40
  def judge!