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
@@ -1,68 +1,19 @@
1
1
  module Hecks
2
2
  module Bluebook
3
3
  module DSL
4
- # `identified_by` — shared by AggregateBuilder and EntityBuilder
5
- # only (S9, ADR 0025 — "EntityBuilder's duplicate identified_by and
6
- # resolve_pending_identity! go"): a piece's own identity cannot
7
- # spell differently from its aggregate's, and until this slice it
8
- # was hand-duplicated onto both rather than shared.
9
- #
10
- # A separate module from AttributeCollector on purpose — every
11
- # `attribute()`-taking builder (Command, Query, PortOperation,
12
- # ValueObject, ...) `include`s that one too, and none of them
13
- # declares an identity of its own ; folding `identified_by` in
14
- # there made it answer for six builders that never earned the
15
- # word (`syntax_conformance_spec.rb` catches exactly this — a
16
- # builder answering a method the grammar never grants it).
17
- #
18
- # Requires its includer to also `include AttributeCollector`
19
- # (for `attributes`/`resolve_identity_field!`/`resolve_identity_
20
- # type!`, still declared there since every includer of that
21
- # module needs them) and to supply `identity_pool` (private) —
22
- # the value-object list a bare field's own type resolves
23
- # against: AggregateBuilder's own `@value_objects + closed_sets`,
24
- # or EntityBuilder's owner's, since a piece mints none of its own.
4
+ # `identified_by`, shared by AggregateBuilder and EntityBuilder (ADR 0025).
5
+ # The includer must include AttributeCollector and define a private `identity_pool`.
25
6
  module IdentityDeclaration
26
- # Records which of the three live `identified_by` forms a builder declared, deferring
27
- # resolution until build time.
28
- #
29
- # There are three live forms, deliberately distinguishable at the
30
- # declaration site:
7
+ # Records which `identified_by` form a builder declared; resolution waits for build time.
31
8
  #
32
9
  # identified_by AccountNumber, as: :number # one identity concept
33
10
  # identified_by do ... end # a bespoke concept
34
11
  # identified_by :branch, :number # an existing compound key
35
12
  #
36
- # One symbol is retired: it cannot say whether the author means a
37
- # value concept or a field-shaped database key. Frozen source still
38
- # reaches the old interpretation through `legacy_identified_by`.
39
- # Both `AggregateBuilder` and `EntityBuilder` name this method in their Keyword rows'
40
- # `calls:` column, so `GenericDispatch` forwards `identified_by` here unchanged, both
41
- # after boot (reading the live grammar table) and during it
42
- # (`GenericDispatch::BOOTSTRAP_CALLS_FALLBACK`, which carries every `calls:`-routed row
43
- # unconditionally, not a hand-picked bootstrap-reachable subset — though this one is
44
- # exercised during boot too, since every self-hosted aggregate/entity declares an identity).
45
- # Dispatches across the three live forms documented above (value-
46
- # object + block, single type target, single/compound field
47
- # target), each an early return that sets exactly one pending
48
- # ivar. Splitting per form would need each branch's own `return`-
49
- # with-nil semantics and the shared `@name`/`identity_pool`
50
- # threaded back out as parameters, for no gain beyond what the
51
- # three-forms comment above already documents.
52
- #
53
- # @param targets [Array<Symbol, Module>] zero or more identity targets: a value-object
54
- # type (a bareword, resolved by `ConstShim` to a `Module`), one or more attribute-name
55
- # symbols for a field or compound key, or empty when `definition` is given
56
- # @param as [Symbol, nil] the field name to mint for a value-object-type target; not
57
- # accepted with a field or compound-key target
58
- # @yield a bespoke value-object body, `instance_eval`'d by `ValueObjectBuilder.build` to
59
- # mint the identity's own anonymous value object
60
- # @return [Array<Symbol>, Array<String>, nil] `targets` when a compound key is declared,
61
- # the resolved identity paths from `legacy_identified_by` in shadow-parsing mode, or
62
- # `nil` otherwise; callers reach this through `GenericDispatch`, which discards it
63
- # @raise [Bluebook::DSL::Malformed] if `identified_by` was already called, combines a
64
- # block with targets, names no identity, mixes a value-object type with field names,
65
- # passes `as:` with a field or compound key, or the block declares no attributes
13
+ # @param targets [Array<Symbol, Module>] a value-object type or attribute names
14
+ # @param as [Symbol, nil] the field name to mint for a value-object-type target
15
+ # @yield a bespoke value-object body for the identity's own value object
16
+ # @raise [Bluebook::DSL::Malformed] on a repeat declaration or an invalid mix of forms
66
17
  # rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
