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
@@ -11,7 +11,7 @@ module Hecks
11
11
  # Whether a command may run at all: its declared givens, and the
12
12
  # lifecycle transition it asks for.
13
13
  module Admissibility
14
- # WRAPS `subject` so a guard can read a DECLARED-but-storage-absent
14
+ # Wraps `subject` so a guard can read a declared-but-storage-absent
15
15
  # optional attribute as nil, not "cannot resolve." `Instance
16
16
  # #hydrate_with_defaults` deliberately leaves one absent rather
17
17
  # than nil-filled — "an attribute with no default stays absent,
@@ -25,10 +25,10 @@ module Hecks
25
25
  # exact behavior, zero risk to a path this bug was never measured
26
26
  # against.
27
27
  #
28
- # NIL IS NOT THE ONLY OUTCOME, though. The Item.Promote fix above
29
- # covered an OPTIONAL field — the honest case, where absence is
28
+ # NIL is not the only outcome, though. The Item.Promote fix above
29
+ # covered an optional field — the honest case, where absence is
30
30
  # exactly what optional means. It also, as a side effect, let a
31
- # NON-optional field predating a record read nil the same way,
31
+ # non-optional field predating a record read nil the same way,
32
32
  # which is the `ne:`/array-`in:` bug class applied to rule
33
33
  # evaluation: a predicate silently answers against a value nobody
34
34
  # ever wrote (ADR 0025, "Added attributes and absence"). `[]`
@@ -40,14 +40,14 @@ module Hecks
40
40
  def initialize(instance)
41
41
  @instance = instance
42
42
  @declared = instance.respond_to?(:aggregate) ? instance.aggregate.attributes.to_h { |a| [a.name, a] } : {}
43
- # S12, ADR 0025 — a SEPARATE index, the same reason
43
+ # S12, ADR 0025 — a separate index, the same reason
44
44
  # `Aggregate#projected_fields` is a separate IR collection
45
45
  # rather than folded into `attributes` (see that field's
46
46
  # own comment): a projected field's absence means
47
47
  # something different from an ordinary attribute's, so it
48
48
  # needs its own refusal below, not `AttributeAbsent`'s.
49
- # `projects` is AGGREGATE-scoped only — an entity's own
50
- # `instance.aggregate` answers the ENTITY construct here
49
+ # `projects` is aggregate-scoped only — an entity's own
50
+ # `instance.aggregate` answers the entity construct here
51
51
  # (EntityInterpreter's own subject), which declares no
52
52
  # `projected_fields` of its own, hence the extra guard
53
53
  # `@declared` above does not need.
@@ -67,17 +67,17 @@ module Hecks
67
67
  return nil if attribute.nil? || attribute.optional?
68
68
 
69
69
  raise AttributeAbsent,
70
- RefusalWording.render("AttributeAbsent", "absent_read",
71
- aggregate: @instance.aggregate.hecks_name, field: name)
70
+ RefusalWording.render_site("AttributeAbsent", "absent_read",
71
+ aggregate: @instance.aggregate.hecks_name, field: name)
72
72
  end
73
73
 
74
74
  private
75
75
 
76
76
  def raise_projection_absent(projected)
77
77
  raise ProjectionAbsent,
78
- RefusalWording.render("ProjectionAbsent", "absent_read",
79
- aggregate: @instance.aggregate.hecks_name, field: projected.name,
80
- reference: projected.reference, remote_field: projected.remote_field)
78
+ RefusalWording.render_site("ProjectionAbsent", "absent_read",
79
+ aggregate: @instance.aggregate.hecks_name, field: projected.name,
80
+ reference: projected.reference, remote_field: projected.remote_field)
81
81
  end
82
82
  end
83
83
  private_constant :GuardState
@@ -89,54 +89,54 @@ module Hecks
89
89
  # `Instance`); a `subject` with no `.aggregate` just hydrates
90
90
  # nothing from state, same as GuardState degrades above.
91
91
  #
92
- # MERGE ORDER MATTERS, and it is NOT "args always win": an
92
+ # Merge order matters, and it is not "args always win": an
93
93
  # unaliased command-level reference dereferences under a
94
94
  # different name than the argument holds (`account_id` the arg,
