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
@@ -5,82 +5,16 @@ require_relative "../../cache_dir"
5
5
  module Hecks
6
6
  module Bluebook
7
7
  module MetaValidator
8
- # S14, ADR 0026 — dispatches the language's own grammar table into
9
- # itself, once, so `Keyword`/`Argument`'s own `status` genuinely is a
10
- # lifecycle — checked at real dispatch time (the same admission/
11
- # coercion/lifecycle-guard door every other command goes through),
12
- # not merely declared and never exercised.
8
+ # Dispatches the language's own grammar table through a real runtime so
9
+ # `Keyword`/`Argument` status is a lifecycle, not just declared (ADR 0026).
13
10
  #
14
- # ## The source stays static
15
- #
16
- # Aggregate-local `KeywordSeed`/`ArgumentSeed` value objects (still
17
- # hand-written `member` rows — now beside the concepts they spell)
18
- # are what gets written ; this is what turns them into what gets
19
- # read. `Judge`/`Reconstruction` already draw exactly this line
20
- # everywhere else in the meta-domain (a chapter's own declarations
21
- # versus what gets dispatched from them) — this runs the same
22
- # distinction one level further out, for the language's own grammar
23
- # table.
24
- #
25
- # ## A dedicated runtime
26
- #
27
- # Not `MetaValidator.fresh_runtime`. That one is reserved for
28
- # `Judge`'s own bootstrap (dispatching a chapter's declarations into
29
- # the meta-domain's grammar) — a different act from this one
30
- # (dispatching the meta-domain's own grammar table data into a live
31
- # "Bluebook" domain instance). Sharing the runtime would let one
32
- # boot's own repository state leak into the other's.
33
- #
34
- # ## Usage
35
- #
36
- # MetaValidator.syntax_table # => { keywords: [...], arguments: [...] }
37
- #
38
- # each row a plain Hash, string values, `status` included — the
39
- # exact shape `ParserTable`/`syntax_conformance_spec` already read
40
- # off the old closed-set members, so neither consumer had to change
41
- # what it does with a row, only where the row comes from.
11
+ # SyntaxBoot.call # => { keywords: [...], arguments: [...] }
42
12
  module SyntaxBoot
43
13
  module_function
44
14
 
45
- # Memoized the same way `MetaValidator.grammar_registry` itself
46
- # is — the ~284-command dispatch sequence below is real work, not
47
- # something three separate callers (ParserTable, syntax_
48
- # conformance_spec, bin/reference) should each pay for on every
49
- # call.
50
- #
51
- # Keyed by the grammar registry's own chapter set, not by a
52
- # "ready" flag. `boot` reads exactly two things: the registry's
53
- # "Bluebook" chapter (the core seed rows) and every chapter in the
54
- # registry that `attaches_to` a core context (Paging's rows). So
55
- # the table is a pure function of which chapter objects the
56
- # registry holds — and that is the cache key: the same chapters,
57
- # by identity, mean the same table; a chapter replaced (the
58
- # fixpoint judge swapping a raw chapter for its assembled self)
59
- # or added (`load_attached_grammar_into`) means a fresh boot.
60
- #
61
- # Why not the earlier `grammar_registry_ready?` guard. That guard
62
- # was right about the hazard — a snapshot taken mid-build, before
63
- # Paging attached, would be missing limit/offset/cursor/nulls
64
- # forever — and wrong about the cost of its cure. It refused to
65
- # cache anything until the whole grammar registry had finished
66
- # building, calling that window "narrow" and recomputing in it
67
- # "cheap". Measured (hecks_ai_training, a six-entity chess domain,
68
- # 2026-08-22): every `word_gate_dispatch` landing in that window
69
- # re-ran the full ~284-dispatch boot at ~0.76s each — 42 times per
70
- # process, 32 of a 35-second `Hecks.boot`, 95% of which had
71
- # nothing to do with the domain being booted. Keying on the
72
- # chapter set closes the same hazard by construction (a snapshot
73
- # can only be served while the chapters it was read from are
74
- # still the chapters the registry holds) and lets the window's
75
- # own repeated, identical calls share one boot. A registry reset
76
- # (fixpoint_spec's own `@grammar_registry = nil`) yields new
77
- # chapter objects, so it invalidates this the same way it always
78
- # invalidated `grammar_registry_ready?`.
15
+ # Memoized per grammar-registry chapter set (identity, not a "ready"
16
+ # flag), and cross-process on disk, since a full boot is real work.
79
17
  #
