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
@@ -4,38 +4,11 @@ require_relative "vocabulary"
4
4
 
5
5
  module Hecks
6
6
  module Projections
7
- # The language's closed sets, projected into the Rust kernel — one
8
- # `rust/src/kernel/vocab/<table>.rs` per Vocabulary table, each a
9
- # `pub enum` plus `match`-based accessors with no wildcard arm, so a
10
- # row the chapter gains is a compile error at every exhaustive match
11
- # over it rather than a silent gap.
7
+ # The language's closed sets as Rust enums, one `rust/src/kernel/vocab/<table>.rs` per table,
8
+ # matched with no wildcard arm so a new row fails to compile until it is handled.
12
9
  #
13
10
  # Projector.call(:rust_vocabulary, bluebook: <the Bluebook chapter>)
14
11
  # # => { "vocab/mod.rs" => "...", "vocab/refusal_template.rs" => "...", ... }
15
- #
16
- # Paths are relative to rust/src/kernel/; bin/project_rust_vocabulary
17
- # writes them. This generalizes the old bin/project_refusal_wording,
18
- # which read Runtime::RefusalWording::TEMPLATES — a hand-typed copy of
19
- # the RefusalTemplate rows. This reads the chapter itself.
20
- #
21
- # ## Only `TABLES` the kernel needs
22
- #
23
- # Each entry in `TABLES` names its enum and its generated extras; a
24
- # table not listed is not projected. The enum names that differ from
25
- # the table name keep existing Rust call sites (`RefusalSite`) and the
26
- # dispatch-step names D1 consumes (`AggregateStep`, `EntityStep`).
27
- #
28
- # ## Typed refusal arguments
29
- #
30
- # The templates table also reads RefusalSiteArgument: every site gets a
31
- # `<Variant>Args` struct whose fields are exactly the site's declared
32
- # arguments (a `&str` per scalar, a `&[&str]` per list) and a
33
- # `render_args` that formats each one by its row. `render` itself stays
34
- # private to the generated module, so no call site can pass an argument
35
- # list by hand — leaving one out does not compile. The generated test
36
- # pins every site's `render_args` output (empty, single and multiple
37
- # unsorted lists) against Runtime::RefusalWording.render_with, computed
38
- # here in Ruby.
39
12
  module RustVocabulary
40
13
  extend Projector::Target
41
14
 
@@ -44,10 +17,8 @@ module Hecks
44
17
  GENERATOR = "bin/project_rust_vocabulary".freeze
45
18
  SOURCE = "lib/hecks/language/bluebook/vocabulary.bluebook".freeze
46
19
 
