hecks 2.7.0 → 2.9.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 (463) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +11 -0
  3. data/lib/hecks/adapters/driven/claude_code.rb +4 -104
  4. data/lib/hecks/adapters/driven/d1.rb +44 -237
  5. data/lib/hecks/adapters/driven/folder.rb +17 -76
  6. data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
  7. data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
  8. data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
  9. data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
  10. data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
  11. data/lib/hecks/adapters/driven/heki.rb +13 -42
  12. data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
  13. data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
  14. data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
  15. data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
  16. data/lib/hecks/adapters/driven/lambda.rb +10 -84
  17. data/lib/hecks/adapters/driven/local_storage.rb +5 -40
  18. data/lib/hecks/adapters/driven/memory.rb +18 -99
  19. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
  20. data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
  21. data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
  22. data/lib/hecks/adapters/driven/postgres/reconnect.rb +4 -30
  23. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
  24. data/lib/hecks/adapters/driven/postgres.rb +145 -134
  25. data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
  26. data/lib/hecks/adapters/driven/prism.rb +7 -30
  27. data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
  28. data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
  29. data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
  30. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
  31. data/lib/hecks/adapters/driven/sqlite.rb +128 -65
  32. data/lib/hecks/adapters/driven/tenant_provisioner.rb +15 -37
  33. data/lib/hecks/adapters/driven.rb +5 -36
  34. data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
  35. data/lib/hecks/behaviors/dsl.rb +7 -25
  36. data/lib/hecks/behaviors/expectations.rb +32 -142
  37. data/lib/hecks/behaviors/ir.rb +7 -20
  38. data/lib/hecks/behaviors/rspec.rb +6 -17
  39. data/lib/hecks/behaviors/runner.rb +10 -34
  40. data/lib/hecks/behaviors.rb +4 -8
  41. data/lib/hecks/bluebook/aggregate.rb +9 -75
  42. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
  43. data/lib/hecks/bluebook/assembly/build.rb +4 -15
  44. data/lib/hecks/bluebook/assembly/contract.rb +15 -136
  45. data/lib/hecks/bluebook/assembly/contracts.rb +54 -174
  46. data/lib/hecks/bluebook/assembly/marks.rb +31 -223
  47. data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
  48. data/lib/hecks/bluebook/assembly.rb +6 -45
  49. data/lib/hecks/bluebook/attribute.rb +12 -61
  50. data/lib/hecks/bluebook/behaviour/aggregate.rb +10 -39
  51. data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
  52. data/lib/hecks/bluebook/behaviour/chapter.rb +17 -42
  53. data/lib/hecks/bluebook/behaviour/command.rb +14 -66
  54. data/lib/hecks/bluebook/behaviour/domain_port.rb +4 -20
  55. data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
  56. data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
  57. data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
  58. data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
  59. data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
  60. data/lib/hecks/bluebook/behaviour/read_model.rb +38 -26
  61. data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
  62. data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
  63. data/lib/hecks/bluebook/capabilities.rb +17 -49
  64. data/lib/hecks/bluebook/chapter.rb +10 -48
  65. data/lib/hecks/bluebook/command.rb +23 -81
  66. data/lib/hecks/bluebook/domain_port.rb +14 -63
  67. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
  68. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
  69. data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
  70. data/lib/hecks/bluebook/dsl/binding_proxy.rb +17 -65
  71. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +86 -708
  72. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +56 -170
  73. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +1 -0
  74. data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
  75. data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
  76. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +12 -87
  77. data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
  78. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
  79. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +26 -189
  80. data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
  81. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
  82. data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
  83. data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
  84. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
  85. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
  86. data/lib/hecks/bluebook/dsl/query_builder.rb +11 -42
  87. data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
  88. data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
  89. data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
  90. data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
  91. data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
  92. data/lib/hecks/bluebook/dsl/world_builder.rb +19 -106
  93. data/lib/hecks/bluebook/entity.rb +13 -71
  94. data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
  95. data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
  96. data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
  97. data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
  98. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
  99. data/lib/hecks/bluebook/expression/resolver.rb +37 -660
  100. data/lib/hecks/bluebook/hexagon.rb +5 -28
  101. data/lib/hecks/bluebook/lifecycle.rb +5 -16
  102. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
  103. data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
  104. data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
  105. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
  106. data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
  107. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +24 -176
  108. data/lib/hecks/bluebook/meta_validator/shapes.rb +54 -268
  109. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -308
  110. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
  111. data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
  112. data/lib/hecks/bluebook/meta_validator.rb +79 -349
  113. data/lib/hecks/bluebook/model_check/client_profile.rb +10 -91
  114. data/lib/hecks/bluebook/model_check.rb +102 -600
  115. data/lib/hecks/bluebook/pattern_subset.rb +11 -69
  116. data/lib/hecks/bluebook/process_manager.rb +13 -83
  117. data/lib/hecks/bluebook/project_loader.rb +3 -39
  118. data/lib/hecks/bluebook/project_register.rb +12 -60
  119. data/lib/hecks/bluebook/query.rb +9 -48
  120. data/lib/hecks/bluebook/read_model.rb +57 -81
  121. data/lib/hecks/bluebook/reference.rb +7 -41
  122. data/lib/hecks/bluebook/smoke_test.rb +8 -98
  123. data/lib/hecks/bluebook/synthesizer.rb +13 -62
  124. data/lib/hecks/bluebook/translation.rb +26 -62
  125. data/lib/hecks/bluebook/value_object.rb +11 -36
  126. data/lib/hecks/bluebook.rb +5 -22
  127. data/lib/hecks/cache_dir.rb +84 -0
  128. data/lib/hecks/cli/document.rb +86 -0
  129. data/lib/hecks/cli/ir.rb +45 -0
  130. data/lib/hecks/cli/mcp.rb +31 -0
  131. data/lib/hecks/cli/mcp_door.rb +366 -0
  132. data/lib/hecks/cli/model_check.rb +203 -0
  133. data/lib/hecks/cli/project_cli.rb +90 -0
  134. data/lib/hecks/cli/project_diagrams.rb +36 -0
  135. data/lib/hecks/cli/run.rb +173 -0
  136. data/lib/hecks/cli/smoke_test.rb +45 -0
  137. data/lib/hecks/cli/stores.rb +53 -0
  138. data/lib/hecks/cli.rb +160 -0
  139. data/lib/hecks/construct.rb +8 -34
  140. data/lib/hecks/deploy/bluebook/deploy.bluebook +33 -142
  141. data/lib/hecks/deploy/bluebook/deploy.hecksagon +2 -9
  142. data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
  143. data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
  144. data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
  145. data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
  146. data/lib/hecks/embryonaut_bluebook.rb +4 -71
  147. data/lib/hecks/facade/cli_door.rb +24 -106
  148. data/lib/hecks/facade/cli_runner.rb +28 -172
  149. data/lib/hecks/facade/command_request.rb +13 -33
  150. data/lib/hecks/facade/handle.rb +34 -121
  151. data/lib/hecks/facade/json_door.rb +31 -146
  152. data/lib/hecks/facade/surface/aggregate_door.rb +39 -104
  153. data/lib/hecks/facade/surface/chapter.rb +10 -54
  154. data/lib/hecks/facade/surface.rb +8 -23
  155. data/lib/hecks/facade.rb +10 -25
  156. data/lib/hecks/forms/app.rb +15 -70
  157. data/lib/hecks/forms/command_form_renderer.rb +10 -29
  158. data/lib/hecks/forms/field_renderer.rb +17 -156
  159. data/lib/hecks/forms/field_shape.rb +30 -222
  160. data/lib/hecks/forms/html.rb +12 -47
  161. data/lib/hecks/forms/index_renderer.rb +1 -4
  162. data/lib/hecks/forms/page.rb +3 -9
  163. data/lib/hecks/forms/params.rb +14 -60
  164. data/lib/hecks/forms/port_argument.rb +2 -19
  165. data/lib/hecks/forms/query_form_renderer.rb +4 -79
  166. data/lib/hecks/forms/record_renderer.rb +8 -75
  167. data/lib/hecks/forms/record_table.rb +7 -50
  168. data/lib/hecks/forms/reference_options.rb +3 -30
  169. data/lib/hecks/forms/value_object_shape.rb +8 -35
  170. data/lib/hecks/forms.rb +5 -33
  171. data/lib/hecks/fqn.rb +5 -12
  172. data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
  173. data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
  174. data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
  175. data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
  176. data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
  177. data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
  178. data/lib/hecks/framework.rb +11 -80
  179. data/lib/hecks/freezer.rb +5 -39
  180. data/lib/hecks/grammar/expression.bluebook +15 -40
  181. data/lib/hecks/grammar/translation.bluebook +3 -6
  182. data/lib/hecks/grammar.rb +16 -41
  183. data/lib/hecks/ir.rb +14 -83
  184. data/lib/hecks/language/adapter.bluebook +2 -7
  185. data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
  186. data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
  187. data/lib/hecks/language/bluebook/bluebook.bluebook +15 -83
  188. data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
  189. data/lib/hecks/language/bluebook/command.bluebook +27 -144
  190. data/lib/hecks/language/bluebook/entity.bluebook +24 -97
  191. data/lib/hecks/language/bluebook/policy.bluebook +16 -67
  192. data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
  193. data/lib/hecks/language/bluebook/projection.bluebook +126 -60
  194. data/lib/hecks/language/bluebook/query.bluebook +12 -43
  195. data/lib/hecks/language/bluebook/shape.bluebook +23 -73
  196. data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
  197. data/lib/hecks/language/bluebook/vocabulary.bluebook +98 -197
  198. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
  199. data/lib/hecks/language/hecksagon/domain_port.bluebook +4 -19
  200. data/lib/hecks/language/hecksagon/hecksagon.bluebook +6 -25
  201. data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
  202. data/lib/hecks/language/oidc.json +35 -0
  203. data/lib/hecks/language/port.bluebook +4 -17
  204. data/lib/hecks/language/translation/translation.bluebook +3 -9
  205. data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
  206. data/lib/hecks/language/world/wiring.bluebook +1 -3
  207. data/lib/hecks/language/world/world.bluebook +5 -7
  208. data/lib/hecks/literal.rb +8 -50
  209. data/lib/hecks/mcp_door_scope.rb +95 -0
  210. data/lib/hecks/mcp_stdio_guard.rb +4 -41
  211. data/lib/hecks/naming.rb +29 -137
  212. data/lib/hecks/ports/access_control.rb +7 -23
  213. data/lib/hecks/ports/agent/answers.rb +5 -23
  214. data/lib/hecks/ports/agent.rb +47 -172
  215. data/lib/hecks/ports/authentication.rb +12 -39
  216. data/lib/hecks/ports/authorization.rb +16 -43
  217. data/lib/hecks/ports/clock.rb +5 -45
  218. data/lib/hecks/ports/extraction.rb +7 -12
  219. data/lib/hecks/ports/identity_assignment.rb +8 -29
  220. data/lib/hecks/ports/identity_generation.rb +6 -29
  221. data/lib/hecks/ports/identity_resolution.rb +2 -10
  222. data/lib/hecks/ports/key_vault.rb +9 -45
  223. data/lib/hecks/ports/persistence/append_only.rb +62 -65
  224. data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
  225. data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
  226. data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
  227. data/lib/hecks/ports/persistence/plugin.rb +13 -42
  228. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +38 -141
  229. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
  230. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +16 -84
  231. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +7 -26
  232. data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +3 -22
  233. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
  234. data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
  235. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
  236. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
  237. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
  238. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
  239. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
  241. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +18 -75
  242. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
  243. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
  244. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
  245. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
  246. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
  247. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +14 -115
  248. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
  249. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +127 -554
  250. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
  251. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
  252. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
  253. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
  254. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
  255. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
  256. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +9 -25
  257. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +22 -122
  258. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
  259. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
  260. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
  261. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
  262. data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
  263. data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
  264. data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
  265. data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
  266. data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
  267. data/lib/hecks/ports/persistence/state_codec.rb +23 -103
  268. data/lib/hecks/ports/persistence.rb +7 -14
  269. data/lib/hecks/ports/projection.rb +42 -84
  270. data/lib/hecks/ports/query/in_memory.rb +10 -58
  271. data/lib/hecks/ports/query/ordering.rb +11 -32
  272. data/lib/hecks/ports/query.rb +14 -37
  273. data/lib/hecks/ports.rb +2 -8
  274. data/lib/hecks/projections/bootstrap_table.rb +11 -43
  275. data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
  276. data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
  277. data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
  278. data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
  279. data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
  280. data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
  281. data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
  282. data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
  283. data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
  284. data/lib/hecks/projections/deploy/fargate.rb +35 -202
  285. data/lib/hecks/projections/deploy/lambda.rb +151 -679
  286. data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
  287. data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
  288. data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
  289. data/lib/hecks/projections/deploy/preview/script.rb +2 -14
  290. data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
  291. data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
  292. data/lib/hecks/projections/deploy/preview/template.rb +2 -58
  293. data/lib/hecks/projections/deploy/preview.rb +2 -67
  294. data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
  295. data/lib/hecks/projections/deploy/scripts.rb +4 -57
  296. data/lib/hecks/projections/deploy/shared.rb +47 -146
  297. data/lib/hecks/projections/deploy/smoke.rb +4 -61
  298. data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
  299. data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
  300. data/lib/hecks/projections/deploy/template_diff.rb +5 -57
  301. data/lib/hecks/projections/diagrams.rb +20 -582
  302. data/lib/hecks/projections/glossary/html.rb +14 -130
  303. data/lib/hecks/projections/glossary/markdown.rb +8 -69
  304. data/lib/hecks/projections/glossary/mermaid.rb +9 -66
  305. data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
  306. data/lib/hecks/projections/glossary/sentences.rb +14 -159
  307. data/lib/hecks/projections/glossary.rb +30 -222
  308. data/lib/hecks/projections/ir.rb +3 -10
  309. data/lib/hecks/projections/model/deviations.rb +15 -42
  310. data/lib/hecks/projections/model.rb +12 -51
  311. data/lib/hecks/projections/oidc.rb +12 -56
  312. data/lib/hecks/projections/parser_table.rb +9 -28
  313. data/lib/hecks/projections/reference.rb +9 -16
  314. data/lib/hecks/projections/rust_vocabulary.rb +12 -250
  315. data/lib/hecks/projections/shape.rb +3 -29
  316. data/lib/hecks/projections/statements.rb +7 -86
  317. data/lib/hecks/projections/vocabulary.rb +6 -22
  318. data/lib/hecks/projections.rb +2 -16
  319. data/lib/hecks/projector/cli_projector.rb +60 -375
  320. data/lib/hecks/projector/docs_projector.rb +10 -201
  321. data/lib/hecks/projector/exporter.rb +46 -138
  322. data/lib/hecks/projector/ir_projector.rb +2 -9
  323. data/lib/hecks/projector/narrate_projector.rb +15 -189
  324. data/lib/hecks/projector/target.rb +13 -76
  325. data/lib/hecks/projector.rb +30 -121
  326. data/lib/hecks/query_specification/common/comparators.rb +5 -26
  327. data/lib/hecks/query_specification/common/comparison.rb +35 -143
  328. data/lib/hecks/query_specification/common/dsl.rb +8 -24
  329. data/lib/hecks/query_specification/common/null_policy.rb +20 -70
  330. data/lib/hecks/query_specification/common/options.rb +2 -6
  331. data/lib/hecks/query_specification/common/where_clause.rb +2 -10
  332. data/lib/hecks/query_specification/field_path.rb +37 -77
  333. data/lib/hecks/query_specification/hop_path.rb +12 -76
  334. data/lib/hecks/release/gem_pin.rb +2 -26
  335. data/lib/hecks/release/runner/ci_publisher.rb +93 -0
  336. data/lib/hecks/release/runner/commands.rb +66 -0
  337. data/lib/hecks/release/runner/console.rb +52 -0
  338. data/lib/hecks/release/runner/gem_publisher.rb +43 -0
  339. data/lib/hecks/release/runner/git.rb +48 -0
  340. data/lib/hecks/release/runner/npm_publisher.rb +75 -0
  341. data/lib/hecks/release/runner/preflight.rb +104 -0
  342. data/lib/hecks/release/runner/published.rb +55 -0
  343. data/lib/hecks/release/runner/tagger.rb +80 -0
  344. data/lib/hecks/release/runner.rb +215 -0
  345. data/lib/hecks/rendering.rb +4 -26
  346. data/lib/hecks/router/namespace_installer.rb +12 -36
  347. data/lib/hecks/router.rb +4 -8
  348. data/lib/hecks/runtime/aggregate_lock.rb +8 -33
  349. data/lib/hecks/runtime/boot_gates.rb +3 -18
  350. data/lib/hecks/runtime/caller.rb +19 -59
  351. data/lib/hecks/runtime/capability_graph.rb +5 -21
  352. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
  353. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +23 -160
  354. data/lib/hecks/runtime/command_interpreter.rb +125 -307
  355. data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
  356. data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
  357. data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
  358. data/lib/hecks/runtime/command_rules/emission.rb +8 -21
  359. data/lib/hecks/runtime/command_rules/references.rb +23 -202
  360. data/lib/hecks/runtime/dependency_planning.rb +30 -102
  361. data/lib/hecks/runtime/dispatcher.rb +82 -241
  362. data/lib/hecks/runtime/entity_element.rb +40 -462
  363. data/lib/hecks/runtime/entity_interpreter.rb +65 -220
  364. data/lib/hecks/runtime/errors.rb +32 -115
  365. data/lib/hecks/runtime/event.rb +3 -25
  366. data/lib/hecks/runtime/identity.rb +18 -154
  367. data/lib/hecks/runtime/instance.rb +18 -150
  368. data/lib/hecks/runtime/interpreting.rb +11 -70
  369. data/lib/hecks/runtime/invocation.rb +28 -164
  370. data/lib/hecks/runtime/loader.rb +48 -186
  371. data/lib/hecks/runtime/outbox.rb +38 -261
  372. data/lib/hecks/runtime/policy_interpreter.rb +38 -200
  373. data/lib/hecks/runtime/port_operation_interpreter.rb +26 -87
  374. data/lib/hecks/runtime/query_interpreter.rb +45 -187
  375. data/lib/hecks/runtime/reaction_invocation.rb +36 -138
  376. data/lib/hecks/runtime/read_model_interpreter.rb +139 -208
  377. data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
  378. data/lib/hecks/runtime/reference_hop.rb +8 -81
  379. data/lib/hecks/runtime/refusal_wording.rb +8 -89
  380. data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
  381. data/lib/hecks/runtime/registry/verification.rb +52 -225
  382. data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
  383. data/lib/hecks/runtime/registry.rb +103 -244
  384. data/lib/hecks/runtime/remote_dispatcher.rb +37 -152
  385. data/lib/hecks/runtime/routing.rb +4 -15
  386. data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
  387. data/lib/hecks/runtime/saga_interpreter.rb +79 -263
  388. data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
  389. data/lib/hecks/runtime/tenant_check.rb +6 -68
  390. data/lib/hecks/runtime/tenant_scope.rb +3 -28
  391. data/lib/hecks/runtime/value/admission.rb +16 -67
  392. data/lib/hecks/runtime/value/coercion.rb +155 -641
  393. data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
  394. data/lib/hecks/runtime/value.rb +12 -84
  395. data/lib/hecks/runtime.rb +17 -65
  396. data/lib/hecks/storehouse.rb +146 -567
  397. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +8 -32
  398. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
  399. data/lib/hecks/vendoring/git_environment.rb +2 -8
  400. data/lib/hecks/vendoring/git_source.rb +4 -10
  401. data/lib/hecks/vendoring.rb +7 -46
  402. data/lib/hecks/version.rb +3 -14
  403. data/lib/hecks/vocabulary.rb +5 -0
  404. data/lib/hecks.rb +32 -82
  405. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
  406. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
  407. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
  408. metadata +30 -59
  409. data/lib/hecks/bench/cli.rb +0 -74
  410. data/lib/hecks/bench/environment.rb +0 -100
  411. data/lib/hecks/bench/postgres_probe.rb +0 -41
  412. data/lib/hecks/bench/report.rb +0 -116
  413. data/lib/hecks/bench/ruby_runner.rb +0 -151
  414. data/lib/hecks/bench/run.rb +0 -55
  415. data/lib/hecks/bench/rust_runner.rb +0 -165
  416. data/lib/hecks/bench/stats.rb +0 -75
  417. data/lib/hecks/bench/suite.rb +0 -172
  418. data/lib/hecks/bench/workload.rb +0 -137
  419. data/lib/hecks/bench.rb +0 -28
  420. data/lib/hecks/codemod.rb +0 -443
  421. data/lib/hecks/corpus.rb +0 -479
  422. data/lib/hecks/doc/reference.rb +0 -585
  423. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -684
  424. data/lib/hecks/fuzzing/combination_miner.rb +0 -178
  425. data/lib/hecks/fuzzing/concurrent_dispatch.rb +0 -469
  426. data/lib/hecks/fuzzing/coverage_campaign.rb +0 -161
  427. data/lib/hecks/fuzzing/differential.rb +0 -192
  428. data/lib/hecks/fuzzing/domain_generator.rb +0 -871
  429. data/lib/hecks/fuzzing/era_boundary.rb +0 -154
  430. data/lib/hecks/fuzzing/form_census.rb +0 -285
  431. data/lib/hecks/fuzzing/generated_domain_check.rb +0 -171
  432. data/lib/hecks/fuzzing/invalid_value_generator.rb +0 -125
  433. data/lib/hecks/fuzzing/isolated_boot.rb +0 -658
  434. data/lib/hecks/fuzzing/nondeterministic.rb +0 -79
  435. data/lib/hecks/fuzzing/persistence_parity.rb +0 -253
  436. data/lib/hecks/fuzzing/properties/corrections.rb +0 -125
  437. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +0 -688
  438. data/lib/hecks/fuzzing/properties/guards.rb +0 -398
  439. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +0 -399
  440. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +0 -137
  441. data/lib/hecks/fuzzing/properties/outbox.rb +0 -180
  442. data/lib/hecks/fuzzing/properties/querying.rb +0 -260
  443. data/lib/hecks/fuzzing/properties.rb +0 -267
  444. data/lib/hecks/fuzzing/qa_settings.rb +0 -164
  445. data/lib/hecks/fuzzing/replay.rb +0 -930
  446. data/lib/hecks/fuzzing/rotation_priority.rb +0 -114
  447. data/lib/hecks/fuzzing/rust_gap_manifest.rb +0 -139
  448. data/lib/hecks/fuzzing/self_consistency.rb +0 -825
  449. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +0 -532
  450. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +0 -171
  451. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +0 -127
  452. data/lib/hecks/fuzzing/sequence_generator/picker.rb +0 -116
  453. data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +0 -138
  454. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +0 -344
  455. data/lib/hecks/fuzzing/sequence_generator.rb +0 -311
  456. data/lib/hecks/fuzzing/shrinker.rb +0 -309
  457. data/lib/hecks/fuzzing/structural_skips.rb +0 -53
  458. data/lib/hecks/fuzzing/sweep_depth.rb +0 -61
  459. data/lib/hecks/fuzzing/target_capabilities.rb +0 -255
  460. data/lib/hecks/fuzzing/value_generator.rb +0 -340
  461. data/lib/hecks/fuzzing.rb +0 -23
  462. data/lib/hecks/grammar/evolve.rb +0 -524
  463. data/lib/hecks/query_ir.rb +0 -482