80
- # `equal?`, not `==`, on the chapters — identity is the fact being
81
- # tracked. Holding the chapter objects themselves (not their ids)
82
- # in the key also means a collected chapter can never hand its id
83
- # to a newcomer behind this cache's back.
84
18
  # @return [Hash{Symbol => Array<Hash{Symbol => String}>}] `:keywords`
85
19
  # and `:arguments`, each an array of plain, string-valued row
86
20
  # hashes (`status` included)
@@ -99,15 +33,8 @@ module Hecks
99
33
  result
100
34
  end
101
35
 
102
- # Compares the in-process cache key against the registry's current
103
- # chapters.
104
- #
105
- # @param cached [Array<Array(String, Object)>] the `[name, chapter]`
106
- # pairs `call` last cached against
107
- # @param current [Array<Array(String, Object)>] the registry's
108
- # current `[name, chapter]` pairs
109
- # @return [Boolean] whether `cached` and `current` name the same
110
- # chapters, by identity, in the same order
36
+ # `equal?`, not `==` — chapter identity, not value equality, is the
37
+ # fact this cache key tracks.
111
38
  def same_chapters?(cached, current)
112
39
  cached.size == current.size &&
113
40
  cached.zip(current).all? do |(cached_name, cached_chapter), (name, chapter)|
@@ -115,73 +42,17 @@ module Hecks
115
42
  end
116
43
  end
117
44
 
118
- # Cross-process persistence for the same ~1s-per-build work `call`
119
- # above already memoizes in-process — this file's own chapter-
120
- # identity keying only ever helps callers sharing one process (the
121
- # in-memory fixpoint window, or `bin/reference`'s single run); every
122
- # fresh process (a `qa_sweep --all` child, a `parallel_rspec`
123
- # worker, `bin/qa_sweep` itself) pays both real builds again from
124
- # scratch even when the grammar source hasn't changed at all since
125
- # the last process that built it.
126
- #
127
- # Not a fix for the two-builds-per-process shape — investigated and
128
- # confirmed genuine, not waste (see this module's own header
129
- # history: the previous "wait for the whole registry" design cost
130
- # 42 rebuilds/32s per process precisely because real callers need a
131
- # correct table mid-bootstrap, before Paging attaches). Both builds
132
- # still happen once each per process; this only makes each of them
133
- # a cheap disk read instead of a real ~1s dispatch, once some
134
- # earlier process has already paid for that exact chapter-set +
135
- # grammar-content combination.
136
- #
137
- # Keyed the same way `same_chapters?` is, translated across process
138
- # boundaries — chapter *object identity* (what the in-memory cache
139
- # keys on) means nothing to a different process; chapter *names*,
140
- # in the same order, do. Combined with a content hash of every
141
- # grammar file `boot` can read from (`seed_chapters` walks every
142
- # bluebook the registry holds, so this must cover the core chapters
143
- # and every attached one, not just "Bluebook" + "Paging") — a
144
- # source edit anywhere in that set correctly misses the old cache
145
- # entry rather than silently serving a stale table.
146
- #
147
- # Fails toward a real boot, never toward a wrong table — same
148
- # loud-not-silent discipline this codebase already holds CI to
149
- # (`postgres_io_relevant_changed`'s own header). A missing file, a corrupt
150
- # Marshal blob, a permission error or an unwritable cache directory degrades
151
- # to "no disk cache today", never to a crash or a served-but-wrong table.
152
- # The cache lives under `Hecks::CacheDir`, never the gem's read-only directory.
153
- #
154
- # **Atomic write, not a lock** — `qa_sweep --all` spawns up to 4
155
- # children at once, any of which could reach a cold cache
156
- # simultaneously and each compute the identical real boot result
157
- # for the identical key. Writing to a PID-suffixed temp file and
158
- # `File.rename`ing it into place (a single atomic syscall on the
159
- # same filesystem) means a concurrent second writer's rename just
160
- # overwrites the first with byte-identical content — never a torn
161
- # or partially-written file a concurrent reader could observe.
162
- #
163
- # `HECKS_SYNTAX_BOOT_CACHE=off` — an escape hatch needing no code
164
- # change, the same shape `Storehouse::BOOT_ROOT`'s own
165
- # `HECKS_STOREHOUSE_ROOT` override uses, for the day this needs to
166
- # be ruled out while debugging something else entirely.
167
- #
168
- # @return [String] the directory cache entries are written to:
169
- # `hecks_syntax_boot_cache` under `Hecks::CacheDir`
45
+ # Cross-process persistence for the same build `call` already memoizes
46
+ # in-process, keyed by chapter name (not identity, which means nothing
47
+ # across processes) plus a content hash of every grammar file `boot`
48
+ # can read from — so a source edit anywhere in that set misses the
49
+ # cache rather than silently serving a stale table.
170
50
  def cache_dir = Hecks::CacheDir.path("hecks_syntax_boot_cache")
