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,19 +1,11 @@
1
1
  module Hecks
2
2
  module Bluebook
3
3
  module DSL
4
- # Shared mixin for every DSL builder that declares attributes
5
- # (Aggregate/Entity/Command/Query/PortOperation/ValueObject) — the
6
- # `attribute`/`list_of`/`one_of` words themselves, closed-set
7
- # synthesis, duplicate-name and pattern refusals, and the
8
- # `identified_by` field/type resolution both a construct's own
9
- # identity and a compound key are built from.
4
+ # Mixin for DSL builders that declare attributes: `attribute`, `list_of`, `one_of`,
5
+ # closed-set synthesis, and `identified_by` resolution.
10
6
  module AttributeCollector
11
7
  ListOf = Struct.new(:type)
12
- # `:values` shadows Struct#values on purpose — with one member, the
13
- # generated accessor returns the flat array of permitted values
14
- # directly (what every caller actually wants), not Struct#values'
15
- # own `[self.values]`. No caller anywhere reads the built-in
16
- # behavior; verified before disabling this cop for it.
8
+ # `:values` shadows Struct#values so the accessor returns the flat permitted-value array.
17
9
  # rubocop:disable-next Lint/StructNewOverride
18
10
  OneOf = Struct.new(:values)
19
11
 
@@ -31,73 +23,20 @@ module Hecks
31
23
  # @return [Array<Bluebook::ValueObject>] the value objects synthesised so far
32
24
  def closed_sets = @closed_sets ||= []
33
25
 
34
- # Declares one field on the owning construct, with its type and, optionally, a default,
35
- # an optionality flag, a pattern, a closed-set reference, or an inline closed set.
36
- #
37
- # `admits:` names a closed set that is already declared elsewhere —
26
+ # Declares one field on the owning construct; the type is a bare constant (ADR 0025).
38
27
  #
39
28
  # attribute :op, String, admits: "Vocabulary::QueryComparator"
40
29
  #
41
- # which is the difference between it and `one_of`: `one_of` synthesises
42
- # a fresh value object named for the attribute, so it can only ever name
43
- # something new. `admits` points at a set the language already holds, so
44
- # the same set can be named from many places without being written twice.
45
- #
46
- # Qualified, because a closed set is a value object inside an aggregate
47
- # and `reference_to` reaches heads only — so this is text, checked where
48
- # it is read rather than by reference resolution.
49
- #
50
- # And written as text, not as the constant path `Vocabulary::QueryComparator`
51
- # it reads like. The constant spelling was tried — `ConstShim` returning
52
- # a Module so Ruby's `::` reaches a second `const_missing` — and it
53
- # cannot hold: `Facade::Surface` installs every aggregate name as a
54
- # top-level constant, so the moment any facade exists, `Vocabulary`
55
- # resolves to that module and the shim is never asked. A spelling that
56
- # works only until a facade is built is worse than a quoted one.
30
+ # `admits:` names an already-declared closed set as qualified text, checked on read.
31
+ # `one_of:` declares an inline closed set and is only meaningful inside a `value_object`.
57
32
  #
