hecks 2.8.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 (404) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +4 -6
  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 +17 -98
  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 +5 -48
  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 +31 -141
  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 +14 -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 +25 -31
  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 +16 -69
  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 -194
  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 -111
  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 +53 -267
  109. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +43 -305
  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 +6 -21
  114. data/lib/hecks/bluebook/model_check.rb +100 -597
  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 +4 -23
  128. data/lib/hecks/cli/document.rb +3 -21
  129. data/lib/hecks/cli/ir.rb +3 -5
  130. data/lib/hecks/cli/mcp.rb +2 -3
  131. data/lib/hecks/cli/mcp_door.rb +19 -114
  132. data/lib/hecks/cli/model_check.rb +18 -85
  133. data/lib/hecks/cli/project_cli.rb +7 -40
  134. data/lib/hecks/cli/project_diagrams.rb +0 -7
  135. data/lib/hecks/cli/run.rb +12 -58
  136. data/lib/hecks/cli/smoke_test.rb +2 -16
  137. data/lib/hecks/cli/stores.rb +1 -2
  138. data/lib/hecks/cli.rb +18 -24
  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 +82 -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 +9 -90
  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 +61 -64
  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 +6 -25
  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 +18 -124
  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 +150 -678
  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 +2 -15
  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 +42 -134
  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 +3 -6
  336. data/lib/hecks/release/runner/commands.rb +2 -4
  337. data/lib/hecks/release/runner/gem_publisher.rb +2 -3
  338. data/lib/hecks/release/runner/npm_publisher.rb +6 -20
  339. data/lib/hecks/release/runner/preflight.rb +4 -19
  340. data/lib/hecks/release/runner/tagger.rb +2 -9
  341. data/lib/hecks/release/runner.rb +3 -32
  342. data/lib/hecks/rendering.rb +4 -26
  343. data/lib/hecks/router/namespace_installer.rb +12 -36
  344. data/lib/hecks/router.rb +4 -8
  345. data/lib/hecks/runtime/aggregate_lock.rb +8 -33
  346. data/lib/hecks/runtime/boot_gates.rb +3 -18
  347. data/lib/hecks/runtime/caller.rb +19 -59
  348. data/lib/hecks/runtime/capability_graph.rb +5 -21
  349. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
  350. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +23 -160
  351. data/lib/hecks/runtime/command_interpreter.rb +124 -306
  352. data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
  353. data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
  354. data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
  355. data/lib/hecks/runtime/command_rules/emission.rb +8 -21
  356. data/lib/hecks/runtime/command_rules/references.rb +23 -202
  357. data/lib/hecks/runtime/dependency_planning.rb +30 -102
  358. data/lib/hecks/runtime/dispatcher.rb +82 -241
  359. data/lib/hecks/runtime/entity_element.rb +40 -462
  360. data/lib/hecks/runtime/entity_interpreter.rb +64 -219
  361. data/lib/hecks/runtime/errors.rb +32 -115
  362. data/lib/hecks/runtime/event.rb +3 -25
  363. data/lib/hecks/runtime/identity.rb +18 -154
  364. data/lib/hecks/runtime/instance.rb +18 -150
  365. data/lib/hecks/runtime/interpreting.rb +11 -70
  366. data/lib/hecks/runtime/invocation.rb +28 -164
  367. data/lib/hecks/runtime/loader.rb +48 -186
  368. data/lib/hecks/runtime/outbox.rb +38 -261
  369. data/lib/hecks/runtime/policy_interpreter.rb +38 -200
  370. data/lib/hecks/runtime/port_operation_interpreter.rb +26 -87
  371. data/lib/hecks/runtime/query_interpreter.rb +45 -187
  372. data/lib/hecks/runtime/reaction_invocation.rb +36 -138
  373. data/lib/hecks/runtime/read_model_interpreter.rb +117 -208
  374. data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
  375. data/lib/hecks/runtime/reference_hop.rb +8 -81
  376. data/lib/hecks/runtime/refusal_wording.rb +8 -89
  377. data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
  378. data/lib/hecks/runtime/registry/verification.rb +52 -225
  379. data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
  380. data/lib/hecks/runtime/registry.rb +99 -244
  381. data/lib/hecks/runtime/remote_dispatcher.rb +37 -152
  382. data/lib/hecks/runtime/routing.rb +4 -15
  383. data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
  384. data/lib/hecks/runtime/saga_interpreter.rb +79 -263
  385. data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
  386. data/lib/hecks/runtime/tenant_check.rb +6 -68
  387. data/lib/hecks/runtime/tenant_scope.rb +3 -28
  388. data/lib/hecks/runtime/value/admission.rb +16 -67
  389. data/lib/hecks/runtime/value/coercion.rb +155 -641
  390. data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
  391. data/lib/hecks/runtime/value.rb +12 -84
  392. data/lib/hecks/runtime.rb +17 -65
  393. data/lib/hecks/storehouse.rb +141 -568
  394. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +8 -32
  395. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
  396. data/lib/hecks/vendoring/git_environment.rb +2 -8
  397. data/lib/hecks/vendoring/git_source.rb +4 -10
  398. data/lib/hecks/vendoring.rb +7 -46
  399. data/lib/hecks/version.rb +3 -14
  400. data/lib/hecks.rb +26 -81
  401. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
  402. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
  403. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
  404. metadata +3 -2
