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
@@ -2,126 +2,27 @@ require_relative "generic_dispatch"
2
2
  module Hecks
3
3
  module Bluebook
4
4
  module DSL
5
- # The Ruby-side `word_gate` (`rust/parser/src/parse/mod.rs`'s own,
6
- # read there first — this is the same job, one level up: Rust's own
7
- # gate refuses a mistyped/inadmissible word directly, at the
8
- # moment it reads a line of `.bluebook` source text, before any
9
- # per-construct parsing runs. Ruby never lexes source text — a
10
- # `.bluebook` file is Ruby, so `given("x")` is already a real
11
- # method call by the time any of this code runs, and Ruby's own
12
- # method dispatch already refuses an arity mismatch on an
13
- # existing method for free. What Ruby's own dispatch does not do
14
- # is consult the self-hosted grammar table at all — a mistyped
15
- # word (`giv3n("x")`) or a word used in the wrong context
16
- # (`identified_by` inside a `command` block) just raises Ruby's
17
- # own generic `NoMethodError`, naming nothing about what the
18
- # language actually admits. This module closes that gap.
5
+ # Checks undefined DSL words against the self-hosted grammar table, dispatching admitted ones
6
+ # through `GenericDispatch` and refusing the rest with the table's own message.
19
7
  #
20
- # ## What reaches this module
21
- #
22
- # `method_missing`/`respond_to_missing?` only — a word this
23
- # builder class already answers with an ordinary `def` (or a
24
- # method a shared mixin such as `AttributeCollector` defines) never
25
- # reaches this module at all; Ruby's own method lookup finds it
26
- # first, and not every word has had its hand-written method
27
- # removed. A word the grammar admits whose builder has no
28
- # hand-written method executes for real here, via `GenericDispatch`
29
- # (item #13's full metaprogrammed dispatch, whole-project
30
- # table-unification survey) — see that module's own header for
31
- # exactly which ones, and the full account of what was verified
32
- # before each was migrated. A mistyped or wrongly-contexted word
33
- # gets the same real, helpful, table-driven refusal Rust's own
34
- # `word_gate` already gives, instead of Ruby's own generic
35
- # `NoMethodError`.
36
- #
37
- # ## `GRAMMAR_CONTEXT`
38
- #
39
- # `self.class::GRAMMAR_CONTEXT` — each including class names which
40
- # row of the self-hosted `Context` closed set it corresponds to
41
- # (`AggregateBuilder::GRAMMAR_CONTEXT = "Aggregate"`, etc.) — the
42
- # same string `word_gate`'s own `context` parameter already is on
43
- # the Rust side, read off the identical table.
44
- #
45
- # ## Bootstrapping
46
- #
47
- # Bootstrapping gated, the same reason `RuleReference#lookup`
48
- # already is (`rule_reference.rb`'s own comment has the full
49
- # story) — the meta-domain's own bootstrap calls dozens of
50
- # keywords on itself before its own grammar table exists to
51
- # check them against. For most words, this module steps aside
52
- # entirely during bootstrap (`super`, Ruby's own ordinary
53
- # `NoMethodError`) — the exact behavior every builder already had
54
- # before this module existed, and (unlike `RuleReference`) there
55
- # is deliberately no fallback covering the whole ~200-row table —
56
- # that would defeat the entire point.
57
- #
58
- # One narrow exception (item #13's full metaprogrammed dispatch,
59
- # slice 3, whole-project table-unification survey):
60
- # `GenericDispatch::BOOTSTRAP_CALLS_FALLBACK`, an explicit table
61
- # naming the same (context, word) -> method pairs the real
62
- # `calls:` column carries, projected ahead of time into the
63
- # committed `bootstrap_table.rb` — it matters only for words both
64
- # migrated to the `calls:` shape and bootstrap-reachable
65
- # (`attribute`, for one). This is the one place in this whole arc a
66
- # bootstrap fallback was worth building despite `RuleReference`'s
67
- # own precedent against it: it duplicates no logic, only a method
68
- # name — `attribute_impl`'s own real, hand-written body is called
69
- # either way, bootstrap or not, so there is nothing here that can
70
- # drift the way a full behavioral duplicate could.
71
- #
72
- # ## `word_gate_dispatch` and the type-position fallback
73
- #
74
- # Two further pieces, both slice 5:
75
- # - `word_gate_dispatch` is the same admission+dispatch logic
76
- # `method_missing` below runs, factored out so a class with
77
- # its own class-level `method_missing` (`HecksagonBuilder`'s/
78
- # `WorldBuilder`'s genuinely open-ended verb vocabulary) can
79
- # call it directly and fall back to its own open-verb handling
80
- # only when this returns `NOT_ADMITTED` — a class-level `def`
81
- # always wins over an included module's in Ruby's own method
82
- # resolution, so their own `method_missing` is the only one
83
- # that ever runs for them, and this is what lets a real,
84
- # closed-set word (`port`/`realm`/`latest`) still reach
85
- # `GenericDispatch` despite that.
86
- # - the "Type"-position fallback inside `word_gate_dispatch`
87
- # itself, for `one_of`/`list_of` — called inside an
88
- # attribute's own type argument, with `self` as whatever
89
- # builder is currently `instance_eval`ing, never a dedicated
90
- # "Type" builder `self.class::GRAMMAR_CONTEXT` could ever
91
- # name. See that method's own comment.
8
+ # Each including class names its grammar row in `GRAMMAR_CONTEXT`. While the meta-domain
9
+ # boots there is no table, so only `GenericDispatch::BOOTSTRAP_CALLS_FALLBACK` applies.
92
10
  module WordGate
