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
@@ -3,23 +3,11 @@ require_relative "../../bluebook/hexagon"
3
3
  module Hecks
4
4
  module Runtime
5
5
  class Registry
6
- # The wiring gate: every bind names a declared aggregate, every
7
- # adapter satisfies the verb its port declares, every world setting is
8
- # a field the adapter admits, and the default adapter is usable at
9
- # all. Included into Registry — `verify!` is what a boot calls after
10
- # loading, and the smaller checks are also called piecemeal by the
11
- # repository factory.
6
+ # The wiring gate: every bind names a declared aggregate, every adapter satisfies its
7
+ # port's verb, and every world default is usable. `verify!` runs it all at boot.
12
8
  module Verification
13
- # Runs the whole wiring gate against this registry's loaded bluebooks,
14
- # hexagons, ports and adapters.
15
- #
16
- # @return [Runtime::Registry] self
17
- # @raise [Runtime::WiringError] if a bind names an undeclared aggregate, an
18
- # adapter cannot satisfy its port's verb or declared `answers`, a world
19
- # setting names a field its adapter does not declare, the default adapter
20
- # is unusable, a world's `default_adapter` is not a persistence adapter, a
21
- # command declares a role with no authorization provider attached, or a
22
- # membership chapter is loaded with no identity chapter
9
+ # Runs every wiring check against this registry's loaded bluebooks, hexagons, ports
10
+ # and adapters.
23
11
  def verify!
24
12
  verify_default_adapter!
25
13
  verify_world_defaults!
@@ -35,19 +23,9 @@ module Hecks
35
23
  refuse_bounded_without_acl!(hexagon)
36
24
 
37
25
  hexagon.binds.each do |bind|
38
- # A domain-level default (§0) — `persisted_by "Heki"` bare,
39
- # applying to whichever aggregates don't override it — names
40
- # no aggregate of its own, so there's nothing to look up in
41
- # the bluebook for this row specifically. Still validate its
42
- # own adapter/verb shape (the same reason
43
- # `verify_default_adapter!` checks the framework-wide
44
- # default the same way, aggregate-less). Coverage of real
45
- # aggregates that only resolve through this default comes
46
- # from their own dispatch-time `BindingPolicy.resolve` —
47
- # deliberately not required to be exhaustive here, the same
48
- # leniency this method already extended to any aggregate
49
- # left out of an explicit bind list entirely (real test
50
- # fixtures bind only the aggregates they exercise).
26
+ # A domain-level default (§0) names no aggregate of its own; still validate its
27
+ # adapter/verb shape. Real aggregates resolving through it are covered by their
28
+ # own dispatch-time `BindingPolicy.resolve`, not required to be exhaustive here.
51
29
  if bind.aggregate.nil?
52
30
  check_verb(bind)
53
31
  next
@@ -67,13 +45,7 @@ module Hecks
67
45
  self
68
46
  end
69
47
 
70
- # Checks that the framework-wide default persistence adapter (used by any
71
- # aggregate left out of an explicit bind list) is itself wired correctly.
72
- #
73
- # @return [Runtime::Registry] self
74
- # @raise [Runtime::WiringError] if the default adapter cannot satisfy the
75
- # persistence port's verb, is missing a declared `answers` method, or has
76
- # no Ruby implementation
48
+ # Checks that the framework-wide default persistence adapter is itself wired correctly.
77
49
  def verify_default_adapter!
78
50
  name = Ports::Persistence::DEFAULT_ADAPTER
79
51
 
@@ -92,14 +64,7 @@ module Hecks
92
64
  "aggregate with no bind could not be given one: #{e.message}"
93
65
  end
94
66
 
95
- # Checks that `bind`'s adapter implements the port it names and satisfies
96
- # the verb the bind declares.
97
- #
98
- # @param bind [Bluebook::Bind] the bind to check
99
- # @return [void]
100
- # @raise [Runtime::WiringError] if `bind`'s adapter is unknown, declares an
101
- # unknown port, is missing a declared `answers` method, or cannot satisfy
102
- # `bind`'s own verb
67
+ # Checks that `bind`'s adapter implements the port it names and satisfies its verb.
103
68
  def check_verb(bind)
