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
@@ -4,35 +4,19 @@ module Hecks
4
4
  module Bluebook
5
5
  module Behaviour
6
6
  # What an aggregate does, as opposed to what it holds.
7
- #
8
- # The holding half — the field list, the readers, the emission — is
9
- # the same list the language already declares in
10
- # `language/bluebook/aggregate.bluebook`, said a second and third
11
- # time in Ruby. This half is not: derived identity, the name
12
- # indexes, the owner stamping and the finders are decisions about
13
- # how the declared shape is used, and no grammar states them.
14
- #
15
- # Split so the holding half can be generated from the language
16
- # without any of this being in the blast radius of a regeneration.
17
- # Everything here is hand-written and permanent.
18
- #
19
- # The three traits are shared with Entity (and, for `Indexed`,
20
- # with Command and PortOperation) — see behaviour/traits.rb on why
21
- # they are one module rather than four copies.
7
+ # Hand-written, so regenerating the declared field list never touches it.
22
8
  module Aggregate
23
9
  include Identified
24
10
  include Indexed
25
11
  include Owns
26
12
 
27
- # An aggregate is a member of its chapter's namespace — "Pizzas::Pizza" —
28
- # where everything else is declared on its owner and joins with ".".
13
+ # An aggregate joins its chapter's namespace with "::" ("Pizzas::Pizza");
14
+ # everything else joins its owner with ".".
29
15
  #
30
16
  # @return [String] the literal string `"::"`
31
17
  def hecks_separator = "::"
32
18
 
33
- # The hook the generated constructor calls once every declared
34
- # field is assigned. Nothing here is derivable from the
35
- # declaration, which is exactly why it is not generated.
19
+ # The hook the generated constructor calls once every declared field is assigned.
36
20
  #
37
21
  # @return [Bluebook::Aggregate] self, once identity is derived, every
38
22
  # declaration is indexed and its commands, value objects, entities and
@@ -40,8 +24,7 @@ module Hecks
40
24
  def settle
41
25
  derive_identity
42
26
  index_declarations
43
- # An entity stamps its own commands and queries when it is
44
- # declared, so the chain closes downward from here.
27
+ # An entity stamps its own commands and queries when declared.
45
28
  stamp(@commands, @value_objects, @entities, @queries)
46
29
  self
47
30
  end
@@ -56,10 +39,7 @@ module Hecks
56
39
  @commands_by_name = index_by_hecks_name(@commands)
57
40
  @queries_by_name = index_by_hecks_name(@queries)
58
41
  @ports_by_name = @ports.to_h { |port| [port.name, port] }
59
- # S12, ADR 0025 — keyed by symbol, the same convention
60
- # `Indexed#attribute` already uses; `GuardState` asks for one
61
- # by name at every dispatch, the rebuild sweep walks all of
62
- # them once per pass.
42
+ # Keyed by symbol, like `Indexed#attribute` (ADR 0025).
63
43
  @projected_fields_by_name = @projected_fields.to_h { |field| [field.name, field] }
64
44
  end
65
45
 
@@ -70,11 +50,7 @@ module Hecks
70
50
  # `nil` if none is declared under that name
71
51
  def projected_field(named) = @projected_fields_by_name[named.to_sym]
72
52
 
73
- # A value object is a class now, so `name` is Ruby's answer (the constant
74
- # path) and the declared name is `hecks_name`. This finder is on its way
75
- # out — once an attribute's type is the class there is nothing to find —
76
- # but every consumer still asks by type string, so it stays until they
77
- # stop.
53
+ # Finds a value object by declared name; `name` on the class is the constant path.
78
54
  #
79
55
  # @param named [String, Symbol] the value object's declared name
80
56
  # @return [Class, nil] the value object class (a `Bluebook::ValueObject`
@@ -88,14 +64,9 @@ module Hecks
88
64
  # none is attached under that name
89
65
  def port(named) = @ports_by_name[named.to_s]
90
66
 