93
- # A caller with its own class-level `method_missing`
94
- # (`HecksagonBuilder`/`WorldBuilder` — see `word_gate_dispatch`'s
95
- # own header) checks for this to tell "not a word the grammar
96
- # admits at all" apart from every other outcome below (a real
97
- # dispatch, or a raised refusal) — never raised itself, so a
98
- # caller can fall through to its own open-ended handling instead.
11
+ # Returned by `word_gate_dispatch` for a word no grammar row admits, so a caller with
12
+ # its own `method_missing` can fall back to open-ended handling.
99
13
  NOT_ADMITTED = Object.new.freeze
100
14
 
101
- # Private, matching Ruby's own convention for both (`Object`
102
- # defines them private too) — and load-bearing here, not just
103
- # style: `spec/syntax_conformance_spec.rb`'s "declares every
104
- # word X answers" check walks `public_instance_methods`, and a
105
- # public `method_missing`/`respond_to_missing?` would show up
106
- # there as two more "answered words" no row of the grammar ever
107
- # declares, on every builder this module touches.
15
+ # Private like Object's own; public ones would appear as extra "answered words" in
16
+ # spec/syntax_conformance_spec.rb, which walks `public_instance_methods`.
108
17
 
109
18
  private
110
19
 
111
20
  def method_missing(word, *args, **kwargs, &block)
112
21
  if MetaValidator.bootstrapping?
113
22
  fallback = GenericDispatch::BOOTSTRAP_CALLS_FALLBACK
114
- # Own context first, "Type" second — the same order the
115
- # ordinary (non-bootstrapping) `word_gate_dispatch` path
116
- # below checks them in, for the same reason: `list_of`/
117
- # `one_of` used in an attribute's own type position never
118
- # arrive with `self.class::GRAMMAR_CONTEXT == "Type"`.
23
+ # Own context first, then "Type", as in `word_gate_dispatch`.
119
24
  own_key = [self.class::GRAMMAR_CONTEXT, word.to_s]
120
25
  type_key = ["Type", word.to_s]