67
18
  def identified_by_impl(*targets, as: nil, &definition)
68
19
  return legacy_identified_by(*targets, as: as, &definition) if MetaValidator.shadow_parsing?
@@ -84,20 +35,8 @@ module Hecks
84
35
  &definition
85
36
  )
86
37
  rescue NameError => e
87
- # A removed spelling must refuse loudly, not degrade into a raw
88
- # Ruby error — the one contract `EraGuard.shadow_parse` leans
89
- # on to know a normal parse genuinely could not read this text
90
- # (only `Malformed` triggers its shadow-mode retry, era_guard.rb's
91
- # own comment). The old `identified_by { name.value }` — a block
92
- # whose text was never called, only extracted (legacy_
93
- # identified_by, below) — is exactly this shape: read under the
94
- # current grammar it is instead instance_eval'd as a value-object
95
- # definition, and a bare identifier like `name` inside it resolves
96
- # to nothing WordGate#method_missing recognizes, so Ruby itself
97
- # raises NameError. Left uncaught, that NameError skipped
98
- # shadow_parse's rescue entirely and reached callers as a raw
99
- # crash instead of the frozen-era fallback that exists for
100
- # precisely this text.
38
+ # Must raise Malformed: EraGuard.shadow_parse retries frozen text only on
39
+ # Malformed, and a bare identifier in an old block form raises NameError here.
101
40
  raise Malformed,
102
41
  "#{@name}.identified_by do ... end could not be read as a value-object " \
103
42
  "definition: #{e.message}"
@@ -122,10 +61,7 @@ module Hecks
122
61
  raise Malformed,
123
62
  "#{@name}.identified_by takes no as: — name the declared field itself"
124
63
  end
125
- # Transitional compatibility: the self-hosted language and live
126
- # corpus still contain this form. Keep it readable until their
127
- # exemplar-led migration is complete; the final lifecycle cutover
128
- # replaces this assignment with the targeted refusal.
64
+ # Transitional: the self-hosted language and live corpus still use this form.
129
65
  @identity_field_pending = field
130
66
  return
131
67
  end
@@ -141,11 +77,7 @@ module Hecks
141
77
 
142
78
  private
143
79
 
144
- # Resolves whichever of the three `identified_by` shapes is
145
- # pending, against `identity_pool` — the includer's own private
146
- # hook. Called at build time, not at `identified_by`'s own call
147
- # time — see `AttributeCollector#resolve_identity_field!`'s own
148
- # comment on why.
80
+ # Resolves the pending identity against `identity_pool` at build time, not call time.
149
81
  def resolve_pending_identity!
150
82
  if @identity_type_pending
151
83
  type, as, insert_at = @identity_type_pending
@@ -162,11 +94,7 @@ module Hecks
162
94
  def identity_type?(target) = target.to_s.match?(/\A[A-Z]/)
163
95
 
164
96
  def refuse_second_identity!
165
- # During the staged migration a transitional one-symbol declaration
166
- # may be replaced by the new declaration later in the same builder.
167
- # This keeps existing builder fixtures/source readable while their
168
- # exemplar is migrated. Once one-symbol identity is retired this
169
- # compatibility branch disappears with it.
97
+ # Transitional: a one-symbol declaration may still be replaced by a later one.
170
98
  if @identity_field_pending && !@identity_type_pending && !@identity_fields_pending