91
- # A port is declared in the hecksagon, not the bluebook — the
92
- # boundary between the domain and its adapters, in hexagonal terms,
93
- # is exactly what a `.hecksagon` file already is for every other
94
- # port (persistence, projection, ...). So this attaches after the
95
- # aggregate already exists and is registered — `HecksagonBuilder`
96
- # calls it once per `port` declaration, having already stamped each
97
- # operation's reference attributes with `declared_in = self`, since
98
- # nothing upstream of a hecksagon load does that for it.
67
+ # Attaches a port declared in the hecksagon, after the aggregate exists.
68
+ # `HecksagonBuilder` stamps each operation's reference attributes with
69
+ # `declared_in = self` before calling it.
99
70
  #
100
71
  # @param port [Bluebook::DomainPort] the aggregate-scoped port to attach
101
72
  # @return [void]
@@ -1,10 +1,7 @@
1
1
  module Hecks
2
2
  module Bluebook
3
3
  module Behaviour
4
- # **What an attribute does**. The declared half — name, type, list,
5
- # default, optional, pattern, admits — is what the language states
6
- # in `aggregate.bluebook`'s own `Field`. These are the questions
7
- # readers ask about that shape, which no declaration states.
4
+ # **What an attribute does**: the questions readers ask about its declared shape.
8
5
  module Attribute
9
6
  # Says whether this attribute was declared `list`.
10
7
  #
@@ -21,16 +18,8 @@ module Hecks
21
18
  # @return [Boolean] whether this attribute's type is a `reference_to` another aggregate
22
19
  def reference? = @type.is_a?(Reference)
23
20
 
24
- # May this fact be left out?
25
- #
26
- # Required is the default and by far the common case — a command takes
27
- # the arguments it declares, and all of them — so the exception is what
28
- # gets marked. Marking the other way would annotate almost every
29
- # attribute in the corpus to say nothing.
30
- #
31
- # Only a command enforces this. An aggregate's own attributes are filled
32
- # by the commands that set them, and a value object's by its
33
- # constructor ; neither is a payload anyone hands in.
21
+ # May this fact be left out? Required is the default; only a command enforces
22
+ # this, since aggregate and value object attributes are not caller payloads.
34
23
  #
35
24
  # @return [Boolean] whether a command may omit this attribute from its payload
36
25
  def optional? = @optional
@@ -3,22 +3,15 @@ require_relative "traits"
3
3
  module Hecks
4
4
  module Bluebook
5
5
  module Behaviour
6
- # **What a chapter does**. The declared half is the roll-call of what a
7
- # bluebook holds; these are the finders over it, plus `verbs` — the
8
- # chapter's own list of every dispatchable name, which is derived
9
- # from the aggregates rather than declared anywhere.
6
+ # What a chapter does. The declared half is the roll-call of what a
7
+ # bluebook holds; these are the finders over it, plus `verbs`.
10
8
  module Chapter
11
9
  include Owns
12
10
 
13
- # The hook the generated constructor calls. Three things a
14
- # declaration does not state: that a chapter is the root of the
15
- # owner chain (nothing declares it, it is what having no owner
16
- # means), the ports table — which a `.hecksagon` fills later, so
17
- # the bluebook cannot declare it — and stamping its own children,
18
- # the same act an Aggregate performs one level down.
11
+ # Marks this chapter the root of the owner chain, attaches the ports
12
+ # table (filled later by a `.hecksagon`), and stamps ownership.
19
13
  #
20
- # @return [Bluebook::Chapter] self, once root marking, the ports table and ownership
21
- # stamping are all set up
14
+ # @return [Bluebook::Chapter] self
22
15
  def settle
23
16
  @hecks_root = true
24
17
  @ports = []
@@ -47,11 +40,7 @@ module Hecks
47
40
  # by that name
48
41
  def port(named) = @ports_by_name[named.to_s]
49
42
 
50
- # What this chapter declared it provides — `{ key => local verb }`
51
- # for one capability, or nil when it declares none. Read by
52
- # everything that resolves a capability's provider from what a
53
- # chapter declares, rather than from the chapter's own name
54
- # (`Registry#authorization_provider_for`).
43
+ # What this chapter declared it provides for one capability.
55
44
  #
56
45
  # @param capability [String, Symbol] the capability's name, such as