121
- # key? first, never `||` — a target method name is never
122
- # actually stored as `false`, but the fallback lookup itself
123
- # must not silently prefer "Type" over this class's own
124
- # context on the strength of a falsy-looking value.
125
26
  found = fallback.key?(own_key) || fallback.key?(type_key)
126
27
  target = fallback.key?(own_key) ? fallback[own_key] : fallback[type_key]
127
28
  return send(target, *args, **kwargs, &block) if found
@@ -135,31 +36,8 @@ module Hecks
135
36
  result
136
37
  end
137
38
 
138
- # The core admission+dispatch logic, factored out of
139
- # `method_missing` — item #13's full metaprogrammed dispatch
140
- # (slice 5, whole-project table-unification survey) — so a
141
- # class with its own class-level `method_missing`
142
- # (`HecksagonBuilder`'s/`WorldBuilder`'s genuinely open-ended
143
- # verb vocabulary, `persisted_by "Heki"`/`posted_by "Carrier"`,
144
- # can never be a closed table) can still route a word the
145
- # grammar admits through here first, falling back to its own
146
- # open-verb handling only for what this doesn't recognize at
147
- # all — unblocking `Hecksagon#port`/`World#realm`/`World#latest`,
148
- # each a real, closed-set word that happened to sit on a class
149
- # whose own `method_missing` a class-level `def` always wins
150
- # over Ruby's own module-inclusion order.
151
- #
152
- # Never raises "not admitted" — returns `NOT_ADMITTED` instead,
153
- # so the caller (this module's own `method_missing`, or one of
154
- # the two above) decides what that means for it. Does still
155
- # raise the richer, table-driven refusals below once a word is
156
- # admitted-but-unimplemented, or admitted-somewhere-else-only —
157
- # those are real, useful refusals regardless of which
158
- # `method_missing` is asking.
159
- # One ordered admission-then-dispatch pipeline (own context, then
160
- # "Type" fallback, then admitted-elsewhere check, then dispatch) —
161
- # see this method's own header comment above for the full,
162
- # order-dependent account of why each check runs where it does.
39
+ # Admission then dispatch: own context, "Type" fallback, admitted-elsewhere check,
40
+ # `GenericDispatch`. Returns `NOT_ADMITTED` for an unknown word rather than raising.
163
41
  # rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
164
42
  def word_gate_dispatch(word, args, kwargs, block)
165
43
  context = self.class::GRAMMAR_CONTEXT
@@ -167,19 +45,9 @@ module Hecks
167
45
  keywords = rows[:keywords]
168
46
  admitted = keywords.select { |row| row[:context] == context && (row[:word] == word.to_s || row[:was] == word.to_s) }
169
47
 
170
- # **The type-position fallback** — item #13's full metaprogrammed
171
- # dispatch (slice 5). `one_of`/`list_of`, called inside an
172
- # attribute's own type argument (`attribute :x,
173
- # one_of("a","b")`), run with `self` as whatever builder is
174
- # currently instance_eval'ing — there is no dedicated "Type"
175
- # builder of its own; every attribute()-taking builder answers
176
- # these identically, through the shared `AttributeCollector`
177
- # mixin. `self.class::GRAMMAR_CONTEXT` can never actually be
178
- # "Type", so a word admitted only there would otherwise look
179
- # inadmissible everywhere. Checked only once this context has
180
- # already come up empty, so a context with its own same-named
181
- # row (`ValueObject`'s own `one_of`, the block-wrapper form)
182
- # keeps using that instead, unaffected.
48
+ # `one_of`/`list_of` in an attribute's type position run on whichever builder is
49
+ # evaluating, whose context is never "Type". Try "Type" only when its own context has
50
+ # no row, so a same-named row of its own (ValueObject's `one_of`) still wins.
183
51
  if admitted.empty?
184
52
  type_admitted = keywords.select { |row| row[:context] == "Type" && row[:word] == word.to_s }
185
53
  unless type_admitted.empty?
@@ -196,13 +64,6 @@ module Hecks
196
64
  "'#{word}' is not a word #{context} admits — legal words here: #{legal.join(', ')}"