104
69
  port = port_for(bind)
105
70
  check_answers(port, bind.adapter)
@@ -110,20 +75,8 @@ module Hecks
110
75
  "and cannot satisfy #{bind.verb}"
111
76
  end
112
77
 
113
- # The method contract a `.port` file's `verb`/`signal` never
114
- # carried — an adapter can name the right port, satisfy the right
115
- # verb, and admit every `.world` setting `check_settings` checks,
116
- # and still be missing the one method a live dispatch will
117
- # actually call. `answers` is optional per port (an empty list is
118
- # today's pre-existing behavior, unchecked), so this only ever
119
- # tightens a port that opted in.
120
- #
121
- # @param port [Bluebook::Port] the port whose declared `answers` methods
122
- # `adapter_name` must respond to
123
- # @param adapter_name [String] the adapter's declared name to check
124
- # @return [void]
125
- # @raise [Runtime::WiringError] if `adapter_name` has no Ruby implementation,
126
- # or its implementation does not respond to one of `port.answers`
78
+ # `answers` is optional per port, so an adapter can satisfy a port's verb and still
79
+ # miss a method live dispatch will call; this only tightens ports that opt in.
127
80
  def check_answers(port, adapter_name)
128
81
  answers = Array(port.answers)
129
82
  return if answers.empty?
@@ -138,27 +91,12 @@ module Hecks
138
91
  "#{answers.map(&:inspect).join(', ')}"
139
92
  end
140
93
 
141
- # **The nine singleton ports' own gap** — `persistence`, `projection`
142
- # and `loading` are per-aggregate bindings, checked above through
143
- # every real `bind` a hexagon declares; a singleton port
144
- # (`clock`, `authorization`, …) is never bound to an aggregate at
145
- # all, so nothing above ever resolves one and nothing above ever
146
- # ran `check_answers` against it. Each one's own `Ports::*.adapter`
147
- # already refuses zero or multiple implementations, live, at
148
- # first dispatch — that stays exactly as-is here (0 or 2+ is
149
- # ambiguity, not a method-contract question, and asserting every
150
- # declared port must have exactly one adapter would wrongly
151
- # refuse a boot that simply never wires a port it doesn't use).
152
- # This only ever tightens the one case those checks don't cover:
153
- # exactly one adapter, wired, missing a method `answers` names.
94
+ # persistence/projection/loading are per-aggregate bound and already checked via
95
+ # each bind above; a singleton port is never bound to an aggregate at all.
154
96
  PER_AGGREGATE_PORTS = %w[persistence projection loading].freeze
155
97
 
156
- # Checks every singleton port (not per-aggregate-bound) with exactly one
157
- # wired adapter against its own declared `answers` methods.
158
- #
159
- # @return [Runtime::Registry] self
160
- # @raise [Runtime::WiringError] if a singleton port's one wired adapter is
161
- # missing one of its declared `answers` methods
98
+ # Checks every singleton port with exactly one wired adapter against its own
99
+ # declared `answers` methods.
162
100
  def verify_singleton_port_answers!
163
101
  @ports.each_value do |port|
164
102
  next if PER_AGGREGATE_PORTS.include?(port.name)
@@ -172,16 +110,8 @@ module Hecks
172
110
  self
173
111
  end
174
112
 
175
- # Checks that every setting `settings` declares (besides `:adapter`) is a
176
- # field `bind`'s adapter actually admits.
177
- #
178
- # @param bind [Bluebook::Bind] the bind naming the adapter to check against;
179
- # a no-op if its adapter is unknown
180
- # @param settings [Hash{Symbol => Object}] the world's declared settings for
181
- # this bind
182
- # @return [void]
183
- # @raise [Runtime::WiringError] if `settings` declares a field `bind`'s
184
- # adapter does not declare
113
+ # Checks that every setting `settings` declares (besides `:adapter`) is a field
114
+ # `bind`'s adapter actually admits.
185
115
  def check_settings(bind, settings)