57
46
  # `Bluebook::Capabilities::AUTHORIZATION`
@@ -80,9 +69,8 @@ module Hecks
80
69
  local && "#{name}::#{local}"
81
70
  end
82
71
 
83
- # A port is declared in the hecksagon, not the bluebook — so it
84
- # attaches after the chapter already exists, the same way an
85
- # aggregate's own ports do.
72
+ # A port attaches after the chapter already exists, once its
73
+ # hecksagon is built — the same way an aggregate's own ports do.
86
74
  #
87
75
  # @param port [Bluebook::DomainPort] the operations-shaped port to attach
88
76
  # @return [void]
@@ -91,33 +79,20 @@ module Hecks
91
79
  @ports_by_name[port.name] = port
92
80
  end
93
81
 
94
- # A TRANSLATED REACTION IS ALSO DECLARED IN THE HECKSAGON —
95
- # `HecksagonBuilder#translates` builds an ordinary `Policy` (same
96
- # shape, same `PolicyInterpreter` runtime, as one written inside a
97
- # `policy` block in this chapter's own `.bluebook`) and attaches it
98
- # here, after the chapter already exists, the same reasoning
99
- # `add_port` gives one method up. Kept out of the bluebook itself
100
- # on purpose: which FOREIGN domain's event this chapter reacts to
101
- # is a wiring/context-mapping decision, not a fact the domain
102
- # states about its own model.
82
+ # A translated reaction also attaches after the chapter already
83
+ # exists: which foreign domain's event it reacts to is a wiring
84
+ # decision, not a fact the domain states about its own model.
85
+ #
86
+ # @param policy [Bluebook::Policy] the translated reaction to attach
87
+ # @return [Array<Bluebook::Policy>] this chapter's policies, with `policy` appended
103
88
  def add_policy(policy)
104
89
  @policies << policy
105
90
  end
106
91
 
107
92
  # Every dispatchable name this chapter answers to, spelled exactly
108
- # as Dispatcher#dispatch takes it. Derived from the aggregates,
109
- # never declared — which is why Projections::OIDC can hold its own
110
- # scope list equal to this and have that mean something.
111
- #
112
- # Recurses into entities, not just an aggregate's own direct
113
- # commands — `Dispatcher#dispatch` already routes a dotted
114
- # `Domain::Aggregate.Entity.Command` verb to `EntityInterpreter`
115
- # (a command_name with a "." in it), so a verb this method left
116
- # out was never "not a verb," only one this list forgot to name.
117
- # Ported from the same recursive shape `spec/judge_coverage_spec.rb`
118
- # already proved out for the meta-domain's own grammar (S17, ADR
119
- # 0026) — entities nest arbitrarily deep (`Dispatch`, inside
120
- # `Handler`), so one flat level isn't enough.
93
+ # as `Dispatcher#dispatch` takes it. Derived from the aggregates,
94
+ # never declared, and recurses into entities since a command can be
95
+ # nested arbitrarily deep.
121
96
  #
122
97
  # @return [Array<String>] every command verb reachable on this chapter, spelled
123
98
  # `"Domain::Aggregate.command"` or, nested, `"Domain::Aggregate.Entity.command"`
@@ -3,13 +3,11 @@ require_relative "traits"
3
3
  module Hecks
4
4
  module Bluebook
5
5
  module Behaviour
6
- # **What a command does**. Extended, not included — a command is a
7
- # class, one per declared verb.
6
+ # **What a command does**. Extended, not included: a command is a class per verb.
8
7
  module Command
9
8
  include Indexed
10
9
 
11
- # Indexed once — attributes are final once absorbed, and every
12
- # dispatch asks this finder by name.
10
+ # Indexes the attributes once; they are final once absorbed.
13
11
  #
14
12
  # @return [Class] self — the command class, once its attributes are
15
13
  # indexed
@@ -21,25 +19,15 @@ module Hecks
21
19
  # The construct this verb acts upon — the construct itself, not its name.
22
20
  #
23
21
  # A verb declared on an entity always acts on that piece. It never