197
65
  end
198
66
 
199
- # Item #13's full metaprogrammed dispatch — the word is
200
- # admitted here, and this builder has no hand-written method
201
- # left for it; before falling through to the "not yet
202
- # implemented" refusal every word without one still gets,
203
- # offer it to GenericDispatch — the safe, verified subset of
204
- # words whose whole behavior is now executed off this same
205
- # table, not just checked against it.
206
67
  dispatched = GenericDispatch.try(self, context, word.to_s, args, kwargs, block, rows)
207
68
  return dispatched unless dispatched.equal?(GenericDispatch::NOT_HANDLED)
208
69
 
@@ -221,15 +82,8 @@ module Hecks
221
82
  super
222
83
  end
223
84
 
224
- # A word admitted somewhere, just not in this context, still
225
- # falls through to Ruby's own `NoMethodError` rather than this
226
- # module's own richer refusal — `method_missing` fires for
227
- # every typo in the whole codebase (this class's own genuinely
228
- # private helper methods included), not just DSL keyword calls;
229
- # only raise the rich, table-driven message when the word is at
230
- # least something the grammar knows about, anywhere, so an
231
- # unrelated Ruby-level typo inside a builder's own private code
232
- # keeps its own ordinary, unconfusing `NoMethodError`.
85
+ # `method_missing` fires for every typo in a builder, so only words the grammar knows
86
+ # anywhere get the rich refusal; other typos keep Ruby's ordinary `NoMethodError`.
233
87
  def admitted_anywhere?(rows, word)
234
88
  rows.any? { |row| row[:word] == word.to_s || row[:was] == word.to_s }
235
89
  end
@@ -2,17 +2,13 @@ require_relative "word_gate"
2
2
  module Hecks
3
3
  module Bluebook
4
4
  module DSL
5
- # A generic keyword-call sink for one bind's own settings block (e.g.
6
- # `persisted_by "Heki" do dir :default end`) — every method call made
7
- # on it inside the block is recorded verbatim by name, with no fixed
8
- # vocabulary of its own; `WorldBuilder#record_binding` reads `#to_h`
9
- # back out.
5
+ # Records every keyword call made inside a bind's settings block, by name, with
6
+ # no fixed vocabulary of its own.
10
7
  class SettingsCollector
11
- # Starts with no settings recorded.
12
8
  def initialize = @values = {}
13
9
 
14
- # A call with a block records the block's own settings as a nested Hash, so a bind can
15
- # group settings (`preview do ... end`); a call without one records its argument.
10
+ # A call with a block records its own settings as a nested Hash; a bare call
11
+ # keeps a single argument as is, several as an array.
16
12
  def method_missing(key, *args, &block)
17
13
  @values[key.to_sym] =
18
14
  if block
@@ -29,30 +25,15 @@ module Hecks
29
25
  def to_h = @values
30
26
  end
31
27
 
32
- # The aggregate-qualified mirror (#143) — a `.world` file's own
33
- # `Pizzas::Order.charged_by("Stripe") do ... end` visually mirrors the
34
- # same bind line the sibling `.hecksagon` file already writes
35
- # (`HecksagonBuilder`'s own `BindingProxy`), but `IR::World#for_verb`/
36
- # `#for_binding` key purely by verb and adapter name — the aggregate
37
- # qualifier is never read back out, it exists only for that visual
38
- # mirroring. So unlike `BindingProxy`, nothing here needs to hold onto
39
- # the resolved constant chain at all: every verb call, qualified or
40
- # not, has to land in the exact same `@settings` write path
41
- # (`WorldBuilder#record_binding`).
28
+ # Stands in for a bare aggregate constant inside a `.world` block, so a bind line
29
+ # can visually mirror its sibling `.hecksagon` spelling; the qualifier is never read back out.
42
30
  class WorldConstProxy