@@ -6,103 +6,20 @@ require_relative "../naming"
6
6
 
7
7
  module Hecks
8
8
  module Runtime
9
- # **The transactional outbox** — the durable hand-off between "a command
10
- # committed" and "everything that was owed because it committed":
11
- # the policies that react to its events, the process managers that
12
- # advance on them, and (through a policy whose trigger is an
13
- # outbound port operation) the external effects those reactions
14
- # cause. `future-features.md` item 8, built.
15
- #
16
- # ## The shape
17
- #
18
- # One row per (event, consumer). A consumer is a named
19
- # policy or process manager that would react to the event — resolved
20
- # at enqueue time from the registry (`Fanout`), so the outbox records
21
- # who was owed what, not just that an event happened. Rows move
22
- # `pending → claimed → delivered | failed`:
23
- #
24
- # pending written in the same adapter transaction as the
25
- # aggregate save (`Interpreting#run_dispatch_order`
26
- # wraps `save` + `emit` + enqueue in `repository.
27
- # transaction`), so a row exists iff the state change
28
- # it reacts to committed — never one without the other.
29
- # claimed the relay is about to run this consumer. Set before
30
- # the reaction (a policy's `reenter`, a saga leg's
31
- # dispatch, an adapter call) runs.
32
- # delivered the consumer ran to completion — including the
33
- # "ran and was refused" case, which is a delivered
34
- # outcome the reaction log already records; the outbox
35
- # tracks delivery, not the domain's answer.
36
- # failed the consumer raised a defect (non-refusal error).
37
- #
38
- # ## Delivery is inline by default
39
- #
40
- # The dispatcher drains the rows it
41
- # just wrote, in the same call, in the order C10.2 fixes (per event
42
- # in `emits` order: that event's policy rows, then its saga rows —
43
- # the emitting domain's own policies before other domains'). Nothing about the
44
- # happy path is deferred or asynchronous; a caller still sees every
45
- # reaction settled when `dispatch` returns. What changes is the
46
- # crash window: without a durable row, a process that dies between
47
- # commit and reaction loses the reaction silently. The row survives,
48
- # and `Relay#redrive!` — run at boot by `Loader.run_boot_gates!` —
49
- # finds it.
50
- #
51
- # ## What redrive does, and deliberately doesn't
52
- #
53
- # A `pending` row is
54
- # redriven: its consumer provably never started (claiming is the
55
- # first thing delivery does), so running it now is exactly-once by
56
- # construction. A `claimed` row is not auto-redriven: the consumer
57
- # started and the crash hid its outcome — the same reasoning
58
- # `saga_pending_dispatch.rb` gives (a stalled transfer is a better
59
- # defect than a double-credited one). It is surfaced loudly
60
- # (`warn`, and a `stalled: true` entry in `Relay#log`) and left for
61
- # `Relay#redrive!(claimed: true)` — an explicit operator decision,
62
- # never a boot-time default. `delivery_id` (event uid + consumer) is
63
- # unique per store, so a re-enqueue of the same fact to the same
64
- # consumer is a no-op rather than a second row.
65
- #
66
- # ## Which adapters
67
- #
68
- # Memory (in-process rows — visible to specs,
69
- # gone with the process, exactly like everything else Memory holds),
70
- # Sqlite and Postgres (a `hecks_outbox` table in the aggregate's own
71
- # database — the only way the enqueue can share the save's
72
- # transaction). An adapter without the contract (`outbox_enqueue`/
73
- # `outbox_claim`/`outbox_settle`/`outbox_rows`) gets today's
74
- # behaviour unchanged — reactions run directly, nothing durable —
75
- # and `Registry::Verification#warn_undurable_outbox!` says so at
76
- # boot when the domain declares anything that would have needed it.
9
+ # A durable outbox (ADR 0053): one row per (event, consumer), written in
10
+ # the same transaction as the aggregate save so a reaction is never lost.
77
11
  module Outbox
