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
@@ -5,7 +5,7 @@ require_relative "../../rendering"
5
5
  module Hecks
6
6
  module Runtime
7
7
  class Value
8
- # HOW A `list_of` ATTRIBUTE'S OWN ELEMENTS GET HYDRATED — entity-typed
8
+ # How a `list_of` attribute's own elements GET hydrated — entity-typed
9
9
  # and value-object-typed alike — split out of `Coercion` (this file's
10
10
  # sibling, extended into `Value` alongside it exactly the way
11
11
  # `Admission` already is) once `Coercion` itself grew past
@@ -16,19 +16,19 @@ module Hecks
16
16
  # made the split necessary). Cross-calls into `Coercion`'s own
17
17
  # `for_attribute`/`build`/`fields_for`/`value_object_for`/
18
18
  # `trusting_stored_state?` work unqualified here exactly as they did
19
- # before the split, because both modules land on the SAME `Value`
19
+ # before the split, because both modules land on the same `Value`
20
20
  # singleton class once extended — `self` never has to know which file
21
21
  # a sibling method actually lives in.
22
22
  module EntityListCoercion
23
- # S17, ADR 0026 — SEARCHES THE WHOLE ENTITY TREE, not only the
23
+ # S17, ADR 0026 — searches the whole entity tree, not only the
24
24
  # root's own direct children. `aggregate` here is always the
25
- # ROOT aggregate — `for_attribute`'s own `aggregate` argument is
25
+ # root aggregate — `for_attribute`'s own `aggregate` argument is
26
26
  # never reassigned as hydration recurses into a nested element,
27
27
  # because coercion has to resolve value objects, and only the
28
28
  # root answers `.value_object` at all (Entity's own header
29
- # comment: an entity must NOT answer to it, or `Value.
29
+ # comment: an entity must not answer to it, or `Value.
30
30
  # for_attribute` could no longer tell a piece from a head). So
31
- # a NESTED entity — Dispatch, inside Handler — is not a direct
31
+ # a nested entity — Dispatch, inside Handler — is not a direct
32
32
  # child of the root the way Handler itself is, and a plain
33
33
  # `aggregate.entities.find` stops one level short of it.
34
34
  def find_entity(construct, name)
@@ -57,16 +57,16 @@ module Hecks
57
57
  # raw `Hash`) then always failed, since `Hash#==` refuses anything
58
58
  # that isn't itself a compatible Hash — the bug ADR 0047 traces in
59
59
  # full. Delegating to `hydrate_value_object_list` below closes
60
- # that gap the same way the ENTITY branch already worked: build a
60
+ # that gap the same way the entity branch already worked: build a
61
61
  # real, validated `Value` per element, reusing `for_attribute`'s
62
62
  # own composite-construction path rather than inventing a second
63
63
  # one.
64
64
  # BUG#32 (QualityControl ledger) — `remove:`'s own single-target
65
65
  # value used to fall straight into `Array(value).map { ... }`
66
- # below UNGUARDED, unlike this method's own delegated
66
+ # below unguarded, unlike this method's own delegated
67
67
  # `hydrate_value_object_list` sibling, whose `value.is_a?(Array)`
68
68
  # check exists for exactly this shape (see that method's own
69
- # comment). For an ENTITY-typed list, `remove:`'s scalar target
69
+ # comment). For an entity-typed list, `remove:`'s scalar target
70
70
  # (`Ledger.Void`'s `sequence: EntrySequence`) is never a Hash, so
71
71
  # `Array(2)` merely wrapped it as `[2]` rather than shredding it —
72
72
  # but the wrapping itself was still wrong: `MutationApplier#
@@ -89,7 +89,7 @@ module Hecks
89
89
  acc[key] = field ? for_attribute(aggregate, field, field_value) : field_value
90
90
  end
91
91
  end
92
- # BUG#33 — only a genuine WHOLE-LIST offering (`value.is_a?(Array)`)
92
+ # BUG#33 — only a genuine whole-list offering (`value.is_a?(Array)`)
93
93
  # is a caller naming every element's own identity at once; the
94
94
  # single-target shape this same method also hydrates (a `remove:`
95
95
  # target, wrapped one level up by `Array()`) never reaches this
@@ -101,16 +101,16 @@ module Hecks
101
101
 
102
102
  # `MutationApplier#check_entity_collision`'s own guard
103
103
  # (mutation_applier.rb), extended from a single caller-supplied