43
- # Mints the stand-in module a bare domain constant resolves to inside a `.world` block.
44
- #
45
- # @param builder [Bluebook::DSL::WorldBuilder] the builder every verb called through the
46
- # module's proxies records its settings on
47
- # @return [Module] an anonymous module whose `const_missing` answers a `WorldConstProxy`,
48
- # whatever aggregate name follows `::`
49
31
  def self.namespace(builder)
50
32
  Module.new do
51
33
  define_singleton_method(:const_missing) { |_aggregate| WorldConstProxy.new(builder) }
52
34
  end
53
35
  end
54
36
 
55
- # @param builder [Bluebook::DSL::WorldBuilder] the builder verb calls are recorded on
56
37
  def initialize(builder) = @builder = builder
57
38
 
58
39
  def method_missing(verb, *args, **kwargs, &block) = @builder.record_binding(verb, args, kwargs, block)
@@ -60,76 +41,36 @@ module Hecks
60
41
  def respond_to_missing?(_name, _include_private = false) = true
61
42
  end
62
43
 
63
- # Parses a `.world` file's top-level DSL block into a `World` — a
64
- # domain's own `realm`/`latest` version markers plus its adapter bind
65
- # settings, one entry per `verb("Adapter") do ... end` call (whether
66
- # written bare or aggregate-qualified through `WorldConstProxy`'s
67
- # visual mirror of a sibling `.hecksagon` file's own bind).
44
+ # Parses a `.world` file's top-level DSL block into a `World` — a domain's own
45
+ # `realm`/`latest` markers plus its adapter bind settings.
68
46
  class WorldBuilder
69
47
  GRAMMAR_CONTEXT = "World".freeze
70
48
 
71
49
  include WordGate
72
50
 
73
- # @param domain [String] name of the domain whose world this is
74
51
  def initialize(domain)
75
52
  @domain = domain
76
53
  @settings = {}
77
54
  end
78
55
 
79
- # Names the realm this world belongs to, such as `"Examples"` or `"QA"`.
80
- #
81
- # `realm_impl`/`latest_impl` answer the `realm`/`latest` words
82
- # through the table's `calls:` column — item #13's full
83
- # metaprogrammed dispatch (slice 5). Neither bootstrap-reachable
84
- # (checked directly). Reached through `WordGate`'s
85
- # `word_gate_dispatch`, called explicitly below since
86
- # `WorldBuilder`'s own class-level `method_missing` (the
87
- # open-verb catch-all beneath this) always wins over the
88
- # module's — see `word_gate.rb`'s own header for the full
89
- # mechanism.
90
- #
91
- # @param value [String, Symbol] the realm's name; blankness is judged by the world
92
- # language at `build`, not here
93
- # @return [String] the realm as stored
56
+ # Reached through `WordGate`'s `word_gate_dispatch`, called explicitly since this
57
+ # class's own `method_missing` would otherwise always win over the module's.
94
58
  def realm_impl(value)
95
59
  @realm = required(value, "realm")
96
60
  end
97
61
 
98
- # Names the bluebook version this world treats as latest, which `ProjectRegister` compares
99
- # with the bluebook's own declared `version`.
100
- #
101
- # @param value [String, Symbol, Numeric] the version marker; blankness is judged by the
102
- # world language at `build`, not here
103
- # @return [String] the version as stored
62
+ # `ProjectRegister` compares this against the bluebook's own declared `version`.
104
63
  def latest_impl(value)
105
64
  @latest = required(value, "latest version")
106
65
  end
107
66
 
108
- # Names the connection every chapter's database-taking persistence adapter uses
109
- # unless that chapter's own world settings name one.
110
- #
111
- # Answers the `default_database` word through the table's `calls:` column, the
112
- # same way `realm_impl` does. A chapter's own
113
- # `persisted_by("Adapter") { database ... }` still wins for that adapter.
114
- #
115
- # @param value [String] the connection, such as a database URL; blankness is
116
- # judged by the world language at `build`, not here
117
- # @return [String] the connection as stored
67
+ # A chapter's own `persisted_by("Adapter") { database ... }` still wins for that adapter.
118
68
  def default_database_impl(value)