24
- # self-references, because an element is addressed through its parent —
25
- # which means `creates?` answers true for every one of them, and reading
26
- # `acts_on` off `creates?` alone would report that `LedgerEntry.Amend`
27
- # brings a ledger entry into being. Three of banking's commands were
28
- # about to say exactly that, and nothing would have contradicted them.
29
- #
30
- # On an aggregate, a creating command acts on no existing root, so nil is
31
- # the truth: there is nothing there yet.
22
+ # self-references, so `creates?` is true for it and cannot decide this alone.
23
+ # A creating command on an aggregate acts on nothing yet, so nil.
32
24
  #
33
25
  # @return [Class, Bluebook::Aggregate, nil] the entity class (a
34
26
  # `Bluebook::Entity` subclass) this verb acts on when declared on an
35
27
  # entity, the aggregate instance when declared on an aggregate and
36
28
  # non-creating, or `nil` for a creating command
37
29
  def acts_on
38
- # Fully qualified, and it has to be: inside `module Behaviour`
39
- # the bare name `Entity` resolves to Behaviour::Entity — this
40
- # module's sibling — not to the construct. Comparing a Class to
41
- # a Module answers nil, so the guard silently fell through and
42
- # every entity verb reported acting on nothing.
30
+ # Fully qualified: a bare `Entity` here resolves to Behaviour::Entity, not the construct.
43
31
  return hecks_owner if hecks_owner.is_a?(Class) && hecks_owner < Bluebook::Entity
44
32
 
45
33
  creates? ? nil : hecks_owner
@@ -51,54 +39,18 @@ module Hecks
51
39
  # it declares no `reference_to` back to its own owner
52
40
  def creates? = @references.nil?
53
41
 
54
- # Every reason this verb can refuse on a rule — the descriptions of
55
- # its givens and its ensures, the exact text the runtime quotes
56
- # after "refused — " when a guard is not met (see
57
- # command_rules/admissibility.rb's GivenNotMet/EnsuresNotMet). A
58
- # property that asks "did the runtime only ever refuse for a rule
59
- # the language wrote" reads this rather than re-deriving the two
60
- # collections; `compact` because a rule's description is optional
61
- # (behavior.bluebook's Rule) and an unnamed one quotes nothing.
42
+ # Every reason this verb can refuse on a rule: the descriptions of its givens and
43
+ # ensures, as the runtime quotes them after "refused — ". Unnamed rules are skipped.
62
44
  #
63
45
  # @return [Array<String>] every named given's and ensure's own
64
46
  # description text, skipping unnamed rules
65
47
  def guard_descriptions = (@givens + @ensures).map(&:description).compact
66
48
 
67
- # The argument name that addresses an instance of `aggregate_name`
68
- # for this command — the one fact `PolicyInterpreter`'s own
69
- # `for_each` fan-out needs and, until this reading existed, had
70
- # to guess at (see git blame: `Behaviour::Policy
71
- # #fan_out_reference_key`, which hardcoded `<aggregate>_id`
72
- # unconditionally and refused every dispatch to a self-
73
- # addressing command as a result — `Account.Freeze`, addressed
74
- # by `number`/`account`, not `account_id`).
75
- #
76
- # Two shapes, the same two `CommandBuilder#reference_to` already
77
- # tells apart at declare time (command_builder.rb's own comment
78
- # on `cross_reference` — "`as:` means a named attribute... a
79
- # command can point at another instance of its own kind"):
80
- #
81
- # self-addressing — `references == aggregate_name` (this verb
82
- # is declared on the very aggregate it acts on, `reference_to
83
- # Account` on a command Account itself owns). No attribute was
84
- # minted for it at all; the same bare key
85
- # `CommandInterpreter::ArgumentGate#reference_key` already
86
- # accepts as "addressing, not describing" is reused here
87
- # rather than re-derived — one door, not two.
88
- #
89
- # cross-referencing — a real, declared reference-typed
90
- # attribute whose own target is `aggregate_name` (`customer_id`
91
- # on `Account.Open`, or whatever `as:` named it). Its name is
92
- # the key, exactly as declared — never re-derived from the
93
- # target's name, because an `as:` reference's name and its
94
- # target's snake case can legitimately differ (`Transfer`'s own
95
- # `source`/`destination`, both `Reference<Account>`).
49
+ # The argument name that addresses an instance of `aggregate_name` for this command.
96
50
  #