104
- # APPEND (BUG#13) to a whole-list REPLACE — `sets :entries` bare
104
+ # append (BUG#13) to a whole-list replace — `sets :entries` bare
105
105
  # (`Ledger.ReplaceEntries`, the corpus's first `list_of(ENTITY)`
106
106
  # command argument/mutation, qa/stress_domains/corrections). The
107
107
  # array branch above rebuilds each offered element's own declared
108
- # fields but never checked the OFFERED LIST ITSELF for either way
108
+ # fields but never checked the offered list itself for either way
109
109
  # it can misname its own entities:
110
110
  #
111
111
  # - two elements sharing one identity — the same silent-duplicate
112
112
  # hazard BUG#13's own comment describes: `EntityInterpreter#
113
- # element_of`'s own `find_index` always matches the FIRST
113
+ # element_of`'s own `find_index` always matches the first
114
114
  # match, so the second becomes permanently unaddressable by any
115
115
  # later command.
116
116
  # - an element missing its identity altogether — there is no
@@ -120,14 +120,14 @@ module Hecks
120
120
  # whole state, offered at once), so an absent identity is
121
121
  # refused rather than guessed.
122
122
  #
123
- # NON-COMPOSITE identities only, exactly BUG#13's own scope
123
+ # Non-composite identities only, exactly BUG#13's own scope
124
124
  # (`entity.identified_by` answers a single Symbol only when
125
125
  # `identity_heads.size == 1`, `Behaviour::Traits#derive_identity`) —
126
126
  # a composite identity's own duplicate/missing question is the
127
127
  # same pre-existing, narrower gap BUG#13 documented and left open,
128
128
  # not widened here.
129
129
  #
130
- # SKIPPED under `trusting_stored_state?`, the same guard `validate!`
130
+ # Skipped under `trusting_stored_state?`, the same guard `validate!`
131
131
  # already gives every value object (C6.3): a record already
132
132
  # written is trusted as it was, so tightening this check can never
133
133
  # make an old, already-persisted record unreadable.
@@ -144,32 +144,32 @@ module Hecks
144
144
  offered = fields[identity]
145
145
  if offered.nil?
146
146
  raise TypeMismatch,
147
- RefusalWording.render("TypeMismatch", "numeric_field",
148
- type: entity.hecks_name, field: identity,
149
- expected: field&.type, offered: "nil")
147
+ RefusalWording.render_site("TypeMismatch", "numeric_field",
148
+ type: entity.hecks_name, field: identity,
149
+ expected: field&.type, offered: "nil")
150
150
  end
151
151
 
152
152
  if seen.include?(offered)
153
153
  raise AlreadyExists,
154
- RefusalWording.render("AlreadyExists", "entity_duplicate",
155
- entity: entity.hecks_name, aggregate: aggregate.hecks_name,
156
- identity: entity.identity_paths.join(", "),
157
- offered: Rendering.describe(offered))
154
+ RefusalWording.render_site("AlreadyExists", "entity_duplicate",
155
+ entity: entity.hecks_name, aggregate: aggregate.hecks_name,
156
+ identity: entity.identity_paths.join(", "),
157
+ offered: [Rendering.describe(offered)])
158
158
  end
159
159
  seen << offered
160
160
  end
161
161
  end
162
162
 
163
163
  # BUG#32 — `remove:`'s own single-target value against an
164
- # ENTITY-typed list. An entity is never offered to `remove:`
165
- # WHOLE the way a value object is (`hydrate_value_object_list`'s
164
+ # entity-typed list. An entity is never offered to `remove:`
165
+ # whole the way a value object is (`hydrate_value_object_list`'s
166
166
  # own `element == value` full-value-equality shape) — an entity
167
167
  # must never answer `.value_object` at all (`Entity`'s own header
168
168
  # comment), so there is no whole-value shape here to rebuild in
169
- # the first place, only the ONE field a caller would otherwise
170
- # have to NAME to address that element any other way
169
+ # the first place, only the one field a caller would otherwise
170
+ # have to name to address that element any other way
171
171
  # (`EntityElement#element_of`'s own `wants`). So this coerces the
172
- # offered scalar against the entity's OWN identity field's
172
+ # offered scalar against the entity's own identity field's
173
173
  # declared type — not the entity's full shape — and hands back a
174
174
  # real, correctly-typed `Value` ready to compare against each
175
175
  # stored element's own identity field
@@ -177,9 +177,9 @@ module Hecks
177
177
  # `MutationApplier#removed` and `EntityElement#
178
178
  # removed_from_element` match against).