@@ -3,53 +3,18 @@ require_relative "../forms/field_shape"
3
3
 
4
4
  module Hecks
5
5
  module Projector
6
- # A bluebook, projected as prose an SME can read back and confirm.
7
- #
8
- # ## What this is for
9
- #
10
- # `DocsProjector` already answers "what can I call and what does it
11
- # want" for the person implementing against a domain — tables of
12
- # arguments, shapes, refusal reasons. That is the wrong register for
13
- # the person who can actually say whether the domain is right: the
14
- # subject-matter expert who knows what an account is and has never
15
- # read a markdown table in their life. This projects the same IR as
16
- # sentences instead — "Debit — take money out. Issued by a Teller.
17
- # It only goes through if the balance covers it." — so a domain can
18
- # be read back to the person who can validate it without them
19
- # learning the DSL first.
20
- #
21
- # Same source, same guarantee `DocsProjector` gives: nothing here is
22
- # invented. Every sentence quotes a `description`, `goal`, or `given`
23
- # already declared in the chapter; where a chapter says nothing, this
24
- # says nothing rather than manufacturing a sentence out of an
25
- # identifier. Registered as `:narrate` beside `:docs`, same call shape
26
- # (`Projector.call(:narrate, bluebook: ...)`), same aggregate-scoping
27
- # via `options[:aggregate]`.
28
- #
29
- # ## What it does not do
30
- #
31
- # Replace `DocsProjector`. A shape table still says "id of a
32
- # Customer" more precisely than any sentence would, and an
33
- # implementer still wants that. This is the other document the same
34
- # IR is owed — one written for the reader who is being asked "is
35
- # this right?", not "how do I call it?"
6
+ # A bluebook projected as prose an SME can read back and confirm.
7
+ # Every sentence quotes a declared `description`, `goal` or `given`; nothing is invented.
36
8
  module NarrateProjector
37
9
  module_function
38
10
 
39
- # Projects `bluebook` as prose an SME can read back and confirm.
40
- #
41
- # `options[:heading]` sets the top heading level, exactly as
42
- # `DocsProjector` does — so this, too, can be spliced into a larger
43
- # document rather than always starting at H1.
11
+ # Projects `bluebook` as prose; `options[:heading]` sets the top heading level.
44
12
  #
45
13
  # @param bluebook [Bluebook::Behaviour::Chapter] the chapter to narrate
46
- # @param options [Hash] optional inputs
47
- # @option options [Integer, String] :heading the top heading level; defaults to 1
48
- # @option options [String, Symbol, nil] :aggregate narrows the narrative to one
49
- # aggregate, omitting the chapter intro and reactions sections
50
- # @return [String] the narrative, as Markdown prose, ending in a newline
51
- # @raise [Runtime::NotFound] if `options[:aggregate]` names no aggregate `bluebook`
52
- # declares
14
+ # @param options [Hash] `:heading` (Integer, default 1) and `:aggregate` (narrows to one
15
+ # aggregate, omitting the chapter intro and reactions)
16
+ # @return [String] Markdown prose ending in a newline
17
+ # @raise [Runtime::NotFound] if `options[:aggregate]` names no declared aggregate
53
18
  def call(bluebook:, options: {})