58
- # The type position takes a bare constant, always required (ADR 0025,
59
- # "Attributes") — omitting it (a mint default of String) and quoting
60
- # it as text both refuse now. Neither had a real reason left: no
61
- # corpus attribute ever omitted the type, and `ConstShim#const_missing`
62
- # (S0b) already resolves a bare, not-yet-declared constant to the
63
- # same forward reference the quoted form existed for — a bareword
64
- # `Name` reaches a value object named "Name" declared later in the
65
- # same block, exactly what the quoted form `"Name"` would have
66
- # reached — `spell`'s own `to_s` renders either one identically.
67
- # Neither form appears in any frozen era text (checked directly), so
68
- # both are refused unconditionally — nothing for
69
- # `MetaValidator.shadow_parsing?` to answer for.
70
- #
71
- # The word `attribute` itself is not a real method any builder answers
72
- # directly: every (context, word) Keyword row for it carries
73
- # `calls: "attribute_impl"`, and `GenericDispatch` forwards the whole
74
- # call here untouched. `attribute_collector_spec.rb`
75
- # (`AttributeCollector has no method without a test` —
76
- # dsl_coverage_spec.rb) and the bootstrap fallback
77
- # (`GenericDispatch::BOOTSTRAP_CALLS_FALLBACK`) both name this same
78
- # string; they must never drift apart.
79
- #
80
- # @param name [Symbol] the attribute's name
81
- # @param type [Module, Symbol, ListOf, OneOf] the attribute's type: a bare constant
82
- # (resolved by `ConstShim`), or the `ListOf`/`OneOf` wrapper `list_of`/`one_of` return
83
- # when called in this same type position; quoted text is refused
84
- # @param default [Object, nil] the value an omitted attribute defaults to; not type-checked
85
- # here
86
- # @param optional [Boolean] whether the attribute may be omitted entirely
87
- # @param pattern [Regexp, String, nil] a pattern the attribute's value must match; refused
88
- # if it uses a construct `PatternSubset` disallows
89
- # @param admits [String, nil] the qualified name of an already-declared closed set this
90
- # attribute's value may come from, such as `"Vocabulary::QueryComparator"`
91
- # @param one_of [Array<String, Symbol>, nil] permitted values for a field-shaped closed
92
- # set, declared inline via `one_of: [...]`; meaningful only inside a `value_object`
93
- # (`ValueObjectBuilder` overrides `install_inline_closed_set`) — refused everywhere else
33
+ # @param type [Module, ListOf, OneOf] a bare constant or a `list_of`/`one_of` wrapper
94
34
  # @return [void]
95
- # @raise [Bluebook::DSL::Malformed] if `name` is already declared, `type` is omitted or
96
- # quoted text, `pattern` uses a disallowed construct, or `one_of:` is given outside a
97
- # `value_object`
35
+ # @raise [Malformed] on a duplicate name, a missing or quoted type, a disallowed
36
+ # pattern, or `one_of:` outside a `value_object`
98
37
  def attribute_impl(name, type = UNSET, default: nil, optional: false, pattern: nil,
99
38
  admits: nil, one_of: nil)
100
- # moved to the language: FieldName invariant, on Root.Attribute
39
+ # The FieldName invariant on Root.Attribute enforces the name.
101
40
 
102
41
  refuse_duplicate_attribute!(name)
103
42
 
@@ -106,10 +45,7 @@ module Hecks
106
45
  "there is no default"
107
46
  end
108
47
 
109
- # `list_of("X")` carries the same quoted text one level down — a
110
- # bare constant is required there too, checked before it unwraps
111
- # below, not after (once unwrapped, a plain String in the `type:`
112
- # slot looks identical to one that legitimately belongs there).
48
+ # `list_of("X")` carries quoted text one level down; check it before unwrapping.
113
49
  quoted = type.is_a?(ListOf) ? type.type : type
114
50
  if quoted.is_a?(::String)
115
51
  raise Malformed, "#{name}'s type #{quoted.inspect} is quoted text — give the bare constant " \
@@ -134,73 +70,24 @@ module Hecks
134
70
  install_inline_closed_set(name, one_of) if one_of
135
71
  end
136
72
 
137
- # Wraps a type so `attribute_impl` records it as a list-valued attribute.
138
- #
139
- # Called in an attribute's own type position (`attribute :x,
140
- # list_of(Y)`), never through a `def list_of` any one builder
141
- # answers as its own word — reached via
142
- # `WordGate#word_gate_dispatch`'s "Type"-context fallback, the same
143
- # one `one_of_impl` below uses. Bootstrap-reachable (every core
144
- # chapter's own list-typed attributes use it), so
145
- # `GenericDispatch::BOOTSTRAP_CALLS_FALLBACK` carries a single
146
- # `["Type", "list_of"]` entry rather than one per calling context —
147
- # the bootstrap branch checks that key too, same reasoning as the
148
- # ordinary fallback.
73
+ # Wraps a type so `attribute_impl` records it as list-valued: `attribute :x, list_of(Y)`.
149
74
  #