179
179
  #
180
- # A COMPOSITE identity (more than one head) has no single field a
180
+ # A composite identity (more than one head) has no single field a
181
181
  # bare `remove:` target could mean, so this passes the value
182
- # through UNCOERCED rather than guessing which head — the same
182
+ # through uncoerced rather than guessing which head — the same
183
183
  # "nothing in this corpus needs it yet" boundary
184
184
  # `MutationApplier#check_entity_collision`'s own header already
185
185
  # draws for entity identity elsewhere in this runtime.
@@ -200,7 +200,7 @@ module Hecks
200
200
 
201
201
  # The value-object sibling of the entity branch above: an element
202
202
  # already shaped like the target `Value` (or a `Hash`/scalar that
203
- # `fields_for` can still open) is rebuilt through the SAME `build`
203
+ # `fields_for` can still open) is rebuilt through the same `build`
204
204
  # a scalar composite attribute already uses (`for_attribute`'s own
205
205
  # `coerced = ... build(value_object, fields_for(...), aggregate)`
206
206
  # line) — same defaults, same `pattern:`/`admits:`/invariant
@@ -210,15 +210,15 @@ module Hecks
210
210
  # element passes through unchanged, exactly as the entity branch's
211
211
  # own non-Hash elements do.
212
212
  #
213
- # NOT `Array(value).map` (unlike the entity branch above) — `value`
213
+ # Not `Array(value).map` (unlike the entity branch above) — `value`
214
214
  # here is not always genuinely list-shaped. `MutationApplier#
215
215
  # removed`'s own `Value.for_attribute(aggregate, attribute, value)`
216
- # call (`attribute` = the LIST attribute, `mutation.target`; `value`
217
- # = the single REMOVE-target argument, already a real `Value` by
216
+ # call (`attribute` = the list attribute, `mutation.target`; `value`
217
+ # = the single remove-target argument, already a real `Value` by
218
218
  # the time it gets here) reuses this exact branch — for `remove:`,
219
219
  # not for a whole-list `sets`. `Array(a_real_Value)` alone would be
220
220
  # harmless (`Value` defines neither `to_a` nor `to_ary`, so Kernel
221
- # wraps it `[value]`), but `Array(a_Hash)` is NOT harmless: Ruby's
221
+ # wraps it `[value]`), but `Array(a_Hash)` is not harmless: Ruby's
222
222
  # `Array()` opens a bare Hash into its own `[[k, v], ...]` pairs,
223
223
  # not `[hash]` — silently shredding a single-element Hash-shaped
224
224
  # target into garbage instead of hydrating it. Branching on
@@ -8,7 +8,7 @@ require_relative "value/admission"
8
8
  module Hecks
9
9
  module Runtime
10
10
  # A typed value object in hand: frozen fields, read by name. How one is
11
- # MADE — coerced from a raw argument, checked against its declared
11
+ # made — coerced from a raw argument, checked against its declared
12
12
  # numeric types, patterns and closed sets — is the class-side engine in
13
13
  # value/coercion.rb, value/entity_list_coercion.rb (a `list_of`
14
14
  # attribute's own elements — split out once growing Coercion tripped
@@ -22,10 +22,10 @@ module Hecks
22
22
 
23
23
  attr_reader :value_object
24
24
 
25
- # FROZEN THROUGH, not just on top.
25
+ # Frozen through, not just on top.
26
26
  #
27
27
  # `@fields.freeze` alone stops a key being added or removed and
28
- # nothing else: the String, Array or Hash a field HOLDS stays
28
+ # nothing else: the String, Array or Hash a field holds stays
29
29
  # mutable, so `vo[:value] << "!"` edits a value object in place —
30
30
  # demonstrated on a real dispatch before this was written, not
31
31
  # supposed. Same shape as the three freezing bugs already fixed
@@ -33,7 +33,7 @@ module Hecks
33
33
  # was frozen and the contents were not.
34
34
  #
35
35
  # A value object is the one thing in the domain that has no
36
- # identity to change over — `with` already answers a NEW one rather
36
+ # identity to change over — `with` already answers a new one rather
37
37
  # than mutating — so freezing it through is what it always claimed
38
38
  # to be.
39
39
  def initialize(value_object, fields)
@@ -68,13 +68,13 @@ module Hecks
68
68
  # `materialize`, but a single-attribute value object (`sole_attribute`
69
69
  # — [[feedback_name_the_scalar_field]]) recurses into its own bare