12
+ # pending -> claimed -> delivered | failed
78
13
  STATUSES = %w[pending claimed delivered failed].freeze
79
14
 
80
15
  Row = Struct.new(:id, :delivery_id, :event_uid, :aggregate, :domain, :kind, :consumer, :event,
81
16
  :status, :attempts, :error, keyword_init: true) do
82
- # Reports whether this row is still waiting to be claimed.
83
- #
84
- # @return [Boolean] true if this row's status is `"pending"`
85
17
  def pending? = status == "pending"
86
-
87
- # Reports whether this row's consumer is currently running.
88
- #
89
- # @return [Boolean] true if this row's status is `"claimed"`
90
18
  def claimed? = status == "claimed"
91
-
92
- # Reports whether this row's consumer ran to completion.
93
- #
94
- # @return [Boolean] true if this row's status is `"delivered"`
95
19
  def delivered? = status == "delivered"
96
-
97
- # Reports whether this row's consumer raised a defect.
98
- #
99
- # @return [Boolean] true if this row's status is `"failed"`
100
20
  def failed? = status == "failed"
101
21
 
102
- # Wire-shaped — what an adapter persists. `event` is the event's
103
- # own `to_h` plus correlation; `Row.event_from` reverses it.
104
- #
105
- # @return [Hash{Symbol => Object}] this row's own fields, keyed by name
22
+ # Wire shape persisted by adapters; `Outbox.event_from` reverses it.
106
23
  def to_h