171
99
  @identity_field_pending = nil
172
100
  return
@@ -178,10 +106,7 @@ module Hecks
178
106
  raise Malformed, "#{@name} declares identified_by more than once"
179
107
  end
180
108
 
181
- # Legacy — the two removed spellings (a value object + as:, and the
182
- # multi-line block), kept alive only for `EraGuard.shadow_parse`
183
- # (S0a, ADR 0025) to still make sense of frozen era text that used
184
- # them; unreachable outside `MetaValidator.shadow_parsing?`.
109
+ # Parses the spellings frozen era text uses, for `EraGuard.shadow_parse`.
185
110
  def legacy_identified_by(*targets, as:, &path)
186
111
  target = targets.first
187
112
  if target
@@ -2,11 +2,7 @@ require_relative "word_gate"
2
2
  module Hecks
3
3
  module Bluebook
4
4
  module DSL
5
- # Parses a `lifecycle :field, default: ... do transition ... end`
6
- # block into a `Lifecycle` — the field an aggregate or entity's own
7
- # state machine lives on, its starting value, and the `command =>
8
- # target_state` transition table (with an optional `from:` guard)
9
- # each `transition_impl` call adds a row to.
5
+ # Parses a `lifecycle :field, default: ... do transition ... end` block into a `Lifecycle`.
10
6
  class LifecycleBuilder
11
7
  GRAMMAR_CONTEXT = "Lifecycle".freeze
12
8
 
@@ -22,11 +18,7 @@ module Hecks
22
18
 
23
19
  # Records one transition row per command in `mapping`, all sharing its `from:` guard.
24
20
  #
25
- # Answers the `transition` word, which the grammar table routes here
26
- # through its `calls:` column — item #13's full metaprogrammed
27
- # dispatch (slice 4c). Bootstrap-reachable (syntax.bluebook's
28
- # own Keyword/Argument entities describe their `status`
29
- # lifecycle with it), so in `BOOTSTRAP_CALLS_FALLBACK`.
21
+ # Listed in `BOOTSTRAP_CALLS_FALLBACK` because syntax.bluebook uses it during boot.
30
22
  #
31
23
  # @param mapping [Hash{String, Symbol => String, Symbol, Array<String>}] command name to
32
24
  # target state, as in `"Purchase" => "sold"`; the optional `:from` key holds the
@@ -70,17 +62,11 @@ module Hecks
70
62
 
71
63
  private
72
64
 
73
- # C5.3 (docs/semantics/bluebook-semantics.md) — two transitions for
74
- # one command whose `from:` sets overlap (or where either has no
75
- # `from:` at all) were silently first-wins; refused where the state
76
- # machine can be read whole. Two transitions for one command from
77
- # disjoint states are the legitimate shape (`match_transition`
78
- # picks by the current state) and stay. A `from:` naming a state
79
- # nothing declares is not refused here: it is a reachability
80
- # finding `bin/model_check` already reports (unreachable state,
81
- # dead transition), and a bluebook may declare it on purpose.
65
+ # C5.3 (docs/semantics/bluebook-semantics.md): overlapping `from:` sets for one command
66
+ # are refused. Disjoint sets are legitimate. An undeclared `from:` state is left to
67
+ # `bin/model_check`.
82
68
  def refuse_ambiguity!
83
- return if MetaValidator.shadow_parsing? # frozen era text is history
69
+ return if MetaValidator.shadow_parsing? # frozen era text is exempt
84
70
 
85
71
  @transitions.each_with_index do |(command, transition), index|
86
72
  earlier = @transitions[0...index].find do |other_command, other|
@@ -2,12 +2,8 @@ require_relative "word_gate"
2
2
  module Hecks
3
3
  module Bluebook
4
4
  module DSL