171
51
 
172
- # Reports whether the cross-process disk cache is turned on.
173
- #
174
- # @return [Boolean] whether the cross-process disk cache is turned
175
- # on (`HECKS_SYNTAX_BOOT_CACHE=off` turns it off)
176
52
  def disk_cache_enabled? = ENV["HECKS_SYNTAX_BOOT_CACHE"] != "off"
177
53
 
178
- # Reads an already-written cache entry for `chapters`, if any.
179
- #
180
- # @param chapters [Array<Array(String, Object)>] the `[name,
181
- # chapter]` pairs to key the cache entry on
182
- # @return [Hash{Symbol => Array<Hash{Symbol => String}>}, nil] the
183
- # cached syntax table, or `nil` if the cache is disabled, no entry
184
- # exists yet, or the entry could not be read
54
+ # Fails toward a real boot, never toward a wrong table: a missing
55
+ # file, a corrupt blob, or a permission error just misses the cache.
185
56
  def read_disk_cache(chapters)
186
57
  return nil unless disk_cache_enabled?
187
58
 
@@ -193,13 +64,9 @@ module Hecks
193
64
  nil
194
65
  end
195
66
 
196
- # Writes `result` to the disk cache for `chapters`, atomically.
197
- #
198
- # @param chapters [Array<Array(String, Object)>] the `[name,
199
- # chapter]` pairs to key the cache entry on
200
- # @param result [Hash{Symbol => Array<Hash{Symbol => String}>}] the
201
- # syntax table to persist
202
- # @return [void]
67
+ # Writes to a PID-suffixed temp file and renames it into place, so a
68
+ # concurrent writer's rename can only overwrite with identical
69
+ # content, never leave a torn file for a concurrent reader.
203
70
  def write_disk_cache(chapters, result)
204
71
  return unless disk_cache_enabled?
205
72
 
@@ -212,38 +79,18 @@ module Hecks
212
79
  nil
213
80
  end
214
81
 
215
- # Builds the disk cache file path for `chapters`.
216
- #
217
- # @param chapters [Array<Array(String, Object)>] the `[name,
218
- # chapter]` pairs to key the cache entry on
219
- # @return [String] the disk cache file path for `chapters`
220
82
  def disk_cache_path(chapters)
221
83
  File.join(cache_dir, "#{disk_cache_key(chapters)}.marshal")
222
84
  end
223
85
 
224
- # Builds the cache key for `chapters`.
225
- #
226
- # @param chapters [Array<Array(String, Object)>] the `[name,
227
- # chapter]` pairs to key the cache entry on
228
- # @return [String] a SHA-256 digest of the chapter names and the
229
- # current grammar source
230
86
  def disk_cache_key(chapters)
231
87
  names = chapters.map { |name, _chapter| name }