70
70
  # field instead of building `{field: ...}` — a Board's own `label`
71
- # unwraps to `"Kanban"`, not `{value: "Kanban"}`. NOT a replacement
71
+ # unwraps to `"Kanban"`, not `{value: "Kanban"}`. Not a replacement
72
72
  # for `materialize` itself: every existing report/query/command
73
73
  # caller keeps the wrapped shape it already depends on (Banking's
74
74
  # own `CustomerPortfolio` reads `payment[:amount][:cents]`, and
75
75
  # changing that out from under it would be a real breaking change,
76
76
  # not a bug fix). This is read_model_interpreter.rb's own opt-in,
77
- # used ONLY for a `group_by`-declared head's own rows — grouping
77
+ # used only for a `group_by`-declared head's own rows — grouping
78
78
  # needs a real scalar to key by regardless, so a report already
79
79
  # asking for that gets the unwrap for free.
80
80
  def self.materialize_unwrapped(value)
@@ -83,12 +83,12 @@ module Hecks
83
83
  sole = value.value_object.sole_attribute
84
84
  return materialize_unwrapped(value[sole.name]) if sole
85
85
 
86
- # NOT `value.to_h` — `Value#to_h` materializes each field through
86
+ # Not `value.to_h` — `Value#to_h` materializes each field through
87
87
  # plain `materialize`, so a VO nested inside a multi-attribute VO
88
88
  # would already be a plain Hash by the time this method ever saw
89
89
  # it, and never reach the `when self` branch above. Read each
90
90
  # field straight off `value` instead, so recursion actually
91
- # happens through THIS method the whole way down.
91
+ # happens through this method the whole way down.
92
92
  value.value_object.attributes.to_h { |attr| [attr.name, materialize_unwrapped(value[attr.name])] }
93
93
  when Array then value.map { |item| materialize_unwrapped(item) }
94
94
  when Hash then value.transform_values { |item| materialize_unwrapped(item) }
@@ -96,17 +96,17 @@ module Hecks
96
96
  end
97
97
  end
98
98
 
99
- # REDUCES AN APPEND-ONLY SUB-LOG TO ITS CURRENT STATE — the same
99
+ # Reduces an append-only sub-log to its current state — the same
100
100
  # "a later fact supersedes an earlier one" reduction this runtime
101
- # already performs replaying an AGGREGATE's own command history
101
+ # already performs replaying an aggregate's own command history
102
102
  # into its current attributes, applied here to a single `list_of`
103
- # FIELD acting as its own miniature append-only log (a placement
103
+ # field acting as its own miniature append-only log (a placement
104
104
  # history, a tombstone-style soft-delete list, a versioned
105
105
  # setting). `rows` is what a `list_of` attribute hands back — an
106
106
  # Array of `Value`, in append order — and `key` names the field
107
107
  # that identifies "the same logical thing" across entries.
108
108
  #
109
- # GROUPING ONLY, NEVER INTERPRETATION. What counts as "removed,"
109
+ # **Grouping only, never interpretation**. What counts as "removed,"
110
110
  # how to order what survives — that meaning belongs to whichever
111
111
  # domain declared the field, never here: a generic reduction that
112
112
  # started guessing domain semantics would need to keep guessing
@@ -119,17 +119,17 @@ module Hecks
119
119
  def method_missing(name, *args)
120
120
  return @fields[name] if @fields.key?(name)
121
121
 
122
- # THE LANGUAGE RULE, not a convenience: ANY value object with
122
+ # The language rule, not a convenience: any value object with
123
123
  # exactly one declared attribute answers `.value`, whatever that
124
124
  # attribute is actually named — a single-attribute value object
125
- # is a NAME for a scalar, not a genuine group
125
+ # is a name for a scalar, not a genuine group
126
126
  # ([[feedback_name_the_scalar_field]], `Behaviour::ValueObject#
127
127
  # sole_attribute`), so `money.value` reads `Money`'s own `amount`
128
128
  # exactly as `label.value` reads a shorthand-declared `value`.
129
- # AFTER the real-field lookup above, on purpose: a field
130
- # literally named `value` is already answered there (and IS the
129
+ # After the real-field lookup above, on purpose: a field
130
+ # literally named `value` is already answered there (and is the
131
131
  # sole attribute whenever the count is one), so this branch only
132
- # ever aliases, never shadows. A MULTI-attribute value object
132
+ # ever aliases, never shadows. A multi-attribute value object
133
133
  # keeps its NoMethodError — `sole_attribute` answers nil for it,