95
95
  # `account` the hydrated key — no collision, order is moot). An
96
- # ALIASED one (`reference_to Customer, as: :customer`) hydrates
97
- # under the SAME name the argument itself holds — `customer` is
96
+ # aliased one (`reference_to Customer, as: :customer`) hydrates
97
+ # under the same name the argument itself holds — `customer` is
98
98
  # both the raw id an arg puts there and the key `customer.status`
99
99
  # expects to dig into. If `args` merged last, the raw id (a
100
100
  # String) would win and `.status` on a String is where a fuzzer
101
101
  # found this — TypeError, not a refusal. Command-level
102
- # dereferencing is the one thing that is SUPPOSED to override
102
+ # dereferencing is the one thing that is supposed to override
103
103
  # its own source argument for exactly this reason; args still
104
- # wins over stored OWNER state (unchanged from before this fix).
105
- # `parent:` is an entity command's OWN parent aggregate record
106
- # (EntityInterpreter's `ctx.instance` — "the PARENT aggregate
104
+ # wins over stored owner state (unchanged from before this fix).
105
+ # `parent:` is an entity command's own parent aggregate record
106
+ # (EntityInterpreter's `ctx.instance` — "the parent aggregate
107
107
  # record", its own doc comment) — the entity's containment, not a
108
108
  # declared reference attribute, so it doesn't come from
109
109
  # `dereference`'s attribute scan the way `owner`'s do. Hydrated
110
- # the same shape regardless: the parent's own state, MERGED so
110
+ # the same shape regardless: the parent's own state, merged so
111
111
  # the dereferenced hash wins over the raw reference it replaces
112
112
  # (ADR 0025 dropped the `_id` suffix that used to keep the two
113
113
  # apart by name, so `parent.state.merge(dereference(...))` is
114
- # now load-bearing, not redundant) — plus ITS OWN references
114
+ # now load-bearing, not redundant) — plus its own references
115
115
  # dereferenced one level in, so `parent.customer.status` (a
116
- # parent aggregate reaching ITS OWN customer) resolves the same
116
+ # parent aggregate reaching its own customer) resolves the same
117
117
  # way `account.customer.status` does for a command-level reference.
118
118
  # nil for an aggregate command — CommandInterpreter never passes it.
119
119
  # `correction:` — the `{as_name => payload}` bindings
120
120
  # `enforce_correction_target` (above) already located, merged in
121
- # LAST so an `as:` name wins the same way `old:` always wins in
121
+ # last so an `as:` name wins the same way `old:` always wins in
122
122
  # `enforce_ensures`, below — it is a fresh local binding a
123
123
  # `corrects` command introduces, not a real argument/state field
124
124
  # a caller could collide with by accident.
125
125
  def enforce_givens(subject, command, args, domain:, declaring: nil, parent: nil, correction: {})
126
126
  state = GuardState.new(subject)
127
- # A RULE MAY ONLY READ WITHIN ITS OWN AGGREGATE BOUNDARY (S12,
128
- # ADR 0025) — `subject`'s own STORED references are no longer
127
+ # A rule may only read within its own aggregate boundary (S12,
128
+ # ADR 0025) — `subject`'s own stored references are no longer
129
129
  # dereferenced here at all. What used to be a live query against
130
130
  # another aggregate's own repository is now just `subject`'s own
131
131
  # state: a `projects :customer_status, from: :"customer.status"`
132
- # field is a REGULAR stored attribute, already present in
132
+ # field is a regular stored attribute, already present in
133
133
  # `subject`/`state` with no hydration step needed. `dereference`
134
134
  # is still called on `command`/`args`, below — that is a
135
- # DIFFERENT case the ADR explicitly keeps in bounds ("its command
136
- # arguments"): a reference-typed ARGUMENT this dispatch was just
135
+ # different case the ADR explicitly keeps in bounds ("its command
136
+ # arguments"): a reference-typed argument this dispatch was just
137
137
  # handed (`Dispute`'s own `disputed_by`, say) has nothing stored
138
138
  # to project yet, so resolving it here, once, synchronously with