54
19
  depth = (options[:heading] || 1).to_i
55
20
  only = options[:aggregate]
@@ -63,14 +28,6 @@ module Hecks
63
28
  "#{sections.compact.join("\n\n").rstrip}\n"
64
29
  end
65
30
 
66
- # ── the chapter ───────────────────────────────────────────────────
67
-
68
- # Narrates the chapter-level intro: its vision, classification, former
69
- # name, and the aggregates it's told through.
70
- #
71
- # @param bluebook [Bluebook::Behaviour::Chapter] the chapter to narrate
72
- # @param depth [Integer] the heading level for the chapter's own title
73
- # @return [String] the intro's Markdown prose
74
31
  def chapter_intro(bluebook, depth)
75
32
  parts = [DocsProjector.h(depth, bluebook.name)]
76
33
  parts << bluebook.vision if bluebook.vision
@@ -85,14 +42,6 @@ module Hecks
85
42
  parts.join("\n\n")
86
43
  end
87
44
 
88
- # ── one aggregate ─────────────────────────────────────────────────
89
-
90
- # Narrates one aggregate: its description, identity, references,
91
- # lifecycle, commands, queries, and nested entities.
92
- #
93
- # @param aggregate [Bluebook::Aggregate] the aggregate to narrate
94
- # @param depth [Integer] the heading level for the aggregate's own title
95
- # @return [String] the aggregate's Markdown prose
96
45
  def aggregate_narrative(aggregate, depth)
97
46
  parts = [DocsProjector.h(depth, aggregate.hecks_name)]
98
47
  parts << aggregate.description if aggregate.description
@@ -113,23 +62,12 @@ module Hecks
113
62
  parts.compact.join("\n\n")
114
63
  end
115
64
 
116
- # Names how a holder is identified.
117
- #
118
- # @param holder [Bluebook::Aggregate, Bluebook::Entity] the holder to describe
119
- # @return [String, nil] a sentence naming `holder`'s identity fields, or nil if
120
- # it declares none
121
65
  def identity_sentence(holder)
122
66
  return nil if holder.identity_heads.empty?
123
67
 
124
68
  "Every #{holder.hecks_name} is identified by its #{to_sentence_list(holder.identity_heads.map { |h| "`#{h}`" })}."
125
69
  end
126
70
 
127
- # Narrates one entity nested under `aggregate`.
128
- #
129
- # @param aggregate [Bluebook::Aggregate] the entity's own owning aggregate
130
- # @param entity [Bluebook::Entity] the entity to narrate
131
- # @param depth [Integer] the heading level for the entity's own title
132
- # @return [String] the entity's Markdown prose
133
71
  def entity_narrative(aggregate, entity, depth)
134
72
  parts = [DocsProjector.h(depth, "#{entity.hecks_name} (within #{aggregate.hecks_name})")]
135
73
  parts << entity.description if entity.description
@@ -142,13 +80,6 @@ module Hecks
142
80
  parts.compact.join("\n\n")
143
81
  end
144
82
 
145
- # ── the machine ───────────────────────────────────────────────────
146
-
147
- # Narrates a holder's own lifecycle transitions.
148
- #
149
- # @param holder [Bluebook::Aggregate, Bluebook::Entity] the holder to describe
150
- # @return [String, nil] a sentence per lifecycle transition, or nil if `holder`
151
- # declares no lifecycle
152
83
  def lifecycle_narrative(holder)
153
84
  lifecycle = holder.lifecycle or return nil
154
85
 
@@ -161,15 +92,6 @@ module Hecks
161
92
  sentences.join(" ")
162
93
  end
163
94
 
164
- # ── the verbs ─────────────────────────────────────────────────────
165
-
166
- # Narrates every command a holder declares.
167
- #
168
- # @param holder [Bluebook::Aggregate, Bluebook::Entity] the holder whose
169
- # commands to narrate
170
- # @param depth [Integer] the heading level for the "What can happen" section
171
- # @return [String, nil] the section's Markdown prose, or nil if `holder`
172
- # declares no command
173
95
  def verbs_narrative(holder, depth)
