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,25 +1,7 @@
1
1
  module Hecks
2
2
  module Bluebook
3
- # **Which regexes a bluebook may say**.
4
- #
5
- # A `pattern:` is a fact about a value, carried in a bluebook — declared
6
- # data, not Ruby code, so it must not lean on what any one engine happens
7
- # to accept. Regex engines disagree in two different ways :
8
- #
9
- # only a backtracking engine can match it — lookahead, lookbehind,
10
- # backreferences, atomic groups, possessive quantifiers. None of these
11
- # can be matched in linear time, and linear-time engines refuse them
12
- # outright. Refused here for the same reason.
13
- #
14
- # every engine parses it and they mean different things — the dangerous
15
- # half, because nothing errors. `\d` `\w` `\s` are ASCII in some engines
16
- # and Unicode in others ; `[:digit:]` and friends flip the same way in
17
- # the other direction. Both families are refused, and a domain spells
18
- # the range it means.
19
- #
20
- # What remains — explicit ranges, alternation, quantifiers, anchors,
21
- # groups — reads identically everywhere, with `^` and `$` as line anchors
22
- # (Ruby's reading). The evidence is spec/corpus/fixtures/patterns.json.
3
+ # Which regexes a bluebook `pattern:` may say: only what every engine reads the same way.
4
+ # Backtracking-only and ASCII/Unicode-dependent constructs are refused.
23
5
  module PatternSubset
24
6
  Rejection = Struct.new(:construct, :reason)
25
7
 
@@ -55,36 +37,19 @@ module Hecks
55
37
 
56
38
  module_function
57
39
 
58
- # nil when the pattern is admitted, a Rejection when it is not.
40
+ # Returns nil when the pattern is admitted, a Rejection when it is not.
59
41
  #
60
- # A character walk, deliberately plain : the subset is defined by this
61
- # walk, and a cleverer spelling would hide what it admits. An escaped
62
- # construct is a literal, not a violation — `\(\?=` is the three
63
- # characters "(?=" and says nothing about lookahead — which is why this
64
- # steps over each backslash pair rather than matching the pattern as a
65
- # whole.
66
- # One character walk is the subset's definition (see the method
67
- # comment above): each construct-check is a branch in a single
68
- # ordered pass sharing `index`/`in_class`/`class_start`. Splitting
69
- # the branches into separate methods would force those three cursor
70
- # variables to thread as parameters/return values between them,
71
- # turning "the subset is this walk" into "the subset is these
72
- # methods agreeing about a shared cursor" — exactly what the walk's
73
- # own comment says a cleverer spelling would obscure.
42
+ # One ordered character walk defines the subset; an escaped construct is a literal,
43
+ # which is why each backslash pair is stepped over rather than matched as a whole.
74
44
  # rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
75
45
  #
76
46
  # @param pattern [String, Symbol, #to_s] the declared `pattern:` regex source
77
- # @return [Rejection, nil] the reason the pattern is refused, or `nil` if it is
78
- # entirely within the portable subset
47
+ # @return [Rejection, nil] the reason the pattern is refused, or `nil` if admitted
79
48
  def validate(pattern)
80
49
  chars = pattern.to_s.chars
81
50
  index = 0
82
- # A character-class interior is a different alphabet : inside `[...]`,
83
- # `*`, `+`, `?`, `(`, `?` are literal characters, not quantifiers or
84
- # group syntax — `[*+]` means "a literal asterisk or plus". `]` is
85
- # only the class's close when it isn't the first character after `[`
86
- # or `[^` (where it is itself a literal, per POSIX bracket-expression
87
- # rules).
51
+ # Inside `[...]` quantifier characters are literals, and `]` closes the class unless
52
+ # it is the first character after `[` or `[^`.
88
53
  in_class = false
89
54
  class_start = nil
90
55
 
@@ -136,8 +101,7 @@ module Hecks
136
101
  nil
137
102
  end
138
103
 
139
- # Spelled out, not derived from the key : these strings are the refusal
140
- # a caller reads.
104
+ # Spelled out, not derived from the key: callers read these strings in refusals.
141
105
  CONSTRUCTS = {
142
106
  backreference: "backreference",
143
107
  named_backreference: "named backreference",
@@ -149,17 +113,8 @@ module Hecks
149
113
  possessive: "possessive quantifier"
150
114
  }.freeze