150
- # @param type [Module, Symbol] the list's element type, a bare constant
151
- # @return [Bluebook::DSL::AttributeCollector::ListOf] the wrapper `attribute_impl` reads
152
- # to mark the attribute list-valued
75
+ # Reached through WordGate's "Type"-context fallback; one `["Type", "list_of"]` entry in
76
+ # GenericDispatch::BOOTSTRAP_CALLS_FALLBACK covers bootstrap.
153
77
  def list_of_impl(type) = ListOf.new(type)
154
78
 
155
- # `reference_to Account` mints `:account` — no `_id` — the default
156
- # every `reference_to`-shaped word (`AggregateBuilder`,
157
- # `EntityBuilder`, `CommandBuilder#cross_reference`,
158
- # `QueryBuilder`, `PortOperationBuilder`, all `include
159
- # AttributeCollector`) shares, since dropping the suffix is what
160
- # makes `/` a real traversal operator possible at all (ADR 0025,
161
- # "References" — a hop crosses at `/`, a field walk crosses at
162
- # `.`; deriving the hop name from `account_id` is what made an
163
- # explicit operator impossible before).
164
- #
165
- # Legacy under shadow-parsing (S0a's own bridge): frozen era text
166
- # was minted under the old default, and `EraGuard.shadow_parse`
167
- # reconstructs a held aggregate's shape to diff against the
168
- # current one — reading that text through the new default would
169
- # silently reconstruct the wrong historical name, not merely
170
- # refuse a spelling the way S1's `identified_by` legacy forms do.
171
- # This is a mint default changing, not a syntax being removed, so
172
- # there is nothing to refuse here — only a fork in what gets
173
- # minted when `as:` is omitted.
79
+ # `reference_to Account` mints `:account`, no `_id` (ADR 0025). Under shadow-parsing the
80
+ # suffix is kept so frozen era text reconstructs the name it was minted under.
174
81
  private def default_reference_name(target)
175
82
  suffix = MetaValidator.shadow_parsing? ? "_id" : ""
176
83
  :"#{Naming.snake(target)}#{suffix}"
177
84
  end
178
85
 
179
- # A closed set declared inline on the attribute:
86
+ # Wraps permitted values so `attribute_impl` synthesises a closed-set value object:
180
87
  #
181
88
  # attribute :status, one_of("open", "shut")
182
89
  #
183
- # Desugars to a value object named for the attribute, so it goes through
184
- # exactly the machinery a hand-written one_of does — and so the
185
- # attribute's type is still a declared value object, which is now a
186
- # structural rule rather than a predicate.
187
- #
188
- # Wraps a list of permitted values so `attribute_impl` synthesises a closed-set value
189
- # object for them.
190
- #
191
- # The desugaring is pinned — the same bluebook must always yield the
192
- # same IR, so a plain String attribute silently discarding the
193
- # values is not an outcome this spelling can produce.
194
- #
195
- # Reached the same way `list_of_impl` above is. Same name as
196
- # `ValueObjectBuilder#one_of_impl`'s own override on purpose —
197
- # that method's own `super(*values)` call (the no-block, bare
198
- # type-position case) resolves by method name up the ancestor
199
- # chain, and renaming only one side would silently break it.
200
- #
201
- # @param values [Array<String, Symbol>] the permitted values
202
- # @return [Bluebook::DSL::AttributeCollector::OneOf] the wrapper `attribute_impl` reads to
203
- # synthesise the closed-set value object
90
+ # Shares its name with `ValueObjectBuilder#one_of_impl`, whose `super` resolves by name.
204
91
  def one_of_impl(*values) = OneOf.new(values)
205
92
 
206
93
  private