119
69
  @default_database = required(value, "default database")
120
70
  end
121
71
 
122
- # Names the persistence adapter every aggregate binds to unless its own chapter's
123
- # hecksagon binds it.
124
- #
125
- # Answers the `default_adapter` word through the table's `calls:` column, the same
126
- # way `realm_impl` does. Sits between an explicit bind and the framework's
127
- # in-memory fallback; whether the adapter really is a persistence adapter is
128
- # judged at boot, where adapters are known.
129
- #
130
- # @param value [String, Symbol] the adapter's declared name, such as `"PostgresEra"`;
131
- # blankness is judged by the world language at `build`, not here
132
- # @return [String] the adapter name as stored
72
+ # Sits between an explicit bind and the framework's in-memory fallback; whether the
73
+ # adapter really is a persistence adapter is judged at boot, where adapters are known.
133
74
  def default_adapter_impl(value)
134
75
  @default_adapter = required(value, "default adapter")
135
76
  end
@@ -143,20 +84,8 @@ module Hecks
143
84
 
144
85
  def respond_to_missing?(_name, _include_private = false) = true
145
86
 
146
- # Records one bind's settings under both its verb and its `verb:adapter` key.
147
- #
148
- # A method of its own, apart from `method_missing` (#143), so
149
- # `WorldConstProxy`'s own aggregate-qualified verb calls
150
- # (`Pizzas::Order.charged_by(...)`) write into the exact same
151
- # place the bare top-level spelling (`charged_by(...)`) already
152
- # does — one write path, two spellings.
153
- #
154
- # @param verb [Symbol, String] the bind verb, such as `:persisted_by`
155
- # @param args [Array<Object>] the call's positional arguments; the first names the adapter
156
- # @param kwargs [Hash{Symbol => Object}] settings given inline as keyword arguments
157
- # @param block [Proc, nil] a settings block, evaluated against a `SettingsCollector`
158
- # @return [Hash{Symbol => Object}] the settings just recorded: `:adapter` (a String),
159
- # then the keyword arguments, then the block's settings, later ones winning
87
+ # A method of its own, apart from `method_missing`, so `WorldConstProxy`'s
88
+ # aggregate-qualified verb calls write into the same place the bare spelling does.
160
89
  def record_binding(verb, args, kwargs, block)
161
90
  collector = SettingsCollector.new
162
91
  collector.instance_eval(&block) if block
@@ -165,11 +94,6 @@ module Hecks
165
94
  @settings["#{verb}:#{args.first.to_s.downcase}"] = value
166
95
  end
167
96
 
168
- # Assembles the realm, version marker and bind settings, judged by the world language.
169
- #
170
- # @return [Bluebook::World] the world, returned once the language accepts it
171
- # @raise [Bluebook::DSL::Malformed] if the world language refuses the declaration, such
172
- # as a blank `realm`
173
97
  def build