174
96
  return nil if holder.commands.empty?
175
97
 
@@ -178,18 +100,7 @@ module Hecks
178
100
  "#{header}\n\n#{body}"
179
101
  end
180
102
 
181
- # One paragraph, built from independent sentences — each sentence
182
- # below states one unrelated fact about `command` (its goal, who
183
- # issues it, whether it creates the holder, what it takes, what it
184
- # references, what gates it, what it guarantees, what it emits), in
185
- # the fixed order a reader expects them; nothing after the first
186
- # sentence depends on anything before it. Same nil-or-string +
187
- # `compact.join` shape `aggregate_narrative`/`entity_narrative`
188
- # already use above for the identical reason.
189
- #
190
- # @param command [Bluebook::Command] the command to narrate
191
- # @param holder [Bluebook::Aggregate, Bluebook::Entity] `command`'s own holder
192
- # @return [String] the command's own paragraph
103
+ # Each sentence states one independent fact, so nil-or-string plus `compact.join` suffices.
193
104
  def command_paragraph(command, holder)
194
105
  [
195
106
  command_headline_sentence(command),
@@ -203,48 +114,25 @@ module Hecks
203
114
  ].compact.join(" ")
204
115
  end
205
116
 
206
- # The goal, verbatim — same rule `DocsProjector` holds to: quoted
207
- # exactly as declared, not recased to fit mid-sentence, because the
208
- # promise this whole projector makes is that a sentence here is a
209
- # sentence the chapter actually wrote.
210
- #
211
- # @param command [Bluebook::Command] the command to name
212
- # @return [String] the command's own bold name, plus its goal if it declares one
117
+ # The goal is quoted exactly as declared, never recased to fit mid-sentence.
213
118
  def command_headline_sentence(command)
214
119
  "**#{command.hecks_name}**#{command.goal ? " — #{command.goal}." : '.'}"
215
120
  end
216
121
 
217
- # Names who issues a command.
218
- #
219
- # @param command [Bluebook::Command] the command to describe
220
- # @return [String, nil] a sentence naming who issues `command`, or nil if it
221
- # declares no role
222
122
  def command_role_sentence(command)
223
123
  return nil unless command.role
224
124
 
225
125
  "Issued by #{a_or_an(command.role)} #{command.role}."
226
126
  end
227
127
 
228
- # `acts_on.nil?`, not `creates?` — `creates?` answers true for every
229
- # verb an entity declares (it never references itself; see
230
- # `Command#acts_on`'s own comment), so reading it directly here would
231
- # tell an SME that `LedgerEntry.Amend` brings a new ledger entry into
232
- # being, which is exactly backwards.
233
- # @param command [Bluebook::Command] the command to check
234
- # @param holder [Bluebook::Aggregate, Bluebook::Entity] `command`'s own holder
235
- # @return [String, nil] a sentence saying `command` creates `holder`, or nil if
236
- # `command` acts on an existing record instead
128
+ # `acts_on.nil?`, not `creates?`: `creates?` is true for every entity verb, which would
129
+ # wrongly say `LedgerEntry.Amend` creates a new ledger entry.
237
130
  def command_creation_sentence(command, holder)
238
131
  return nil unless command.acts_on.nil?
239
132
 
240
133
  "This is how a new #{holder.hecks_name} comes into being."
241
134
  end
242
135
 
243
- # Lists a command's own non-reference arguments.
244
- #
245
- # @param command [Bluebook::Command] the command to describe
246
- # @return [String, nil] a sentence listing `command`'s non-reference arguments,
247
- # or nil if it declares none
248
136
  def command_arguments_sentence(command)
249
137
  arguments = command.attributes.reject(&:reference?)
250
138
  return nil if arguments.empty?
@@ -252,11 +140,6 @@ module Hecks
252
140
  "It takes #{to_sentence_list(arguments.map { |a| Forms::Humanize.label(a.name.to_s).downcase })}."
253
141
  end
254
142
 