186
116
  adapter = @adapters[bind.adapter]
187
117
  return unless adapter
@@ -196,12 +126,6 @@ module Hecks
196
126
  "Add the field to the adapter, or remove it from the world."
197
127
  end
198
128
 
199
- # Finds the port `bind`'s adapter declares.
200
- #
201
- # @param bind [Bluebook::Bind] the bind naming the adapter to look up
202
- # @return [Bluebook::Port] the port `bind`'s adapter declares
203
- # @raise [Runtime::WiringError] if `bind` names an unknown adapter, or one
204
- # declaring an unknown port
205
129
  def port_for(bind)
206
130
  adapter = @adapters[bind.adapter]
207
131
  raise WiringError, "unknown adapter #{bind.adapter.inspect}" unless adapter
@@ -210,12 +134,6 @@ module Hecks
210
134
  raise(WiringError, "adapter #{bind.adapter} declares unknown port #{adapter.port.inspect}")
211
135
  end
212
136
 
213
- # Finds the Ruby module implementing the adapter declared `name`.
214
- #
215
- # @param name [String] the adapter's declared name, such as `"PostgresEra"`
216
- # @return [Module] the adapter module or class under `Hecks::Adapters`
217
- # @raise [Runtime::WiringError] if no Ruby implementation named `name` exists
218
- # under `Hecks::Adapters`
219
137
  def adapter_class(name)
220
138
  Adapters.const_get(name)
221
139
  rescue NameError
@@ -225,33 +143,10 @@ module Hecks
225
143
 
226
144
  private
227
145
 
228
- # `role` is real access control only when governance can check it
229
- # against something — a command that declares a role but whose
230
- # domain never attaches Governance would leave that role forever
231
- # unchecked, exactly the defect ADR 0025 §9 names ("role gates
232
- # access control by exact string equality ... Governance ...
233
- # connected to none of it"). Checked here, at `verify!` — recovered
234
- # and moved, not new: running this per-block, at hecksagon
235
- # build time (Bluebook::DSL::HecksagonBuilder#build), breaks
236
- # the moment a domain is split across multiple hecksagon
237
- # blocks (base + an `environments/<name>.hecksagon` overlay,
238
- # Runtime::Loader.boot's `environment:` — see its own comment for
239
- # the recovery provenance): every block but the one declaring
240
- # `uses_framework "Governance"` would be refused there, even
241
- # though `Registry#add_hecksagon` merges every block for a domain
242
- # into one Hecksagon before anything ever dispatches against it.
243
- # Checking the merged result once, here, after every file for
244
- # this domain has loaded, is both more permissive (no need to
245
- # repeat `uses_framework` in every file) and strictly more
246
- # correct (a check against an incomplete, not-yet-merged
247
- # hecksagon can never see the real final shape).
248
- #
249
- # A provider is recognised by its declaration, not its name —
250
- # `authorization_provider_for` answers for the domain's own
251
- # chapter too, so Governance (which declares `provides
252
- # "authorization"`) passes here because of what it declares, and
253
- # the same rule `CommandRules::Authorization#governance_attached?`
254
- # applies at dispatch time.
146
+ # Checked once against the merged hecksagon so a domain split across multiple
147
+ # hecksagon files sees every uses_framework declaration first. A role is real
148
+ # access control only once an authorization provider exists to check it against
149
+ # (ADR 0025); a provider is recognized by declaring authorization, not by name.
255
150
  def refuse_ungoverned_roles!(hexagon)
256
151
  return if authorization_provider_for(hexagon.domain)
257
152
 
@@ -268,15 +163,9 @@ module Hecks
268
163
  "without that it is silent decoration, the exact defect this refusal exists to catch"
269
164
  end
270
165
 