174
98
  MetaValidator.call_world(
175
99
  World.new(domain: @domain, realm: @realm, latest: @latest, settings: @settings,
@@ -177,19 +101,8 @@ module Hecks
177
101
  )
178
102
  end
179
103
 
180
- # Evaluates a `Hecks.world` block against a fresh builder and returns the world it declared.
181
- #
182
- # `ConstShim`'s resolver, the same bridge `HecksagonBuilder`/
183
- # `BluebookBuilder` already wrap their own `instance_eval` in
184
- # (#143) — without it, `Pizzas::Order.charged_by(...)` raises
185
- # `NameError: uninitialized constant Pizzas` for every `.world`
186
- # file using the aggregate-qualified mirror form, since a bare
187
- # `Pizzas` has no real constant to resolve to.
188
- #
189
- # @param domain [String] name of the domain whose world this is
190
- # @yield the world body, evaluated with the builder as `self`; may be omitted
191
- # @return [Bluebook::World] the judged world
192
- # @raise [Bluebook::DSL::Malformed] if the world language refuses the declaration
104
+ # Wraps `instance_eval` in `ConstShim`'s resolver: without it, an aggregate-qualified
105
+ # verb call raises `NameError`, since the bare constant has nothing to resolve to.
193
106
  def self.build(domain, &block)
194
107
  builder = new(domain)
195
108
  resolver = ->(_domain) { WorldConstProxy.namespace(builder) }
@@ -200,7 +113,7 @@ module Hecks
200
113
  private
201
114
 
202
115
  def required(value, _label)
203
- # moved to the language: Realm / Latest invariants, in world.bluebook
116
+ # Validation lives in the world language (world.bluebook), not here.
204
117
  value.to_s
205
118
  end
206
119
  end
@@ -3,28 +3,11 @@ require_relative "expression/ast_json"
3
3
 
4
4
  module Hecks
5
5
  module Bluebook
6
- # An entity, as a Ruby class — a piece of an aggregate that has an identity
7
- # of its own.
8
- #
9
- # Crossing over closes the owner chain. An entity declares commands, and
10
- # until now those commands had no owner that could state an identity: an
11
- # entity was an IR object, not a construct, so `Construct#hecks_fqn` refused
12
- # rather than answering "Deposit" and looking right. Four of banking's
13
- # commands were in that state. They can say what they are now —
14
- # `Banking::Account.Ledger.Deposit` — which is the id the judge already mints
15
- # for them.
16
- #
17
- # Not const_set, for the same reason a command is not: a name inside one
18
- # aggregate can denote more than one kind of thing, so the constant tree
19
- # cannot index it.
20
- #
21
- # It must stay structurally interchangeable with an aggregate — the runtime
22
- # builds `Instance.new(aggregate: entity)` and `CommandRules` takes either as
23
- # `declaring` — so it answers `hecks_name`, `attributes`, `attribute`,
24
- # `identified_by` and `lifecycle` exactly as an aggregate does. And it must
25
- # keep not answering `value_object`: `Value.for_attribute` sniffs for that
26
- # method to tell a piece from a head.
6
+ # An entity as a Ruby class: a piece of an aggregate that has an identity of its own.
7
+ # Not const_set, because a name inside one aggregate can denote more than one kind of thing.
27
8
  class Entity
9
+ # Stays interchangeable with an aggregate (`Instance.new(aggregate: entity)`, `CommandRules`
10
+ # `declaring`) but must not answer `value_object`, which `Value.for_attribute` sniffs for.
28
11
  extend Construct
29
12
  extend Hecks::IR
30
13
  extend Behaviour::Entity
@@ -36,32 +19,12 @@ module Hecks
36
19
  attributes: many(:attributes),
37
20
  commands: many(:commands),
38
21
  queries: many(:queries),
39
- # S17, ADR 0026 — "That is what `entity` is for, and `entity` is
40
- # declared by the language and used zero times in it" (the ADR's
41
- # own words). Dispatch nests inside Handler, so an entity's own
42
- # nested entities are part of its wire shape now, the same way
43
- # an aggregate's always were — the field the ADR names as
44
- # declared-but-unused until this slice.
45
22
  entities: many(:entities),
46
- # ADR 0028 — a piece's own `given`, the same shape
47
- # `Aggregate#preconditions` already carries (its own `emits_ir`
48
- # row, identical). A precondition shared across this piece's own
49
- # commands, declared once — a command references it back by
50
- # name; the resolved text still lands on each referencing
51
- # command's own `givens` either way, so this field is read-only
52
- # documentation of what the piece itself declared, the same
53
- # relationship `Aggregate.preconditions` already has to its own
54
- # commands.
23
+ # Read-only record of the piece's own `given`; resolved text lands on each command's
24
+ # `givens`.
55
25
  preconditions: -> { preconditions.map { |rule| Expression::AstJson.rule_row(rule) } },
56
- # A piece's own shape rule, checked against every instance of
57
- # this piece the aggregate holds (Admissibility#enforce_
58
- # invariants' own recursive walk) — the same relationship
59
- # `ValueObject#invariants` already has to its own instances,
60
- # one level up the construct tree. Not a separate enforcement
61
- # boundary; still checked at the same two points (after every
62
- # mutation, before save) the aggregate's own invariants always
63
- # were — see that method's own comment for why this does not
64
- # contradict "there is no separate entity invariant."
26
+ # Checked against every instance of this piece, at the same points as an aggregate's
27
+ # invariants.
65
28
  invariants: -> { invariants.map { |rule| Expression::AstJson.rule_row(rule) } },
66
29
  lifecycle: one(:lifecycle)
67
30
  )