107
24
  { id: id, delivery_id: delivery_id, event_uid: event_uid, aggregate: aggregate, domain: domain,
108
25
  kind: kind, consumer: consumer, event: event, status: status, attempts: attempts, error: error }
@@ -114,34 +31,17 @@ module Hecks
114
31
 
115
32
  module_function
116
33
 
117
- # Renders an event as the wire-shaped Hash an outbox row's own `event`
118
- # field stores.
119
- #
120
- # @param event [Runtime::Event] the event to serialize
121
- # @return [Hash{Symbol => Object}] `event`'s own `to_h`, with `correlation`
122
- # merged in
123
34
  def serialize_event(event)
124
35
  event.to_h.merge(correlation: event.correlation)
125
36
  end
126
37
 
127
- # The emitting domain's own bluebook first, then the rest in load
128
- # order (C10.2) — the one policy ordering both `PolicyInterpreter#
129
- # policies_for` and `Fanout.policies` read.
130
- #
131
- # @param registry [Runtime::Registry] the booted registry whose loaded
132
- # bluebooks are ordered
133
- # @param domain [String, Symbol] the emitting domain, sorted first
134
- # @return [Array<Bluebook::Chapter>] every loaded chapter, `domain`'s own first
38
+ # Emitting domain's own bluebook first, then load order (C10.2) — the
39
+ # same order `PolicyInterpreter#policies_for` and `Fanout.policies` use.
135
40
  def bluebooks_home_first(registry, domain)