271
- # A vendored embryonaut bluebook is a bounded context, not a pile of
272
- # types the consumer inlines. `uses_embryonaut_bluebook` only loads
273
- # the package's `.bluebook` files — persistence, Governance, and the
274
- # anti-corruption layer (`translates` field mapping) live on a named
275
- # sibling hecksagon the CONSUMER must declare. Without that hexagon
276
- # the package has no wiring of its own, and cross-context field
277
- # mapping has nowhere to be written. Breaking in 2.0: attaching a
278
- # vendored chapter without `Hecks.hecksagon "PackageName"` refuses
279
- # at boot rather than silently sharing the consumer's hexagon.
166
+ # `uses_embryonaut_bluebook` only loads a package's `.bluebook` files; persistence,
167
+ # Governance and the `translates` ACL live on a sibling hecksagon the consumer must
168
+ # declare, or cross-context field mapping has nowhere to be written.
280
169
  def refuse_unwired_vendored_bluebooks!(hexagon)
281
170
  Array(hexagon.vendored_bluebooks).each do |package|
282
171
  chapter_name = Naming.pascal(package)
@@ -291,10 +180,8 @@ module Hecks
291
180
  end
292
181
  end
293
182
 
294
- # Same gate as vendored packages: `uses_framework` loads a bounded
295
- # context, and the consumer must declare the sibling hecksagon that
296
- # is its ACL. Governance/Identity/Privacy already follow this in
297
- # every real consumer; boot now refuses a silent miss.
183
+ # `uses_framework` loads a bounded context; the consumer must declare the sibling
184
+ # hecksagon that is its ACL (Governance/Identity/Privacy already do).
298
185
  def refuse_unwired_framework_members!(hexagon)
299
186
  Array(hexagon.framework_members).each do |member|
300
187
  next if hecksagon(member)
@@ -308,19 +195,12 @@ module Hecks
308
195
  end
309
196
  end
310
197
 
311
- # An explicit `bounded` mark on a consumer chapter always needs an
312
- # ACL — at least one `translates` block. Any field can be mapped;
313
- # the BC does not list which. `uses_framework` / `uses_embryonaut_bluebook`
314
- # mark the ATTACHED chapter bounded (module wrap, no Object shortcut)
315
- # and require the sibling hecksagon above; they do not require a
316
- # `translates` on that sibling unless the consumer also wrote `bounded`.
317
- # rust/host Google sign-in reads `ir.json`'s `membership` and
318
- # `identity` keys (Exporter.membership / Exporter.identity) —
319
- # never a deploy-time env var. Membership without Identity is
320
- # the exact gap that produced a live `google_unlinked` after a
321
- # successful Google handshake: provision cannot Register/Link.
322
- # Refuse at Ruby boot (and project_rust, which exports the same
323
- # pair) so a missing sibling cannot ship.
198
+ # An explicit `bounded` mark on a consumer chapter always needs an ACL. `uses_framework`
199
+ # / `uses_embryonaut_bluebook` mark the attached chapter bounded and require the sibling
200
+ # hecksagon above; they don't require a `translates` on it unless the consumer also
201
+ # wrote `bounded`.
202
+ # rust/host Google sign-in reads ir.json's membership/identity keys, never a deploy-time
203
+ # env var; Membership without Identity means provision cannot Register/Link an identity.
324
204
  def refuse_membership_without_identity!
325
205
  return unless @bluebooks.values.any? { |chapter| chapter.provides?(Bluebook::Capabilities::MEMBERSHIP) }
326
206
  return if @bluebooks.values.any? { |chapter| chapter.provides?(Bluebook::Capabilities::IDENTITY) }
@@ -333,11 +213,8 @@ module Hecks
333
213
  "identity verbs are exported onto ir.json, not guessed at deploy."
334
214
  end
335
215
 
336
- # A `provides` row whose contract kind is `:port_operation` names an
337
- # operation the chapter's hecksagon declares, and the hecksagon
338
- # attaches after the chapter is built, so this is the first point the
339
- # operation can be checked. Without it, a host reading the declared
340
- # verb would dispatch to an operation nothing declares.
216
+ # A hecksagon attaches after its chapter builds, so this is the first point a
217
+ # declared `:port_operation` capability can be checked against it.
341
218
  def refuse_unresolved_port_operations!
342
219
  @bluebooks.each_value do |chapter|