232
88
  Digest::SHA256.hexdigest("#{names.join(',')}:#{grammar_content_digest}")
233
89
  end
234
90
 
235
- # Every file `boot` can possibly read from, via `seed_chapters`
236
- # walking every bluebook the registry holds — not just "Bluebook"
237
- # and "Paging" (the two chapters this module's own comments name
238
- # most often), because World/Hecksagon/any future attached chapter
239
- # are equally eligible to carry their own `KeywordSeed`/
240
- # `ArgumentSeed` value object. Coarser than strictly necessary (any
241
- # one file changing invalidates every cached key, not just the
242
- # chapter it belongs to) — deliberately, since under-covering this
243
- # set is a correctness bug (a stale table survives a real grammar
244
- # edit) and over-covering it is only ever a wasted cache miss.
245
- # @return [String] a SHA-256 digest of every grammar file's own
246
- # current content, sorted for a stable digest
91
+ # Covers every chapter's grammar files, not just the core ones —
92
+ # coarser than strictly necessary, but under-covering this set would
93
+ # let a stale table survive a real grammar edit.
247
94
  def grammar_content_digest
248
95
  files = (MetaValidator::GRAMMAR_FILES + MetaValidator::WORLD_GRAMMAR + MetaValidator::HECKSAGON_GRAMMAR +
249
96
  Dir.glob(File.join(MetaValidator::ATTACHED_GRAMMAR_DIR, "*.bluebook"))).sort
@@ -252,21 +99,11 @@ module Hecks
252
99
 
253
100
  # Dispatches every seed row into a fresh "Bluebook" instance and
254
101
  # reads the result back.
255
- #
256
- # @return [Hash{Symbol => Array<Hash{Symbol => String}>}] `:keywords`
257
- # and `:arguments`, each an array of plain, string-valued row
258
- # hashes (`status` included)
259
102
  def boot
260
103
  bluebook = MetaValidator.grammar_registry.bluebook("Bluebook")
261
- # `MetaValidator.fresh_runtime`, not a brand-new `Runtime::
262
- # Registry` — the grammar registry's own copy already has
263
- # "Bluebook" registered (`grammar_registry`'s own boot already
264
- # ran `registry.add_bluebook`) and its adapter ports already
265
- # loaded ; a standalone registry would need both wired by hand.
266
- # `fresh_runtime` resets `@repositories` on the same registry —
267
- # the identical isolation `Judge.new` already relies on for
268
- # every real domain it judges, proven safe by every dispatch
269
- # this session has ever made.
104
+ # `fresh_runtime`, not a new `Runtime::Registry` — the grammar
105
+ # registry already has "Bluebook" registered and its adapter
106
+ # ports already loaded.
270
107
  runtime = MetaValidator.fresh_runtime
271
108
 
272
109
  declare_syntax(runtime, bluebook)
@@ -276,56 +113,26 @@ module Hecks
276
113
  read_back(runtime, bluebook)
277
114
  end
278
115
 
279
- # Wraps `text` as a single-field value-object payload, for a
280
- # dispatch's own `with:`.
281
- #
282
- # An Integer stays an Integer — `position` is `Position`-typed
283
- # (`attribute :value, Integer`), so stringifying it fails the type
284
- # gate rather than feeding it, the same reading `Judge#v` gives.
285
- #
286
- # @param text [String, Integer] the scalar to wrap
287
- # @return [Hash{Symbol => String, Integer}] `{value: text}`,
288
- # stringified unless `text` is already an Integer
116
+ # An Integer stays an Integer — `position` is `Position`-typed, so
117
+ # stringifying it would fail the type gate rather than feed it.
289
118
  def v(text)
290
119
  return { value: text } if text.is_a?(Integer)
291
120
 
292
121
  { value: text.to_s }
293
122
  end
294
123
 