47
- # table name => enum name, variant-naming fields, file stem, kind.
48
- # `:order` tables also get `ORDER` and `position`; `:templates`
49
- # gets `render`, the typed `<Variant>Args` (read off the `arguments`
50
- # table) and the placeholder and argument-rendering tests.
20
+ # Table name => enum name, variant-naming fields, file stem and kind.
21
+ # `:order` adds `position`; `:templates` adds `render` and the typed `<Variant>Args`.
51
22
  TABLES = {
52
23
  "RefusalTemplate" => { enum: "RefusalSite", variant_from: %w[refusal site], file: "refusal_template",
53
24
  kind: :templates, arguments: "RefusalSiteArgument" },
@@ -65,24 +36,8 @@ module Hecks
65
36
 
66
37
  module_function
67
38
 
68
- # The projector protocol.
69
- #
70
- # @param bluebook [Bluebook::Behaviour::Chapter] the chapter declaring the
71
- # Vocabulary aggregate to project
72
- # @param options [Hash] unused; accepted to satisfy the registry's call shape
73
- # @return [Hash{String => String}] each generated file's path, relative to
74
- # `rust/src/kernel/`, mapped to its full Rust source
75
39
  def call(bluebook:, options: {}) = render(bluebook)
76
40
 
77
- # Renders every file `TABLES` projects: `vocab/mod.rs` plus one `.rs` file
78
- # per table, each an exhaustive enum with accessors and a pinned test module.
79
- #
80
- # @param bluebook [Bluebook::Behaviour::Chapter] the chapter declaring the
81
- # Vocabulary aggregate to render
82
- # @return [Hash{String => String}] each generated file's path, relative to
83
- # `rust/src/kernel/`, mapped to its full Rust source
84
- # @raise [ArgumentError] if `bluebook` does not declare a `TABLES`-named table,
85
- # or the `:arguments` table a `:templates` entry names
86
41
  def render(bluebook)
87
42
  tables = Vocabulary.tables(bluebook)
88
43
  files = TABLES.to_h do |table, spec|
@@ -95,11 +50,6 @@ module Hecks
95
50
  { "vocab/mod.rs" => mod_file }.merge(files)
96
51
  end
97
52
 
98
- # The generated-file banner every projected file opens with.
99
- #
100
- # @param table [String] the Vocabulary table name being projected, such as
101
- # `"RefusalTemplate"`
102
- # @return [String] the banner, as Rust line comments
103
53
  def header(table)
104
54
  <<~RUST
105
55
  // GENERATED by #{GENERATOR} (Hecks::Projections::RustVocabulary,
@@ -109,10 +59,6 @@ module Hecks
109
59
  RUST
110
60
  end
111
61
 
112
- # Renders `vocab/mod.rs`, the entry point that re-exports every projected enum.
113
- #
114
- # @return [String] `vocab/mod.rs`'s full source: one `pub mod` and `pub use`
115
- # per entry in `TABLES`
116
62
  def mod_file
117
63
  mods = TABLES.values.map { |spec| "pub mod #{spec[:file]};" }.join("\n")
118
64
  exports = TABLES.values.map { |spec| "pub use #{spec[:file]}::#{spec[:enum]};" }.join("\n")
@@ -132,18 +78,6 @@ module Hecks
132
78
  RUST
133
79
  end
134
80
 
135
- # One table's full `.rs` source: its exhaustive enum, per-field accessors,
136
- # `from_name`, its `:order`/`:templates` extras, and its `#[cfg(test)]` module.
137
- #
138
- # @param table [String] the Vocabulary table name, such as `"RefusalTemplate"`
139
- # @param spec [Hash] the table's `TABLES` entry (`:enum`, `:variant_from`,
140
- # `:file`, `:kind`, and, for `:templates`, `:arguments`)
141
- # @param rows [Array<Hash{String => String}>] the table's rows, as read off
142
- # the chapter by `Vocabulary.tables`
143
- # @param argument_rows [Array<Hash{String => String}>, nil] the
144
- # `RefusalSiteArgument` rows, only when `spec[:kind] == :templates`
145
- # @return [String] the table's full `.rs` file source
146
- # @raise [ArgumentError] if two rows would generate the same enum variant name
147
81
  def table_file(table, spec, rows, argument_rows = nil)
148
82
  variants = rows.map { |row| variant_name(row, spec[:variant_from]) }
149
83
  duplicates = variants.tally.select { |_, count| count > 1 }.keys
@@ -172,14 +106,6 @@ module Hecks
172
106
  "#{body.flatten.join("\n").rstrip}\n"
173
107
  end
174
108
 
175
- # Renders the enum's declared-order constant: `ORDER` for `:order`, `ALL` otherwise.
176
- #
177
- # @param enum [String] the Rust enum name, such as `"RefusalSite"`
178
- # @param variants [Array<String>] each row's generated variant name, in
179
- # declared order
180
- # @param kind [Symbol] the table's `:kind` (`:order`, `:templates`, or `:set`)
181
- # @return [Array<String>] the lines declaring the enum's `ORDER` constant
182
- # (`:order`) or `ALL` constant (otherwise)
183
109
  def constants(enum, variants, kind)
184
110
  list = variants.map { |variant| " #{enum}::#{variant}," }
185
111
  if kind == :order
@@ -191,16 +117,6 @@ module Hecks
191
117
  end
192
118
  end
193
119
 
194
- # Renders one field's `pub fn` accessor, an exhaustive match over every variant.
195
- #
196
- # @param enum [String] the Rust enum name
197
- # @param field [String] the row field this accessor reads, such as `"name"`
198
- # @param variants [Array<String>] each row's generated variant name, in
199
- # declared order, matching `rows`
200
- # @param rows [Array<Hash{String => String}>] the table's rows, in the same
201
- # order as `variants`
202
- # @return [Array<String>] the lines for the field's `pub fn` accessor, one
203
- # match arm per variant
204
120
  def accessor(enum, field, variants, rows)
205
121
  arms = variants.zip(rows).map { |variant, row| " #{enum}::#{variant} => #{rust_string(row.fetch(field))}," }
206
122
  [" /// The row's declared `#{field}`.",
@@ -212,12 +128,7 @@ module Hecks
212
128
  ""]
213
129
  end
214
130
 
215
- # Built on the enum's own list and name accessor, not a string
216
- # match, so it needs no wildcard arm either.
217
- #
218
- # @param enum [String] the Rust enum name
219
- # @param kind [Symbol] the table's `:kind` (`:order`, `:templates`, or `:set`)
220
- # @return [Array<String>] the lines for the enum's `from_name` associated function
131
+ # Built on the enum's own list and name accessor, not a string match, so no wildcard arm.
221
132
  def from_name(enum, kind)
222
133
  list = kind == :order ? "ORDER" : "ALL"
223
134
  field = kind == :templates ? "site" : name_field(kind)
@@ -228,14 +139,6 @@ module Hecks
228
139
  ""]