97
- # `nil` when neither shape matches — a creating command (nothing
98
- # to address yet) or one that simply never references this
99
- # aggregate at all. A caller minting a fan-out dispatch is
100
- # expected to treat `nil` as "this command cannot be addressed by
101
- # a row of this aggregate," not to fall back on a guess.
51
+ # Self-addressing commands (`references == aggregate_name`) use the bare reference
52
+ # key. Cross-referencing ones use the declared reference attribute's own name, never
53
+ # re-derived from the target, since `as:` names can differ.
102
54
  #
103
55
  # @param aggregate_name [String, Symbol] the aggregate a fan-out dispatch is
104
56
  # addressing an instance of
@@ -112,14 +64,10 @@ module Hecks
112
64
  end
113
65
  end
114
66
 
115
- # **A mutation's own readings**. Included (not extended) — Mutation is
116
- # a Struct, so these are instance methods.
67
+ # **A mutation's own readings**. Included, not extended: Mutation is a Struct.
117
68
  module Mutation
118
- # An append binds several fields at once, each from either a command
119
- # argument (a Symbol) or a literal. Spelled through `Literal.render`,
120
- # the same self-describing form a where-clause's own value already
121
- # uses, rather than a bare Symbol paired with an inspected literal —
122
- # see Hecks::Literal.
69
+ # An append binds several fields at once, each from a command argument (a Symbol)
70
+ # or a literal, spelled through `Literal.render`.
123
71
  #
124
72
  # @return [Hash{Symbol => String}] the append's field bindings, each
125
73
  # value rendered through `Literal.render`
@@ -13,16 +13,8 @@ module Hecks
13
13
  # @return [nil] always `nil`
14
14
  def references = nil
15
15
 
16
- # Never a creating command — a port operation always acts on an
17
- # aggregate that already exists (`operation.to`/`identity_attribute`
18
- # both name where its receiver comes from, never a birth). Answered
19
- # explicitly, not derived from `references` the way `Command
20
- # #creates?` is (`references.nil?` would read every operation as
21
- # creating, since `references` above is unconditionally nil) —
22
- # needed so `ReactionInvocation#source_receiver_for` can call
23
- # `target.command.creates?` on a port operation the same way it
24
- # already does on an ordinary command, and correctly lift a
25
- # same-aggregate policy's own Event.id as the operation's receiver.
16
+ # A port operation always acts on an existing aggregate. Answered explicitly
17
+ # because `references.nil?` would read every operation as creating.
26
18
  #
27
19
  # @return [Boolean] always `false`
28
20
  def creates? = false
@@ -37,16 +29,8 @@ module Hecks
37
29
  @attributes.find { |attribute| attribute.reference? && attribute.type.target_name == owner_name.to_s }
38
30
  end
39
31
 
40
- # The same reading `Command#addressing_key_for` gives, minus its
41
- # self-addressing branch — a port operation's `references` is
42
- # unconditionally nil (above), so it never means "this verb is
43
- # declared on the very aggregate it acts on" the way a command's
44
- # does; a port operation's only path back to its owner is a real,
45
- # declared reference-typed attribute, which is exactly what
46
- # `identity_attribute` already finds. Needed for the identical
47
- # reason `Command#addressing_key_for` is: `ReactionInvocation
48
- # #aggregate_aliases` calls it on whatever `target.command` holds,
49
- # a `PortOperation` now included since a policy can trigger one.
32
+ # Like `Command#addressing_key_for` without the self-addressing branch: the
33
+ # reference attribute is the only path back to the owner.
50
34
  #
51
35
  # @param aggregate_name [String, Symbol] the name of the aggregate a row of which
52
36
  # would address this operation
@@ -6,12 +6,8 @@ module Hecks
6
6
  # **What an entity does**. Extended, not included — an entity is a
7
7
  # class, so this is singleton behaviour.
8
8
  #