136
41
  home, others = registry.bluebooks.each_value.partition { |bluebook| bluebook.name == domain }
137
42
  home + others
138
43
  end
139
44
 
140
- # Rebuilds a frozen event from an outbox row's own stored `event` field.
141
- #
142
- # @param hash [Hash{String, Symbol => Object}] the wire-shaped event Hash,
143
- # as `serialize_event` built it (String or Symbol keys either way)
144
- # @return [Runtime::Event] the rebuilt, frozen event
145
45
  def event_from(hash)
146
46
  hash = hash.transform_keys(&:to_sym)
147
47
  Event.new(
@@ -154,12 +54,6 @@ module Hecks
154
54
  ).emit!
155
55
  end
156
56
 
157
- # Recursively symbolizes every Hash key reachable from `value`.
158
- #
159
- # @param value [Object] the value to symbolize; typically a Hash or Array,
160
- # possibly nested
161
- # @return [Object] `value` with every Hash key (at any depth) turned into a
162
- # Symbol; a non-Hash, non-Array value passes through unchanged
163
57
  def deep_symbolize(value)
164
58
  case value
165
59
  when Hash then value.to_h { |k, v| [k.to_sym, deep_symbolize(v)] }
@@ -168,28 +62,14 @@ module Hecks
168
62
  end