5
- # Parses a `policy "Name" do ... end` block into a `Policy` — a
6
- # reaction wired at chapter scope: `on` the event it watches, an
7
- # optional `where` guard evaluated against the event's own payload, an
8
- # optional `for_each` fan-out query, and the `trigger` command it
9
- # dispatches (`with:` projecting the event's payload onto the
10
- # command's own arguments when the two shapes differ).
5
+ # Parses a `policy "Name" do ... end` block into a `Policy`: the event it reacts to (`on`),
6
+ # an optional `where` guard, an optional `for_each` fan-out, and the `trigger` it dispatches.
11
7
  class PolicyBuilder
12
8
  GRAMMAR_CONTEXT = "Policy".freeze
13
9
 
@@ -20,20 +16,8 @@ module Hecks
20
16
 
21
17
  # Records the event this policy reacts to.
22
18
  #
23
- # `on Account::AccountFrozen` — a bare constant accepted (ADR
24
- # 0025, S6 — "events first-class"), resolved through `ConstShim`
25
- # the same way `trigger`/`dispatch` already resolve a command
26
- # reference (`Naming.event_ref`, that method's own header). Not
27
- # a required spelling yet, unlike `trigger`'s own quoted-text
28
- # refusal — see `policy.bluebook`'s own KeywordSeed comment for
29
- # why: event names aren't 100% migrated across the live corpus
30
- # the way command references are, so both `on "Account.
31
- # AccountFrozen"` (quoted) and `on Account::AccountFrozen`
32
- # (bare) stay admitted until a full migration lands.
33
- #
34
- # Reached through `calls: "on_impl"` rather than `GenericDispatch`'s generic single-fill
35
- # coercion, the same way `trigger_impl` below overrides its own generic default — `on`
36
- # admits both a bare constant and quoted text, not one single argument kind.
19
+ # Reached through `calls: "on_impl"` because `on` admits both a bare constant
20
+ # (`on Account::AccountFrozen`) and quoted text, not one single argument kind.
37
21
  #
38
22
  # @param event_ref [Symbol, String, Module] the event, as a bare constant (a
39
23
  # `ScopedConstant` module `ConstShim` resolves) or quoted text
@@ -42,45 +26,16 @@ module Hecks
42
26
  @on_event = Naming.event_ref(event_ref)
43
27
  end
44
28
 
45
- # Records the command this policy dispatches and, optionally, how the event's payload
46
- # projects onto it.
47
- #
48
- # `with:` — what the trigger is given, when the event's own shape
49
- # is not it. Omitted, the whole event payload forwards verbatim.
50
- #
51
- # Same `key => value` shape a saga's own `dispatch ..., with:`
52
- # takes, and read the same way at runtime: a Symbol names a field
53
- # on the triggering event, anything else is a literal the policy
54
- # supplies itself. The reason it exists is the reason a saga's
55
- # does — a reaction crosses an aggregate boundary, and the event
56
- # on one side is under no obligation to be shaped like the
57
- # command on the other. Without it the target has to declare
58
- # every field the event happens to carry, whether it reads them
59
- # or not.
60
- # The command itself, not its name (ADR 0025, "events and
61
- # reactions" — command references become first-class): `trigger
62
- # Account::Debit`, a bare constant `ConstShim` resolves the same
63
- # way `reference_to Account` always has, not a quoted verb string.
64
- # Matches the qualified-or-not shape a saga's own `dispatch`
65
- # command name takes — see `Naming.command_ref`'s own header for
66
- # how the `::`/`.` rewrite works, and `SagaInterpreter#qualified`
67
- # for why an unqualified form is always enough (same-domain is
68
- # the fallback, so `Account::Debit` and `Banking::Account::Debit`
69
- # mean the same thing here).
29
+ # Records the command this policy dispatches and how the event payload projects onto it.
70
30
  #
71
- # Legacy under shadow-parsing (S0a's own bridge) — frozen era
72
- # text still writes the quoted form.
31
+ # With `with:`, a Symbol value names a field on the triggering event and anything else is
32
+ # a literal. Omitted, the whole payload forwards.
33
+ # In `GenericDispatch::BOOTSTRAP_CALLS_FALLBACK`.
73
34
  #