9
- # `settle` is the same seam an Aggregate has, reached from `absorb`
10
- # rather than from a constructor because a declared entity is built
11
- # by subclassing rather than by `new`. The traits are the same
12
- # ones, which is the whole point of them being traits: an entity's
13
- # identity is derived exactly as an aggregate's is, and was written
14
- # out twice before anyone could see that.
9
+ # `settle` is reached from `absorb` rather than a constructor, because a declared
10
+ # entity is built by subclassing.
15
11
  module Entity
16
12
  include Identified
17
13
  include Indexed
@@ -36,32 +32,16 @@ module Hecks
36
32
  @queries_by_name = index_by_hecks_name(@queries)
37
33
  end
38
34
 
39
- # S17, ADR 0026 — `@entities`, now genuinely nested entities
40
- # (Dispatch, inside Handler) rather than always `[]`. Kept as a
41
- # real reader rather than a hardcoded empty list for two
42
- # reasons at once: `Value::Coercion#for_attribute` calls
43
- # `.entities` on whatever owner it is handed — an aggregate's or
44
- # an entity's own — the moment it meets any `list_of(...)`
45
- # attribute (entity-typed or not — `hydrate_entity_list`'s own
46
- # fallback, `return value unless entity`, only runs once
47
- # `.entities` has already answered) ; and `EntityInterpreter`
48
- # now walks a dotted chain of entities one level at a time
49
- # (`walk_entity_chain`) exactly the way an aggregate's own
50
- # `.entities` is walked for its direct children. Entity's own
51
- # header comment already promises it stays "structurally
52
- # interchangeable with an aggregate" for exactly this reason.
35
+ # Nested entities, structurally interchangeable with an aggregate's `entities`:
36
+ # `Value::Coercion#for_attribute` and `EntityInterpreter` both read it (ADR 0026).
53
37
  #
54
38
  # @return [Array<Class>] this entity's own nested entities (each a `Bluebook::Entity`
55
39
  # subclass), or `[]` if it declares none
56
40
  def entities = @entities || []
57
41
 
58
- # A piece owns the verbs declared on it, so they can state an
59
- # identity — `Banking::Account.Ledger.Deposit` rather than a
60
- # command that cannot say what it belongs to. Separate from
61
- # `settle` because `declare` stamps after absorbing, once the
62
- # subclass that will own them exists. `@entities` too now
63
- # (S17, ADR 0026) — a nested entity states its own owner chain
64
- # exactly the way a nested command does.
42
+ # Stamps this entity as owner of its commands, queries and nested entities, so
43
+ # verbs read `Banking::Account.Ledger.Deposit`. Separate from `settle` because
44
+ # `declare` stamps after the owning subclass exists.
65
45
  #
66
46
  # @return [void]
67
47
  def stamp_children = stamp(@commands, @queries, @entities)
@@ -1,32 +1,26 @@
1
1
  module Hecks
2
2
  module Bluebook
3
3
  module Behaviour
4
- # **What a hecksagon does** — the lookups over its declared binds.
4
+ # Lookups over a hecksagon's declared binds.
5
5
  module Hecksagon
6
- # Aggregate-specific bind wins when one was declared; otherwise
7
- # falls back to a domain-level default (`b.aggregate.nil?` — see
8
- # `HecksagonBuilder#method_missing`). Checked directly rather than
9
- # via `aggregate_name`/`Naming.demodulise`, which would need its own
10
- # nil-handling for the default row.
6
+ # Finds the bind for an aggregate and verb, falling back to the domain-level default.
11
7
  #
12
- # @param aggregate_name [String, Symbol] the aggregate to find a bind for
13
- # @param verb [String, Symbol] the port verb name to find a bind for
14
- # @return [Bluebook::Bind, nil] the aggregate-specific bind when one is
15
- # declared, the domain-level default bind for `verb` otherwise, or
16
- # `nil` when neither exists
8
+ # The default row is matched with `b.aggregate.nil?` rather than via
9
+ # `aggregate_name`, which would need its own nil handling.
10
+ #
11
+ # @param aggregate_name [String, Symbol]
12
+ # @param verb [String, Symbol]
13
+ # @return [Bluebook::Bind, nil]
17
14
  def bind_for(aggregate_name, verb)