169
63
  end
170
64
 
171
- # **Who is owed what** — the same selection `PolicyInterpreter#policies_for`
172
- # and `SagaInterpreter#advance` make at delivery time, made once at
173
- # enqueue time so the row names its consumer. Policy rows first,
174
- # then saga rows, event order preserved within each: exactly the
175
- # order `Dispatcher#dispatch` always ran them in.
65
+ # Resolves each event's consumers once, at enqueue time, in the same
66
+ # order a direct dispatch would react to them (policies then sagas).
176
67
  module Fanout
177
68
  module_function
178
69
 
179
- # One UID per event for this enqueue — the Event struct is
180
- # frozen after `emit!`, so the uid lives on the rows rather than
181
- # on it (and stays off `Event#to_h`, whose shape the golden and
182
- # parity specs pin). Policy and saga rows for the same event
183
- # share it, which is what makes `delivery_id` mean "this fact,
184
- # this consumer".
185
- # Row order is delivery order (C10.2): per event, in `emits`
186
- # order — that event's policy rows, then its saga rows.
187
- #
188
- # @param registry [Runtime::Registry] the booted registry every candidate
189
- # consumer is resolved against
190
- # @param events [Array<Runtime::Event>] the just-emitted events to build rows for
191
- # @param domain [String, Symbol] the emitting domain
192
- # @return [Array<Runtime::Outbox::Row>] one pending row per (event, consumer)
70
+ # One UID per event, kept off `Event#to_h` (parity/golden specs pin
71
+ # its shape) — policy and saga rows for the same event share it, which
72
+ # is what makes `delivery_id` mean "this fact, this consumer".
193
73
  def rows_for(registry, events, domain)
194
74
  uids = events.to_h { |event| [event, SecureRandom.uuid] }
195
75
  events.flat_map do |event|
@@ -197,16 +77,6 @@ module Hecks
197
77
  end
198
78
  end
199
79
 
200
- # Builds one pending row per policy `event` triggers.
201
- #
202
- # @param registry [Runtime::Registry] the booted registry policies are
203
- # resolved against
204
- # @param event [Runtime::Event] the just-emitted event
205
- # @param domain [String, Symbol] the emitting domain
206
- # @param uid [String] this event's own enqueue-time UID, shared by every row
207
- # built for it
208
- # @return [Array<Runtime::Outbox::Row>] one pending row per matching policy,
209
- # emitting domain's own bluebook first
210
80
  def policies(registry, event, domain, uid)
211
81
  emitting = Naming.demodulise(event.aggregate)
212
82
  Outbox.bluebooks_home_first(registry, domain).flat_map do |bluebook|
@@ -222,18 +92,7 @@ module Hecks
222
92
  end
223
93
  end
224
94
 