343
220
  chapter.provides.each do |row|
@@ -352,12 +229,6 @@ module Hecks
352
229
  end
353
230
  end
354
231
 
355
- # Says whether a chapter declares the port operation an
356
- # `"Aggregate.Port.Operation"` verb names.
357
- #
358
- # @param chapter [Bluebook::Chapter] the chapter whose aggregates' ports are searched
359
- # @param verb [String] the verb, spelled `"Aggregate.Port.Operation"`
360
- # @return [Boolean] whether that aggregate has that port with that operation
361
232
  def port_operation_declared?(chapter, verb)
362
233
  aggregate_name, port_name, operation_name = verb.split(".", 3)
363
234
  ports = chapter.aggregate(aggregate_name)&.ports || []
@@ -377,8 +248,8 @@ module Hecks
377
248
  "with: { ... } end` (any field) or drop `bounded`."
378
249
  end
379
250
 
380
- # The suggestion, derived from whichever framework members actually
381
- # declare `provides "authorization"` — never a hardcoded name.
251
+ # Derived from whichever framework members actually declare `provides
252
+ # "authorization"` — never a hardcoded name.
382
253
  def authorization_attachment_hint
383
254
  providers = Framework.providers_of(Bluebook::Capabilities::AUTHORIZATION)
384
255
  return "attaches a chapter that provides \"authorization\" (no framework member declares one)" if providers.empty?
@@ -386,30 +257,17 @@ module Hecks
386
257
  providers.map { |name| "uses_framework #{name.inspect}" }.join(" or ")
387
258
  end
388
259
 
389
- # Every command this domain declares, an aggregate's own and every
390
- # entity nested inside one — the same reach `refuse_role_mismatch`
391
- # itself needs at dispatch time, just walked ahead of time here.
260
+ # Every command this domain declares, an aggregate's own and every entity nested
261
+ # inside one — the same reach dispatch-time role checking needs.
392
262
  def commands_in(bluebook_ir)
393
263
  bluebook_ir.aggregates.flat_map { |aggregate| aggregate.commands + aggregate.entities.flat_map(&:commands) }
394
264
  end
395
265
 
396
- # TWO UNRELATED PACKAGES, ONE CHAPTER NAME BY COINCIDENCE — the
397
- # real risk `Registry#bluebook_sources` exists to catch (found
398
- # live: a stale `vendor/hecksagain` fork's own copy of Governance/
399
- # Identity/Deploy, still reachable on 4 consuming apps' own load
400
- # paths alongside the real gem). `BluebookBuilder.build`'s own
401
- # accumulation (several files declaring the SAME chapter name ON
402
- # PURPOSE — `lib/hecks/language/bluebook/*.bluebook` all open
403
- # `Hecks.bluebook "Bluebook"`) is never touched here — that merge
404
- # stays unconditional, checked only AFTER every file has loaded,
405
- # the same "check the merged final result once" timing
406
- # `refuse_ungoverned_roles!` already uses and for the same reason
407
- # (a check against an incomplete load can never see the real
408
- # shape). What distinguishes intentional accumulation from
409
- # coincidence is PACKAGE ROOT, not file identity: files a real
410
- # gemspec or a `vendor/` boundary already treats as one unit are
411
- # expected to share a name; files from two DIFFERENT roots never
412
- # legitimately do.
266
+ # Two packages can share a chapter name by coincidence (found live: a stale
267
+ # vendor/hecksagain fork of Governance/Identity/Deploy, still on 4 apps' load
268
+ # paths). Intentional accumulation (several files declaring the same chapter on
269
+ # purpose) is distinguished by package root, not file identity, and is left
270
+ # untouched here — checked once, after every file has loaded.
413
271
  def refuse_cross_package_bluebook_merge!
414
272
  @bluebook_sources.each do |name, paths|
415
273
  roots = paths.map { |path| package_root_for(path) }.uniq
@@ -424,15 +282,9 @@ module Hecks
424
282
  end
425
283
  end
426
284
 