18
15
  @binds.find { |b| b.aggregate_name == aggregate_name.to_s && b.verb.to_s == verb.to_s } ||
19
16
  @binds.find { |b| b.aggregate.nil? && b.verb.to_s == verb.to_s }
20
17
  end
21
18
 
22
- # Every bind for `verb`, aggregate-specific ones winning as a group over
23
- # the domain-level default.
19
+ # Every bind for `verb`; aggregate-specific ones win as a group over the default.
24
20
  #
25
- # @param aggregate_name [String, Symbol] the aggregate to find binds for
26
- # @param verb [String, Symbol] the port verb name to find binds for
27
- # @return [Array<Bluebook::Bind>] every aggregate-specific bind for
28
- # `verb` when any are declared, otherwise every domain-level default
29
- # bind for `verb`
21
+ # @param aggregate_name [String, Symbol]
22
+ # @param verb [String, Symbol]
23
+ # @return [Array<Bluebook::Bind>]
30
24
  def binds_for(aggregate_name, verb)
31
25
  specific = @binds.select { |b| b.aggregate_name == aggregate_name.to_s && b.verb.to_s == verb.to_s }
32
26
  return specific if specific.any?
@@ -35,34 +29,22 @@ module Hecks
35
29
  end
36
30
  end
37
31
 
38
- # **What a world does** — settings lookup, with the adapter-specific
39
- # entry falling back to the verb's own.
32
+ # Settings lookup for a world, with adapter-specific entries falling back to the verb's own.
40
33
  module World
41
- # Finds the generic settings declared for a port verb.
34
+ # The settings declared for a port verb.
42
35
  #
43
- # @param verb [String, Symbol] the port verb name, such as `"persistence"`
44
- # @return [Hash{Symbol => Object}] the settings declared for `verb`, or
45
- # `{}` when none are declared
36
+ # @param verb [String, Symbol] such as `"persistence"`
37
+ # @return [Hash{Symbol => Object}] empty when none are declared
46
38
  def for_verb(verb) = @settings.fetch(verb.to_s, {})
47
39
 
48
- # The generic `verb` entry (`persisted_by("Heki") do dir :default
49
- # end`) only answers for the adapter it actually names — falling
50
- # back to it unconditionally applies one adapter's settings to an
51
- # unrelated one. Real, corpus-caught bug: a hecksagon binding two
52
- # aggregates to two different adapters under the same verb (one to
53
- # Heki, one to Memory) sent Memory's lookup down Heki's generic
54
- # entry, then failed `check_settings` with "Memory does not
55
- # declare :dir" — the generic entry's own `settings[:adapter]`
56
- # names Heki, not Memory, so the fallback was never actually for
57
- # this bind. `{}` is exactly right when nothing was configured for
58
- # this adapter — Memory, which takes no values at all.
40
+ # The generic verb entry only answers for the adapter it names. Falling back to it
41
+ # unconditionally would apply one adapter's settings (Heki's `dir`) to another
42
+ # (Memory), which then fails `check_settings`.
59
43
  #
60
- # @param verb [String, Symbol] the port verb name to find settings for
61
- # @param adapter [String, Symbol] the adapter name, such as `"Heki"`, to
62
- # find settings for
63
- # @return [Hash{Symbol => Object}] the adapter-qualified settings when
64
- # declared, the generic verb settings when they name this same
65
- # adapter, or `{}` otherwise
44
+ # @param verb [String, Symbol]
45
+ # @param adapter [String, Symbol] such as `"Heki"`
46
+ # @return [Hash{Symbol => Object}] the adapter-qualified settings, else the generic
47
+ # ones when they name this adapter, else `{}`
66
48
  def for_binding(verb, adapter)
67
49
  qualified = @settings["#{verb}:#{adapter.to_s.downcase}"]
68
50
  return qualified if qualified
@@ -1,50 +1,37 @@
1
1
  module Hecks
2
2
  module Bluebook
3
3
  module Behaviour