74
- # `["Policy", "trigger"] => :trigger_impl` is in
75
- # `GenericDispatch::BOOTSTRAP_CALLS_FALLBACK`, which carries every `calls:`-routed row
76
- # unconditionally — this one is also exercised during boot itself, since every
77
- # self-hosted policy declares a trigger.
78
- #
79
- # @param command_ref [Symbol, String, Module] the command, as a bare constant (a
80
- # `ScopedConstant` module `ConstShim` resolves) or, under shadow-parsing, quoted text
81
- # @param with [Hash{Symbol => Object}, nil] a projection from the triggering event's payload
82
- # onto the command's own arguments; a Symbol value names an event field, anything else is
83
- # a literal; `nil` forwards the whole event payload verbatim
35
+ # @param command_ref [Symbol, String, Module] the command, as a bare constant or, under
36
+ # shadow-parsing, quoted text
37
+ # @param with [Hash{Symbol => Object}, nil] event payload to command arguments;
38
+ # `nil` forwards the whole payload
84
39
  # @return [void]
85
40
  # @raise [Bluebook::DSL::Malformed] if `command_ref` is quoted text outside shadow-parsing
86
41
  def trigger_impl(command_ref, with: nil)
@@ -97,13 +52,8 @@ module Hecks
97
52
 
98
53
  # Records the domain this policy's trigger reaches into.
99
54
  #
100
- # `across "Notifications"` names the domain a trigger reaches into.
101
- # `expect_undelivered: true` declares that this domain expects that
102
- # target never to be reached (no such domain, on purpose), which
103
- # `ModelCheck` holds it to in both directions. Reached through
104
- # `calls: "across_impl"` rather than the generic single-fill
105
- # coercion, because `expect_undelivered:` is a keyword argument the
106
- # generic coercion cannot take.
55
+ # `expect_undelivered: true` declares that the target is expected never to be reached
56
+ # (no such domain, on purpose); `ModelCheck` holds it to that in both directions.
107
57
  #
108
58
  # @param domain [String, Symbol] the target domain's name
109
59
  # @param expect_undelivered [Boolean] whether this domain expects `across`'s target to
@@ -117,20 +67,8 @@ module Hecks
117
67
  # Records the guard predicate that decides whether this policy applies to a triggering
118
68
  # event.
119
69
  #
120
- # **The guard** — same extraction CommandBuilder#given/#ensures already
121
- # use (Ports::Extraction reads the block's source ; the block itself
122
- # is never called, here or at runtime — Runtime::PolicyInterpreter
123
- # evaluates the extracted text through the same
124
- # Bluebook::Expression::Evaluator a command's own given/ensures run
125
- # through). No description argument the way given/ensures each
126
- # carry one : a given's description becomes a GivenNotMet message,
127
- # and a where that does not hold refuses nothing — it just means
128
- # this policy does not apply to this event, exactly like an
129
- # `event_qualifier` miss, which carries no message either.
130
- #
131
- # Evaluated against the triggering event's own payload, not a
132
- # stored record — a policy reacts to what just happened, and has no
133
- # aggregate instance of its own to read state from.
70
+ # The block's source is extracted and never called; a `where` that does not hold refuses
71
+ # nothing, so unlike `given` it takes no description. It sees the event's payload only.
134
72
  #
135
73
  # @yield the guard predicate, extracted as source text and evaluated later by
136
74
  # `Runtime::PolicyInterpreter` against the triggering event's payload; never called here
@@ -147,22 +85,12 @@ module Hecks
147
85
  "could not be read, so no other runtime could ever evaluate it"
148
86
  end
149
87
 
150
- # C3.6 — the same PatternSubset check every rule site gets.
151
88
  ast = Expression::AstJson.emit_predicate(canonical)
152
89
  Expression::AstJson.refuse_unshared_patterns!(ast, owner: @name, word: "where")
153
90
  Expression::AstJson.refuse_unresolvable_lookups!(ast, owner: @name, word: "where")
154
91
  @where = canonical
155
92
  end
156
93
 