255
- # Names what a command references.
256
- #
257
- # @param command [Bluebook::Command] the command to describe
258
- # @return [String, nil] a sentence naming what `command` references, or nil if
259
- # it declares no reference argument
260
143
  def command_references_sentence(command)
261
144
  refs = command.attributes.select(&:reference?)
262
145
  return nil if refs.empty?
@@ -264,12 +147,6 @@ module Hecks
264
147
  "It's aimed at one existing #{to_sentence_list(refs.map { |r| r.type.target_name })}, by id."
265
148
  end
266
149
 
267
- # Lists a command's own required conditions.
268
- #
269
- # @param command [Bluebook::Command] the command to describe
270
- # @param holder [Bluebook::Aggregate, Bluebook::Entity] `command`'s own holder
271
- # @return [String, nil] a sentence listing every required condition, or nil if
272
- # `command` declares none
273
150
  def command_conditions_sentence(command, holder)
274
151
  conditions = conditions_of(command, holder)
275
152
  return nil if conditions.empty?
@@ -277,11 +154,6 @@ module Hecks
277
154
  "It only goes through if #{conditions.join('; ')}."
278
155
  end
279
156
 
280
- # Lists what a command guarantees when it succeeds.
281
- #
282
- # @param command [Bluebook::Command] the command to describe
283
- # @return [String, nil] a sentence listing `command`'s own `ensures`, or nil if
284
- # it declares none
285
157
  def command_guarantees_sentence(command)
286
158
  guarantees = command.ensures.map(&:description)
287
159
  return nil if guarantees.empty?
@@ -289,27 +161,14 @@ module Hecks
289
161
  "When it succeeds: #{guarantees.join('; ')}."
290
162
  end
291
163
 
292
- # Names what a command records.
293
- #
294
- # @param command [Bluebook::Command] the command to describe
295
- # @return [String, nil] a sentence naming what `command` records, or nil if it
296
- # emits nothing
297
164
  def command_emits_sentence(command)
298
165
  return nil if command.emits.empty?
299
166
 
300
167
  "It records `#{command.emits.join('`, `')}` as a fact."
301
168
  end
302
169
 
303
- # Every required condition, stated as something that must be true —
304
- # the same three sources `DocsProjector#refusals_of` reads (the
305
- # lifecycle edge, a reference's existence, and the command's own
306
- # `given`s), but kept positive rather than phrased as a refusal
307
- # reason. "Refused unless not X" is a sentence a reader has to
308
- # invert in their head; "only goes through if X" is not.
309
- #
310
- # @param command [Bluebook::Command] the command to gather conditions for
311
- # @param holder [Bluebook::Aggregate, Bluebook::Entity] `command`'s own holder
312
- # @return [Array<String>] every required condition, stated positively
170
+ # Required conditions stated positively ("only goes through if X"), from the lifecycle
171
+ # edge and the command's `given`s.
313
172
  def conditions_of(command, holder)
314
173
  conditions = []
315
174
 
@@ -328,14 +187,6 @@ module Hecks
328
187
  conditions + command.givens.map(&:description)
329
188
  end
330
189
 
331
- # ── the reads ─────────────────────────────────────────────────────
332
-
333
- # Narrates every query as one line per question.
334
- #
335
- # @param queries [Array<Bluebook::Query>] the queries to narrate
336
- # @param holder_name [String] the queries' own holder's name
337
- # @param depth [Integer] the heading level for the "Questions you can ask" section
338
- # @return [String, nil] the section's Markdown prose, or nil if `queries` is empty
339
190
  def queries_narrative(queries, holder_name, depth)
340
191
  return nil if queries.empty?
341
192
 
@@ -343,10 +194,7 @@ module Hecks
343
194
  lines = queries.map do |query|
344
195
  shape = query.to_h
345
196
  takes = Array(shape[:attributes]).map { |a| Forms::Humanize.label(a[:name].to_s).downcase }
346
- # `w[:value]` already wears its own quotes or colon — it is a
347
- # `Literal.render`ed string (see lib/hecks/literal.rb), not a raw
348
- # Ruby value, so wrapping it in `.inspect` here would quote an
349
- # already-quoted string a second time.
197
+ # `w[:value]` is already `Literal.render`ed (quoted), so no `.inspect`.
350
198
  filters = Array(shape[:wheres]).map { |w| "`#{w[:field]}` #{op_words(w[:op])} #{w[:value]}" }