151
115
 
152
- # Builds the rejection for one refused construct.
153
- #
154
- # @param key [Symbol] a key of `CONSTRUCTS`/`REASONS`, such as `:lookahead`
155
- # @return [Rejection] the construct's name and the reason it is refused
156
116
  def refuse(key) = Rejection.new(CONSTRUCTS.fetch(key), REASONS.fetch(key))
157
117
 
158
- # Says whether a POSIX bracket class (`[:digit:]` and friends) starts at `index`.
159
- #
160
- # @param chars [Array<String>] the pattern, split into characters
161
- # @param index [Integer] the position to check
162
- # @return [Boolean] whether a POSIX bracket class starts at `index`
163
118
  def posix_class_at?(chars, index)
164
119
  return false unless chars[index] == "[" && chars[index + 1] == ":"
165
120
 
@@ -168,14 +123,7 @@ module Hecks
168
123
  chars[cursor] == ":" && chars[cursor + 1] == "]"
169
124
  end
170
125
 
171
- # A possessive quantifier is `*+`, `++`, `?+`, or a bounded `{n}`/{n,m}`
172
- # immediately followed by `+` — only checked outside a character class,
173
- # where `*`, `+`, `?`, `{`, `}` are quantifier syntax rather than
174
- # literal characters.
175
- #
176
- # @param chars [Array<String>] the pattern, split into characters
177
- # @param index [Integer] the position to check
178
- # @return [Boolean] whether a possessive quantifier starts at `index`
126
+ # A possessive quantifier is `*+`, `++`, `?+` or a `{n,m}` bound followed by `+`.
179
127
  def possessive_at?(chars, index)
180
128
  return true if %w[* + ?].include?(chars[index]) && chars[index + 1] == "+"
181
129
  return false unless chars[index] == "{"
@@ -184,13 +132,7 @@ module Hecks
184
132
  !len.nil? && chars[index + len] == "+"
185
133
  end
186
134
 
187
- # Length of a `{n}` / `{n,}` / `{n,m}` bound starting at `index`, or nil
188
- # if what's there isn't one.
189
- #
190
- # @param chars [Array<String>] the pattern, split into characters
191
- # @param index [Integer] the position the bound is expected to start at
192
- # @return [Integer, nil] the bound's length in characters, or `nil` if `index`
193
- # does not start a `{n}`/`{n,}`/`{n,m}` bound
135
+ # Length of a `{n}` / `{n,}` / `{n,m}` bound at `index`, or nil if there is none.
194
136
  def bounded_quantifier_length(chars, index)
195
137
  cursor = index + 1
196
138
  digit_seen = false
@@ -3,19 +3,10 @@ require_relative "../ir"
3
3
 
4
4
  module Hecks
5
5
  module Bluebook
6
- # `compensates` — a second `DispatchSpec`, shape-identical to this
7
- # one, naming the command that undoes this dispatch specifically
8
- # (see `ProcessManagerBuilder::HandlerBuilder#dispatch_impl`'s own
9
- # comment). `nil` for a dispatch with nothing to undo (a pure
10
- # bookkeeping mark, or one whose own effect is superseded by a later
11
- # command rather than needing its own compensation). Never nested
12
- # further — a compensation is not itself compensable; no known
13
- # corpus need, and ADR 0025's own "a word earns its place by being
14
- # used" bar would refuse a second level speculatively.
6
+ # `compensates` is a second `DispatchSpec` naming the command that undoes this one, or nil.
7
+ # Never nested; `reverses` stays reserved for `corrects`.
15
8
  DispatchSpec = Struct.new(:command_name, :with_spec, :compensates, keyword_init: true) do
16
- # A Struct already answers to_h; including the mixin puts the
17
- # declared emission ahead of Struct's own in the ancestry, which
18
- # is what makes the shape data rather than a method body.
9
+ # Struct already answers to_h; the mixin puts the declared emission ahead of it.
19
10
  include Hecks::IR
20
11
 
21
12
  emits_ir(
@@ -37,62 +28,19 @@ module Hecks
37
28
  )
38
29
  end
39
30
 