225
- # Builds one pending row per process manager `event` advances, in `domain`
226
- # only (a saga never reacts across domains).
227
- #
228
- # @param registry [Runtime::Registry] the booted registry process managers
229
- # are resolved against
230
- # @param event [Runtime::Event] the just-emitted event
231
- # @param domain [String, Symbol] the domain whose declared process managers
232
- # are checked
233
- # @param uid [String] this event's own enqueue-time UID, shared by every row
234
- # built for it
235
- # @return [Array<Runtime::Outbox::Row>] one pending row per process manager
236
- # `event` starts, ends, or advances
95
+ # A saga only ever reacts within its own domain.
237
96
  def sagas(registry, event, domain, uid)
238
97
  bluebook = registry.bluebook(domain)
239
98
  return [] unless bluebook
@@ -245,30 +104,14 @@ module Hecks
245
104
  end
246
105
  end
247
106
 
248
- # Reports whether `event` starts, ends, or advances `process_manager`.
249
- #
250
- # @param process_manager [Bluebook::ProcessManager] the declared process
251
- # manager to check
252
- # @param event [Runtime::Event] the just-emitted event
253
- # @return [Boolean] true if `event` names `process_manager`'s own
254
- # `starts_on`, `ends_on`, or a declared handler
255
107
  def listens?(process_manager, event)
256
108
  process_manager.starts_on == event.name || process_manager.ends_on == event.name ||
257
109
  !process_manager.handler_for(event.name).nil?
258
110
  end
259
111
 
260
- # An "effect" is a reaction whose trigger is an outbound port
261
- # operation — the row is the durable record that an external
262
- # call was owed, claimed right before the adapter is asked and
263
- # settled right after. Everything else is a plain "reaction".
264
- #
265
- # @param registry [Runtime::Registry] the booted registry the trigger's own
266
- # aggregate/port are resolved against
267
- # @param policy [Bluebook::Policy] the policy whose trigger is classified
268
- # @param home_domain [String, Symbol] the domain `policy` is declared in,
269
- # used when `policy` declares no `target_domain`
270
- # @return [String] `"effect"` when the trigger resolves to an outbound port
271
- # operation, `"reaction"` otherwise
112
+ # An "effect" is a reaction whose trigger resolves to an outbound port
113
+ # operation, claimed right before the adapter call and settled right
114
+ # after; everything else is a plain "reaction".
272
115
  def kind_for(registry, policy, home_domain)
273
116
  target = "#{policy.target_domain || home_domain}::#{policy.trigger_command}"
274
117
  parsed = Naming.split_verb(target)
@@ -284,65 +127,31 @@ module Hecks
284
127
  end
285
128
  end
286
129
 
287
- # **The relay** — one per `Dispatcher`. Enqueues into a repository's
288
- # store, drains rows inline, and redrives what a previous process
289
- # left behind.
130
+ # One per Dispatcher: enqueues rows into a repository's outbox, drains
131
+ # them inline, and redrives whatever a crash left behind.
290
132
  class Relay
291
133
  attr_reader :registry, :log
292
134
 
293
- # Not `saga_log`/`reaction_log` — those are ported byte-for-byte
294
- # by the Rust kernel (`spec/rust_conformance_spec.rb`); this is
295
- # an additive, Ruby-only log, the same rule `saga_dispatch_log`
296
- # and `policy_dispatch_log` already follow.
297
- #
298
- # @param registry [Runtime::Registry] the booted registry this relay drains
299
- # rows for
135
+ # Additive and Ruby-only, unlike `saga_log`/`reaction_log`, which the
136
+ # Rust kernel ports byte-for-byte (spec/rust_conformance_spec.rb).
300
137
  def initialize(registry)
301
138
  @registry = registry
302
139
  @log = []
303
140
  end
304
141
 
305
- # Attaches the interpreters a delivered row's own consumer runs through.
306
- #
307
- # A Dispatcher hands over the interpreters a consumer runs
308
- # through (`Dispatcher#initialize`). Until then this relay can
309
- # enqueue (that needs only the registry) but not deliver — and
310
- # nothing can dispatch without a dispatcher, so nothing asks it
311
- # to. The registry holds one relay for its lifetime; a second
312
- # dispatcher fronting the same registry re-attaches, which is
313
- # fine because both dispatchers share every log and store.
314
- #
315
- # @param policies [Runtime::PolicyInterpreter] the interpreter a `"policy:"`
316
- # consumer reacts through
317
- # @param sagas [Runtime::SagaInterpreter] the interpreter a `"saga:"` consumer
318
- # advances through
319
- # @return [Runtime::Outbox::Relay] self
142
+ # Re-attaching (a second Dispatcher fronting the same registry) is
143
+ # safe: both dispatchers share this relay's log and every store.
320
144
  def attach(policies:, sagas:)
321
145
  @policies = policies
322
146
  @sagas = sagas
323
147
  self
324
148
  end
325
149
 
326
- # Reports whether a dispatcher has attached its interpreters.
327
- #
328
- # @return [Boolean] true once `attach` has run
329
150
  def attached? = !@policies.nil?
330
151
 
331
- # Writes one pending row per (event, consumer) `events` owes a reaction to.
332
- #
333
- # Called inside the save transaction by `Interpreting` for the
334
- # command/entity paths, and outside one by `Dispatcher` for port
335
- # operations (which save nothing, so there is no transaction to
336
- # share). Returns the rows as stored (ids assigned), or nil when
337
- # the repository has no outbox — the dispatcher then reacts
338
- # directly, exactly as before.
339
- #
340
- # @param repository [Persistence::AppendOnly] the repository whose store the
341
- # rows are enqueued into; a no-op unless it has an outbox
342
- # @param events [Array<Runtime::Event>] the events this dispatch just emitted
343
- # @param domain [String, Symbol] the emitting domain
344
- # @return [Array<Runtime::Outbox::Row>, nil] the stored rows, `id` assigned;
345
- # `nil` when `repository` has no outbox; `[]` when `events` is empty
152
+ # Called inside the save transaction for command/entity paths, and
153
+ # outside one for port operations (which save nothing). Returns nil
154
+ # when the repository has no outbox — callers then react directly.
346
155
  def enqueue(repository, events, domain)