157
- # **The fan-out source** — a query verb, "Aggregate.query_name" or
158
- # "Domain::Aggregate.query_name", the same qualified-or-not shape a
159
- # saga's own `dispatch` command name already takes
160
- # (SagaInterpreter#qualified). Runtime::PolicyInterpreter runs the
161
- # named query against the triggering event's own payload and fires
162
- # `trigger` once per row, instead of once for the event.
163
- # `for_each` — item #13's full metaprogrammed dispatch, slice 1:
164
- # same shape as `on`, above.
165
-
166
94
  # Builds the `Policy` this builder has accumulated.
167
95
  #
168
96
  # @return [Bluebook::Policy] the built policy, carrying every field set by `on`,
@@ -38,12 +38,8 @@ module Hecks
38
38
 
39
39
  # Declares one method an adapter bound to this port must respond to.
40
40
  #
41
- # **The method contract** — the fact a `.port` file's `verb`/`signal`
42
- # never carried: what an adapter must actually respond to for a
43
- # dispatch to reach it without a bare `NoMethodError`. Declared the
44
- # same repeatable way `AdapterBuilder#field`/`#secret` already are,
45
- # so `verify!` can check it with `respond_to?` at boot instead of
46
- # the runtime discovering it live.
41
+ # Repeatable, like `AdapterBuilder#field`; `verify!` checks each name with `respond_to?`
42
+ # at boot so a dispatch never meets a bare `NoMethodError`.
47
43
  #
48
44
  # @param name [Symbol, String] the method name, such as `:ask`
49
45
  # @return [Array<Symbol>] every method declared so far, this one last
@@ -2,40 +2,17 @@ require_relative "word_gate"
2
2
  module Hecks
3
3
  module Bluebook
4
4
  module DSL
5
- # Parses one `operation`/`tells`/`asks` block inside a `domain_port`
6
- # into a `PortOperation` — its own attributes (the external fact's
7
- # payload) plus either the events it `emits` (inbound) or the
8
- # `answers`/`refuses` pair naming its two possible outcomes (outbound).
9
- # `to:` records which aggregate the operation routes to as dispatch
10
- # metadata, never as an attribute — see `to:`'s own comment below.
5
+ # Parses one `operation`/`tells`/`asks` block into a `PortOperation`: its attributes plus
6
+ # either the events it `emits` (inbound) or its `answers`/`refuses` pair (outbound).
11
7
  class PortOperationBuilder
12
8
  GRAMMAR_CONTEXT = "PortOperation".freeze
13
9
 
14
10
  include AttributeCollector
15
11
  include WordGate
16
12
 
17
- # `to:` — the sanctioned replacement for `reference_to` inside an
18
- # operation body: `reference_to_impl`'s own refusal message tells
19
- # authors to "pass the receiving aggregate in to:", and this is
20
- # the argument DomainPort's own grammar (domain_port.bluebook)
21
- # gives operation/tells/asks to receive it.
22
- #
23
- # **Genuine routing metadata, not an attribute** — matching
24
- # rust/parser/src/parse/domain_port.rs's own header comment ("The
25
- # receiving aggregate is routing metadata supplied by to:, not an
26
- # operation attribute"), which anticipated this shape before either
27
- # side actually built it. Stored separately (below, threaded to
28
- # PortOperation as `to:`) rather than reusing reference_to_impl's
29
- # own attribute-adding path — Dispatcher#port_invocation
30
- # (lib/hecks/runtime/dispatcher.rb) is the one place that resolves
31
- # routing at dispatch time; it gained a second, purely additive
32
- # branch for this (falls back to a plain attribute named for the
33
- # owning aggregate's own identified_by field, the same "declare
34
- # only external facts with attribute" the refusal message
35
- # describes) rather than folding `to:` into identity_attribute's
36
- # existing Reference-attribute scan, which every operation already
37
- # in the corpus (Banking, pizzas, a client site's own vendored
38
- # PaymentGateway) still relies on unchanged.
13
+ # `to:` is the sanctioned replacement for `reference_to` inside an operation body —
14
+ # genuine routing metadata, not an attribute, resolved at dispatch time by
15
+ # `Dispatcher#port_invocation` rather than folded into the ordinary attribute scan.
39
16
  #