@@ -216,46 +103,24 @@ module Hecks
216
103
  )
217
104
  end
218
105
 
219
- # `one_of:` names a closed set on the field itself (ADR 0025,
220
- # "Attributes") — joining `pattern:`/`admits:` where value
221
- # constraints already live, for the one context where it means
222
- # anything: a `value_object` block, where it replaces the old
223
- # `one_of do member ... end` wrapper for a single-field set (a
224
- # multi-field set still writes bare `member` lines, unwrapped).
225
- # `ValueObjectBuilder` overrides this; every other includer
226
- # (Aggregate/Entity/Command/Query/PortOperation) inherits this
227
- # refusal — those contexts already have the unchanged type-position
228
- # form (`attribute :status, one_of("open", "shut")`) for an
229
- # anonymous inline set, so `one_of:` naming a *field* there would be
230
- # a second spelling of the same idea, not a new one.
106
+ # `one_of:` on a field is meaningful only inside a `value_object` (ADR 0025);
107
+ # ValueObjectBuilder overrides this and every other includer refuses.
231
108
  def install_inline_closed_set(name, _values)
232
109
  raise Malformed,
233
110
  "#{name}'s one_of: only means something inside a value_object — name a closed set " \
234
111
  "with the type-position one_of(...) instead"
235
112
  end
236
113
 
237
- # A name declared twice on the same owner is two attributes sharing
238
- # one name, and nothing downstream disambiguates them — every
239
- # reader that walks `attributes` looking for one by name
240
- # (`seal_mutation_targets`, `seal_query_field`, `projects`'s own
241
- # local check, `Instance#[]`, ...) uses `Array#find`/`any?`, which
242
- # silently answers whichever declaration happens to come first and
243
- # discards the second — left unrefused, both declarations would
244
- # survive into the IR, one of them permanently unreachable by name.
245
- # Refused here, at the one place every owner
246
- # (Aggregate/Entity/Command/Query/PortOperation/ValueObject, each
247
- # `include AttributeCollector`) mints an attribute through, rather
248
- # than taught to each of those readers individually.
114
+ # Refused where every owner mints an attribute: readers look names up with `find`/`any?`
115
+ # and would silently discard the second declaration.
249
116
  def refuse_duplicate_attribute!(name)
250
117
  return unless attributes.any? { |attribute| attribute.name == name }
251
118
 
252
119
  raise Malformed, "#{name} is declared twice — an attribute name is declared once, not twice"
253
120
  end
254
121
 
255
- # A pattern is refused at declaration, not when a value first meets it :
256
- # a regex whose meaning depends on which engine reads it is a defect in
257
- # the bluebook, and a bluebook that loads is one whose patterns carry
258
- # one meaning. PatternSubset says which those are, and why each is refused.
122
+ # Refused at declaration: a regex whose meaning depends on the engine must not load
123
+ # (PatternSubset says which constructs and why).
259
124
  def refuse_unshared_pattern(name, pattern)
260
125
  rejection = PatternSubset.validate(pattern)
261
126
  return unless rejection
@@ -276,27 +141,12 @@ module Hecks
276
141
  type
277
142
  end
278
143
 
279
- # Every selected identity head contributes all of its recursively
280
- # scalar leaves in declaration order. Named, inline and compound-key
281
- # declarations therefore share one flattening rule.
144
+ # Each selected identity head contributes all its scalar leaves in declaration order.
282
145
  def resolve_identity_field!(field, value_objects, context_name)
283
146
  attr = attributes.find { |a| a.name == field }
284
147
 