229
140
  end
230
141
 
231
- # Renders the extra methods a table's `:kind` adds beyond the shared accessors.
232
- #
233
- # @param enum [String] the Rust enum name
234
- # @param variants [Array<String>] each row's generated variant name, in
235
- # declared order
236
- # @param kind [Symbol] the table's `:kind` (`:order`, `:templates`, or `:set`)
237
- # @return [Array<String>] `:order`'s `position` method, `:templates`'s private
238
- # `render` method, or `[]` for `:set`
239
142
  def extras(enum, variants, kind)
240
143
  case kind
241
144
  when :order
@@ -263,20 +166,8 @@ module Hecks
263
166
  end
264
167
  end
265
168
 
266
- # [refusal, site] => that site's argument rows, in declared order —
267
- # refused unless they name exactly the template's own placeholders,
268
- # in the order each first appears, with only known formatting rules.
269
- #
270
- # @param rows [Array<Hash{String => String}>] the `RefusalTemplate` rows,
271
- # in declared order
272
- # @param argument_rows [Array<Hash{String => String}>] the `RefusalSiteArgument`
273
- # rows for every site
274
- # @return [Hash{Array<String> => Array<Hash{String => String}>}] each
275
- # `[refusal, site]` pair mapped to its declared argument rows, in declared order
276
- # @raise [ArgumentError] if an argument row names a `refusal`/`site` no
277
- # `RefusalTemplate` row declares, if a site's declared arguments do not match
278
- # its template's `{placeholder}`s in order, or if `check_rule!` rejects a
279
- # row's `"shape"`, `"quoting"`, or `"sorted"` value
169
+ # [refusal, site] => that site's argument rows; refused unless they name exactly the
170
+ # template's placeholders, in first-appearance order, with known formatting rules.
280
171
  def site_arguments(rows, argument_rows)
281
172
  grouped = argument_rows.group_by { |row| [row.fetch("refusal"), row.fetch("site")] }
282
173
  orphans = grouped.keys - rows.map { |row| [row.fetch("refusal"), row.fetch("site")] }
@@ -296,18 +187,6 @@ module Hecks
296
187
  end
297
188
  end
298
189
 
299
- # Refuses a `RefusalSiteArgument` row whose formatting fields are not
300
- # recognized rules.
301
- #
302
- # @param key [Array<String>] the `[refusal, site]` pair `spec` belongs to,
303
- # used in the raised message
304
- # @param spec [Hash{String => String}] one `RefusalSiteArgument` row
305
- # (`"shape"`, `"quoting"`, `"sorted"`)
306
- # @return [void]
307
- # @raise [ArgumentError] if `spec`'s `"shape"` is not in
308
- # `Runtime::RefusalWording::SHAPES`, its `"quoting"` is not in
309
- # `Runtime::RefusalWording::QUOTINGS`, or its `"sorted"` is not
310
- # `"true"`/`"false"`
311
190
  def check_rule!(key, spec)
312
191
  where = "#{key.join('/')}.#{spec.fetch('argument')}"
313
192
  unless Runtime::RefusalWording::SHAPES.include?(spec.fetch("shape"))
@@ -321,17 +200,6 @@ module Hecks
321
200
  raise ArgumentError, "#{where}: sorted must be \"true\" or \"false\""
322
201
  end
323
202
 