139
- # THIS command's own admission, is not the live-query-against-
139
+ # this command's own admission, is not the live-query-against-
140
140
  # another-aggregate's-stored-state pattern the boundary rule
141
141
  # forbids.
142
142
  attrs = args.merge(dereference(domain, command, args))
@@ -154,26 +154,26 @@ module Hecks
154
154
  enforce_lifecycle_guard(declaring, command, subject) if declaring
155
155
  end
156
156
 
157
- # `corrects` — CommandBuilder#corrects_impl's own comment. NOT
157
+ # `corrects` — CommandBuilder#corrects_impl's own comment. Not
158
158
  # expressible as an ordinary `given`: "has this exact record
159
159
  # already emitted this exact event" is not a predicate over the
160
- # record's OWN fields, it is a fact about the event log, so it is
160
+ # record's own fields, it is a fact about the event log, so it is
161
161
  # raised structurally here, the same way NotFound/AlreadyExists
162
162
  # are, rather than through the expression evaluator. The build-
163
- # time half — does ANYTHING in this aggregate ever emit the named
163
+ # time half — does anything in this aggregate ever emit the named
164
164
  # event at all — is `AggregateBuilder#seal_correction_targets`;
165
- # this is the dispatch-time half — has THIS record actually done
165
+ # this is the dispatch-time half — has this record actually done
166
166
  # so yet.
167
167
  #
168
- # ALSO LOCATES the matched event now, not just its existence, and
168
+ # Also locates the matched event now, not just its existence, and
169
169
  # returns a `{as_name => payload}` bindings hash — one entry per
170
170
  # `:corrects` mutation that named an `as:` — so `given`/`ensures`
171
- # on a corrects-bearing command can reference the located OLD
171
+ # on a corrects-bearing command can reference the located old
172
172
  # event by that name, the same shape `enforce_ensures`'s own
173
173
  # `old:` binding already has (CommandBuilder#corrects_impl's own
174
174
  # comment: `as:` was stored, from the start, specifically to be
175
175
  # wired into the evaluator once a real runtime consumer existed —
176
- # this is that consumer). `.reverse.find` — the MOST RECENT
176
+ # this is that consumer). `.reverse.find` — the most recent
177
177
  # matching event, if this record has somehow emitted the same
178
178
  # correction target more than once; the prior existence-only
179
179
  # check never had to make this choice, so it's a genuinely new
@@ -181,7 +181,7 @@ module Hecks
181
181
  # corrected," which is naturally the latest fact on record, not
182
182
  # an arbitrary one.
183
183
  # C9.2 (docs/semantics/bluebook-semantics.md) — a correction target
184
- # is judged against the record's DURABLE history: the events the
184
+ # is judged against the record's durable history: the events the
185
185
  # aggregate's own store recorded (`AppendOnly#events`), which
186
186
  # survive a restart the way the Rust kernel's persisted
187
187
  # `emitted_<event>` flag does. The in-process log is the fallback
@@ -213,14 +213,14 @@ module Hecks
213
213
  bindings
214
214
  end
215
215
 
216
- # LIFECYCLE STATE AS A COMMAND GUARD (S10, ADR 0025) — `command
217
- # "Debit", from: "open"` checked here, folded into the SAME
216
+ # Lifecycle state as a command guard (S10, ADR 0025) — `command
217
+ # "Debit", from: "open"` checked here, folded into the same
218
218
  # dispatch step `given` already runs at (both are preconditions,
219
219
  # evaluated before any mutation) rather than earning its own
220
- # DISPATCH_ORDER entry. A GUARD, never a transition: it names no
220
+ # DISPATCH_ORDER entry. A guard, never a transition: it names no
221
221
  # target state and `step_advance_lifecycle` never sees it — see
222
222
  # `admissible_transition`, right below, for the transition this
223
- # is deliberately NOT reusing (its own `StateTransition#target`
223
+ # is deliberately not reusing (its own `StateTransition#target`
224
224
  # is required, and a guard-only command has none to give it).
225
225
  def enforce_lifecycle_guard(declaring, command, subject)
226
226
  return unless command.from
@@ -229,8 +229,8 @@ module Hecks
229
229
  current = Value.scalar(subject[lifecycle.field]).to_s
230
230
  return if Array(command.from).include?(current)