347
156
  return nil unless repository.outbox?
348
157
  return [] if events.empty?
@@ -352,22 +161,12 @@ module Hecks
352
161
  repository.outbox_enqueue(rows)
353
162
  end
354
163
 
355
- # Drain the rows a dispatch just committed. `rows` nil means "no
356
- # outbox here" — react directly, the pre-outbox path.
357
- #
358
- # @param rows [Array<Runtime::Outbox::Row>, nil] the just-enqueued rows to
359
- # deliver; nil to react directly instead (no outbox on this repository)
360
- # @param events [Array<Runtime::Event>] the events this dispatch just emitted,
361
- # read when `rows` is nil
362
- # @param domain [String, Symbol] the emitting domain
363
- # @param repository [Persistence::AppendOnly] the repository `rows` were
364
- # enqueued into
365
- # @return [void]
164
+ # `rows` nil means no outbox on this repository — react directly,
165
+ # the pre-outbox path.
366
166
  def deliver(rows, events, domain, repository)
367
167
  if rows.nil?
368
168
  # Per event, in `emits` order — its policies, then its sagas
369
- # (C10.2, docs/semantics/bluebook-semantics.md); the same
370
- # order `Fanout.rows_for` lays the outbox rows in.
169
+ # (C10.2, docs/semantics/bluebook-semantics.md).
371
170
  events.each do |event|
372
171
  @policies.react(event, domain)
373
172
  @sagas.advance(event, domain)
@@ -378,13 +177,8 @@ module Hecks
378
177
  rows.each { |row| deliver_row(row, repository) }
379
178
  end
380
179
 
381
- # One row: claim, run its consumer, settle. A claim that fails
382
- # means another relay (or this one, re-entrantly) already has it.
383
- #
384
- # @param row [Runtime::Outbox::Row] the row to claim and deliver
385
- # @param repository [Persistence::AppendOnly] the repository `row` is stored in
386
- # @return [Boolean] true when this call claimed and delivered `row`; false
387
- # when the claim failed, or the consumer raised a defect (recorded on `log`)
180
+ # Claim, run the consumer, then settle. A failed claim means another
181
+ # relay already has this row.
388
182
  def deliver_row(row, repository)
389
183
  return false unless repository.outbox_claim(row.id)
390
184
 
@@ -395,11 +189,9 @@ module Hecks
395
189
  row.status = "delivered"
396
190
  true
397
191
  rescue StandardError => e
398
- # A DOMAIN_REFUSAL never reaches here — PolicyInterpreter and
192
+ # A DOMAIN_REFUSAL never reaches here (PolicyInterpreter and
399
193
  # SagaInterpreter both rescue it as a recorded, undelivered
400
- # reaction. Anything that does reach here is a defect in the
401
- # relay's own path (a consumer that no longer exists, an
402
- # adapter that raised outside the interpreters' own rescue).
194
+ # reaction) — anything here is a defect in the relay's own path.
403
195
  repository.outbox_settle(row.id, status: "failed", error: "#{e.class}: #{e.message}")
404
196
  row.status = "failed"
405
197
  row.error = "#{e.class}: #{e.message}"
@@ -409,25 +201,14 @@ module Hecks
409
201
  end
410
202
  end
411
203
 
412
- # Every row in every bound store, newest last. `status:` narrows.
413
- #
414
- # @param status [String, Symbol, nil] keep only rows with this status; nil
415
- # for every row
416
- # @return [Array<Runtime::Outbox::Row>] copies of the matching rows, across
417
- # every store with an outbox
204
+ # Every row across every bound store, newest last.
418
205
  def rows(status: nil)
419
206
  stores.flat_map { |repository| repository.outbox_rows(status: status) }
420
207
  end
421
208
 
422
- # Runs the boot-time reconciliation over every bound store.
423
- #
424
- # **Boot-time reconciliation**. Redrives `pending` rows (never
425
- # claimed — safe by construction); surfaces `claimed` rows and
426
- # redrives them only when told to (`claimed: true`).
427
- #
428
- # @param claimed [Boolean] whether to also redrive `claimed` rows (an
429
- # explicit operator decision); false leaves them surfaced and untouched
430
- # @return [Array<Runtime::Outbox::Row>] every row this call actually delivered
209
+ # `pending` rows are always safe to redrive (never claimed yet).
210
+ # `claimed` rows are only surfaced — redelivering a maybe-already-run
211
+ # consumer needs an explicit `claimed: true`.
431
212
  def redrive!(claimed: false)
432
213
  redriven = []
433
214
  stores.each do |repository|
@@ -480,13 +261,9 @@ module Hecks
480
261
  event: row.event[:name], aggregate: row.event[:aggregate], id: row.event[:id] }
481
262
  end
482
263
 
483
- # Every repository the registry can resolve, one per (domain,
484
- # aggregate), keeping only those with an outbox. Bluebooks, not
485
- # hecksagons: a domain with no hecksagon at all is bound to the
486
- # default adapter (Memory), which has one. An aggregate a
487
- # hecksagon deliberately left unbound raises WiringError from
488
- # `repository` and is skipped — the same "forgotten decision"
489
- # rule dispatch itself applies, not softened here.
264
+ # Bluebooks, not hecksagons: a domain with no hecksagon is still
265
+ # bound to the default Memory adapter. An aggregate a hecksagon left
266
+ # unbound raises WiringError here and is skipped.
490
267
  def stores
491
268
  @registry.bluebooks.each_value.flat_map do |bluebook|
492
269
  bluebook.aggregates.filter_map do |aggregate|