324
- # Renders every `:templates` variant's typed argument struct, plus the two
325
- # helper functions (`quoted`, `list`) they share.
326
- #
327
- # @param enum [String] the Rust enum name
328
- # @param variants [Array<String>] each row's generated variant name, matching `rows`
329
- # @param rows [Array<Hash{String => String}>] the `RefusalTemplate` rows, in
330
- # the same order as `variants`
331
- # @param by_site [Hash{Array<String> => Array<Hash{String => String}>}] each
332
- # `[refusal, site]` pair's declared argument rows, as built by `site_arguments`
333
- # @return [Array<String>] the shared `quoted`/`list` helper functions, followed
334
- # by every variant's `<Variant>Args` struct and `render_args` implementation
335
203
  def argument_types(enum, variants, rows, by_site)
336
204
  support = [
337
205
  "/// Ruby's `#inspect` of a name, as a refusal quotes it: `{:?}` on a",
@@ -362,15 +230,6 @@ module Hecks
362
230
  end
363
231
  end
364
232
 
365
- # Renders one variant's `<Variant>Args` struct and its `render_args` method.
366
- #
367
- # @param enum [String] the Rust enum name
368
- # @param variant [String] the row's generated variant name
369
- # @param row [Hash{String => String}] the `RefusalTemplate` row this variant projects
370
- # @param specs [Array<Hash{String => String}>] the variant's declared
371
- # `RefusalSiteArgument` rows, in declared order
372
- # @return [Array<String>] the lines for the variant's `<Variant>Args` struct
373
- # and its `render_args` method
374
233
  def args_struct(enum, variant, row, specs)
375
234
  fields = specs.flat_map do |spec|
376
235
  type = spec.fetch("shape") == "list" ? "&'a [&'a str]" : "&'a str"
@@ -401,15 +260,6 @@ module Hecks
401
260
  ""]
402
261
  end
403
262
 
404
- # The `let` binding, if any, `args_struct` inserts before a variant's
405
- # `render_args` computes its argument pairs.
406
- #
407
- # @param spec [Hash{String => String}] one `RefusalSiteArgument` row
408
- # (`"argument"`, `"shape"`, `"quoting"`, and, for a list, `"sorted"`,
409
- # `"separator"`, `"when_empty"`)
410
- # @return [String, nil] the `let` line formatting the argument through
411
- # `list`/`quoted`, or `nil` if the argument needs no formatting local
412
- # (a scalar written as-is)
413
263
  def formatted_local(spec)
414
264
  name = spec.fetch("argument")
415
265
  field = "self.#{rust_field(name)}"
@@ -421,13 +271,6 @@ module Hecks
421
271
  end
422
272
  end
423
273
 
424
- # Describes one argument's formatting rule in English, for its struct field's doc comment.
425
- #
426
- # @param spec [Hash{String => String}] one `RefusalSiteArgument` row
427
- # (`"shape"`, `"quoting"`, and, for a list, `"sorted"`, `"separator"`,
428
- # `"when_empty"`)
429
- # @return [String] a short English reading of the row's formatting rule,
430
- # used as the struct field's own doc comment
431
274
  def rule_reading(spec)
432
275
  quoting = spec.fetch("quoting") == "inspect" ? ", quoted" : ""
433
276
  return "scalar#{quoting}" unless spec.fetch("shape") == "list"
@@ -436,33 +279,10 @@ module Hecks
436
279
  "list#{sorted}#{quoting}, joined #{spec.fetch('separator').inspect}, empty reads #{spec.fetch('when_empty').inspect}"
437
280
  end
438
281
 
439
- # The local variable name `formatted_local` binds an argument's formatted value to.
440
- #
441
- # @param argument [String] the `RefusalSiteArgument` row's `"argument"` name
442
- # @return [String] the Rust local variable name `formatted_local` binds the
443
- # formatted value to
444
282
  def local_name(argument) = "#{argument}_text"
445
283
 
446
- # An argument name, escaped for use as a Rust field/parameter identifier.
447
- #
448
- # @param argument [String] the `RefusalSiteArgument` row's `"argument"` name
449
- # @return [String] `argument`, prefixed with `r#` if it collides with a Rust
450
- # keyword in `RUST_KEYWORDS`
451
284
  def rust_field(argument) = RUST_KEYWORDS.include?(argument) ? "r##{argument}" : argument
452
285
 