231
231
 
232
- # ROUTED THROUGH RefusalWording's OWN "transition_blocked"
233
- # TEMPLATE — the same one #admissible_transition, right below,
232
+ # Routed through RefusalWording's own "transition_blocked"
233
+ # template — the same one #admissible_transition, right below,
234
234
  # already raises LifecycleRefused through for the same
235
235
  # refusal class. This used to hand-roll its own wording
236
236
  # inline ("...only runs from..." vs. the template's "...moves
@@ -239,22 +239,22 @@ module Hecks
239
239
  # property, a spec, a caller) had to know both existed rather
240
240
  # than one.
241
241
  raise LifecycleRefused,
242
- RefusalWording.render("LifecycleRefused", "transition_blocked",
243
- command: command.hecks_name, field: lifecycle.field,
244
- current: Rendering.describe(current),
245
- allowed: Array(command.from).map(&:inspect).join(" or "))
242
+ RefusalWording.render_site("LifecycleRefused", "transition_blocked",
243
+ command: command.hecks_name, field: lifecycle.field,
244
+ current: Rendering.describe(current),
245
+ allowed: Array(command.from))
246
246
  end
247
247
 
248
- # The far side of the contract: evaluated against the SETTLED record
248
+ # The far side of the contract: evaluated against the settled record
249
249
  # — after mutations and the lifecycle move, before anything persists
250
250
  # — with `old` carrying the state as the givens saw it. Injected into
251
251
  # the attrs at evaluation time only; the payload gate never sees it.
252
252
  #
253
- # `old` — and every dispatch ARGUMENT — wins over a same-named STATE
253
+ # `old` — and every dispatch argument — wins over a same-named state
254
254
  # field in expression scope (Resolver#fetch checks attrs first). An
255
255
  # ensures naming a field the command also takes as an argument (or,
256
256
  # on an entity, a field that doubles as the addressing argument
257
- # element_of reads) will read the ARGUMENT, not the settled value.
257
+ # element_of reads) will read the argument, not the settled value.
258
258
  # Not new to ensures — `given` lives under the same rule — but an
259
259
  # ensures is more likely to collide, since it typically re-reads a
260
260
  # field the command just took in to mutate it.
@@ -264,14 +264,14 @@ module Hecks
264
264
  # above: `subject`'s own stored references are no longer
265
265
  # dereferenced here; a `projects`-maintained field is already
266
266
  # part of `state`. `command`/`args` still dereferences — a
267
- # fresh reference-typed ARGUMENT stays in bounds.
267
+ # fresh reference-typed argument stays in bounds.
268
268
  # `old` still wins over everything, unchanged. `correction`
269
269
  # (an `as:`-bound corrected event, if this command declares
270
270
  # one) wins right alongside it — a settled-record ensures can
271
271
  # reference the correction target exactly as freely as a
272
272
  # pre-mutation given already can.
273
273
  # C2.3 (docs/semantics/bluebook-semantics.md) — an ensures reads
274
- # the SETTLED STATE first: an argument that shares a field's
274
+ # the settled state first: an argument that shares a field's
275
275
  # name does not shadow the candidate here (it does in a given,
276
276
  # C2.2), so `sets :note` + `ensures { note == ... }` judges what
277
277
  # landed, and `old.<field>` remains the pre-state.
@@ -286,20 +286,20 @@ module Hecks
286
286
  end
287
287
  end
288
288
 
289
- # THE AGGREGATE BOUNDARY, checked after every command, before
289
+ # The aggregate boundary, checked after every command, before
290
290
  # save (S10, ADR 0025 — "Rules") — the same point `enforce_
291
291
  # ensures` already checks at, and for the same reason: an
292
- # invariant is a claim about the SETTLED record, not the
292
+ # invariant is a claim about the settled record, not the
293
293
  # command that produced it, so it reads no `args`/`old` at all,
294
294
  # only the record's own state. `subject` here is
295
- # always the AGGREGATE's own instance — `CommandInterpreter`
295
+ # always the aggregate's own instance — `CommandInterpreter`
296
296
  # passes its own `ctx.instance`, and `EntityInterpreter` passes
