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
@@ -19,7 +19,7 @@ module Hecks
19
19
  include Interpreting
20
20
  include CommandInterpreter::ArgumentGate
21
21
 
22
- Context = Struct.new(:domain, :aggregate, :operation, :args, :route, :instance, :result)
22
+ Context = Struct.new(:domain, :aggregate, :operation, :args, :route, :instance, :result, :invocation)
23
23
 
24
24
  DISPATCH_ORDER = %i[
25
25
  refuse_unknown_arguments refuse_absent_arguments normalize_args resolve_references resolve_route emit
@@ -30,9 +30,12 @@ module Hecks
30
30
  @rules = rules
31
31
  end
32
32
 
33
- def call(domain, aggregate, operation, args, route:)
34
- ctx = Context.new(domain, aggregate, operation, args)
35
- ctx.route = route
33
+ # `invocation` the `Runtime::Invocation` `Dispatcher` built;
34
+ # `ctx.args` is its `to_args`, `ctx.route` its `target`.
35
+ def call(domain, aggregate, operation, invocation)
36
+ ctx = Context.new(domain, aggregate, operation, invocation.to_args)
37
+ ctx.invocation = invocation
38
+ ctx.route = invocation.target
36
39
  run_dispatch_order(DISPATCH_ORDER, ctx)
37
40
  ctx.result
38
41
  end
@@ -66,13 +69,13 @@ module Hecks
66
69
  ctx.result = step(:emit) { ctx.operation.outbound? ? ask(ctx) : emit(ctx) }
67
70
  end
68
71
 
69
- # THE DOMAIN CALLING OUT, AND BOTH ENDINGS RECORDED.
72
+ # The domain calling out, and both endings recorded.
70
73
  #
71
74
  # The adapter is found the same way every other port's is — by name,
72
75
  # across whatever adapters this boot loaded — so an `asks` is bound by
73
76
  # an adapter declaring `port "IssueTracker"` and nothing new to learn.
74
77
  #
75
- # EVERY FAILURE IS AN ANSWER. A raise from the far side of a boundary is
78
+ # Every failure is an answer. A raise from the far side of a boundary is
76
79
  # not an exception in this domain's terms, it is the outside saying no,
77
80
  # and the chapter already named the word for that. So the rescue is
78
81
  # deliberately wide: a timeout, a bad credential, an adapter that does
@@ -80,22 +83,22 @@ module Hecks
80
83
  # `refuses` event, carrying what was said. A policy reacts to it, a
81
84
  # retry counter reads it, and nothing has to catch anything.
82
85
  #
83
- # AN ASK IS HANDED THE RECORD IT IS ABOUT.
86
+ # An ask is handed the record it is about.
84
87
  #
85
- # An INBOUND operation deliberately cannot read state — it is the
88
+ # An inbound operation deliberately cannot read state — it is the
86
89
  # anti-corruption boundary, translating a fact from outside, and letting
87
90
  # it read the aggregate would make it a second place rules live. That
88
91
  # rule was written for that direction and does not survive the crossing.
89
92
  #
90
93
  # An outbound one almost always needs the record. `asks "File"` names
91
94
  # `reference_to Ticket` and the adapter needs the ticket's repository,
92
- # title and body — which are ON the ticket, and which the policy that
95
+ # title and body — which are on the ticket, and which the policy that
93
96
  # triggered this cannot supply because a command's event payload is its
94
- # ARGUMENTS, not its state. Without this, every ask would have to have
97
+ # arguments, not its state. Without this, every ask would have to have
95
98
  # its data re-passed through the command that fired it, so the same text
96
99
  # would live in two places and could differ.
97
100
  #
98
- # ARGUMENTS WIN over state, because an argument is what THIS call said
101
+ # Arguments win over state, because an argument is what this call said
99
102
  # and state is what the record happens to hold.
100
103
  def ask(ctx)
101
104
  payload = held_state(ctx).merge(materialise(ctx.args))
@@ -105,13 +108,13 @@ module Hecks
105
108
  announce(ctx, ctx.operation.refuses, ctx.args.merge(refusal: { value: "#{e.class}: #{e.message}" }))
106
109
  end
107
110
 
108
- # THE ANSWER IS SPREAD, NOT NESTED — and that is what makes the loop
109
- # close. A policy re-enters its target with the event payload VERBATIM;
111
+ # The answer is spread, not nested — and that is what makes the loop
112
+ # close. A policy re-enters its target with the event payload verbatim;
110
113
  # it cannot reach inside a key. So an answer tucked under `answered:`
111
114
  # can be read by a human and by nothing else, and the command that
112
115
  # should record the issue number never gets one.
113
116
  #
114
- # Spread, the adapter's own keys ARE the arguments of whatever command
117
+ # Spread, the adapter's own keys are the arguments of whatever command
115
118
  # reacts to the answering event. Which is a real contract on the adapter
116
119
  # — it must return what that command takes, in the shape the runtime
117
120
  # coerces (`{ number: { value: 43 } }`, not `43`) — and naming it here
@@ -134,7 +137,7 @@ module Hecks
134
137
  end
135
138
  end
136
139
 
137
- # THE RECORD, IF THERE IS ONE. A record that does not exist yet is not
140
+ # The record, if there is one. A record that does not exist yet is not
138
141
  # an error here — the ask still goes, carrying only its arguments, and
139
142
  # whatever the adapter makes of that is its own business. Refusing
140
143
  # would put a second existence check behind the one `resolve_references`
@@ -145,10 +148,10 @@ module Hecks
145
148
  {}
146
149
  end
147
150
 
148
- # THE PORT THIS OPERATION BELONGS TO, found by asking the aggregate
151
+ # The port this operation belongs to, found by asking the aggregate
149
152
  # rather than threading it through the call — the dispatcher already
150
153
  # resolved it once to get here, and a second parameter carried purely so
151
- # this method can read it would be a parameter every OTHER step ignores.
154
+ # this method can read it would be a parameter every other step ignores.
152
155
  def port_name_for(ctx)
153
156
  owning = ctx.aggregate.ports.find { |port| port.operations.any? { |op| op.equal?(ctx.operation) } }
154
157
  owning&.name or raise WiringError,
@@ -185,9 +188,9 @@ module Hecks
185
188
  [event]
186
189
  end
187
190
 
188
- # THE ONE PLACE THIS DIFFERS FROM CommandRules::Emission — there is no
191
+ # The one place this differs from CommandRules::Emission — there is no
189
192
  # mutated instance to read an id off, because nothing was hydrated or
190
- # saved. The record this event is ABOUT is named by whichever attribute
193
+ # saved. The record this event is about is named by whichever attribute
191
194
  # is a reference to the owning aggregate (PortOperationBuilder#build
192
195
  # already refused to build an operation with none), so its coerced
193
196
  # value — already a plain id, never an object, per
@@ -15,7 +15,7 @@ module Hecks
15
15
  # repository: prefers a native adapter hook (Ports::Query.execute)
16
16
  # when the store can answer directly, falling back to interpreting
17
17
  # wheres/order_by/limit/offset over every loaded record itself.
18
- # #reference_call/#reference_interpret are a SEPARATE, deliberately
18
+ # #reference_call/#reference_interpret are a separate, deliberately
19
19
  # naive re-implementation of the same evaluation, used only as the
20
20
  # fuzzer's oracle to catch divergence between adapters and this
21
21
  # interpreter's own native path.
@@ -32,10 +32,10 @@ module Hecks
32
32
  declared = declared_query(aggregate, query_name)
33
33
  args = normalize_args(aggregate, declared, args)
34
34
  declared = TenantScope.apply(declared, args)
35
- # AFTER TenantScope, so its synthetic clause is already present
36
- # in `.wheres` and rides through as an ordinary LOCAL clause on
37
- # the OUTER query. It does not reach the hop's own inner
38
- # sub-query against the TARGET aggregate — a hop's target may
35
+ # After TenantScope, so its synthetic clause is already present
36
+ # in `.wheres` and rides through as an ordinary local clause on
37
+ # the outer query. It does not reach the hop's own inner
38
+ # sub-query against the target aggregate — a hop's target may
39
39
  # not even declare the same tenant boundary, and propagating one
40
40
  # aggregate's tenant scope onto an unrelated aggregate's own
41
41
  # query is a real design question of its own, not answered here.
@@ -51,14 +51,14 @@ module Hecks
51
51
  if (native = Ports::Query.execute(repository, declared, args,
52
52
  context: { domain: domain, aggregate: aggregate, registry: @registry }))
53
53
  records = native
54
- # `record.state.merge(id: record.id)` — id LAST, not first. See
54
+ # `record.state.merge(id: record.id)` — id last, not first. See
55
55
  # Instance#to_h's own comment: an aggregate free to declare its
56
56
  # own attribute literally named `id` has that attribute's own
57
57
  # wrapped value sitting in `record.state[:id]` already; merging
58
- # it OVER a `{id:}.merge(state)` used to let it silently
58
+ # it over a `{id:}.merge(state)` used to let it silently
59
59
  # clobber the correct bare identity this row is supposed to
60
60
  # carry.
61
- # A QUERY ROW IS AN ANSWER, NOT A HANDLE. Mutating one edits
61
+ # A query row is an answer, not a handle. Mutating one edits
62
62
  # nobody's state and silently disagrees with the store.
63
63
  return Freezer.deep(records.map { |record| record.state.merge(id: record.id) })
64
64
  end
@@ -66,18 +66,18 @@ module Hecks
66
66
  Freezer.deep(interpret(repository.all, declared, args, domain: domain))
67
67
  end
68
68
 
69
- # The REFERENCE answer — this interpreter's own evaluation, never an
69
+ # The reference answer — this interpreter's own evaluation, never an
70
70
  # adapter's native hook. The fuzzer's query oracle replays every
71
71
  # generated ask through both paths and treats a difference as a
72
72
  # finding: the differential gate the retired cross-runtime harness
73
73
  # should always have been, aimed where the divergence actually
74
74
  # lives — between the engines inside this one runtime.
75
75
  #
76
- # A hop clause is answered here by its OWN, deliberately naive
76
+ # A hop clause is answered here by its own, deliberately naive
77
77
  # walk (reference_where_holds?) — never Runtime::ReferenceHop's
78
- # partition/fold/IN-clause. Sharing that algorithm would have made
78
+ # partition/fold/in-clause. Sharing that algorithm would have made
79
79
  # this oracle blind to exactly the code the hop feature adds: every
80
- # PHASE of a shared fold would still get diffed against the native
80
+ # phase of a shared fold would still get diffed against the native
81
81
  # adapters, but the fold itself — the empty candidate set, a
82
82
  # duplicate id, a dangling reference, a chain's inside-out
83
83
  # resolution order — would only ever be compared against itself.
@@ -95,14 +95,14 @@ module Hecks
95
95
 
96
96
  def declared_query(aggregate, query_name)
97
97
  aggregate.query(query_name) ||
98
- raise(UnknownVerb, RefusalWording.render("UnknownVerb", "no_query",
99
- aggregate: aggregate.hecks_name, query: query_name.inspect))
98
+ raise(UnknownVerb, RefusalWording.render_site("UnknownVerb", "no_query",
99
+ aggregate: aggregate.hecks_name, query: query_name))
100
100
  end
101
101
 
102
102
  def interpret(records, declared, args, domain: nil)
103
103
  matched = records.select { |r| declared.wheres.all? { |w| where_holds?(w, r, args, domain: domain) } }
104
104
  ordered = ordered(matched, declared.order_by, declared.null_semantics)
105
- # OFFSET FIRST, THEN LIMIT — the order SQL means by `LIMIT n
105
+ # **Offset first, then limit** — the order SQL means by `LIMIT n
106
106
  # OFFSET m`, and the order Ports::Query::InMemory#execute already
107
107
  # applies (see that file's own comment). This interpreter used to
108
108
  # never read declared.offset at all — offset silently vanished for
@@ -110,7 +110,7 @@ module Hecks
110
110
  skipped = declared.offset ? ordered.drop(resolve_query_value(declared.offset.value, args).to_i) : ordered
111
111
  capped = declared.limit ? skipped.first(resolve_query_value(declared.limit.value, args).to_i) : skipped
112
112
 
113
- # id LAST — see the native-path comment above; same clobbering
113
+ # id last — see the native-path comment above; same clobbering
114
114
  # risk for the in-memory reference interpreter's own rows.
115
115
  capped.map { |r| r.state.merge(id: r.id) }
116
116
  end
@@ -120,7 +120,7 @@ module Hecks
120
120
  # reference is answered by reference_where_holds? instead of the
121
121
  # plain FieldPath.dig(record, field) `where_holds?` uses (which
122
122
  # has no concept of a reference at all — it would just read the
123
- # raw id straight off the record and compare THAT).
123
+ # raw id straight off the record and compare that).
124
124
  def reference_interpret(records, declared, args, domain:, shape:)
125
125
  matched = records.select do |r|
126
126
  declared.wheres.all? do |w|
@@ -128,20 +128,20 @@ module Hecks
128
128
  end
129
129
  end
130
130
  ordered = ordered(matched, declared.order_by, declared.null_semantics)
131
- # OFFSET FIRST, THEN LIMIT — same fix, same reasoning, as
131
+ # **Offset first, then limit** — same fix, same reasoning, as
132
132
  # #interpret's own rows above.
133
133
  skipped = declared.offset ? ordered.drop(resolve_query_value(declared.offset.value, args).to_i) : ordered
134
134
  capped = declared.limit ? skipped.first(resolve_query_value(declared.limit.value, args).to_i) : skipped
135
135
 
136
- # id LAST — same reasoning, same fix, as interpret's own rows.
136
+ # id last — same reasoning, same fix, as interpret's own rows.
137
137
  capped.map { |r| r.state.merge(id: r.id) }
138
138
  end
139
139
 
140
- # THE NAIVE READING OF A HOP: not a fold, not an id set — for
140
+ # **The naive reading of a hop**: not a fold, not an id set — for
141
141
  # each candidate row, walk the reference by hand and dig the
142
142
  # field out of whatever it actually points at. A nil reference,
143
143
  # or one that resolves to nothing (a dangling id), makes the
144
- # WHOLE clause false outright, whatever the comparator — "points
144
+ # whole clause false outright, whatever the comparator — "points
145
145
  # at a client that is not active" is false for a proposal with no
146
146
  # client at all, the same way it is false for one whose client
147
147
  # really is active; falling through to holds?(clause, nil, args)
@@ -177,8 +177,8 @@ module Hecks
177
177
 
178
178
  ordered = ordered_elements(rows, declared.order_by, declared.null_semantics,
179
179
  parent_key, entity.identity_heads)
180
- # OFFSET FIRST, THEN LIMIT — same fix, same reasoning, as
181
- # #interpret's own rows above. `entity_rows` is the ONLY engine
180
+ # **Offset first, then limit** — same fix, same reasoning, as
181
+ # #interpret's own rows above. `entity_rows` is the only engine
182
182
  # for entity/sub-list queries, so a declared offset here silently
183
183
  # vanished for every entity query, not merely one path among
184
184
  # several.
@@ -186,31 +186,28 @@ module Hecks
186
186
  declared.limit ? skipped.first(resolve_query_value(declared.limit.value, args).to_i) : skipped
187
187
  end
188
188
 
189
- # THE THREE DECLARATIONS `entity_rows` NEEDS BEFORE IT CAN READ A
190
- # SINGLE RECORD — the entity itself, its declared query, and the
189
+ # The three declarations `entity_rows` needs before it can read a
190
+ # single record — the entity itself, its declared query, and the
191
191
  # list attribute that holds it on the aggregate. Extracted from
192
192
  # `entity_rows` (pure extraction, same lookups, same order, same
193
193
  # UnknownVerb refusals) purely to separate "which declarations does
194
194
  # this dotted name resolve to" from the row-computation that follows.
195
195
  def resolve_entity_query(aggregate, entity_name, query_name)
196
196
  entity = aggregate.entities.find { |piece| piece.hecks_name == entity_name } ||
197
- raise(UnknownVerb, RefusalWording.render("UnknownVerb", "entity_unknown",
198
- aggregate: aggregate.hecks_name, entity: entity_name.inspect))
197
+ raise(UnknownVerb, RefusalWording.render_site("UnknownVerb", "entity_unknown",
198
+ aggregate: aggregate.hecks_name, entity: entity_name))
199
199
  declared = entity.query(query_name) ||
200
- raise(UnknownVerb, RefusalWording.render("UnknownVerb", "entity_query_missing",
201
- entity: entity_name, query: query_name.inspect))
200
+ raise(UnknownVerb, RefusalWording.render_site("UnknownVerb", "entity_query_missing",
201
+ entity: entity_name, query: query_name))
202
202
  list_attr = aggregate.attributes.find { |a| a.list? && a.type.to_s == entity_name } ||
203
- raise(UnknownVerb, RefusalWording.render("UnknownVerb", "entity_holds_no_list",
204
- aggregate: aggregate.hecks_name, entity: entity_name))
203
+ raise(UnknownVerb, RefusalWording.render_site("UnknownVerb", "entity_holds_no_list",
204
+ aggregate: aggregate.hecks_name, entity: entity_name))
205
205
  [entity, declared, list_attr]
206
206
  end
207
207
 
208
- # FieldPath.dig, not a raw `element[clause.field.to_sym]` — an
209
- # entity sub-list row is a plain hash merged from stored state
210
- # (mixed string/symbol keys depending on adapter, per `#cell`'s own
211
- # comment below), and a dotted `where` (`where "price.cents" < 100`)
212
- # needs the same segment-by-segment walk every other query path
213
- # already gets. Reading only the symbol spelling of the WHOLE
208
+ # FieldPath.dig, not a raw `element[clause.field.to_sym]` — a dotted
209
+ # `where` (`where "price.cents" < 100`) needs the same segment-by-
210
+ # segment walk every other query path already gets. Reading the whole
214
211
  # dotted string as one key always missed — `element[:"price.cents"]`
215
212
  # is never a real key — so a dotted where on an entity query
216
213
  # silently matched nothing, on the only engine entity queries have.
@@ -218,28 +215,22 @@ module Hecks
218
215
  holds?(clause, QuerySpecification::FieldPath.dig(element, clause.field), args)
219
216
  end
220
217
 
221
- # A row's own key, however the store spells it. A sub-list row is a plain hash
222
- # merged from stored state, so its keys arrive as strings from one adapter and
223
- # symbols from anotherand reading only one spelling gave every row the SAME
224
- # identity, which is a tie, which is the exact nondeterminism this tier exists
225
- # to remove. It rides `comparable` for the same reason a where-clause does : an
226
- # identity is a value object, and `to_s` on one is an OBJECT ADDRESS — a sort key
218
+ # A row's own key. A sub-list row is a hydrated entity element (symbol-keyed
219
+ # since every adapter decodes through `Ports::Persistence::StateCodec` and
220
+ # `EntityListCoercion#hydrate_entity_list` symbolizes each element PR A4
221
+ # removed the string-spelling fallback that coped with the old per-adapter
222
+ # shapes). It rides `comparable` for the same reason a where-clause does : an
223
+ # identity is a value object, and `to_s` on one is an object address — a sort key
227
224
  # that differs run to run, which is worse than the store order it replaced.
228
- # `key?` decides which spelling answers, never `||` — a row whose
229
- # value is a genuinely-held `false` must not fall through to the
230
- # other spelling (usually absent) and land on `nil`.
231
- def cell(row, key)
232
- sym = key.to_sym
233
- row.key?(sym) ? row[sym] : row[key.to_s]
234
- end
225
+ def cell(row, key) = row[key.to_sym]
235
226
 
236
- # A sub-list row is identified by its PARENT and then its own key : two
227
+ # A sub-list row is identified by its parent and then its own key : two
237
228
  # entities under different parents can share a sequence, so the parent has
238
229
  # to lead or the tie is not broken at all.
239
230
  #
240
- # EVERY KEY THE PIECE IS KNOWN BY, in declaration order, for the same
231
+ # Every key the piece is known by, in declaration order, for the same
241
232
  # reason the parent leads: a part that ties is a part that breaks no tie.
242
- # This took `identified_by`, which is the SINGLE head and is nil the
233
+ # This took `identified_by`, which is the single head and is nil the
243
234
  # moment an identity has two parts — and `cell(row, nil)` calls
244
235
  # `nil.to_sym`, so a query against a composite piece did not sort wrongly,
245
236
  # it raised. A piece known by one key sorts exactly as it did.
@@ -262,7 +253,7 @@ module Hecks
262
253
  # Ports::Query::InMemory#holds? used to carry a copy each and the
263
254
  # two drifted — `none_in_state` reached only one of them, and
264
255
  # `comparable` disagreed about value objects with two numeric
265
- # members. What stays here is how a value is REACHED for this
256
+ # members. What stays here is how a value is reached for this
266
257
  # path: the registry is instance state rather than an argument.
267
258
  def holds?(clause, held, args, record: nil, domain: nil)
268
259
  QuerySpecification::Common::Comparison.holds?(
@@ -276,8 +267,8 @@ module Hecks
276
267
 
277
268
  # `boundary: false` always (C3.8 — a query's declared argument types
278
269
  # name the argument for callers and generators, never a runtime
279
- # shape checked here). A null required VALUE-OBJECT-typed query
280
- # argument, though, is NOT a runtime-shape question at all: C3.7
270
+ # shape checked here). A null required value-object-typed query
271
+ # argument, though, is not a runtime-shape question at all: C3.7
281
272
  # says a named query's declared value-object arguments are checked
282
273
  # the same way a command argument's own is, so a `nil` offered for
283
274
  # a non-optional value-object-typed query attribute
@@ -286,30 +277,30 @@ module Hecks
286
277
  # let it through as a silent, unfiltered query instead, a real
287
278
  # Ruby/Rust divergence the fuzzer caught (QualityControl BUG#2).
288
279
  #
289
- # `checked_vo?` true is handled by `null_vo_argument!` DIRECTLY,
280
+ # `checked_vo?` true is handled by `null_vo_argument!` directly,
290
281
  # never by routing through `Value.for_attribute(argument: true)`
291
- # into the shared `Value::Coercion#nil_argument` the COMMAND door
282
+ # into the shared `Value::Coercion#nil_argument` the command door
292
283
  # (`Interpreting#coerce_declared_arguments`) still uses — that
293
- # method builds a null value object from ZERO fields, which
294
- # SUCCEEDS (silently absorbing the null via the type's own field
284
+ # method builds a null value object from zero fields, which
285
+ # succeeds (silently absorbing the null via the type's own field
295
286
  # defaults) whenever every field happens to have one
296
287
  # (`Lease.Expired`'s `now`, a `LeaseInstant` with a `default: 0`
297
288
  # field; `Account.Overdrawn`/`HighBalance`/`StrictlyAbove`/
298
289
  # `AtMost`'s `floor`/`cap`, a two-defaulted-field `Money`) and only
299
290
  # refuses when a field has none (`Order.CostingLessThan`'s
300
- # `ceiling`, a defaultless `Price`) — a real QUERY-side divergence
291
+ # `ceiling`, a defaultless `Price`) — a real query-side divergence
301
292
  # from Rust, which always refuses `TypeMismatch` on an explicit
302
293
  # null argument regardless of any default (QualityControl BUG#36).
303
294
  # `null_vo_argument!` instead treats an explicit null exactly the
304
- # way `Value.fields_for` already treats any other WRONG-SHAPED
295
+ # way `Value.fields_for` already treats any other wrong-shaped
305
296
  # (non-Hash, non-Value) value offered for that same attribute — a
306
297
  # single-field value object auto-wraps into `{field: nil}` (whose
307
- # OWN `nil` is a PRESENT key, so `Value.build`'s `apply_defaults`
298
+ # own `nil` is a present key, so `Value.build`'s `apply_defaults`
308
299
  # never fills it, and `check_required_fields` refuses it exactly
309
300
  # as any other missing required field would); a multi-field value
310
301
  # object refuses immediately with the same `value_object_shape`
311
302
  # wording an ordinary wrong-shaped scalar already gets. Command
312
- # arguments are deliberately UNTOUCHED — this is a query-only
303
+ # arguments are deliberately untouched — this is a query-only
313
304
  # door; `nil_argument`'s own default-absorbing fallback still
314
305
  # governs a null command argument exactly as it always has.
315
306
  #
@@ -49,7 +49,7 @@ module Hecks
49
49
  end
50
50
  end
51
51
 
52
- # ONE `with:` SOURCE, RESOLVED — pulled out of resolve_mapping
52
+ # One `with:` source, resolved — pulled out of resolve_mapping
53
53
  # because it is a pure function of its own arguments (a literal, a
54
54
  # binding, or a name visible in some scope), with no dependency on
55
55
  # anything else resolve_mapping's own to_h block is doing.
@@ -60,10 +60,10 @@ module Hecks
60
60
  visible = scopes.find { |scope| scope.facts.key?(source) }
61
61
  unless visible
62
62
  names = scopes.map(&:name).join(" then ")
63
- # WHAT IS VISIBLE, NAMED. A refusal that only says which name is
63
+ # **What is visible, named**. A refusal that only says which name is
64
64
  # missing sent a modeler guessing field after field
65
65
  # (`number`, `reference`…) at a fan-out row that is addressed
66
- # by ONE key — `account`, the lowercase aggregate — which
66
+ # by one key — `account`, the lowercase aggregate — which
67
67
  # nothing else in the domain spells out. The names each scope
68
68
  # actually offers are the whole diagnosis; the refusal now
69
69
  # lists them, scope by scope.
@@ -80,10 +80,10 @@ module Hecks
80
80
  # command attributes enter `with:`, while identities become `to:`.
81
81
  # `consumed` accumulates across the aggregate-identity and entity-
82
82
  # identity steps below, and refuse_unconsumed! at the end reads the
83
- # FINAL list — an ordering dependency threaded through one shared
83
+ # final list — an ordering dependency threaded through one shared
84
84
  # local. Already leans on private helpers (identity_for,
85
85
  # source_receiver_for, command_facts, refuse_unconsumed!) for every
86
- # piece that IS self-contained; what remains is the sequencing
86
+ # piece that is self-contained; what remains is the sequencing
87
87
  # itself, which further splitting would only relocate, not remove.
88
88
  # rubocop:disable-next Metrics/MethodLength, Metrics/PerceivedComplexity
89
89
  def build(registry:, verb:, projected:, explicit:, passthrough: [], source_receiver: nil)
@@ -99,7 +99,7 @@ module Hecks
99
99
  rescue UnknownVerb
100
100
  return args
101
101
  end
102
- # AN ENTITY TARGET HAS NO SHAPE THIS BRANCH CAN BUILD — an
102
+ # An entity target has no shape this branch can build — an
103
103
  # implicit (unprojected) `to:` is always a bare scalar, the
104
104
  # aggregate's own identity alone; an entity command's receiver is
105
105
  # `{aggregate:, entities:}`, which needs the entity's own
@@ -167,13 +167,13 @@ module Hecks
167
167
 
168
168
  *entity_names, command_name = command_path.split(".")
169
169
 
170
- # A PORT OPERATION, reached by the SAME two-segment tail shape an
171
- # entity command uses ("Head.Rest") — checked FIRST, same order
170
+ # A port operation, reached by the same two-segment tail shape an
171
+ # entity command uses ("Head.Rest") — checked first, same order
172
172
  # `Dispatcher#dispatch` already resolves a live verb in (an
173
173
  # aggregate that declared both a port and an entity of the same
174
174
  # name would resolve to the port there too; no domain in this
175
175
  # corpus does). A port has no `entities` of its own — the
176
- # RECEIVER is always the aggregate itself — so `Target#entities`
176
+ # receiver is always the aggregate itself — so `Target#entities`
177
177
  # stays empty and `#command` holds the `PortOperation`, which
178
178
  # answers `#creates?` (always false) the same way an ordinary
179
179
  # `Command` does, letting `source_receiver_for` lift a same-
@@ -215,37 +215,37 @@ module Hecks
215
215
  private_class_method :aggregate_aliases
216
216
 
217
217
  # Event.id names the aggregate that emitted the event. It can therefore
218
- # supply only the receiver of a non-creating command on that SAME root;
218
+ # supply only the receiver of a non-creating command on that same root;
219
219
  # it cannot address another aggregate, invent an entity identity, or turn
220
220
  # a creation into a mutation. An explicit projected receiver is resolved
221
221
  # first and remains authoritative.
222
222
  #
223
- # ANSWERS REGARDLESS OF `target.entities` — the value this method hands
224
- # back is ONLY EVER the ROOT AGGREGATE'S OWN identity (`source_receiver`
223
+ # Answers regardless of `target.entities` — the value this method hands
224
+ # back is only ever the root aggregate's own identity (`source_receiver`
225
225
  # carries nothing else: `event.aggregate`/`event.id` name the emitting
226
- # AGGREGATE, never one of its entities). An entity target's own identity
226
+ # aggregate, never one of its entities). An entity target's own identity
227
227
  # is resolved entirely separately, from `args` (`build`'s own `entity_
228
228
  # identities` loop) — this method is never consulted for it, so
229
229
  # answering for an entity target does not "invent an entity identity"
230
- # any more than answering for a plain one invents THAT identity; it was
230
+ # any more than answering for a plain one invents that identity; it was
231
231
  # already the one thing this method has ever supplied. `build`'s own
232
- # EXPLICIT branch (below) already applies this correctly either way
232
+ # explicit branch (below) already applies this correctly either way
233
233
  # (`aggregate_identity ||= inherited_receiver`, entity identities read
234
234
  # from `args` regardless) — the caller that actually needed a guard
235
- # here is the IMPLICIT one, above, which has no shape to build a
235
+ # here is the implicit one, above, which has no shape to build a
236
236
  # `{aggregate:, entities:}` receiver from an inherited scalar alone,
237
237
  # and now guards itself for exactly that reason instead of this method
238
238
  # doing it on that caller's behalf and, as a side effect, also refusing
239
- # the EXPLICIT caller's own legitimate case — confirmed missing until
239
+ # the explicit caller's own legitimate case — confirmed missing until
240
240
  # `qa/stress_domains/waybill` (BUG#6) exercised it for the first time
241
241
  # anywhere in the corpus: a saga dispatching into a nested entity's own
242
242
  # command, inheriting its aggregate receiver from the event that
243
243
  # triggered it.
244
244
  def source_receiver_for(target, source_receiver)
245
245
  return nil unless source_receiver
246
- # `target.command.creates?` ALONE MISREADS EVERY ENTITY COMMAND
246
+ # `target.command.creates?` alone misreads every entity command
247
247
  # `Behaviour::Command#creates?`'s own comment: "a verb declared on
248
- # an ENTITY always acts on that piece... which means `creates?`
248
+ # an entity always acts on that piece... which means `creates?`
249
249
  # answers true for every one of them" (it never sets `@references`
250
250
  # the way an aggregate-level command's own `reference_to` does,
251
251
  # not because it brings anything new into being). `build`'s own
@@ -253,7 +253,7 @@ module Hecks
253
253
  # 20-odd lines below, already reads `creates?` correctly for
254
254
  # exactly this reason — an entity command is never a genuine
255
255
  # creation, whatever `creates?` alone answers — so this checks the
256
- # SAME compound condition instead of the bare, misleading half of
256
+ # same compound condition instead of the bare, misleading half of
257
257
  # it. Left unfixed, an entity target's own receiver was refused
258
258
  # here even after this method stopped refusing on `target.entities`
259
259
  # alone — the second half of BUG#6's own fix.