351
199
 
352
200
  sentence = "- **#{query.hecks_name}**"
@@ -359,23 +207,10 @@ module Hecks
359
207
  "#{header}\n\n#{lines.join("\n")}"
360
208
  end
361
209
 
362
- # Translates a query comparator into plain English.
363
- #
364
- # @param comparator [String, Symbol] a where-clause comparator, such as `:eq`
365
- # @return [String] the comparator in plain words, or `comparator.to_s` verbatim
366
- # for one this file has no rendering rule for
367
210
  def op_words(comparator)
368
211
  { eq: "is", lt: "under", lte: "at most", gt: "over", gte: "at least" }[comparator.to_s.to_sym] || comparator.to_s
369
212
  end
370
213
 
371
- # ── what happens on its own ───────────────────────────────────────
372
-
373
- # Narrates what happens on its own: every policy and every saga.
374
- #
375
- # @param bluebook [Bluebook::Behaviour::Chapter] the chapter to narrate
376
- # @param depth [Integer] the heading level for the "Reactions" section
377
- # @return [String, nil] the section's Markdown prose, or nil if `bluebook`
378
- # declares no policy and no process manager
379
214
  def reactions_narrative(bluebook, depth)
380
215
  return nil if bluebook.policies.empty? && bluebook.process_managers.empty?
381
216
 
@@ -395,19 +230,10 @@ module Hecks
395
230
  parts.join("\n\n")
396
231
  end
397
232
 
398
- # ── small sentence carpentry ──────────────────────────────────────
399
-
400
- # Both now live in `Naming` (a second projection, the glossary,
401
- # needed them); kept here as names so this file reads as it did.
402
- #
403
- # @param items [Array<#to_s>] items to join, in order
404
- # @param conj [String] conjunction placed before the last item
405
- # @return [String] the joined sentence fragment, `""` for an empty `items`
406
233
  def to_sentence_list(items, conj: "and") = Naming.to_sentence_list(items, conj: conj)
407
234
 
408
- # Picks the English indefinite article for a word.
235
+ # Picks the article for `word`.
409
236
  #
410
- # @param word [String, Symbol] the word the article precedes
411
237
  # @return [String] `"a"` or `"an"`
412
238
  def a_or_an(word) = Naming.a_or_an(word)
413
239
  end
@@ -1,89 +1,26 @@
1
1
  module Hecks
2
2
  module Projector
3
- # What makes a module a projection target. `Projector.register` has
4
- # always accepted anything answering `call(bluebook:, options:)` —
5
- # this only removes the second step, so a target declares its own key
6
- # beside its own implementation instead of being registered from
7
- # somewhere else that has to be kept in sync with it.
3
+ # A projection target declares its own registration key beside its own
4
+ # implementation, instead of a separate registry entry that can drift.
8
5
  #
9
6
  # module Hecks::Projections::OIDC
10
7
  # extend Hecks::Projector::Target
11
8
  # projects_as :oidc
12
- #
13
- # module_function
14
- #
15
- # def call(bluebook:, options: {}) = { ... }
9
+ # def self.call(bluebook:, options: {}) = { ... }
16
10
  # end
17
11
  #
18
- # Named `Target`, not `Projection`, on purpose. "Projection" already
19
- # means two other things in this codebase: `Ports::Projection` is
20
- # read-model catch-up (events folded into view state), and `bin/project`
21
- # forces that catch-up by hand. Neither has anything to do with
22
- # "canonical IR in, external artifact out". A third meaning under the
23
- # same word would make the two impossible to grep apart — and from a
24
- # domain's point of view `project(X)` really does read as "project to
25
- # a target", so the narrower word is also the more accurate one.
12
+ # Named `Target`, not `Projection`, which already means read-model catch-up elsewhere.
26
13
  module Target