427
- # THE NEAREST BOUNDARY A PATH ALREADY BELONGS TO — a real
428
- # gemspec (this IS a package, whatever depends on it or vendors
429
- # it), or a bare `vendor/` path component, treated as its OWN
430
- # root regardless of what gemspec might sit above it: vendored
431
- # code should never be considered "the same package" as whatever
432
- # it's vendored into, even when nothing else marks the boundary.
433
- # Neither found, the path's own directory is the root — two
434
- # files with no closer marker only "belong together" if they are
435
- # literally the same file.
285
+ # The nearest boundary a path belongs to: a real gemspec, or a bare `vendor/`
286
+ # component (vendored code is never "the same package" as what vendors it).
287
+ # Falls back to the path's own directory when neither is found.
436
288
  def package_root_for(path)
437
289
  return path.to_s if path.nil?
438
290
 
@@ -448,37 +300,10 @@ module Hecks
448
300
  end
449
301
  end
450
302
 
451
- # A domain that declares a `process_manager` but whose
452
- # `saga_persistence` resolves to `NULL_SAGA_STORE` (no anchor
453
- # aggregate, a RemoteRuntime-shaped adapter, an adapter that
454
- # doesn't `respond_to?(:save_saga)`, or a rescued WiringError —
455
- # see `SagaPersistence#resolve_saga_persistence`) gets sagas that
456
- # advance correctly in-process and vanish on restart: no
457
- # checkpoint written, nothing for `rehydrate_sagas!` to find, no
458
- # compensation ever replayed. That is silent right up until the
459
- # process actually dies mid-saga — the same "consistency/
460
- # freshness defect applied to access control, failing open" ADR
461
- # 0025 named for an unchecked `role`, here applied to saga
462
- # durability instead.
463
- #
464
- # A warning, not a refusal — unlike `refuse_ungoverned_roles!`,
465
- # running sagas on a store with no `save_saga` is legitimate on
466
- # purpose in a fast in-memory test/dev boot (this project's own
467
- # `saga_durability_spec.rb` boots a process manager on `Memory`
468
- # specifically to exercise the saga_mutex without real I/O), so
469
- # refusing the boot outright would break a choice an author made
470
- # deliberately. What a deploy needs is for the gap to be loud and
471
- # undeniable, not for local dev/test to become impossible.
472
- # The outbox's twin of `warn_undurable_sagas!` — a domain that
473
- # declares anything a commit could owe a reaction to (a policy
474
- # listening to one of its events, or a process manager) but is
475
- # bound to an adapter with no outbox (`AppendOnly#outbox?`) gets
476
- # reactions the pre-outbox way: run inline, lost on a crash
477
- # between commit and reaction. A warning, not a refusal, for the
478
- # reason `warn_undurable_sagas!` gives — and Memory has an outbox
479
- # (in-process, like everything else it holds), so a dev/test
480
- # boot stays quiet; this speaks up for the file/remote adapters
481
- # that persist state durably but hand reactions to nothing.
303
+ # A domain with policies/a process_manager but no outbox on its bound adapter
304
+ # (`AppendOnly#outbox?`) runs reactions inline — lost on a crash between a
305
+ # commit and its reaction. A warning, not a refusal: Memory has an in-process
306
+ # outbox, so dev/test stays quiet, but file/remote adapters need this to be loud.
482
307
  def warn_undurable_outbox!(hexagon)
483
308
  bluebook_ir = bluebook(hexagon.domain)
484
309
  return unless bluebook_ir
@@ -505,6 +330,8 @@ module Hecks
505
330
  @bluebooks.each_value.any? { |candidate| candidate.policies.any? { |policy| emitted.include?(policy.event_name.to_s) } }
506
331
  end
507
332
 
333
+ # A warning, not a refusal: running sagas on a store with no `save_saga` is
334
+ # legitimate on purpose in a fast in-memory test/dev boot.
508
335
  def warn_undurable_sagas!(hexagon)
509
336
  bluebook_ir = bluebook(hexagon.domain)
510
337
  return unless bluebook_ir
@@ -1,42 +1,11 @@
1
1
  module Hecks