295
- # Wraps `text` as an `optional: true` command argument's own
296
- # payload, or omits it.
297
- #
298
- # Absent stays absent. A seed row's own optional columns ("was",
299
- # "at", "named", ...) are empty strings, not nil — `Literal`/CSV-
300
- # shaped grammar data has no `nil` to write — so this is the one
301
- # place that decides "" means "not given" for the purpose of an
302
- # `optional: true` command argument, the same reading `Judge#v`
303
- # makes for the meta-domain's own dispatches.
304
- #
305
- # @param text [String, nil] the seed row's own column value
306
- # @return [Hash{Symbol => String}, nil] `v(text)`, or `nil` when
307
- # `text` is `nil` or empty
124
+ # A seed row's own optional columns are "", not nil (CSV-shaped
125
+ # grammar data has no nil to write) — this is where "" is read as
126
+ # "not given".
308
127
  def optional(text)
309
128
  return nil if text.nil? || text.to_s.empty?
310
129
 
311
130
  v(text)
312
131
  end
313
132
 
314
- # `Syntax.Declare`'s own `reference_to Bluebook` names the chapter
315
- # it belongs to — the same fact every other top-level aggregate's
316
- # own creating command carries (`ProcessManager.Declare`,
317
- # `Policy.Declare`, ...). This fresh runtime holds no chapter
318
- # record of its own yet (nothing else here needs one), so one is
319
- # declared first, named after the real chapter, purely to satisfy
320
- # the reference — its own vision/classification are never read
321
- # by anything this boot does.
322
- #
323
- # @param runtime [Runtime::Dispatcher] the fresh runtime to
324
- # dispatch into
325
- # @param bluebook [Bluebook::Chapter] the language's own assembled
326
- # "Bluebook" chapter, read for its `hecks_name` and `"Syntax"`
327
- # aggregate
328
- # @return [void]
133
+ # This fresh runtime holds no chapter record of its own, so one is
134
+ # declared first, purely to satisfy `Syntax.Declare`'s `reference_to
135
+ # Bluebook` — its vision/classification are never read afterward.
329
136
  def declare_syntax(runtime, bluebook)
330
137
  syntax = bluebook.aggregate("Syntax")
331
138
  runtime.dispatch("Bluebook::Bluebook.Declare",
@@ -337,21 +144,10 @@ module Hecks
337
144
  with: { bluebook: bluebook.hecks_name, name: v(syntax.hecks_name) })
338
145
  end
339
146
 
340
- # `to: "Syntax"` names the record already opened by `declare_syntax`
341
- # above — an append onto an existing aggregate, not a second creation
342
- # of it. Smuggling `name: v("Syntax")` into the payload instead — the
343
- # pre-routing convention `Judge#appends` (the same append shape, for
344
- # `ValueObject.Member`/`ProcessManager.Handler`) already left behind
345
- # for `to:`/`with:` — would carry the receiver in the payload,
346
- # making `Syntax.Keyword`'s own `command.creates?` (true: it
347
- # declares no `reference_to`) look like a fresh identity to mint,
348
- # colliding with the very "Syntax" row `declare_syntax` just opened.
349
- #
350
- # @param runtime [Runtime::Dispatcher] the fresh runtime to
351
- # dispatch into
352
- # @param bluebook [Bluebook::Chapter] the language's own assembled
353
- # "Bluebook" chapter, read for its `KeywordSeed` rows
354
- # @return [void]
147
+ # `to: "Syntax"` appends onto the record `declare_syntax` already
148
+ # opened; putting the receiver in the payload instead would make
149
+ # `Syntax.Keyword` look like a fresh identity to mint, colliding
150
+ # with that row.
355
151
  def admit_keywords(runtime, bluebook)
356
152
  all_rows(bluebook, "KeywordSeed").each_with_index do |row, index|