@@ -73,20 +36,11 @@ module Hecks
73
36
  # Mints a new piece class for one declared entity and absorbs its fields into it.
74
37
  #
75
38
  # @param name [String, Symbol] the entity's declared name
76
- # @param description [String, nil] the entity's declared prose description
77
39
  # @param identified_by [String, Symbol, Array<String, Symbol>, nil] the identity
78
40
  # path(s) this entity is addressed by
79
- # @param attributes [Array<Bluebook::Attribute>] the entity's declared fields
80
- # @param commands [Array<Class>] the command classes (`Bluebook::Command` subclasses)
81
- # declared on this entity
82
- # @param queries [Array<Bluebook::Query>] the queries declared on this entity
83
- # @param entities [Array<Class>] the entity classes (`Bluebook::Entity` subclasses)
84
- # nested directly under this entity
85
- # @param preconditions [Array<Bluebook::Given>] this entity's own named `given`s
86
- # @param invariants [Array<Bluebook::Invariant>] the rules checked against every
87
- # instance of this entity
88
- # @param lifecycle [Bluebook::Lifecycle, nil] the entity's declared state machine,
89
- # or `nil` if it declares none
41
+ # @param commands [Array<Class>] the command classes declared on this entity
42
+ # @param entities [Array<Class>] the entity classes nested directly under this entity
43
+ # @param lifecycle [Bluebook::Lifecycle, nil] the declared state machine, or `nil`
90
44
  # @return [Class] the minted piece class (a `Bluebook::Entity` subclass)
91
45
  def declare(name:, description: nil, identified_by: nil, attributes: [],
92
46
  commands: [], queries: [], entities: [], preconditions: [], invariants: [], lifecycle: nil)
@@ -100,20 +54,8 @@ module Hecks
100
54
  piece
101
55
  end
102
56
 
103
- # Assigns what the language declares, then hands off to the
104
- # behaviour's own `settle` — derived identity and the name
105
- # indexes, neither of which the declaration states.
106
- #
107
- # @param description [String, nil] see `declare`
108
- # @param identified_by [String, Symbol, Array<String, Symbol>, nil] see `declare`
109
- # @param attributes [Array<Bluebook::Attribute>] see `declare`
110
- # @param commands [Array<Class>] see `declare`
111
- # @param queries [Array<Bluebook::Query>] see `declare`
112
- # @param entities [Array<Class>] see `declare`
113
- # @param preconditions [Array<Bluebook::Given>] see `declare`
114
- # @param invariants [Array<Bluebook::Invariant>] see `declare`
115
- # @param lifecycle [Bluebook::Lifecycle, nil] see `declare`
116
- # @return [Class] this piece's own class, self, once identity and indexes are derived
57
+ # Assigns the declared fields, then lets the behaviour's `settle` derive identity and
58
+ # indexes.
117
59
  def absorb(description:, identified_by:, attributes:, commands:, queries:, entities:, preconditions:, invariants:,
118
60
  lifecycle:)
119
61
  @description = description