2
2
  module Runtime
3
3
  class Registry
4
- # **World defaults** — the `default_database` and `default_adapter` words a
5
- # `.world` can declare once for every chapter a boot loaded, resolved against
6
- # the registry's own worlds. Included into Registry; the callers are the
7
- # persistence binding policy (`default_adapter_for`), every reader of a bind's
8
- # world settings (`binding_settings`), and `verify!` (`verify_world_defaults!`).
9
- #
10
- # **Resolution order**, most specific first — nothing here ever overrides a
11
- # chapter's own explicit declaration:
12
- #
13
- # 1. the chapter's own `persisted_by(...) { database ... }` block, and the
14
- # hecksagon bind (aggregate-specific, then domain-level) that names its adapter;
15
- # 2. the default declared by the chapter's own world;
16
- # 3. the default declared by the project's world — the world of the first
17
- # chapter the boot loaded, the same convention `Loader#dispatcher_for` uses
18
- # to find the domain a boot targets;
19
- # 4. today's behavior: no database setting, and the framework's in-memory
20
- # adapter for a chapter with no hecksagon.
21
- #
22
- # A default is resolved when a bind's settings or binding are asked for, never
23
- # written into a chapter's world or hecksagon, so a chapter's own declarations
24
- # stay exactly what its files say and a hecksagon-less chapter still trips the
25
- # sibling-hecksagon gates the way it always did.
4
+ # The `default_database`/`default_adapter` a `.world` declares once for every chapter;
5
+ # resolved most-specific-first (own bind, own world, project world) and never written back.
26
6
  module WorldDefaults
27
- # The settings a chapter's world gives one bind, with the project's default
28
- # database filled in where the chapter left it out.
29
- #
30
- # The default database only ever reaches a persistence bind whose adapter
31
- # declares a `database` field — a projection or an adapter without one is
32
- # untouched. A `database` the chapter's own settings name wins; every other
33
- # setting the chapter declared rides along unchanged.
34
- #
35
- # @param domain [String, Symbol] the domain whose world is asked
36
- # @param verb [String, Symbol] the bind's port verb, such as `"persisted_by"`
37
- # @param adapter [String, Symbol] the bind's adapter name
38
- # @return [Hash{Symbol => Object}] the chapter's own settings for the bind, plus
39
- # `:database` from the default when one applies; `{}` when there is nothing
7
+ # The default database only reaches a persistence bind whose adapter declares a
8
+ # `database` field; a `database` the chapter's own settings name always wins.
40
9
  def binding_settings(domain, verb, adapter)
41
10
  declared = world(domain)&.for_binding(verb, adapter) || {}
42
11
  database = default_database_for(domain)
@@ -45,28 +14,10 @@ module Hecks
45
14
  { adapter: adapter.to_s, database: database }.merge(declared)
46
15
  end
47
16
 
48
- # The persistence adapter a chapter's aggregates fall back to when their
49
- # hecksagon does not bind them.
50
- #
51
- # @param domain [String, Symbol] the domain to resolve the default for
52
- # @return [String, nil] the chapter's own world's `default_adapter`, else the
53
- # project's; `nil` when neither declares one
54
17
  def default_adapter_for(domain) = world_default(domain, :default_adapter)
55
18
 
56
- # The database connection a chapter's database-taking persistence adapter uses
57
- # when its own settings name none.
58
- #
59
- # @param domain [String, Symbol] the domain to resolve the default for
60
- # @return [String, nil] the chapter's own world's `default_database`, else the
61
- # project's; `nil` when neither declares one
62
19
  def default_database_for(domain) = world_default(domain, :default_database)
63
20
 
64
- # Refuses a `default_adapter` that no persistence adapter answers to.
65
- #
66
- # @return [Runtime::Registry] self
67
- # @raise [Runtime::WiringError] if a world's `default_adapter` names an unknown
68
- # adapter, one that is not a persistence adapter, or one with no Ruby
69
- # implementation
70
21
  def verify_world_defaults!
71
22
  @worlds.each_value do |declared|
72
23
  name = declared.default_adapter