357
153
  runtime.dispatch("Bluebook::Syntax.Keyword", to: "Syntax",
@@ -369,14 +165,7 @@ module Hecks
369
165
  end
370
166
  end
371
167
 
372
- # Admits every `ArgumentSeed` row as a `Syntax.Argument`, the same
373
- # `to: "Syntax"` append shape `admit_keywords` uses one type over.
374
- #
375
- # @param runtime [Runtime::Dispatcher] the fresh runtime to
376
- # dispatch into
377
- # @param bluebook [Bluebook::Chapter] the language's own assembled
378
- # "Bluebook" chapter, read for its `ArgumentSeed` rows
379
- # @return [void]
168
+ # Same `to: "Syntax"` append shape `admit_keywords` uses, one type over.
380
169
  def admit_arguments(runtime, bluebook)
381
170
  all_rows(bluebook, "ArgumentSeed").each_with_index do |row, index|
382
171
  runtime.dispatch("Bluebook::Syntax.Argument", to: "Syntax",
@@ -396,49 +185,18 @@ module Hecks
396
185
  end
397
186
  end
398
187
 
399
- # Every aggregate-local table in every loaded language chapter.
400
- # The table's presence is the registration: no chapter, aggregate,
401
- # filename, or context catalog is maintained here. This finds the core
402
- # Bluebook concepts, the sibling artifact languages (World, Hecksagon,
403
- # Port, Adapter, Translation), and attached sub-languages alike.
404
- # Concatenated into one sequence because `position` is minted from the
405
- # walk index and must not collide across concepts.
406
- #
407
- # @param bluebook [Bluebook::Chapter] the language's own assembled
408
- # "Bluebook" chapter, read first, before every other loaded
409
- # chapter
410
- # @param name [String] the local value-object name to collect rows
411
- # of, such as `"KeywordSeed"`
412
- # @return [Array<Hash{Symbol => String}>] every matching row, across
413
- # every loaded chapter, in chapter order
188
+ # Concatenated into one sequence because `position` is minted from
189
+ # the walk index and must not collide across concepts.
414
190
  def all_rows(bluebook, name)
415
191
  seed_chapters(bluebook).flat_map { |chapter| rows(chapter, name) }
416
192
  end
417
193
 
418
- # Keep the core chapter first, then registry insertion order for every
419
- # sibling/extension. The name rejection avoids reading the same core
420
- # object twice without relying on object identity across fixpoint
421
- # assembly.
422
- #
423
- # @param bluebook [Bluebook::Chapter] the language's own assembled
424
- # "Bluebook" chapter
425
- # @return [Array<Bluebook::Chapter>] `bluebook` first, then every
426
- # other chapter the grammar registry holds
194
+ # `bluebook` first, then registry insertion order, so the core
195
+ # chapter is never read twice.
427
196
  def seed_chapters(bluebook)
428
197
  [bluebook] + MetaValidator.grammar_registry.bluebooks.values.reject { |chapter| chapter.name == bluebook.name }
429
198
  end
430
199
 
431
- # The seed rows themselves — plain hashes, string values, read from
432
- # every aggregate that owns a same-named local value object. Repeating
433
- # the value-object shape is deliberate: each concept remains readable
434
- # by itself, while this discovery is the only grouping mechanism.
435
- #
436
- # @param bluebook [Bluebook::Chapter] the chapter to search
437
- # @param name [String] the local value-object name to collect rows
438
- # of, such as `"KeywordSeed"`
439
- # @return [Array<Hash{Symbol => String}>] one hash per member row,
440
- # `[]` if no aggregate in `bluebook` owns a value object named
441
- # `name`
442
200
  def rows(bluebook, name)
443
201
  bluebook.aggregates.flat_map do |aggregate|
444
202
  value_object = aggregate.value_objects.find { |vo| vo.hecks_name == name }
@@ -448,18 +206,8 @@ module Hecks
448
206
  end
449
207
  end
450
208
 
451
- # Reads the dispatched result back into the same shape `rows`
452
- # above hands the seed data in as — plain hashes, string values,
453
- # `status` included — so `ParserTable`/`syntax_conformance_spec`
454
- # need not know or care that a real dispatch happened in between.
455
- #
456
- # @param runtime [Runtime::Dispatcher] the runtime `boot` dispatched
457
- # every seed row into
458
- # @param bluebook [Bluebook::Chapter] the language's own assembled
459
- # "Bluebook" chapter, read for its `"Syntax"` aggregate
460
- # @return [Hash{Symbol => Array<Hash{Symbol => String}>}] `:keywords`
461
- # and `:arguments`, each an array of plain, string-valued row
462
- # hashes (`status` included)
209
+ # Reads the dispatched result back into the same plain-hash shape
210
+ # `rows` hands the seed data in as.
463
211
  def read_back(runtime, bluebook)
464
212
  syntax = bluebook.aggregate("Syntax")
465
213
  repository = runtime.registry.repository("Bluebook", syntax)
@@ -471,23 +219,13 @@ module Hecks
471
219
  }
472
220
  end
473
221
 
474
- # Flattens one dispatched record into a plain, string-valued row.
475
- #
476
- # @param row [Object] one dispatched keyword or argument record,
477
- # answering `to_h`
478
- # @return [Hash{Symbol => String}] `row`'s own fields, each value
479
- # unwrapped and stringified
480
222
  def stringify(row)
481
223
  row.to_h.transform_values do |cell|
482
224
  scalar(cell).to_s
483
225
  end
484
226
  end
485
227
 
486
- # Unwraps one field's stored value to its bare scalar.
487
- #
488
- # @param cell [Object] one field's stored value
489
- # @return [Object] `cell`'s sole wrapped value, if `cell` is a
490
- # to_h-able non-String; `cell` unchanged otherwise
228
+ # Unwraps a value-object-wrapped field back to its bare scalar.
491
229
  def scalar(cell)
492
230
  return cell.to_h.values.first if cell.respond_to?(:to_h) && !cell.is_a?(String)
493
231
 
@@ -1,24 +1,8 @@
1
1
  module Hecks
2
2
  module Bluebook
3
3
  module MetaValidator
4
- # Offers a built translation (a `translations/*.bluebook` edge,
5
- # `Hecks.data_translation`'s own real, established file convention —
6
- # there is no separate `.translation` extension) to the language
7
- # that describes translations.
8
- #
9
- # A sibling of a bluebook again, the same shape PortJudge/
10
- # AdapterJudge already are — its own file, its own door, judged
11
- # through its own self-hosted language (translation.bluebook)
12
- # rather than left as plain Ruby structs nothing checks. Walks the
13
- # whole built translation in one pass — the top-level Declare/
14
- # Retire commands, then every nested aggregate's own Declare plus
15
- # one Add* command per rule it carries — the same "one judge, every
16
- # nested record" shape WorldJudge already gives Wiring. Field names
17
- # throughout read lib/hecks/bluebook/translation.rb's own real
18
- # struct/class definitions directly, not the DSL builder's own
19
- # local parameter names (`move(old_path, to:)`'s `old_path` reads
20
- # back as the struct's own `from`). Whole-project table-
21
- # unification survey, item #13's remaining builders.
4
+ # Offers a built translation (a `translations/*.bluebook` edge) to the language that
5
+ # describes translations. Field names follow the `Translation` structs, not the DSL builder.
22
6
  class TranslationJudge
23
7
  attr_reader :refusals
24
8
 
@@ -36,18 +20,8 @@ module Hecks
36
20
 
37
21
  def args(pairs) = pairs.compact
38
22
 
39
- # `Runtime::AlreadyExists` is rescued here but not by World/Port/
40
- # Adapter's own sibling judges — found live, not by inspection.
41
- # Those three each judge a single aggregate per build (Port/Adapter)
42
- # or a Hash keyed by verb (World's own settings, deduped by
43
- # construction), so a duplicate-identity Declare can never reach
44
- # their own runtime. `TranslationBuilder#aggregate` appends every
45
- # block to a plain Array (`@aggregates << builder.build`) with no
46
- # dedup — two `aggregate "Account" do ... end` blocks in the same
47
- # translation are syntactically legal and reach here for real.
48
- # Left unrescued, the second Declare's `AlreadyExists` would crash
49
- # straight through `call_translation` instead of becoming a clean
50
- # refusal — confirmed via direct dispatch.
23
+ # Rescues `AlreadyExists` too: `TranslationBuilder#aggregate` does not dedup, so two
24
+ # same-named aggregate blocks reach here and must become a refusal, not a crash.
51
25
  def offer(label)
52
26
  yield
53
27
  rescue Runtime::GivenNotMet, Runtime::InvariantViolation, Runtime::TypeMismatch,
@@ -66,14 +40,7 @@ module Hecks
66
40
  send_to("Translation::Translation.Declare", t.domain,
67
41
  with: { domain: v(t.domain), from: v(t.from), to: v(t.to) })
68
42
 
69
- # `id:`, computed the same way — `Naming.identity([domain, from,
70
- # to])` — Translation's own identity is composite
71
- # (`identified_by :domain, :from, :to`), the same reason
72
- # `Wiring.Set`'s own self-reference dispatch (world.bluebook,
73
- # `WorldJudge#judge_wiring`) needs a computed `id:` rather than
74
- # a bare field value — a single-field identity (TranslationAggregate's
75
- # own `name`) is the one case where the bare value itself is the
76
- # id, confirmed live via direct dispatch testing, not assumed.
43
+ # Translation's identity is composite, so `id:` must be computed, not a bare field.
77
44
  translation_id = Naming.identity([t.domain, t.from, t.to])
78
45
  Array(t.retired).each do |name|
79
46
  send_to("Translation::Translation.Retire", t.domain, to: translation_id,
@@ -83,11 +50,8 @@ module Hecks
83
50
  Array(t.aggregates).each { |aggregate| judge_aggregate(t, aggregate) }
84
51
  end
85
52
 
86
- # One Declare, then one AddX pass per rule collection the aggregate
87
- # carries — each pass is independent of the others (they mutate
88
- # different fields), so each is its own private method below; only
89
- # Declare-before-any-Add is order-sensitive, and that order is
90
- # preserved here.
53
+ # Declares the aggregate, then adds each rule collection. Only Declare-before-Add is
54
+ # order-sensitive.
91
55
  def judge_aggregate(translation, aggregate)
92
56
  name = aggregate.name
93
57
  declare_aggregate(translation, aggregate, name)
@@ -1,16 +1,11 @@
1
1
  module Hecks
2
2
  module Bluebook
3
3
  module MetaValidator
4
- # Offers a built .world to the language that describes worlds.
5
- #
6
- # A world is a sibling of a bluebook — the same domain runs in many of
7
- # them — so it is judged through its own door, against its own language
8
- # file, and its settings normalise the same way a mutation's fields do:
9
- # an open map becomes one Wiring per verb and one Setting row per value.
4
+ # Judges a built .world against the language that describes worlds,
5
+ # normalizing its settings into one Wiring per verb, one Setting per value.
10
6
  class WorldJudge
11
7
  attr_reader :refusals
12
8
 
13
- # @param world [Bluebook::World] the built world to judge
14
9
  def initialize(world)
15
10
  @world = world
16
11
  @refusals = []
@@ -54,18 +49,11 @@ module Hecks
54
49
  end
55
50
 
56
51
  def judge_wiring(domain, verb, values)
57
- # The same join the language itself derives. Wiring is
58
- # `identified_by do world; verb.value end` — `Wiring.Declare`
59
- # (a creating command) ignores this `id:` entirely and computes its own
60
- # from `world`/`verb`, so a locally minted "#{domain}.#{verb}" named a
61
- # record `Wiring.Set` could never find : the id passed here has to be
62
- # the same derivation, not a second guess at what it must be.
52
+ # Must match Wiring's own `identified_by do world; verb.value end`
53
+ # derivation exactly, or a later `Wiring.Set` could never find it.
63
54
  id = Naming.identity([domain, verb])
64
- # `world_ref` is the world's id and goes bare, the way every reference
65
- # does now ; the language gives it that explicit `as:` because `world`
66
- # beside it is an ordinary text attribute that happens to hold the same
67
- # string, and stays a value object. The two look alike and are not —
68
- # which is exactly why the judge asks the type rather than the name.
55
+ # `world_ref` is the type-checked reference; the plain `world`
56
+ # attribute alongside it just happens to hold the same string.
69
57
  send_to("World::Wiring.Declare", id, world_ref: v(domain),
70
58
  world: v(domain), verb: v(verb), adapter: v(Hash(values)[:adapter]))
71
59