453
- # Renders the table's `#[cfg(test)]` module: every kind's `from_name` round-trip
454
- # test, plus `:order`'s and `:templates`' own tests.
455
- #
456
- # @param enum [String] the Rust enum name
457
- # @param kind [Symbol] the table's `:kind` (`:order`, `:templates`, or `:set`)
458
- # @param variants [Array<String>] each row's generated variant name, only
459
- # read when `kind == :templates`
460
- # @param rows [Array<Hash{String => String}>] the table's rows, only read
461
- # when `kind == :templates`
462
- # @param by_site [Hash{Array<String> => Array<Hash{String => String}>}, nil]
463
- # each `[refusal, site]` pair's declared argument rows, only read when
464
- # `kind == :templates`
465
- # @return [Array<String>] the `#[cfg(test)]` module's full source lines
466
286
  def tests(enum, kind, variants = [], rows = [], by_site = nil)
467
287
  list = kind == :order ? "ORDER" : "ALL"
468
288
  name = accessor_name(kind == :templates ? "site" : name_field(kind))
@@ -488,11 +308,6 @@ module Hecks
488
308
  lines + ["}"]
489
309
  end
490
310
 
491
- # The `:order` kind's own test, checked into every order table's test module.
492
- #
493
- # @param enum [String] the Rust enum name
494
- # @return [Array<String>] the test asserting `ORDER`'s index matches each
495
- # variant's `position`
496
311
  def order_test(enum)
497
312
  [" #[test]",
498
313
  " fn position_is_the_index_in_order() {",
@@ -503,12 +318,7 @@ module Hecks
503
318
  ""]
504
319
  end
505
320
 
506
- # Placeholders are read off each template's own text, never a second
507
- # hand-kept list.
508
- #
509
- # @param enum [String] the Rust enum name
510
- # @return [Array<String>] the test asserting every site's `render` leaves
511
- # no `{...}` placeholder unfilled
321
+ # Placeholders are read off each template's own text, never a second hand-kept list.
512
322
  def placeholder_test(enum)
513
323
  [" #[test]",
514
324
  " fn every_site_renders_with_no_leftover_placeholder() {",
@@ -538,21 +348,8 @@ module Hecks
538
348
  " }"]
539
349
  end
540
350
 
541
- # The Ruby oracle, pinned. Every site renders through its typed
542
- # `render_args` for each edge case a list argument has — empty, one
543
- # item, several out of order — and must equal what
544
- # Runtime::RefusalWording.render_with answers for the same values,
545
- # computed here at generation time. Scalars carry a `"` so quoting
546
- # is compared too.
547
- #
548
- # @param variants [Array<String>] each row's generated variant name, matching `rows`
549
- # @param rows [Array<Hash{String => String}>] the `RefusalTemplate` rows, in
550
- # the same order as `variants`
551
- # @param by_site [Hash{Array<String> => Array<Hash{String => String}>}] each
552
- # `[refusal, site]` pair's declared argument rows, as built by `site_arguments`
553
- # @return [Array<String>] the test asserting every variant's `render_args`
554
- # output for each `argument_cases` case matches
555
- # `Runtime::RefusalWording.render_with`, computed here in Ruby
351
+ # Pins each site's typed `render_args` to Runtime::RefusalWording.render_with, computed here,
352
+ # for empty, single and unsorted list arguments; scalars carry a `"` to compare quoting.
556
353
  def render_args_test(variants, rows, by_site)
557
354
  asserts = variants.zip(rows).flat_map do |variant, row|
558
355
  specs = by_site.fetch([row.fetch("refusal"), row.fetch("site")])
@@ -577,14 +374,6 @@ module Hecks
577
374
 
578
375
  LIST_CASES = [[], ["only \"one\""], %w[zeta alpha mid]].freeze
579
376
 
580
- # Builds the argument-value cases `render_args_test` checks a site's
581
- # `render_args` against.
582
- #
583
- # @param specs [Array<Hash{String => String}>] one site's declared
584
- # `RefusalSiteArgument` rows
585
- # @return [Array<Hash{Symbol => Object}>] one argument Hash per test case —
586
- # `LIST_CASES` (empty, one item, several unsorted) if any spec is
587
- # list-shaped, else a single scalar case, each scalar value carrying a `"`
588
377
  def argument_cases(specs)