285
- # `:id` or an `_id`-suffixed name with no matching attribute is
286
- # not a typo to refuse — it is the language's own walk-parent/
287
- # fallback-identity convention. The `_id` suffix is the meta-
288
- # domain's own (the `Command`/`Entity`/`Aggregate` etc. records
289
- # identify by `owner_id`/`bluebook_id`/`aggregate_id`, supplied
290
- # by the judge's replay rather than declared locally — see
291
- # `behavior.bluebook`'s own "owner_id is not a declared
292
- # attribute" comment); bare `:id` is `Instance#materialize_
293
- # identity!`'s own fallback name (`@aggregate.identified_by ||
294
- # :id`) made explicit rather than left implicit — declaring
295
- # `identified_by :id` says out loud what omitting `identified_by`
296
- # entirely already meant. `reference_to` mints the `_id` suffix
297
- # for the same reason `attr.reference?` below resolves bare: an
298
- # `_id`(-shaped) name is already a scalar by the language's own
299
- # spelling convention, walk-supplied or locally declared alike.
148
+ # A bare `:id` or `_id`-suffixed name with no matching attribute is the walk-parent/
149
+ # fallback-identity convention (Instance#materialize_identity! falls back to `:id`).
300
150
  return [field.to_s] if attr.nil? && (field.to_s == "id" || field.to_s.end_with?("_id"))
301
151
 
302
152
  raise Malformed, "#{context_name}.identified_by :#{field} names no attribute #{context_name} declares" unless attr
@@ -321,26 +171,11 @@ module Hecks
321
171
  "#{context_name}.identified_by #{target} mints :#{field}, but that attribute is already declared"
322
172
  end
323
173
 
324
- # `Attribute.new` directly, not the public `attribute(...)` DSL
325
- # entry — `target` is `Naming.demodulise`'d text, not a bareword
326
- # the bluebook author typed (the type position's own quoted-text
327
- # refusal is about DSL source, not internal minting), and `vo`
328
- # itself can't be passed either: it is the real, already-built
329
- # `ValueObject` subclass, permanently anonymous from Ruby's own
330
- # `to_s` (only `hecks_name` carries its name) — `Attribute#spell`
331
- # would demodulise it to "#<Class:0x...>", not "PizzaName".
174
+ # `Attribute.new` directly: `vo` is an anonymous class whose `to_s` would spell
175
+ # "#<Class:0x...>", so the demodulised `target` text is the type.
332
176
  attributes << Attribute.new(name: field, type: target)
333
- # Moved to `insert_at` — the attribute count at the moment
334
- # `identified_by` was actually called, captured by the caller —
335
- # not left where `attribute` just appended it. Resolution happens
336
- # at build time, after every other attribute in the block has
337
- # already run, so appending would put the identity field last
338
- # regardless of where `identified_by` was actually written.
339
- # Most real bluebooks write it first (insert_at 0); one (a
340
- # ScheduledPayment corpus member) writes it after a reference_to
341
- # and an attribute — this matches either, producing the same
342
- # result a person hand-writing `attribute field, Type` at that
343
- # exact point would.
177
+ # Moved to `insert_at`, the attribute count when `identified_by` was called; resolution
178
+ # runs at build time, so appending would put the identity field last.
344
179
  attributes.insert(insert_at, attributes.pop)
345
180
  vo.attributes.flat_map do |attribute|