40
17
  # @param name [String] the operation's name
41
18
  # @param to [Symbol, String, Module, nil] the aggregate the operation routes to; stored
@@ -50,33 +27,13 @@ module Hecks
50
27
  @emits = []
51
28
  end
52
29
 
53
- # Refuses `reference_to` inside an operation body, except while shadow-parsing, where it
54
- # adds the reference attribute frozen era text declared.
55
- #
56
- # Always an attribute, never the self-reference `CommandBuilder`
57
- # spells — a port operation has no `creates?`/`acts_on` distinction
58
- # to protect, so there is nothing for the self-reference branch to be
59
- # for here. `reference_to Payment, as: :payment_id` reads the same
60
- # even though the target happens to equal the owning aggregate.
61
- # Answers the `reference_to` word through the table's `calls:`
62
- # column — item #13's full metaprogrammed dispatch (slice 4b).
63
- # Bootstrap-reachable, in `GenericDispatch::BOOTSTRAP_CALLS_FALLBACK`.
64
- #
65
- # Disabled, #335 — kept only for MetaValidator's own shadow-parsing
66
- # pass (the self-hosted grammar's own KeywordSeed/ArgumentSeed rows
67
- # for "reference_to" in this context are themselves declared using
68
- # this construct, one level up — deleting the Ruby method would
69
- # break the language describing itself, not just old domain
70
- # authors). Every real domain author reaches `to:` instead, above —
71
- # a genuinely different mechanism now, not a relocated spelling of
72
- # this one (see `to:`'s own comment).
30
+ # Refuses `reference_to` inside an operation body; a port operation has no self-reference
31
+ # to protect the way `CommandBuilder`'s does. Kept only for MetaValidator's own
32
+ # shadow-parsing pass, which still declares itself using this construct — every real
33
+ # domain author reaches `to:` instead (see its own comment above).
73
34
  #
74
- # @param type [Symbol, String, Module] the referenced aggregate, written as a bare constant
75
- # @param as [Symbol, nil] the attribute's name; nil derives it from the target, as in
76
- # `:payment_id` under shadow-parsing
77
- # @return [nil] nothing useful; the reference lands in `attributes`
78
- # @raise [Bluebook::DSL::Malformed] always outside shadow-parsing, since routing belongs
79
- # in `to:`; under shadow-parsing, if the attribute name is already declared
35
+ # @raise [Bluebook::DSL::Malformed] always outside shadow-parsing; under shadow-parsing,
36
+ # if the attribute name is already declared
80
37
  def reference_to_impl(type, as: nil)
81
38
  unless MetaValidator.shadow_parsing?
82
39
  raise Malformed,
@@ -88,25 +45,14 @@ module Hecks
88
45
  end
89
46
 
90
47
  # Names one event an inbound operation records once the external fact has arrived.
91
- #
92
- # @param event_name [String, Symbol] the event's name, such as `"PaymentSettled"`
93
- # @return [Array<String>] every event named so far, this one last
94
48
  def emits(event_name) = @emits << event_name.to_s
95
49
 
96
- # The two halves of an `asks`. An outbound call has exactly two
97
- # endings and the chapter names both — `answers` for what came back,
98
- # `refuses` for what the outside said instead. They are separate words
99
- # rather than two `emits` because a reader has to be able to tell them
100
- # apart without reading the adapter: one is the thing you wanted, the
101
- # other is the thing you have to handle.
102
- # `answers`/`refuses` — item #13's full metaprogrammed dispatch,
103
- # slice 1 (whole-project table-unification survey): both a bare,
104
- # kind-driven coerce-and-assign with nothing else, now executed
105
- # by `GenericDispatch`.
50
+ # `answers`/`refuses`, the two halves of an `asks` — separate words rather than two
51
+ # `emits` so a reader can tell what came back from what the outside refused, without
52
+ # reading the adapter.
106
53
 