589
378
  cases = specs.any? { |spec| spec.fetch("shape") == "list" } ? LIST_CASES : [nil]
590
379
  cases.map do |items|
@@ -595,29 +384,11 @@ module Hecks
595
384
  end
596
385
  end
597
386
 
598
- # The row field a table's `from_name`/round-trip test treats as its "name".
599
- #
600
- # @param kind [Symbol] the table's `:kind` (`:order`, `:templates`, or `:set`)
601
- # @return [String] the row field used as this kind's "name" — `"step"` for
602
- # `:order`, `"name"` otherwise
603
387
  def name_field(kind) = kind == :order ? "step" : "name"
604
388
 
605
- # `refusal` is a Rust-safe word but reads ambiguously beside the
606
- # kernel's own `Refusal` enum; the accessor says what it answers.
607
- #
608
- # @param field [String] a row field name, such as `"name"` or `"refusal"`
609
- # @return [String] the Rust accessor method name for `field` —
610
- # `"refusal_class"` for `"refusal"`, `field` otherwise
389
+ # `refusal` reads ambiguously beside the kernel's own `Refusal` enum.
611
390
  def accessor_name(field) = field == "refusal" ? "refusal_class" : field
612
391
 
613
- # Builds one row's Rust enum variant name from its declared `variant_from` fields.
614
- #
615
- # @param row [Hash{String => String}] the table row to name
616
- # @param fields [Array<String>] the row fields, PascalCased and concatenated
617
- # in order to build the variant name
618
- # @return [String] the row's generated Rust enum variant name
619
- # @raise [ArgumentError] if the built name is not a valid Rust variant
620
- # identifier (uppercase first letter, alphanumeric only)
621
392
  def variant_name(row, fields)
622
393
  name = fields.map { |field| pascal(row.fetch(field)) }.join
623
394
  raise ArgumentError, "#{name.inspect} is not a Rust variant name" unless name.match?(/\A[A-Z][A-Za-z0-9]*\z/)
@@ -625,18 +396,9 @@ module Hecks
625
396
  name
626
397
  end
627
398
 
628
- # PascalCases one field value for use inside a generated variant name.
629
- #
630
- # @param text [String, Symbol, nil] the value to PascalCase; each
631
- # `_`-separated part's first letter is upcased
632
- # @return [String] `text` converted to PascalCase, or `""` if `text` is `nil`
633
399
  def pascal(text) = text.to_s.split("_").map { |part| part[0].to_s.upcase + part[1..].to_s }.join
634
400
 
635
- # A Rust string literal: only `\`, `"` and newlines need escaping in
636
- # the text any vocabulary row holds.
637
- #
638
- # @param text [String] the value to render as a Rust string literal
639
- # @return [String] `text`, backslash/quote/newline-escaped and wrapped in `"..."`
401
+ # Only `\`, `"` and newlines need escaping in the text a vocabulary row holds.
640
402
  def rust_string(text)
641
403
  escaped = text.to_s.gsub("\\") { "\\\\" }.gsub('"') { "\\\"" }.gsub("\n") { "\\n" }
642
404
  "\"#{escaped}\""
@@ -3,21 +3,8 @@ require_relative "../projector"
3
3
 
4
4
  module Hecks
5
5
  module Projections
6
- # The storage shape of one bluebook — the same structural form
7
- # `StorageShape.mint_hash` hashes to name an era, which is what makes
8
- # a bump/no-bump question answerable by diffing two of these.
9
- #
10
- # The retrofit, and the point of it: `Runtime::StorageShape.project`
11
- # was written long before this framework existed, and it already
12
- # takes exactly one bluebook, already returns a plain Hash, already
13
- # touches no disk and no live runtime — it even already uses the
14
- # word. Nothing about it was shaped to fit `call(bluebook:, options:)`.
15
- #
16
- # That it fits anyway, by a two-line keyword adapter and no change to
17
- # `StorageShape` itself, is the evidence that the protocol is a real
18
- # description of what projections do here rather than a shape fitted
19
- # around its own first example (`:ir`, whose `call` is `to_h`, proves
20
- # much less on its own).
6
+ # The storage shape of one bluebook, the form `StorageShape.mint_hash` hashes to name an era.
7
+ # Diffing two of these answers whether a change bumps the era.
21
8
  module Shape
22
9
  extend Projector::Target
23
10
 