27
- # Registering at declaration time means `require`ing a target is
28
- # the whole of installing it — there is no separate manifest that
29
- # can silently disagree about which targets exist.
30
- #
31
- # `requires:` names a capability, not a shape word.
32
- #
33
- # This began as `from: :chapter` / `from: :any` — two hand-kept
34
- # symbols, admitted by duck-typing on `.aggregates`, which is a
35
- # guess at what "is a chapter" means. The capabilities were already
36
- # real by then: `Hecks::IR` is the ability to emit IR (its own
37
- # header says so), and `Behaviour::Chapter` is the ability to answer
38
- # as a chapter. So a projection names the module it needs, and
39
- # admission is a genuine check rather than a proxy for one.
40
- #
41
- # projects_as :ir, requires: Hecks::IR
42
- # projects_as :vocabulary # chapter, the default
43
- #
44
- # It also composes: a projection needing two capabilities names
45
- # both, instead of a third symbol being invented for the pair.
46
- #
47
- # The fail-quiet this closes, unchanged in substance: every
48
- # construct emits its own IR, so handing a projector an aggregate
49
- # instead of a chapter is the natural thing to try. `bluebook:` was
50
- # only ever a parameter name, never a contract. `:oidc` failed
51
- # loudly (no `aggregates` method), but `:shape` returned
52
- # `{"name" => "Order", "aggregates" => []}` — well-formed,
53
- # confident, and wrong.
54
- # `declares:` names an aggregate the chapter must have.
55
- #
56
- # A capability says what a construct can do; this says what it must
57
- # carry. `:vocabulary` needs a chapter declaring a Vocabulary
58
- # aggregate, `:parser_table` one declaring Syntax — declared here
59
- # rather than as a `raise` in the projection's own body, so the
60
- # requirement is stated instead of written as behaviour. The
61
- # registry refuses before the projection runs, so the projection
62
- # itself carries no guard about its own admission.
63
- # `emits:` says what kind of artifact comes back.
64
- #
65
- # `:artifact` (the default) is one thing — a Hash, or a String.
66
- # `:files` is a tree: a Hash of relative path => contents, which is
67
- # what a reference-page or codegen projection produces.
68
- #
69
- # Declared rather than sniffed, deliberately. Inferring a tree from
70
- # an ordinary Hash is guesswork — `{"name" => "Pizzas"}` is
71
- # indistinguishable from a one-file tree — so `write` asks what the
72
- # projection said rather than inspecting what it returned.
73
- # Registers `self` as a projection target under `key`, and stores the
74
- # capability and aggregate requirements `admits!` later checks against.
14
+ # Registers `self` as a projection target under `key`; the registry
15
+ # checks `requires`/`declares` before a projection ever runs, so a
16
+ # projection carries no admission guard of its own.
75
17
  #
76
- # @param key [String, Symbol] the key to register `self` under (converted to a symbol)
77
- # @param requires [Module, Array<Module>, nil] capability module(s) a construct must
78
- # satisfy; nil or empty means `Bluebook::Behaviour::Chapter`
79
- # @param declares [String, Symbol, Array<String, Symbol>, nil] aggregate name(s) the
80
- # chapter must declare; nil means none
81
- # @param emits [Symbol] the kind of artifact `self` returns: `:artifact` (the default,
82
- # a single Hash or String) or `:files` (a path => contents tree)
83
- # @param needs_world [Boolean] whether `self` is an export — a target that reads a
84
- # domain's `.world`/`.hecksagon` bindings, not only its declaration. `false` (the
85
- # default) for an ordinary projection; `true` refuses a `Projector.call` made with
86
- # no `world:`.
18
+ # @param key [String, Symbol] key to register `self` under
19
+ # @param requires [Module, Array<Module>, nil] capability module(s) required;
20
+ # nil/empty means `Bluebook::Behaviour::Chapter`
21
+ # @param declares [String, Symbol, Array, nil] aggregate name(s) the chapter must declare
22
+ # @param emits [Symbol] :artifact (a Hash/String, the default) or :files (a path => tree)
23
+ # @param needs_world [Boolean] true refuses a call made with no `world:` bindings
87
24
  # @return [Symbol] the registered key
88
25
  def projects_as(key, requires: nil, declares: nil, emits: :artifact, needs_world: false)
89
26
  @projection_emits = emits