107
54
  # Assembles the operation, refusing words that belong to the other direction.
108
55
  #
109
- # @return [Bluebook::PortOperation] the operation with its attributes, events and routing
110
56
  # @raise [Bluebook::DSL::Malformed] if an inbound operation declares no `emits` or
111
57
  # declares `answers`/`refuses`, or an outbound one declares `emits` or lacks either
112
58
  # `answers` or `refuses`
@@ -119,9 +65,8 @@ module Hecks
119
65
  direction: @direction, answers: @answers, refuses: @refuses, to: @to
120
66
  )
121
67
 
122
- # An inbound operation still has to say something. Only inbound: an
123
- # `asks` says it with `answers`/`refuses` instead, and
124
- # `refuse_wrong_words!` above has already insisted on both.
68
+ # Only inbound: an `asks` says it with `answers`/`refuses` instead, already enforced
69
+ # above.
125
70
  if !outbound && @emits.empty?
126
71
  raise Malformed,
127
72
  "#{@name} declares no emits — an operation with nothing to say " \
@@ -133,21 +78,15 @@ module Hecks
133
78
 
134
79
  private
135
80
 
136
- # The one place a reference attribute actually gets added — both
137
- # `to:` (initialize, above) and reference_to_impl's own shadow-
138
- # parsing branch call this, so there is exactly one real
139
- # implementation of "carry a Reference-typed external fact,"
140
- # not two that could drift.
81
+ # The one real implementation of "carry a Reference-typed external fact" — both `to:` and
82
+ # `reference_to_impl`'s shadow-parsing branch call this, so there is nothing to drift.
141
83
  def add_reference!(type, as: nil)
142
84
  target = Naming.demodulise(type)
143
85
  attribute_impl(as || default_reference_name(target), Reference.new(target))
144
86
  end
145
87
 
146
- # **Each direction refuses the other's words**. `emits` on an `asks` looks
147
- # right and is not: it would name one ending and leave the other
148
- # nowhere. `answers` on a `tells` is worse — there is no channel back
149
- # to an inbound caller at all, so it would read as a promise the
150
- # runtime cannot keep.
88
+ # Each direction refuses the other's words: `emits` on an `asks` names one ending and
89
+ # leaves the other nowhere; `answers` on a `tells` promises a channel that never exists.
151
90
  def refuse_wrong_words!(outbound)
152
91
  if outbound
153
92
  unless @emits.empty?
@@ -170,21 +109,8 @@ module Hecks
170
109
  end
171
110
  end
172
111
 
173
- # Evaluates one operation block against a fresh builder and returns what it built.
174
- #
175
- # `private` above (scoping the instance methods between it and here)
176
- # doesn't reach a singleton method — correctly so: `.build` is this
177
- # builder's real public entry point (DomainPortBuilder calls it),
178
- # never meant to be private.
179
- #
180
- # @param name [String] the operation's name
181
- # @param to [Symbol, String, Module, nil] the aggregate the operation routes to, or nil
182
- # @param owner [String, nil] name of the aggregate the enclosing port is declared on
183
- # @param direction [Symbol] `:inbound` for `operation`/`tells`, `:outbound` for `asks`
184
- # @yield the operation body, evaluated with the builder as `self`; may be omitted
185
- # @return [Bluebook::PortOperation] the built operation
186
- # @raise [Bluebook::DSL::Malformed] if the body uses the other direction's words, omits
187
- # the ones its own direction requires, or uses a word the grammar does not admit
112
+ # Evaluates one operation block against a fresh builder and returns what it built;
113
+ # `private` above doesn't reach this singleton method, since `.build` is the real entry.
188
114
  # rubocop:disable-next Lint/IneffectiveAccessModifier
189
115
  def self.build(name, to: nil, owner: nil, direction: :inbound, &block)
190
116
  builder = new(name, to: to, owner: owner, direction: direction)