@@ -25,20 +12,7 @@ module Hecks
25
12
 
26
13
  module_function
27
14
 
28
- # ADR 0033 — `Runtime::StorageShape` lives in the era persistence
29
- # plugin now; the `:shape` projection itself stays registered
30
- # unconditionally (the seam `spec/projector_seam_spec.rb` enforces
31
- # is "every file here registers," not "every projection always
32
- # succeeds") but refuses clearly if asked to run with the plugin
33
- # unloaded, rather than raising on an undefined constant.
34
- # Projects the storage shape of `bluebook` — the structural form an era
35
- # bump/no-bump question is answered by diffing.
36
- #
37
- # @param bluebook [Bluebook::Chapter] the bluebook to reduce to its storage shape
38
- # @param options [Hash] unused; accepted to satisfy the registry's call shape
39
- # @return [Hash{String => Object}] `Runtime::StorageShape.project`'s Hash: `"name"`
40
- # and a sorted `"aggregates"` array
41
- # @raise [RuntimeError] if the era persistence plugin is not loaded
15
+ # Registered even when the era plugin is unloaded; the call then refuses clearly.
42
16
  def call(bluebook:, options: {})
43
17
  unless Ports::Persistence.plugin?(:era)
44
18
  raise "the :shape projection needs the era persistence plugin loaded " \
@@ -2,40 +2,10 @@ require_relative "../projector"
2
2
 
3
3
  module Hecks
4
4
  module Projections
5
- # A domain's own declared facts, projected as plain english sentences
6
- # — one atomic, independently-checkable statement per fact, not a
7
- # flowing document (`Projections::Reference`/`DocsProjector` already
8
- # do that job well; this is a flat list a caller can iterate, diff,
9
- # or hand to something else entirely — a review, a test-plan seed,
10
- # a sanity check that the domain still says what someone thinks it
11
- # says).
5
+ # A domain's declared facts as flat plain-English sentences, one checkable statement per fact.
6
+ # Never invents one: relationships read from shape, invariants use the author's description.
12
7
  #
13
- # ## Never invents a sentence from nothing
14
- #
15
- # `DocsProjector`'s own discipline, held here too: a relationship's
16
- # sentence is built mechanically from its own declared shape (holder,
17
- # target, relationship kind — the same facts `Projections::Diagrams`'s
18
- # own relationship_edge already reads), and an invariant's sentence is
19
- # the domain author's own `description`, capitalized and punctuated,
20
- # never paraphrased. If a fact has no author-written description and
21
- # no unambiguous mechanical phrasing, it doesn't get a sentence here —
22
- # a wrong sentence is worse than a missing one.
23
- #
24
- # ## Reachable like any projection
25
- #
26
- # No new facade wiring needed: `Pizzas.project(Projections::Statements)`
27
- # — `Facade::Surface::Chapter#project`'s own comment already settled
28
- # this ("anything genuinely needing the graph is a projector, and a
29
- # projector is given it"). `bin/statements` is a thin, optional
30
- # convenience for reaching the same call from a shell.
31
- #
32
- # ## MVP scope
33
- #
34
- # "has many"/"has a"/"belongs to"/"references" sentences for every
35
- # list or relationship attribute, and every invariant's own
36
- # description (aggregate-level and every nested value object's),
37
- # verbatim. Lifecycle transitions and command given/ensures read the
38
- # same way and are the natural next sentences — not built yet.
8
+ # Pizzas.project(Projections::Statements) # => ["A Pizza has many toppings.", ...]
39
9
  module Statements
40
10
  extend Hecks::Projector::Target
41
11
 
@@ -54,51 +24,17 @@ module Hecks
54
24
  holders(bluebook).flat_map { |holder| statements_for(holder) }
55
25
  end
56
26
 
57
- # Every construct that can carry its own attributes and invariants — an
58
- # aggregate and each of its entities.
59
- #
60
- # @param bluebook [Bluebook::Chapter] the chapter being walked
61
- # @return [Array<Bluebook::Aggregate, Bluebook::Entity>] every aggregate followed
62
- # by its own entities, in declaration order
63
27
  def holders(bluebook) = bluebook.aggregates.flat_map { |aggregate| [aggregate, *aggregate.entities] }
64
28
 