134
134
  # and falling through to `super` is exactly the refusal it
135
135
  # always gave: with two or more fields there is no single value
@@ -151,15 +151,15 @@ module Hecks
151
151
 
152
152
  private
153
153
 
154
- # THE `.value` ALIAS FOR INDEXED ACCESS — the same language rule
154
+ # **The `.value` alias for indexed access** — the same language rule
155
155
  # `method_missing` above enforces for method reads, applied to
156
156
  # `[]`/`key?`/`with`: `:value` names a single-attribute value
157
157
  # object's sole field whatever that field is actually called. A
158
- # REAL key always wins first (a field literally named `value` is
158
+ # real key always wins first (a field literally named `value` is
159
159
  # its own answer, and is the sole attribute anyway whenever the
160
160
  # count is one), so this only ever resolves a `:value` that would
161
- # otherwise MISS — it can never redirect a genuine field read.
162
- # `with(:value, x)` in particular NEEDS this: merging a literal
161
+ # otherwise miss — it can never redirect a genuine field read.
162
+ # `with(:value, x)` in particular needs this: merging a literal
163
163
  # `:value` key beside a sole field named `amount` would build a
164
164
  # two-key hash for a one-field shape and be refused (or worse,
165
165
  # stored) downstream — aliasing at the merge is what keeps the
data/lib/hecks/runtime.rb CHANGED
@@ -6,24 +6,24 @@
6
6
  # declaration is being collected into — sat on the top-level Hecks module
7
7
  # beside the DSL words.
8
8
  #
9
- # What lives here is what RUNS a domain :
9
+ # What lives here is what runs a domain :
10
10
  #
11
11
  # Runtime.boot(path) load a directory and return its Dispatcher
12
12
  # Runtime.with_registry(r) bind the ambient registry for the duration of a load
13
13
  # Runtime.current_registry the registry a declaration is landing in, or nil
14
14
  #
15
- # What does NOT live here is what DECLARES one — `Hecks.bluebook`,
15
+ # What does not live here is what declares one — `Hecks.bluebook`,
16
16
  # `.hecksagon`, `.port`, `.adapter`, `.world` are loading words and stay on the
17
17
  # top-level module, which now reads as a facade over this.
18
18
  #
19
19
  # runtime = Hecks::Runtime.boot("examples/pizzas/bluebook")
20
20
  # runtime.dispatch("Pizzas::Pizza.CreatePizza", name: "Margherita")
21
21
  #
22
- # NOTE, and it is the reason this file exists : `current_registry` is still
22
+ # Note, and it is the reason this file exists : `current_registry` is still
23
23
  # process-global. Each boot builds a fresh Registry, and `Loader.bind_runtime`
24
- # installs a fresh facade door whose modules close over THAT boot's dispatcher
24
+ # installs a fresh facade door whose modules close over that boot's dispatcher
25
25
  # — no class-level runtime binding remains, so two boots in one process no
26
- # longer share dispatch state, only the top-level NAME (the last-bound door
26
+ # longer share dispatch state, only the top-level name (the last-bound door
27
27
  # wins the constant, which is what per-boot install means). Owning the state
28
28
  # here was the first move ; the dispatcher reachable per-runtime rather than
29
29
  # through a constant was the second, and it is done — the door is the only
@@ -91,7 +91,7 @@ module Hecks
91
91
  # the block — who a command's declared `role`, if any, is checked
92
92
  # against.
93
93
  #
94
- # `as_of:` is OPTIONAL, same opt-in shape as `actor_id:` — a caller
94
+ # `as_of:` is optional, same opt-in shape as `actor_id:` — a caller
95
95
  # that wants a Governance `RoleAssignment`'s `starts_at` enforced
96
96
  # passes `as_of: Ports::Clock.now(registry)` here, at the door,
97
97
  # exactly where `cli_runner.rb` already merges `Clock.now` into a
@@ -99,7 +99,7 @@ module Hecks
99
99
  # itself — see `Ports::Clock`'s own header for why — so an unbound
100
100
  # `as_of` leaves `starts_at` unchecked, exactly as before.
101
101
  #
102
- # `scope:` is OPTIONAL too — a caller that states which scope it is
102
+ # `scope:` is optional too — a caller that states which scope it is
103
103
  # acting in gets that scope checked against the matching
104
104
  # `RoleAssignment`'s own `scope`, not just its `role_name`. See
105
105
  # `Runtime::Caller::Current`'s own header for why this lives here