297
- # the PARENT record (`ctx.instance`, not the element), since an
298
- # entity mutation changes data inside the SAME aggregate
297
+ # the parent record (`ctx.instance`, not the element), since an
298
+ # entity mutation changes data inside the same aggregate
299
299
  # boundary the invariant guards; there is no separate "entity
300
300
  # invariant" to check the piece's own view against.
301
301
  #
302
- # NO `dereference` (S12, ADR 0025) — an invariant may only read
302
+ # No `dereference` (S12, ADR 0025) — an invariant may only read
303
303
  # `subject`'s own boundary, same rule `enforce_givens`/
304
304
  # `enforce_ensures` now hold to. No invariant in the corpus has
305
305
  # ever read across a `reference_to` (verified before this
@@ -317,20 +317,20 @@ module Hecks
317
317
  check_entity_invariants(aggregate, subject, domain: domain)
318
318
  end
319
319
 
320
- # A PIECE'S OWN SHAPE RULE, checked against EVERY INSTANCE the
320
+ # A piece's own shape rule, checked against every instance the
321
321
  # aggregate holds — not a separate boundary from the aggregate's
322
322
  # own invariants just above (same two checkpoints: after every
323
- # mutation, before save), just a WIDER one: the aggregate's own
323
+ # mutation, before save), just a wider one: the aggregate's own
324
324
  # consistency includes each of its pieces individually looking
325
325
  # right, the same way `ValueObject#invariants` already checks
326
- # each of ITS OWN instances one construct up. RECURSES into
326
+ # each of its own instances one construct up. Recurses into
327
327
  # nested pieces (S17, ADR 0026 — Dispatch inside Handler) the
328
328
  # same way `check_entity_invariants`'s own caller recurses
329
329
  # nowhere else needs to, since a piece's `entities` are already
330
330
  # exactly as reachable as an aggregate's.
331
331
  #
332
- # `list_attr` reuses the EXACT lookup `EntityInterpreter#
333
- # element_of` already makes to locate a SINGLE addressed
332
+ # `list_attr` reuses the exact lookup `EntityInterpreter#
333
+ # element_of` already makes to locate a single addressed
334
334
  # element by identity — this reads every element instead, but
335
335
  # the "which field on the owner holds this piece's own
336
336
  # instances" question is the identical one. A piece declaring
@@ -348,7 +348,7 @@ module Hecks
348
348
  Array(owner_instance[list_attr.name]).each do |element|
349
349
  wrapped = Instance.new(aggregate: entity, id: nil, state: element)
350
350
  element_state = GuardState.new(wrapped)
351
- # NO `dereference` (S12, ADR 0025) — same boundary rule as
351
+ # No `dereference` (S12, ADR 0025) — same boundary rule as
352
352
  # enforce_invariants above; `parent` (the owner's own
353
353
  # state, projected fields included) stays readable.
354
354
  attrs = { parent: owner_instance.state }
@@ -379,7 +379,7 @@ module Hecks
379
379
  # default `Object#to_s` instead of unwrapping the inner
380
380
  # scalar first -- `current` came back as a raw object-pointer
381
381
  # string (`"#<Hecks::Runtime::Value:0x...>"`) that could
382
- # never match any declared `from` state, so EVERY transition
382
+ # never match any declared `from` state, so every transition
383
383
  # on a VO-typed lifecycle field refused unconditionally, and
384
384
  # when it refused the message leaked the pointer too.
385
385
  # Confirmed live via `Plan::Task.Complete` (status defaults to
@@ -399,10 +399,10 @@ module Hecks
399
399
 
400
400
  allowed = candidates.flat_map { |t| Array(t.from) }.uniq
401
401
  raise LifecycleRefused,
402
- RefusalWording.render("LifecycleRefused", "transition_blocked",
403
- command: command.hecks_name, field: lifecycle.field,
404
- current: Rendering.describe(current),
405
- allowed: allowed.map(&:inspect).join(" or "))
402
+ RefusalWording.render_site("LifecycleRefused", "transition_blocked",
403
+ command: command.hecks_name, field: lifecycle.field,
404
+ current: Rendering.describe(current),
405
+ allowed: allowed)
406
406
  end
407
407
  end
408
408
  end