65
- # All of one holder's sentences: its attribute relationships, then its invariants.
66
- #
67
- # @param holder [Bluebook::Aggregate, Bluebook::Entity] the construct being
68
- # projected
69
- # @return [Array<String>] the holder's sentences
70
29
  def statements_for(holder)
71
30
  attribute_statements(holder) + invariant_statements(holder)
72
31
  end
73
32
 
74
- # "MANY" reads the same way regardless of what's behind it — a
75
- # `has_many` relationship to another aggregate and a plain
76
- # `list_of(Topping)` value-object attribute are the same idea to
77
- # someone reading the domain in English ("an Order has many
78
- # toppings" is true either way), even though they're two
79
- # different IR shapes (a `Reference` versus an ordinary type).
80
- # `attribute.name` carries the noun, not the target's own class
81
- # name, because the field's own name is what the domain author
82
- # actually chose to call the collection — "toppings", not
83
- # "Topping".
84
- # Projects every one of a holder's attributes that says something in plain
85
- # English — a list, or a named relationship.
86
- #
87
- # @param holder [Bluebook::Aggregate, Bluebook::Entity] the construct whose
88
- # attributes are being read
89
- # @return [Array<String>] one sentence per list or relationship attribute; a
90
- # plain scalar attribute contributes none
33
+ # `has_many` and `list_of` read the same in English; `attribute.name` is the author's noun.
91
34
  def attribute_statements(holder)
92
35
  holder.attributes.filter_map { |attribute| attribute_statement(holder, attribute) }
93
36
  end
94
37
 
95
- # Projects one attribute's relationship, if it has one worth stating.
96
- #
97
- # @param holder [Bluebook::Aggregate, Bluebook::Entity] the attribute's owning
98
- # construct, named as the sentence's subject
99
- # @param attribute [Bluebook::Attribute] the attribute being projected
100
- # @return [String, nil] the sentence, or `nil` if `attribute` is neither a list
101
- # nor a `has_one`/`belongs_to`/`reference_to` relationship
102
38
  def attribute_statement(holder, attribute)
103
39
  subject = "#{article(holder.hecks_name)} #{holder.hecks_name}"
104
40
  return "#{subject} has many #{attribute.name}." if attribute.list?
@@ -112,24 +48,12 @@ module Hecks
112
48
  end
113
49
  end
114
50
 
115
- # "An account", not "A ACCOUNT" — every subject/object noun here is
116
- # a bare construct name (`ATMCard`, `ExternalTransfer`, `Account`),
117
- # never free text, so the ordinary "starts with a vowel LETTER"
118
- # heuristic is safe: this language's own naming never produces the
119
- # English exceptions that heuristic gets wrong (an "hour", a
120
- # "university") because a construct name is always spelled as a
121
- # plain word, never an abbreviation read letter-by-letter or a
122
- # word starting with a consonant letter but a vowel sound.
123
- #
51
+ # Vowel-letter heuristic is safe: construct names are plain words, never initialisms.
124
52
  # @param word [String] a construct name to prefix
125
53
  # @return [String] `"An"` if `word` starts with a vowel letter, `"A"` otherwise
126
54
  def article(word) = word.to_s.match?(/\A[AEIOUaeiou]/) ? "An" : "A"
127
55
 
128
- # Invariants live in two places — directly on the holder (an
129
- # aggregate-level rule, checked after every command) and on every
130
- # value object nested inside it — `DocsProjector#rules_of`'s own
131
- # `value_object_for` lookup is the precedent for walking both.
132
- #
56
+ # Invariants sit on the holder and on each nested value object; both are read.
133
57
  # @param holder [Bluebook::Aggregate, Bluebook::Entity] the construct whose
134
58
  # invariants, and whose value objects' invariants, are being read
135
59
  # @return [Array<String>] one sentence per invariant, the holder's own first,
@@ -140,10 +64,7 @@ module Hecks
140
64
  (own + nested).map { |invariant| invariant_statement(invariant) }
141
65
  end
142
66
 
143
- # The domain author's own words, capitalized and punctuated —
144
- # nothing else. `invariant("a pizza is named")` already reads as
145
- # a sentence; this is the entire transformation.
146
- #
67
+ # The author's own description, capitalized and punctuated; no other transformation.
147
68
  # @param invariant [Bluebook::Invariant] the invariant being projected
148
69
  # @return [String] the invariant's `description`, capitalized, ending with `.`,
149
70
  # `!` or `?`