4
- # **What a lifecycle does**. Its declared half is a field, a starting
5
- # state and a transition list. Everything here reads that — which
6
- # states exist, which transition a command takes, and how one
7
- # declared transition expands into the several rows the emission
8
- # carries when `from` names more than one source state.
4
+ # Readings over a lifecycle's field, starting state and transition list.
9
5
  module Lifecycle
10
- # Lists every state this lifecycle can be in.
6
+ # Every state this lifecycle can be in.
11
7
  #
12
- # @return [Array<String>] every state this lifecycle can be in — the
13
- # default plus each declared transition's own target, deduplicated
8
+ # @return [Array<String>] the default plus each transition's target, deduplicated
14
9
  def states
15
10
  ([default] + transitions.map { |_command, t| t.target }).uniq
16
11
  end
17
12
 
18
- # Finds every transition a command declares.
13
+ # Every transition a command declares.
19
14
  #
20
- # @param command [String, Symbol] the command name to find declared
21
- # transitions for
22
- # @return [Array<Bluebook::StateTransition>] every transition declared
23
- # for `command`
15
+ # @param command [String, Symbol]
16
+ # @return [Array<Bluebook::StateTransition>]
24
17
  def transitions_for(command)
25
18
  transitions.select { |name, _| name == command.to_s }.map { |_, t| t }
26
19
  end
27
20
 
28
- # Finds the state a command moves the record to.
21
+ # The state a command moves the record to.
29
22
  #
30
- # @param command [String, Symbol] the command name to find the target
31
- # state for
32
- # @param current_state [String, Symbol, nil] the record's current
33
- # state, to pick the one declared transition that admits it; `nil`
34
- # to skip that check and take the first declared transition
35
- # @return [String, nil] the state `command` moves the record to, or
36
- # `nil` when `command` declares no transition at all
37
- # @raise [Runtime::WiringError] if `command` declares transitions but
38
- # none of them admits `current_state`
23
+ # @param command [String, Symbol]
24
+ # @param current_state [String, Symbol, nil] picks the transition that admits it;
25
+ # `nil` takes the first declared transition
26
+ # @return [String, nil] `nil` when `command` declares no transition
27
+ # @raise [Runtime::WiringError] if transitions are declared but none admits `current_state`
39
28
  def target_for(command, current_state = nil)
40
29
  match_transition(command, current_state)&.target
41
30
  end
42
31
 
43
32
  private
44
33
 
45
- # One declared transition is several rows when `from` names more
46
- # than one source state — the emission carries them flat, so the
47
- # fan-out happens here rather than in whatever reads it.
34
+ # A transition whose `from` names several states becomes one row per source state.
48
35
  def expand(command, transition)
49
36
  sources = transition.from.nil? ? [nil] : Array(transition.from)
50
37
 
@@ -58,20 +45,8 @@ module Hecks
58
45
  return nil if matches.empty?
59
46
  return matches.first unless current_state
60
47
 
61
- # Not `|| matches.first` — that would silently hand back an
62
- # arbitrary declared transition for `command` whenever none of
63
- # them actually admitted `current_state`, picking a `target`
64
- # that command dispatch would in fact refuse (that
65
- # refusal is `CommandRules::Admissibility#admissible_transition`'s
66
- # own job, which raises `LifecycleRefused` for exactly this
67
- # case rather than guessing — this module has no state subject
68
- # to build that refusal message from, only the two bare
69
- # values callers passed in). Zero production callers reach
70
- # this branch today (both real dispatch paths that check a
71
- # transition go through `admissible_transition`, not
72
- # `target_for`/`match_transition`), so this raise is a
73
- # backstop, not a live behaviour change — same shape as
74
- # `CommandRules::Arithmetic#sign_of`'s own fix.
48
+ # No `|| matches.first`: that would return a target command dispatch refuses.
49
+ # `CommandRules::Admissibility#admissible_transition` owns the real refusal.
75
50
  matches.find { |t| applies_from?(t, current_state) } ||
76
51
  raise(Runtime::WiringError,
77
52
  "no transition for #{command.inspect} admits state #{current_state.inspect} " \