40
- # The compensation half of a procedure, as its own thing.
41
- #
42
- # A process manager coordinates: legs, states, an opinion about who goes
43
- # next. A saga undoes: what makes the world good again when a leg it
44
- # dispatched is refused. Two concepts, and the industry slurs them into one
45
- # word — so here they are two objects, and a procedure either has a saga or
46
- # does not.
47
- #
48
- # `undoes` is the ordered list of commands the compensation sends — a
49
- # static preview, declaration order (`Behaviour::ProcessManager#saga`),
50
- # not one instance's own runtime history. Per-dispatch compensation
51
- # (`compensates`, on the step it compensates for) moved most of what
52
- # a saga undoes off this leg's own hand-written body and onto
53
- # whichever forward dispatch each one undoes — this reads every
54
- # declared `compensates` across the whole saga first, then whatever
55
- # this leg's own hand-written body still lists, for compensation
56
- # that isn't expressible as "undo command X." which of a declared
57
- # `compensates` actually fires for one instance, and in what order
58
- # (newest-first, completed-legs-only), is `SagaInterpreter`'s own
59
- # dynamic `completed_compensations` — a per-instance runtime fact
60
- # this declaration-only object could never hold.
61
- #
62
- # **Naming collision, once flagged, now resolved** — `command`'s own
63
- # `corrects event, reverses: true` (docs/implemented/decisions/0036-
64
- # corrects-is-an-appended-fact-not-a-rewrite.md) already claimed
65
- # `reverses` for a different meaning: auto-deriving a command's own
66
- # corrective mutation from a past event, not a saga's own
67
- # compensating leg from a past dispatch. This feature keeps
68
- # `reverses` reserved for `corrects` and uses `compensates` for
69
- # per-dispatch saga compensation instead — a deliberate choice, not
70
- # an accidental collision.
31
+ # The compensation half of a procedure: the commands sent to undo a refused leg.
32
+ # `undoes` is a static declaration-order preview; per-instance order is the runtime's.
71
33
  Saga = Struct.new(:trigger, :from_state, :to_state, :compensations, keyword_init: true) do
72
- # Lists the commands this saga sends to undo a refused leg.
73
- #
74
- # @return [Array<String>] the name of each compensating command, in the order
75
- # `compensations` lists them
76
34
  def undoes = compensations.map(&:command_name)
77
35
 
78
36
  def to_s = "#{trigger} → #{to_state} (#{undoes.join(', ')})"
79
37
  end
80
38
 
81
- # The built form of a `process_manager "Name" do ... end` block,
82
- # produced by `DSL::ProcessManagerBuilder` — its start/end events,
83
- # correlation field, derived states, and handler rows. Its
84
- # compensation half (`saga`, `Behaviour::ProcessManager#saga`) is
85
- # derived from the handler answering `REFUSED`, below, not declared as
86
- # its own construct.
39
+ # The built form of a `process_manager "Name" do ... end` block, made by
40
+ # `DSL::ProcessManagerBuilder`.
87
41
  class ProcessManager
88
- # The bluebook's name for this construct, asked the same way of a class
89
- # that has crossed over and of an IR object that has not. Collapses into
90
- # Construct when this one crosses.
91
- # The trigger of a compensating leg. Not an event name — no aggregate
92
- # announces that a leg the procedure dispatched was declined — so it lives
93
- # here beside the thing it triggers rather than in the runtime that
94
- # notices it. Declared in the language's Trigger vocabulary, which
95
- # spec/vocabulary_conformance_spec holds to this constant.
42
+ # The trigger of a compensating leg. Not an event name: no aggregate announces a declined
43
+ # leg. Held to the language's Trigger vocabulary by spec/vocabulary_conformance_spec.
96
44
  REFUSED = Hecks::Vocabulary.fetch("Trigger").first
97
45
 
98
46
  include Hecks::IR
@@ -100,21 +48,8 @@ module Hecks
100
48
 