346
181
  identity_paths_for_attribute(attribute, value_objects, context_name,
@@ -368,14 +203,8 @@ module Hecks
368
203
  raise Malformed, "#{context_name}'s identity value objects form a cycle: #{cycle}"
369
204
  end
370
205
 
371
- # **A bare field derives one scalar**. `identified_by :ref` (or one leg
372
- # of a compound `identified_by :a, :b`) names a single field, and
373
- # deriving its path only makes sense while every value object along
374
- # the way wraps exactly one field itself — the same "single-field
375
- # value object" ADR 0025 names this shape after. Left unrefused, a
376
- # multi-field value object here would expand silently into every
377
- # one of its own fields, minting an unannounced compound key
378
- # nothing declared.
206
+ # A bare field derives one scalar, so each value object on the way must wrap exactly one
207
+ # field (ADR 0025); otherwise it would silently mint an unannounced compound key.
379
208
  if nested.attributes.size != 1
380
209
  candidates = nested.attributes.map(&:name).join(", ")
381
210
  raise Malformed,
@@ -1,19 +1,10 @@
1
1
  module Hecks
2
2
  module Bluebook
3
3
  module DSL
4
- # What a bare `Domain::Aggregate` constant resolves to inside a
5
- # `.hecksagon`/`.world` block (minted by `.namespace`'s own
6
- # `const_missing`) — `method_missing` turns a bind like
7
- # `Payment.persisted_by "Postgres"` into a queued `Bind`, and `#port`
8
- # is the one real method, for `Aggregate.port("Name") do ... end`.
4
+ # What a bare `Domain::Aggregate` constant resolves to inside a `.hecksagon`/`.world`
5
+ # block; `method_missing` records a bind, `#port` is the one real method on this proxy.
9
6
  class BindingProxy
10
- # Mints the stand-in module a bare domain constant resolves to inside a `.hecksagon` block.
11
- #
12
- # @param domain [Symbol, String] the domain name, the first segment of `Domain::Aggregate`
13
- # @param collector [Array<Bluebook::Bind>] the list every bind made through the module's
14
- # proxies is appended to
15
- # @return [Module] an anonymous module whose `const_missing` answers a `BindingProxy`
16
- # for `"Domain::Aggregate"`
7
+ # Mints the module a bare `Domain::Aggregate` constant resolves to via `const_missing`.
17
8
  def self.namespace(domain, collector)
18
9
  Module.new do
19
10
  define_singleton_method(:const_missing) do |aggregate|
@@ -22,48 +13,26 @@ module Hecks
22
13
  end
23
14
  end
24
15
 
25
- # @param fqn [String] the aggregate's qualified name, `"Domain::Aggregate"`
26
- # @param collector [Array<Bluebook::Bind>] the list each bind made on this proxy is
27
- # appended to
28
16
  def initialize(fqn, collector)
29
17
  @fqn = fqn
30
18
  @collector = collector
31
19
  end
32
20
 
33
- # Declares a port on this aggregate and attaches it to the already-registered bluebook.
34
- #
35
- # **The aggregate-scoped port** — `Payments::Payment.port("Gateway") do
36
- # ... end`, the same receiver a plain bind like `.persisted_by(...)`
37
- # already reaches, because a port belongs to exactly one aggregate
38
- # the same way a bind does. A real method, not method_missing : its
39
- # shape (a name and a block building operations) has nothing to do
40
- # with `Bind`, so it does not belong in that generic verb path.
41
- #
42
- # @param name [String] the port's name, such as `"Gateway"`
43
- # @yield the port body, evaluated against a `DomainPortBuilder`: either `verb`/`signal`
44
- # or `operation`/`tells`/`asks` blocks
45
- # @return [Bluebook::DSL::BindingProxy] this proxy, so further binds can chain
46
- # @raise [Bluebook::DSL::Malformed] if the current registry holds no such aggregate, or
47
- # the body declares both a verb and operations, neither, or an operation the port
48
- # grammar refuses
21
+ # Declares a port on this aggregate. A real method, not method_missing — its
22
+ # shape (name plus an operations block) is unrelated to `Bind`'s generic verb path.
49
23
  def port(name, &block)
50
24
  domain, aggregate_name = @fqn.split("::")
51
25
  aggregate_ir = Hecks.current_registry.bluebook(domain)&.aggregate(aggregate_name) or
52
26
  raise Malformed, "#{@fqn} declares no such aggregate — a port needs one to belong to"
53
27
 
54
- # See HecksagonBuilder#port's own comment on why this resolver
55
- # swap is needed : ConstShim's active resolver is one global for
56
- # the whole dynamic extent, and it is currently this file's own
57
- # BindingProxy-minting one, which would turn a bare `Pizza` inside
58
- # `reference_to Pizza` into another BindingProxy instead of a name.
28
+ # ConstShim's resolver is one global for the whole dynamic extent; without
29
+ # swapping it here, a bare `Pizza` inside `reference_to Pizza` would resolve
30
+ # to another BindingProxy instead of a plain name.
59
31
  built = ConstShim.with(->(const) { const }) { DomainPortBuilder.build(name, owner: aggregate_name, &block) }
60
32
 
61
- # A `verb`-shaped port is a plain `Port` — the exact struct
62
- # `Hecks.port`'s own top-level method registers, so it goes
63
- # through the same `add_port` the registry already answers for
64
- # that call. It belongs to no aggregate IR the way an
65
- # operations-shaped `DomainPort` does; the aggregate above
66
- # was only needed to resolve `owner` for the operations branch.
33
+ # A `verb`-shaped port is a plain `Port`, the same struct `Hecks.port`
34
+ # registers — it belongs to no aggregate IR the way an operations-shaped
35
+ # `DomainPort` does, so it takes the registry's `add_port` directly.
67
36
  if built.is_a?(Port)
68
37
  Hecks.current_registry.add_port(built)
69
38
  return self
@@ -77,14 +46,9 @@ module Hecks
77
46
  end
78
47
 
79
48
  def method_missing(verb, *args, **kwargs, &block)
80
- # A BARE CALL — no args, no kwargs, no block — starts (or
81
- # continues, on `AttributePath` itself below) a Privacy
82
- # marking chain: `Registration.attendee.medications.has_phi(
83
- # readable_by: "Privacy officer")`. No existing real
84
- # `.hecksagon` bind is ever called this way (verified by
85
- # grep before adding this branch — `persisted_by`/
86
- # `opened_by`/every other bind always takes at least one
87
- # arg), so this cannot collide with recording a `Bind`.
49
+ # A bare call (no args/kwargs/block) starts a Privacy marking chain instead
50
+ # of a Bind — no real `.hecksagon` bind is ever called with zero arguments,
51
+ # so this can't collide with recording one.
88
52
  return AttributePath.new(@fqn, [verb.to_s]) if args.empty? && kwargs.empty? && !block
89
53
 
90
54
  @collector << Bind.new(
@@ -102,27 +66,15 @@ module Hecks
102
66
  def to_s = @fqn
103
67
  end
104
68
 
105
- # What a Privacy-marking chain resolves to after its first bare segment —
106
- # `Registration.attendee` returns one of these, `.medications` returns another
107
- # (one segment longer), and a terminal `has_<category>(readable_by:)` records the
108
- # marking and ends the chain. See `BindingProxy#method_missing`'s own header for why
109
- # a bare call is unambiguously the start of one of these, never a `Bind`.
69
+ # What a Privacy-marking chain resolves to after its first bare segment — each
70
+ # bare call extends the path one segment; a terminal `has_<category>(readable_by:)` ends it.
110
71
  class AttributePath
111
- # @param fqn [String] the aggregate's own qualified name, `"Domain::Aggregate"`
112
- # @param path [Array<String>] every segment named so far, e.g. `["attendee"]`
113
72
  def initialize(fqn, path)
114
73
  @fqn = fqn
115
74
  @path = path
116
75
  end
117
76
 
118
- # @param verb [Symbol] `has_<category>` to record the marking and end the chain;
119
- # any other bare name to extend the path one segment further
120
- # @param readable_by [String] required only for a `has_<category>` call — the
121
- # Governance role a read must hold to see this field unredacted
122
- # @return [Bluebook::DSL::AttributePath, nil] a longer chain for a plain segment;
123
- # `nil` (nothing further to chain) for a `has_<category>` call
124
- # @raise [Malformed] if a `has_<category>` call omits `readable_by:`, or any call
125
- # carries positional args or a block (neither shape this chain supports)
77
+ # Records a `has_<category>` marking, or extends the attribute path by one segment.
126
78
  def method_missing(verb, *args, readable_by: nil, **kwargs, &block)
127
79
  name = verb.to_s
128
80
  return record_marking(name.delete_prefix("has_"), readable_by) if name.start_with?("has_")