101
49
  emits_ir(
102
50
  name: :name,
103
- # M11 — `&.`, not `.`: a DSL-built process manager always carries
104
- # a real `correlates_by` (`ProcessManagerBuilder#build` refuses to
105
- # mint one without it), but the IR class itself defaults it to
106
- # `nil` and is what `Assembly::Build`'s `:identity` reader
107
- # (`value&.to_sym`) round-trips against. A bare `.to_s` mapped
108
- # that absent case to `""`, indistinguishable on the wire from a
109
- # real empty name and read back as the wrong, non-nil `:""`
110
- # instead of `nil` — the same nil-erasure S1 fixed for
111
- # `render_value`, one field over. `correlates_by` is always a
112
- # bare Symbol (`SagaInterpreter` hash-looks-up a payload by it),
113
- # never a `Literal`-encoded polymorphic value, so this stays a
114
- # local `&.` rather than routing through `Literal.render` — that
115
- # would wrap a real value in a leading `:` and break both the
116
- # `:identity` reader's plain `to_sym` and the pinned golden IR
117
- # fixtures' bare-string spelling (`"reference.value"`).
51
+ # `&.` because the IR class defaults `correlates_by` to nil; `.to_s` reads back as `""`.
52
+ # A bare Symbol string, not `Literal.render`, to match the golden IR fixtures.
118
53
  correlates_by: -> { correlates_by&.to_s },
119
54
  starts_on: :starts_on,
120
55
  ends_on: :ends_on,
@@ -124,15 +59,10 @@ module Hecks
124
59
 
125
60
  attr_reader :name, :correlates_by, :starts_on, :ends_on, :states, :handlers
126
61
 
127
- # @param name [String, Symbol] the process manager's declared name
128
- # @param correlates_by [Symbol, nil] the payload field a triggering event's
129
- # instances are correlated by
62
+ # @param correlates_by [Symbol, nil] the payload field that correlates a triggering
63
+ # event to an instance
130
64
  # @param starts_on [String, nil] the event that starts a new instance
131
65
  # @param ends_on [String, nil] the event that ends an instance
132
- # @param states [Array<String>] the declared states this procedure's instances pass
133
- # through
134
- # @param handlers [Array<Bluebook::ProcessManagerHandler>] the declared handler rows,
135
- # one per (event, state) leg
136
66
  def initialize(name:, correlates_by: nil, starts_on: nil, ends_on: nil,
137
67
  states: [], handlers: [])
138
68
  @name = name.to_s
@@ -3,9 +3,8 @@ require_relative "project_register"
3
3
 
4
4
  module Hecks
5
5
  module Bluebook
6
- # Boots each discovered directory and feeds its declarations into the
7
- # deterministic project register. Discovery and FQN registration live in
8
- # their own objects so either can be used without executing domains.
6
+ # Boots each discovered directory and feeds its declarations into the project register.
7
+ # Discovery and FQN registration are separate objects so either works without booting domains.
9
8
  class ProjectLoader
10
9
  Entry = ProjectRegister::Entry
11
10
  DuplicateFqn = ProjectRegister::DuplicateFqn
@@ -14,31 +13,15 @@ module Hecks
14
13
 
15
14
  attr_reader :root, :discovery, :register
16
15
 
17
- # Discovers and loads every domain under `root` in one call.
18
- #
19
- # @param root [String] the directory to search under
20
- # @return [Bluebook::ProjectLoader] the loader, with every discovered domain
21
- # booted and registered
22
16
  def self.load(root) = new(root).load
23
17
 
24
- # @param root [String] the directory to search under
25
- # @param discovery [Bluebook::ProjectDiscovery] the discovery this loader walks
26
- # `root` with
27
- # @param register [Bluebook::ProjectRegister] the register booted domains are
28
- # fed into
29
18
  def initialize(root, discovery: ProjectDiscovery.new(root), register: ProjectRegister.new)
30
19
  @root = File.expand_path(root)
31
20
  @discovery = discovery
32
21
  @register = register
33
22
  end
34
23
 
35
- # Boots every domain `discovery` finds under `root` and registers its declarations.
36
- #
37
- # @return [Bluebook::ProjectLoader] self
38
- # @raise [Bluebook::ProjectRegister::MissingRealm] see `ProjectRegister#register`
39
- # @raise [Bluebook::ProjectRegister::LatestMismatch] see `ProjectRegister#register`
40
- # @raise [Bluebook::ProjectRegister::DuplicateFqn] see `ProjectRegister#register`
41
- # @raise [Runtime::WiringError] see `ProjectRegister#register`
24
+ # Errors raised by `ProjectRegister#register` propagate.
42
25
  def load
43
26
  discovery.bluebook_directories.each do |directory|
44
27
  runtime = Runtime.boot(directory)
@@ -47,33 +30,14 @@ module Hecks
47
30
  self
48
31
  end
49
32
 
50
- # Lists every registered entry.
51
- #
52
- # @return [Hash{String => Bluebook::ProjectRegister::Entry}] every registered
53
- # entry, keyed by its FQN
54
33
  def entries = register.entries
55
34
 
56
- # Finds a registered entry by its fully-qualified verb.
57
- #
58
- # @param address [String, #to_s] the FQN to look up
59
- # @return [Bluebook::ProjectRegister::Entry] the entry registered under `address`
60
- # @raise [KeyError] if no entry is registered under `address`
61
35
  def fetch(address) = register.fetch(address)
62
36
 
63
- # Says whether an entry is registered under an address.
64
- #
65
- # @param address [String, #to_s] the FQN to check
66
- # @return [Boolean] whether an entry is registered under `address`
67
37
  def include?(address) = register.include?(address)
68
38
 
69
- # Lists every registered command entry.
70
- #
71
- # @return [Array<Bluebook::ProjectRegister::Entry>] every registered command entry
72
39
  def commands = register.commands
73
40
 
74
- # Lists every registered query entry.
75
- #
76
- # @return [Array<Bluebook::ProjectRegister::Entry>] every registered query entry
77
41
  def queries = register.queries
78
42
  end
79
43
  end
@@ -4,14 +4,8 @@ module Hecks
4
4
  # declarations become public FQNs, but never searches or boots folders.
5
5
  class ProjectRegister
6
6
  Entry = Struct.new(:fqn, :source_directory, :dispatcher, :declared_verb, :domain_version, keyword_init: true) do
7
- # Says whether this entry addresses a command.
8
- #
9
- # @return [Boolean] whether this entry's `fqn` addresses a command
10
7
  def command? = fqn.command?
11
8
 
12
- # Says whether this entry addresses a query.
13
- #
14
- # @return [Boolean] whether this entry's `fqn` addresses a query
15
9
  def query? = fqn.query?
16
10
  end
17
11
 
@@ -21,53 +15,31 @@ module Hecks
21
15
 
22
16
  attr_reader :entries
23
17
 
24
- # Starts an empty register, with no domains loaded yet.
25
18
  def initialize
26
19
  @entries = {}
27
20
  @tenant_directories = Hash.new { |hash, key| hash[key] = [] }
28
21
  end
29
22
 
30
- # Finds a registered entry by its fully-qualified verb.
23
+ # Finds an entry by FQN, such as `"Pizzas.Pizza.Order"`.
31
24
  #
32
- # @param address [String, #to_s] the FQN to look up, such as `"Pizzas.Pizza.Order"`
33
- # @return [Bluebook::ProjectRegister::Entry] the entry registered under `address`
34
25
  # @raise [KeyError] if no entry is registered under `address`
35
26
  def fetch(address) = entries.fetch(address.to_s)
36
27
 
37
- # Says whether an entry is registered under an address.
38
- #
39
- # @param address [String, #to_s] the FQN to check
40
- # @return [Boolean] whether an entry is registered under `address`
41
28
  def include?(address) = entries.key?(address.to_s)
42
29
 
43
- # Lists every registered command entry.
44
- #
45
- # @return [Array<Bluebook::ProjectRegister::Entry>] every registered command entry
46
30
  def commands = entries.values.select(&:command?)
47
31
 
48
- # Lists every registered query entry.
49
- #
50
- # @return [Array<Bluebook::ProjectRegister::Entry>] every registered query entry
51
- def queries = entries.values.select(&:query?)
32
+ def queries = entries.values.select(&:query?)
52
33
 
53
- # Registers every aggregate command/query and read model query a booted chapter
54
- # declares, under its versioned and (if current) unversioned FQNs.
34
+ # Registers every aggregate command/query and read model query of each chapter, under
35
+ # its versioned and (if current) unversioned FQNs.
55
36
  #
56
- # @param bluebooks [Array<Bluebook::Chapter>] the booted chapters to register
57
- # @param registry [Runtime::Registry] the registry `bluebooks` booted into
58
- # @param dispatcher [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted
59
- # dispatcher entries dispatch through
60
- # @param directory [String] the source directory `bluebooks` was discovered under
61
37
  # @return [Bluebook::ProjectRegister] self
62
- # @raise [Bluebook::ProjectRegister::MissingRealm] if a bluebook's world declares no
63
- # realm
64
- # @raise [Bluebook::ProjectRegister::LatestMismatch] if a world's `latest` disagrees
65
- # with its bluebook's own version
66
- # @raise [Bluebook::ProjectRegister::DuplicateFqn] if an FQN this call would register
67
- # is already registered
68
- # @raise [Runtime::WiringError] if a second tenant registers the same on-disk
69
- # directory while any of its aggregates binds to an adapter that is not
70
- # `tenant_capable?`
38
+ # @raise [MissingRealm] if a bluebook's world declares no realm
39
+ # @raise [LatestMismatch] if a world's `latest` disagrees with its bluebook's version
40
+ # @raise [DuplicateFqn] if an FQN this call would register is already registered
41
+ # @raise [Runtime::WiringError] if a second tenant registers the same directory while
42
+ # an aggregate binds to an adapter that is not `tenant_capable?`
71
43
  def register(bluebooks, registry, dispatcher, directory)
72
44
  bluebooks.each do |bluebook|
73
45
  refuse_unless_safe_for_second_tenant!(bluebook, registry, directory)
@@ -87,10 +59,6 @@ module Hecks
87
59
 
88
60
  private
89
61
 
90
- # Split out of `register` per-aggregate: same versioned-then-current
91
- # registration shape as `register_read_model!`, just applied to a
92
- # command/query pair instead of a single report. No state threads
93
- # back to `register` — each `add` call is independent.
94
62
  def register_aggregate!(aggregate, bluebook, world, realm, directory, dispatcher)
95
63
  aggregate.commands.each do |command|
96
64
  if bluebook.version
@@ -116,9 +84,6 @@ module Hecks
116
84
  end
117
85
  end
118
86
 
119
- # Split out of `register` per-read-model: registers the versioned FQN
120
- # (if this bluebook declares a version) and the current/unversioned
121
- # FQN (if this bluebook is the world's latest) for one report.
122
87
  def register_read_model!(model, bluebook, world, realm, directory, dispatcher)
123
88
  if bluebook.version
124
89
  add(Fqn.query(realm: realm, domain: bluebook.name, version: bluebook.version,
@@ -130,22 +95,9 @@ module Hecks
130
95
  end
131
96
  end
132
97
 
133
- # The actual "more than one tenant" moment — Runtime::TenantCheck's
134
- # own header names this table as the one place real multitenancy
135
- # happens: the same on-disk directory (one domain, one
136
- # `persisted_by` binding) registering a second time, under a
137
- # different realm, into this same shared route table. A directory's
138
- # first registration is never refused here — nothing shares its
139
- # data yet, so a plain single-tenant deployment on an ordinary
140
- # adapter (Postgres, no schema story) still boots exactly as
141
- # before. Only the second (and any later) registration of that
142
- # same directory is refused, and refused before this call adds its
143
- # routes to the table — so a leaking tenant's requests never
144
- # become reachable through `Router#resolve` in the first place.
145
- #
146
- # Keyed on `directory` + `bluebook.name` only, not realm or
147
- # `dispatcher` — two tenants share the identical on-disk domain,
148
- # differing only by which realm/environment overlay booted it.
98
+ # A directory's first registration is never refused; only a second one (another tenant
99
+ # sharing the on-disk domain) is, before its routes reach the table. Keyed on
100
+ # `directory` + name, not realm or dispatcher.
149
101
  def refuse_unless_safe_for_second_tenant!(bluebook, registry, directory)
150
102
  key = [directory, bluebook.name]
151
103
  seen_before = @tenant_directories.key?(key) && @tenant_directories[key].any?
@@ -1,33 +1,15 @@
1
1
  require_relative "behaviour/query"
2
2
 
3
3
  module Hecks
4
- # Reopened here only to add `render_value` below — the pinned
5
- # wire-literal rendering (`Literal.render`) the `emits_ir` Procs
6
- # throughout this chapter reach for. See lib/hecks/bluebook.rb's own
7
- # header for what `Bluebook` is as a whole.
4
+ # Reopened to add `render_value`, the wire-literal rendering `emits_ir` procs use.
8
5
  module Bluebook
9
- # Renders a captured Ruby value to its self-describing wire spelling.
10
- #
11
- # @param value [Object] any value an `emits_ir` field carries, such as a Symbol,
12
- # String, Hash, Array, or literal
13
- # @return [String] the value rendered through `Hecks::Literal.render`
6
+ # Renders a captured value to its wire spelling through `Hecks::Literal.render`.
14
7
  def self.render_value(value) = Literal.render(value)
15
8
 
16
9
  # A query — an ask, declared on an aggregate or on one of its entities.
17
10
  #
18
- # It crosses over as an instance rather than a class, and the reason is worth
19
- # stating because it is the boundary of the pattern. A query inherits its
20
- # whole body from `QuerySpecification::Common::Options` — `wheres`,
21
- # `order_by`, `limit`, `offset`, `cursor`,
22
- # `authorization`, `null_semantics`, `inspection` — and those
23
- # are instance methods that the runtime and the SQLite adapter both read.
24
- # Hoisting the declaration onto a metaclass would put the identity and the
25
- # specification on opposite sides of the object.
26
- #
27
- # And nothing is lost, because `Class#name` was the only reason a construct
28
- # ever needed a second word for its own name. An instance answers `name`
29
- # truthfully. So a query gains an owner and an identity — which is what the
30
- # graph is for — and keeps the name it always had.
11
+ # It crosses over as an instance, not a class: its body comes from
12
+ # `QuerySpecification::Common::Options`, whose instance methods the runtime reads.
31
13
  class Query < QuerySpecification::Common::Options
32
14
  include Construct
33
15
 
@@ -45,25 +27,8 @@ module Hecks
45
27
 
46
28
  attr_reader :name, :description, :attributes
47
29
 
48
- # @param name [String, Symbol] the query's declared name
49
- # @param description [String, nil] the query's declared prose description
50
- # @param attributes [Array<Bluebook::Attribute>] the query's declared result fields
51
- # @param wheres [Array<QuerySpecification::Common::WhereClause>] the declared filter
52
- # conditions
53
- # @param order_by [QuerySpecification::Common::OrderBy, nil] the declared sort field
54
- # and direction, or `nil` for no explicit ordering
55
- # @param limit [QuerySpecification::Common::LimitSpec, nil] the declared row limit,
56
- # or `nil` for none
57
- # @param offset [QuerySpecification::Common::OffsetSpec, nil] the declared row offset,
58
- # or `nil` for none
59
- # @param cursor [QuerySpecification::Common::CursorSpec, nil] the declared pagination
60
- # cursor, or `nil` for none
61
- # @param authorization [QuerySpecification::Common::AuthorizationSpec, nil] the declared
62
- # authorization policy, or `nil` for none
63
- # @param null_semantics [QuerySpecification::Common::NullSemantics, nil] how this query
64
- # orders `nil` values; defaults to `NullSemantics.default` when omitted
65
- # @param inspection [QuerySpecification::Common::InspectionSpec, nil] the declared
66
- # inspection mode, or `nil` for none
30
+ # @param null_semantics [QuerySpecification::Common::NullSemantics, nil] defaults to
31
+ # `NullSemantics.default`
67
32
  def initialize(name:, description: nil, attributes: [], wheres: [],
68
33
  order_by: nil, limit: nil, offset: nil, cursor: nil,
69
34
  authorization: nil, null_semantics: nil,
@@ -78,14 +43,10 @@ module Hecks
78
43
  @attributes = attributes
79
44
  end
80
45
 
81
- # A query's shape is not fixed — `extra_options_to_h` carries
82
- # whatever options the specification layer grew (count, median,
83
- # group_by, scope_to). Declared emission covers the settled part
84
- # and `super` hands it over; the tail stays dynamic, which is the
85
- # honest description of it.
46
+ # `extra_options_to_h` (count, median, group_by, scope_to) stays dynamic; `super` covers the
47
+ # declared emission.
86
48
  #
87
- # @return [Hash] the declared emission, merged with whatever `extra_options_to_h`
88
- # the specification layer currently carries
49
+ # @return [Hash] the declared emission merged with `extra_options_to_h`
89
50
  def to_h = super.merge(extra_options_to_h)
90
51
  end
91
52
  end