hecks 0.2.0 → 0.3.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 (408) hide show
  1. checksums.yaml +5 -5
  2. data/lib/hecks/adapters/driven/claude_code.adapter +3 -0
  3. data/lib/hecks/adapters/driven/claude_code.rb +127 -0
  4. data/lib/hecks/adapters/driven/d1.adapter +12 -0
  5. data/lib/hecks/adapters/driven/d1.rb +403 -0
  6. data/lib/hecks/adapters/driven/folder.adapter +3 -0
  7. data/lib/hecks/adapters/driven/folder.rb +199 -0
  8. data/lib/hecks/adapters/driven/google_authentication.adapter +3 -0
  9. data/lib/hecks/adapters/driven/google_authentication.rb +100 -0
  10. data/lib/hecks/adapters/driven/governance_authorization.adapter +3 -0
  11. data/lib/hecks/adapters/driven/governance_authorization.rb +62 -0
  12. data/lib/hecks/adapters/driven/heki/journal.rb +51 -0
  13. data/lib/hecks/adapters/driven/heki/saga_store.rb +0 -0
  14. data/lib/hecks/adapters/driven/heki/snapshot.rb +38 -0
  15. data/lib/hecks/adapters/driven/heki.adapter +4 -0
  16. data/lib/hecks/adapters/driven/heki.rb +148 -0
  17. data/lib/hecks/adapters/driven/identity_registry.adapter +3 -0
  18. data/lib/hecks/adapters/driven/identity_registry.rb +26 -0
  19. data/lib/hecks/adapters/driven/in_memory_ordering.rb +51 -0
  20. data/lib/hecks/adapters/driven/lambda/client.rb +63 -0
  21. data/lib/hecks/adapters/driven/lambda.adapter +4 -0
  22. data/lib/hecks/adapters/driven/lambda.rb +131 -0
  23. data/lib/hecks/adapters/driven/memory.adapter +3 -0
  24. data/lib/hecks/adapters/driven/memory.rb +103 -0
  25. data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +3 -0
  26. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +28 -0
  27. data/lib/hecks/adapters/driven/postgres/codec.rb +80 -0
  28. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +168 -0
  29. data/lib/hecks/adapters/driven/postgres.adapter +5 -0
  30. data/lib/hecks/adapters/driven/postgres.rb +391 -0
  31. data/lib/hecks/adapters/driven/postgres_era/lineage/era_store.rb +171 -0
  32. data/lib/hecks/adapters/driven/postgres_era/lineage/field_cache.rb +190 -0
  33. data/lib/hecks/adapters/driven/postgres_era/lineage/head_compiler.rb +429 -0
  34. data/lib/hecks/adapters/driven/postgres_era/lineage/mint_transaction.rb +166 -0
  35. data/lib/hecks/adapters/driven/postgres_era/lineage/provisioning.rb +286 -0
  36. data/lib/hecks/adapters/driven/postgres_era/lineage/resumable_backfill.rb +168 -0
  37. data/lib/hecks/adapters/driven/postgres_era/lineage/tail_merge.rb +163 -0
  38. data/lib/hecks/adapters/driven/postgres_era/lineage/transform_installer.rb +114 -0
  39. data/lib/hecks/adapters/driven/postgres_era/lineage.rb +137 -0
  40. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/coverage_check.rb +89 -0
  41. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolver.rb +82 -0
  42. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/merge_coordinator.rb +43 -0
  43. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/minter.rb +132 -0
  44. data/lib/hecks/adapters/driven/postgres_era/lineage_manager.rb +74 -0
  45. data/lib/hecks/adapters/driven/postgres_era.adapter +6 -0
  46. data/lib/hecks/adapters/driven/postgres_era.rb +671 -0
  47. data/lib/hecks/adapters/driven/prism.adapter +3 -0
  48. data/lib/hecks/adapters/driven/prism.rb +80 -0
  49. data/lib/hecks/adapters/driven/secure_random_identity.adapter +3 -0
  50. data/lib/hecks/adapters/driven/secure_random_identity.rb +14 -0
  51. data/lib/hecks/adapters/driven/sql_query_builder.rb +221 -0
  52. data/lib/hecks/adapters/driven/sqlite/codec.rb +63 -0
  53. data/lib/hecks/adapters/driven/sqlite/projection.rb +105 -0
  54. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +180 -0
  55. data/lib/hecks/adapters/driven/sqlite.adapter +9 -0
  56. data/lib/hecks/adapters/driven/sqlite.rb +285 -0
  57. data/lib/hecks/adapters/driven/system_clock.adapter +3 -0
  58. data/lib/hecks/adapters/driven/system_clock.rb +14 -0
  59. data/lib/hecks/adapters/driven.rb +36 -0
  60. data/lib/hecks/adapters.rb +6 -0
  61. data/lib/hecks/behaviors/dsl.rb +96 -0
  62. data/lib/hecks/behaviors/expectations.rb +280 -0
  63. data/lib/hecks/behaviors/ir.rb +31 -0
  64. data/lib/hecks/behaviors/rspec.rb +42 -0
  65. data/lib/hecks/behaviors/runner.rb +96 -0
  66. data/lib/hecks/behaviors.rb +25 -0
  67. data/lib/hecks/bluebook/aggregate.rb +108 -0
  68. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +134 -0
  69. data/lib/hecks/bluebook/assembly/build.rb +48 -0
  70. data/lib/hecks/bluebook/assembly/contract.rb +112 -0
  71. data/lib/hecks/bluebook/assembly/contracts.rb +409 -0
  72. data/lib/hecks/bluebook/assembly/marks.rb +227 -0
  73. data/lib/hecks/bluebook/assembly/specializer.rb +70 -0
  74. data/lib/hecks/bluebook/assembly.rb +78 -0
  75. data/lib/hecks/bluebook/attribute.rb +96 -0
  76. data/lib/hecks/bluebook/behaviour/aggregate.rb +83 -0
  77. data/lib/hecks/bluebook/behaviour/attribute.rb +27 -0
  78. data/lib/hecks/bluebook/behaviour/chapter.rb +72 -0
  79. data/lib/hecks/bluebook/behaviour/command.rb +116 -0
  80. data/lib/hecks/bluebook/behaviour/domain_port.rb +25 -0
  81. data/lib/hecks/bluebook/behaviour/entity.rb +59 -0
  82. data/lib/hecks/bluebook/behaviour/hexagon.rb +50 -0
  83. data/lib/hecks/bluebook/behaviour/lifecycle.rb +51 -0
  84. data/lib/hecks/bluebook/behaviour/policy.rb +52 -0
  85. data/lib/hecks/bluebook/behaviour/process_manager.rb +38 -0
  86. data/lib/hecks/bluebook/behaviour/query.rb +10 -0
  87. data/lib/hecks/bluebook/behaviour/read_model.rb +29 -0
  88. data/lib/hecks/bluebook/behaviour/traits.rb +81 -0
  89. data/lib/hecks/bluebook/behaviour/value_object.rb +33 -0
  90. data/lib/hecks/bluebook/chapter.rb +68 -0
  91. data/lib/hecks/bluebook/command.rb +124 -0
  92. data/lib/hecks/bluebook/domain_port.rb +102 -0
  93. data/lib/hecks/bluebook/dsl/adapter_builder.rb +34 -0
  94. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +906 -0
  95. data/lib/hecks/bluebook/dsl/attribute_collector.rb +327 -0
  96. data/lib/hecks/bluebook/dsl/binding_proxy.rb +71 -0
  97. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +1018 -0
  98. data/lib/hecks/bluebook/dsl/command_builder.rb +626 -0
  99. data/lib/hecks/bluebook/dsl/const_shim.rb +81 -0
  100. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +79 -0
  101. data/lib/hecks/bluebook/dsl/entity_builder.rb +305 -0
  102. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +366 -0
  103. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +163 -0
  104. data/lib/hecks/bluebook/dsl/identity_declaration.rb +191 -0
  105. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +44 -0
  106. data/lib/hecks/bluebook/dsl/malformed.rb +7 -0
  107. data/lib/hecks/bluebook/dsl/policy_builder.rb +120 -0
  108. data/lib/hecks/bluebook/dsl/port_builder.rb +30 -0
  109. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +142 -0
  110. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +207 -0
  111. data/lib/hecks/bluebook/dsl/query_builder.rb +113 -0
  112. data/lib/hecks/bluebook/dsl/read_model_builder.rb +233 -0
  113. data/lib/hecks/bluebook/dsl/rule_reference.rb +172 -0
  114. data/lib/hecks/bluebook/dsl/translation_builder.rb +243 -0
  115. data/lib/hecks/bluebook/dsl/value_object_builder.rb +178 -0
  116. data/lib/hecks/bluebook/dsl/word_gate.rb +221 -0
  117. data/lib/hecks/bluebook/dsl/world_builder.rb +77 -0
  118. data/lib/hecks/bluebook/dsl.rb +45 -0
  119. data/lib/hecks/bluebook/entity.rb +103 -0
  120. data/lib/hecks/bluebook/expression/canonical_form.rb +55 -0
  121. data/lib/hecks/bluebook/expression/evaluator.rb +261 -0
  122. data/lib/hecks/bluebook/expression/projection.json +170 -0
  123. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +233 -0
  124. data/lib/hecks/bluebook/expression/resolver.rb +630 -0
  125. data/lib/hecks/bluebook/expression.rb +13 -0
  126. data/lib/hecks/bluebook/hexagon.rb +60 -0
  127. data/lib/hecks/bluebook/lifecycle.rb +42 -0
  128. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +54 -0
  129. data/lib/hecks/bluebook/meta_validator/judge.rb +559 -0
  130. data/lib/hecks/bluebook/meta_validator/plan.rb +332 -0
  131. data/lib/hecks/bluebook/meta_validator/port_judge.rb +47 -0
  132. data/lib/hecks/bluebook/meta_validator/readings.rb +350 -0
  133. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +312 -0
  134. data/lib/hecks/bluebook/meta_validator/shapes.rb +246 -0
  135. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +255 -0
  136. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +138 -0
  137. data/lib/hecks/bluebook/meta_validator/world_judge.rb +78 -0
  138. data/lib/hecks/bluebook/meta_validator.rb +452 -0
  139. data/lib/hecks/bluebook/model_check.rb +318 -0
  140. data/lib/hecks/bluebook/pattern_subset.rb +120 -0
  141. data/lib/hecks/bluebook/policy.rb +41 -0
  142. data/lib/hecks/bluebook/process_manager.rb +86 -0
  143. data/lib/hecks/bluebook/project_discovery.rb +30 -0
  144. data/lib/hecks/bluebook/project_loader.rb +40 -0
  145. data/lib/hecks/bluebook/project_register.rb +82 -0
  146. data/lib/hecks/bluebook/query.rb +61 -0
  147. data/lib/hecks/bluebook/read_model.rb +109 -0
  148. data/lib/hecks/bluebook/reference.rb +74 -0
  149. data/lib/hecks/bluebook/smoke_test.rb +166 -0
  150. data/lib/hecks/bluebook/synthesizer.rb +95 -0
  151. data/lib/hecks/bluebook/translation.rb +92 -0
  152. data/lib/hecks/bluebook/value_object.rb +58 -0
  153. data/lib/hecks/bluebook.rb +74 -0
  154. data/lib/hecks/codemod.rb +342 -0
  155. data/lib/hecks/construct.rb +71 -0
  156. data/lib/hecks/deploy/bluebook/deploy.bluebook +219 -0
  157. data/lib/hecks/deploy/bluebook/deploy.hecksagon +4 -0
  158. data/lib/hecks/deploy/oidc.json +18 -0
  159. data/lib/hecks/doc/reference.rb +389 -0
  160. data/lib/hecks/embryonaut_bluebook.rb +75 -0
  161. data/lib/hecks/facade/cli_door.rb +116 -0
  162. data/lib/hecks/facade/cli_runner.rb +190 -0
  163. data/lib/hecks/facade/command_request.rb +105 -0
  164. data/lib/hecks/facade/handle.rb +173 -0
  165. data/lib/hecks/facade/json_door.rb +154 -0
  166. data/lib/hecks/facade/surface/aggregate_door.rb +185 -0
  167. data/lib/hecks/facade/surface/chapter.rb +107 -0
  168. data/lib/hecks/facade/surface.rb +48 -0
  169. data/lib/hecks/facade.rb +44 -0
  170. data/lib/hecks/forms/app.rb +300 -0
  171. data/lib/hecks/forms/command_form_renderer.rb +113 -0
  172. data/lib/hecks/forms/examples/banking_console.bluebook +3 -0
  173. data/lib/hecks/forms/field_renderer.rb +170 -0
  174. data/lib/hecks/forms/field_shape.rb +232 -0
  175. data/lib/hecks/forms/html.rb +53 -0
  176. data/lib/hecks/forms/index_renderer.rb +35 -0
  177. data/lib/hecks/forms/page.rb +157 -0
  178. data/lib/hecks/forms/params.rb +132 -0
  179. data/lib/hecks/forms/query_form_renderer.rb +114 -0
  180. data/lib/hecks/forms/record_renderer.rb +115 -0
  181. data/lib/hecks/forms/record_table.rb +63 -0
  182. data/lib/hecks/forms/reference_options.rb +30 -0
  183. data/lib/hecks/forms/value_object_shape.rb +46 -0
  184. data/lib/hecks/forms.rb +54 -0
  185. data/lib/hecks/fqn.rb +94 -0
  186. data/lib/hecks/framework/bluebook/compliance.bluebook +1 -0
  187. data/lib/hecks/framework/bluebook/console_settings.bluebook +489 -0
  188. data/lib/hecks/framework/bluebook/framework.hecksagon +32 -0
  189. data/lib/hecks/framework/bluebook/governance.bluebook +130 -0
  190. data/lib/hecks/framework/bluebook/identity.bluebook +90 -0
  191. data/lib/hecks/framework/oidc.json +39 -0
  192. data/lib/hecks/framework.rb +90 -0
  193. data/lib/hecks/freezer.rb +67 -0
  194. data/lib/hecks/fuzzing/invalid_value_generator.rb +86 -0
  195. data/lib/hecks/fuzzing/isolated_boot.rb +92 -0
  196. data/lib/hecks/fuzzing/properties.rb +1146 -0
  197. data/lib/hecks/fuzzing/replay.rb +635 -0
  198. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +93 -0
  199. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +54 -0
  200. data/lib/hecks/fuzzing/sequence_generator/picker.rb +96 -0
  201. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +185 -0
  202. data/lib/hecks/fuzzing/sequence_generator.rb +130 -0
  203. data/lib/hecks/fuzzing/value_generator.rb +177 -0
  204. data/lib/hecks/fuzzing.rb +12 -0
  205. data/lib/hecks/grammar/evolve.rb +291 -0
  206. data/lib/hecks/grammar/expression.bluebook +417 -0
  207. data/lib/hecks/grammar/expression_operators.json +1152 -0
  208. data/lib/hecks/grammar/grammar.hecksagon +20 -0
  209. data/lib/hecks/grammar/oidc.json +69 -0
  210. data/lib/hecks/grammar/translation.bluebook +203 -0
  211. data/lib/hecks/grammar.rb +178 -0
  212. data/lib/hecks/ir.rb +126 -0
  213. data/lib/hecks/language/adapter.bluebook +116 -0
  214. data/lib/hecks/language/bluebook/aggregate.bluebook +581 -0
  215. data/lib/hecks/language/bluebook/attaches/paging.bluebook +76 -0
  216. data/lib/hecks/language/bluebook/bluebook.bluebook +256 -0
  217. data/lib/hecks/language/bluebook/bluebook.hecksagon +24 -0
  218. data/lib/hecks/language/bluebook/command.bluebook +437 -0
  219. data/lib/hecks/language/bluebook/entity.bluebook +316 -0
  220. data/lib/hecks/language/bluebook/policy.bluebook +172 -0
  221. data/lib/hecks/language/bluebook/process_manager.bluebook +264 -0
  222. data/lib/hecks/language/bluebook/projection.bluebook +267 -0
  223. data/lib/hecks/language/bluebook/query.bluebook +245 -0
  224. data/lib/hecks/language/bluebook/shape.bluebook +292 -0
  225. data/lib/hecks/language/bluebook/syntax.bluebook +447 -0
  226. data/lib/hecks/language/bluebook/vocabulary.bluebook +364 -0
  227. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +51 -0
  228. data/lib/hecks/language/hecksagon/domain_port.bluebook +76 -0
  229. data/lib/hecks/language/hecksagon/hecksagon.bluebook +131 -0
  230. data/lib/hecks/language/hecksagon/port_operation.bluebook +102 -0
  231. data/lib/hecks/language/oidc.json +313 -0
  232. data/lib/hecks/language/port.bluebook +92 -0
  233. data/lib/hecks/language/translation/translation.bluebook +110 -0
  234. data/lib/hecks/language/translation/translation_aggregate.bluebook +267 -0
  235. data/lib/hecks/language/world/wiring.bluebook +62 -0
  236. data/lib/hecks/language/world/world.bluebook +84 -0
  237. data/lib/hecks/literal.rb +125 -0
  238. data/lib/hecks/naming.rb +121 -0
  239. data/lib/hecks/ports/access_control.port +4 -0
  240. data/lib/hecks/ports/access_control.rb +62 -0
  241. data/lib/hecks/ports/agent/answers.rb +104 -0
  242. data/lib/hecks/ports/agent.port +4 -0
  243. data/lib/hecks/ports/agent.rb +167 -0
  244. data/lib/hecks/ports/authentication.port +4 -0
  245. data/lib/hecks/ports/authentication.rb +50 -0
  246. data/lib/hecks/ports/authorization.port +4 -0
  247. data/lib/hecks/ports/authorization.rb +59 -0
  248. data/lib/hecks/ports/clock.port +4 -0
  249. data/lib/hecks/ports/clock.rb +62 -0
  250. data/lib/hecks/ports/extraction.port +4 -0
  251. data/lib/hecks/ports/extraction.rb +37 -0
  252. data/lib/hecks/ports/identity_assignment.port +4 -0
  253. data/lib/hecks/ports/identity_assignment.rb +45 -0
  254. data/lib/hecks/ports/identity_generation.port +4 -0
  255. data/lib/hecks/ports/identity_generation.rb +49 -0
  256. data/lib/hecks/ports/identity_resolution.port +4 -0
  257. data/lib/hecks/ports/identity_resolution.rb +40 -0
  258. data/lib/hecks/ports/loading.port +4 -0
  259. data/lib/hecks/ports/loading.rb +13 -0
  260. data/lib/hecks/ports/persistence/append_only.rb +102 -0
  261. data/lib/hecks/ports/persistence/binding_policy.rb +56 -0
  262. data/lib/hecks/ports/persistence/execution.rb +18 -0
  263. data/lib/hecks/ports/persistence/lineage.rb +277 -0
  264. data/lib/hecks/ports/persistence/null_saga_store.rb +25 -0
  265. data/lib/hecks/ports/persistence/remote_runtime.rb +42 -0
  266. data/lib/hecks/ports/persistence/repository_factory.rb +30 -0
  267. data/lib/hecks/ports/persistence.port +4 -0
  268. data/lib/hecks/ports/persistence.rb +39 -0
  269. data/lib/hecks/ports/projection.port +4 -0
  270. data/lib/hecks/ports/projection.rb +76 -0
  271. data/lib/hecks/ports/query/in_memory.rb +60 -0
  272. data/lib/hecks/ports/query/ordering.rb +41 -0
  273. data/lib/hecks/ports/query.rb +36 -0
  274. data/lib/hecks/ports.rb +27 -0
  275. data/lib/hecks/projections/diagrams.rb +413 -0
  276. data/lib/hecks/projections/ir.rb +18 -0
  277. data/lib/hecks/projections/model/deviations.rb +98 -0
  278. data/lib/hecks/projections/model.rb +145 -0
  279. data/lib/hecks/projections/oidc.rb +110 -0
  280. data/lib/hecks/projections/parser_table.rb +159 -0
  281. data/lib/hecks/projections/reference.rb +38 -0
  282. data/lib/hecks/projections/shape.rb +31 -0
  283. data/lib/hecks/projections/statements.rb +110 -0
  284. data/lib/hecks/projections/vocabulary.rb +100 -0
  285. data/lib/hecks/projections.rb +32 -0
  286. data/lib/hecks/projector/cli_projector.rb +437 -0
  287. data/lib/hecks/projector/docs_projector.rb +321 -0
  288. data/lib/hecks/projector/exporter.rb +141 -0
  289. data/lib/hecks/projector/ir_projector.rb +18 -0
  290. data/lib/hecks/projector/narrate_projector.rb +243 -0
  291. data/lib/hecks/projector/target.rb +97 -0
  292. data/lib/hecks/projector.rb +186 -0
  293. data/lib/hecks/query_ir.rb +392 -0
  294. data/lib/hecks/query_specification/common/authorization_spec.rb +9 -0
  295. data/lib/hecks/query_specification/common/comparators.rb +25 -0
  296. data/lib/hecks/query_specification/common/comparison.rb +174 -0
  297. data/lib/hecks/query_specification/common/cursor_spec.rb +9 -0
  298. data/lib/hecks/query_specification/common/dsl.rb +58 -0
  299. data/lib/hecks/query_specification/common/inspection_spec.rb +9 -0
  300. data/lib/hecks/query_specification/common/limit_spec.rb +9 -0
  301. data/lib/hecks/query_specification/common/null_policy.rb +80 -0
  302. data/lib/hecks/query_specification/common/null_semantics.rb +11 -0
  303. data/lib/hecks/query_specification/common/offset_spec.rb +9 -0
  304. data/lib/hecks/query_specification/common/options.rb +32 -0
  305. data/lib/hecks/query_specification/common/order_by.rb +9 -0
  306. data/lib/hecks/query_specification/common/specification.rb +10 -0
  307. data/lib/hecks/query_specification/common/where_clause.rb +9 -0
  308. data/lib/hecks/query_specification/field_path.rb +89 -0
  309. data/lib/hecks/query_specification/hop_path.rb +130 -0
  310. data/lib/hecks/query_specification/read_model/specification.rb +18 -0
  311. data/lib/hecks/query_specification.rb +14 -0
  312. data/lib/hecks/rendering.rb +48 -0
  313. data/lib/hecks/router/namespace_installer.rb +157 -0
  314. data/lib/hecks/router.rb +70 -0
  315. data/lib/hecks/runtime/caller.rb +50 -0
  316. data/lib/hecks/runtime/capability_graph.rb +44 -0
  317. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +124 -0
  318. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +248 -0
  319. data/lib/hecks/runtime/command_interpreter.rb +413 -0
  320. data/lib/hecks/runtime/command_rules/admissibility.rb +307 -0
  321. data/lib/hecks/runtime/command_rules/arithmetic.rb +254 -0
  322. data/lib/hecks/runtime/command_rules/authorization.rb +64 -0
  323. data/lib/hecks/runtime/command_rules/emission.rb +34 -0
  324. data/lib/hecks/runtime/command_rules/references.rb +181 -0
  325. data/lib/hecks/runtime/command_rules.rb +28 -0
  326. data/lib/hecks/runtime/dependency_planning.rb +231 -0
  327. data/lib/hecks/runtime/dispatcher.rb +286 -0
  328. data/lib/hecks/runtime/entity_element.rb +253 -0
  329. data/lib/hecks/runtime/entity_interpreter.rb +228 -0
  330. data/lib/hecks/runtime/era_check.rb +136 -0
  331. data/lib/hecks/runtime/era_guard/shape_diff.rb +128 -0
  332. data/lib/hecks/runtime/era_guard.rb +193 -0
  333. data/lib/hecks/runtime/era_tamper.rb +61 -0
  334. data/lib/hecks/runtime/errors.rb +100 -0
  335. data/lib/hecks/runtime/event.rb +51 -0
  336. data/lib/hecks/runtime/identity.rb +128 -0
  337. data/lib/hecks/runtime/instance.rb +120 -0
  338. data/lib/hecks/runtime/interpreting.rb +69 -0
  339. data/lib/hecks/runtime/loader.rb +143 -0
  340. data/lib/hecks/runtime/policy_interpreter.rb +366 -0
  341. data/lib/hecks/runtime/port_operation_interpreter.rb +210 -0
  342. data/lib/hecks/runtime/query_interpreter.rb +254 -0
  343. data/lib/hecks/runtime/reaction_invocation.rb +245 -0
  344. data/lib/hecks/runtime/read_model_interpreter.rb +266 -0
  345. data/lib/hecks/runtime/rebuild_sweep.rb +74 -0
  346. data/lib/hecks/runtime/reference_hop.rb +99 -0
  347. data/lib/hecks/runtime/refusal_wording.rb +124 -0
  348. data/lib/hecks/runtime/registry/saga_persistence.rb +70 -0
  349. data/lib/hecks/runtime/registry/verification.rb +158 -0
  350. data/lib/hecks/runtime/registry.rb +218 -0
  351. data/lib/hecks/runtime/remote_dispatcher.rb +143 -0
  352. data/lib/hecks/runtime/routing.rb +96 -0
  353. data/lib/hecks/runtime/saga_interpreter/correlation.rb +97 -0
  354. data/lib/hecks/runtime/saga_interpreter.rb +301 -0
  355. data/lib/hecks/runtime/storage_shape.rb +120 -0
  356. data/lib/hecks/runtime/tenant_check.rb +84 -0
  357. data/lib/hecks/runtime/tenant_scope.rb +55 -0
  358. data/lib/hecks/runtime/value/admission.rb +112 -0
  359. data/lib/hecks/runtime/value/coercion.rb +500 -0
  360. data/lib/hecks/runtime/value/invariant_violation.rb +5 -0
  361. data/lib/hecks/runtime/value.rb +125 -0
  362. data/lib/hecks/runtime.rb +95 -0
  363. data/lib/hecks/translation/audit/approval_digest.rb +31 -0
  364. data/lib/hecks/translation/audit/layer_one.rb +37 -0
  365. data/lib/hecks/translation/audit/layer_two.rb +77 -0
  366. data/lib/hecks/translation/audit/unfed_report.rb +42 -0
  367. data/lib/hecks/translation/audit.rb +70 -0
  368. data/lib/hecks/translation/reattest.rb +72 -0
  369. data/lib/hecks/translation/rule_compiler.rb +120 -0
  370. data/lib/hecks/translation/scaffold/differ.rb +183 -0
  371. data/lib/hecks/translation/scaffold/renderer.rb +41 -0
  372. data/lib/hecks/translation/scaffold/writer.rb +28 -0
  373. data/lib/hecks/translation/scaffold.rb +30 -0
  374. data/lib/hecks/translation.rb +11 -0
  375. data/lib/hecks/version.rb +16 -0
  376. data/lib/hecks/vocabulary.rb +213 -0
  377. data/lib/hecks.rb +118 -6
  378. metadata +401 -222
  379. data/bin/hecks +0 -7
  380. data/bin/hecks-package +0 -65
  381. data/bin/hecks_console +0 -12
  382. data/bin/hecks_serverless +0 -6
  383. data/lib/cli/build.rb +0 -14
  384. data/lib/cli/command_runner.rb +0 -28
  385. data/lib/cli/console.rb +0 -10
  386. data/lib/cli/generate.rb +0 -37
  387. data/lib/cli/hecks-cli.rb +0 -27
  388. data/lib/cli/test.rb +0 -57
  389. data/lib/console/commands.rb +0 -8
  390. data/lib/console/hecks-console.rb +0 -1
  391. data/lib/packager/README.md +0 -0
  392. data/lib/packager/app_runner.rb +0 -21
  393. data/lib/packager/args.rb +0 -26
  394. data/lib/packager/compatibility/fixnum.rb +0 -6
  395. data/lib/packager/hecks.rb +0 -39
  396. data/lib/packager/query_runner.rb +0 -21
  397. data/lib/packager/resources/Dockerfile +0 -11
  398. data/lib/packager/resources/app_binary +0 -7
  399. data/lib/packager/resources/bundle_config +0 -3
  400. data/lib/packager/resources/traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz +0 -0
  401. data/lib/packager/resources/traveling-ruby-20150715-2.2.2-osx.tar.gz +0 -0
  402. data/lib/serverless/Domain +0 -32
  403. data/lib/serverless/cli.rb +0 -75
  404. data/lib/serverless/resources/command_name.js +0 -5
  405. data/lib/serverless/resources/environment.js +0 -7
  406. data/lib/serverless/resources/handler.js.tt +0 -28
  407. data/lib/serverless/resources/run_binary.js +0 -22
  408. data/lib/serverless/resources/serverless.yml +0 -20
@@ -0,0 +1,366 @@
1
+ module Hecks
2
+ module Bluebook
3
+ module DSL
4
+ # ITEM #13's FULL METAPROGRAMMED DISPATCH — slices 1-2 of 4, whole-
5
+ # project table-unification survey. WordGate (the first slice,
6
+ # already shipped) only CHECKS a word's admissibility; this module
7
+ # EXECUTES the safe, mechanical subset of what a word actually
8
+ # DOES, read live off the SAME self-hosted grammar table — so a
9
+ # builder method for one of these words no longer needs to be
10
+ # hand-written at all. Called from `WordGate#method_missing`'s own
11
+ # "admitted here, no builder method for it yet" branch, so it only
12
+ # ever sees a word whose (context, word) pair the grammar already
13
+ # admits.
14
+ #
15
+ # SCOPE, deliberately narrow and VERIFIED word-by-word — a full
16
+ # audit read every real Ruby builder method's own source before
17
+ # any of this was written, not inferred from the table's shape
18
+ # alone (which fooled a first pass: `ReadModelBuilder#group_by`/
19
+ # `#include` LOOK like plain fills from `kind`/`fills` alone, but
20
+ # actually wrap their arguments in a Hash/tuple). What's covered:
21
+ #
22
+ # - a SINGLE, non-variadic, positional Argument row whose value
23
+ # is stored with nothing beyond a uniform, kind-driven
24
+ # coercion (`COERCE_BY_KIND`) — or, for `kind: "text"`, no
25
+ # coercion at all when the row's own `coerce: "false"` says so
26
+ # (six real, audited exceptions: `.to_s` on an actual String
27
+ # is a same-object no-op for every real corpus use, but a
28
+ # genuine behavior change for a direct Ruby API call passing
29
+ # something else)
30
+ # - a scalar ASSIGN (`@ivar = value`) or list APPEND (`@ivar <<
31
+ # value`), chosen by whether the ivar `fills:` names is
32
+ # ALREADY an Array at call time (every candidate's own
33
+ # `initialize` pre-populates its accumulating ivars as `[]` —
34
+ # read live, not assumed)
35
+ # - a ZERO-ARGUMENT word, either (a) one of several sibling
36
+ # Keyword rows in the SAME context sharing the SAME `fills:`
37
+ # target — derives its own stored value from ITS OWN word
38
+ # name as a symbol (`core`/`generic`/`supporting` all fill
39
+ # `classification`), or (b) the ONLY Keyword row filling its
40
+ # own `fills:` target — a bare marker, stores literal `true`
41
+ # (`ReadModel#count`)
42
+ # - an OPENS_BLOCK word named in `SAFE_OPENS_BLOCK` below,
43
+ # verified to do NOTHING beyond "build the child, instance_
44
+ # eval the block against it, append the result" — see that
45
+ # constant's own comment
46
+ # - (slice 2) a single-fill word whose row also names a `blank_
47
+ # message:` — raises that EXACT Malformed text if the coerced
48
+ # value is blank, before storing it, matching a real hand-
49
+ # written guard exactly (`Translation#retired`/
50
+ # `TranslationAggregate#drop`, the only two words in the whole
51
+ # grammar with this precise shape — `required: "true"` alone
52
+ # only gates Ruby's own arity, never a present-but-blank
53
+ # value, and most `required: "true"` words do NOT raise on
54
+ # blank, so this needed a real per-row signal, not an
55
+ # assumption from `required:` alone)
56
+ #
57
+ # Explicitly OUT of this slice (found live, during the audit, not
58
+ # assumed) — stays hand-written, unaffected, until a later slice's
59
+ # own new table columns (`gated_by:`/`calls:`) can name
60
+ # what it really does: variadic accumulation with a real transform
61
+ # (`attaches_to`); source-block extraction (`ensures`, `where`);
62
+ # Struct/Hash-wrapping (`limit`, `group_by`, `rekey`); a guard
63
+ # clause NOT reducible to a plain blank-check (`role`'s own "raise
64
+ # if ALREADY set" uniqueness gate — a genuinely different shape
65
+ # from `retired`/`drop`'s own blank-check, needing its own
66
+ # design); a dynamically-BUILT refusal message rather than one
67
+ # fixed string (`TranslationAggregateBuilder#unresolved` — real
68
+ # branching logic choosing between several message shapes, not a
69
+ # simple "always refuses" flag; belongs with `calls:`, slice 4,
70
+ # where a table row can name the real Ruby helper that already
71
+ # builds it); a side effect beyond storage (`uses_framework`,
72
+ # `uses_embryonaut_bluebook`); an opens-block word threading extra
73
+ # constructor args to its child (`asks`/`tells`/`operation`,
74
+ # `Bluebook#aggregate`, `Translation#aggregate`) or doing anything
75
+ # beyond a bare fold after building (`Aggregate#policy`'s stamp,
76
+ # `Aggregate#value_object`'s flatten, `Hecksagon#port`'s resolver-
77
+ # swap-and-branch); the DEFERRED-build queue pattern (`Aggregate`/
78
+ # `Entity`'s own `command`/`entity`/`query`); the shadow_parsing?-
79
+ # gated words (`has_many`/`has_one`/`belongs_to`/`then_set`/
80
+ # `trigger`/`dispatch`/`one_of` — each delegates to its own
81
+ # `legacy_*` method under `MetaValidator.shadow_parsing?`, else
82
+ # refuses; a genuinely different two-branch shape per word, closer
83
+ # to `calls:`'s own territory than a simple fill); and every
84
+ # `File`-context word (routes through `Runtime.current_registry`,
85
+ # a side effect this module has no business performing).
86
+ #
87
+ # TWO FURTHER, DIFFERENT reasons a word can look table-safe and
88
+ # still be excluded, both found live rather than assumed:
89
+ # - BOOTSTRAP REACHABILITY. `WordGate`'s own gate steps aside
90
+ # entirely while `MetaValidator.bootstrapping?` (the meta-
91
+ # domain's own circularity — its grammar table doesn't exist
92
+ # yet to read), and `load_grammar_into` loads REAL `.port`/
93
+ # `.adapter` files, plus every core `.bluebook` chapter, DURING
94
+ # that exact window. Any word those files actually call (found
95
+ # to be nearly every common one — `vision`/`core`/`generic`/
96
+ # `supporting`/`description`/`goal`/`emits`/`role`/`identified_
97
+ # by` describe literally every self-hosted aggregate/command)
98
+ # has NO working method to fall back on if its hand-written
99
+ # `def` is removed — `super` from `WordGate#method_missing`
100
+ # just raises `NoMethodError`. `PortBuilder`/`AdapterBuilder`/
101
+ # `BluebookBuilder` turned out to be entirely off-limits to
102
+ # this slice for exactly this reason, confirmed by cold-
103
+ # booting `MetaValidator.grammar_registry` after each
104
+ # candidate removal, not assumed safe from reading the table
105
+ # alone.
106
+ # - A CONFLICTING HAND-WRITTEN `method_missing`. `WorldBuilder`
107
+ # and `HecksagonBuilder` each define their OWN `method_missing`
108
+ # directly on the class (for genuinely open-ended settings/
109
+ # collector verbs) — a method defined directly on a class always
110
+ # wins over one from an included module in Ruby's own method
111
+ # resolution, so `WordGate`'s (and this module's) own
112
+ # `method_missing` never runs for THEIR builders at all. Their
113
+ # own candidate words (`realm`/`latest`, `subscribe`) stay
114
+ # hand-written for this structural reason, independent of
115
+ # whether their own behavior would otherwise qualify.
116
+ module GenericDispatch
117
+ NOT_HANDLED = Object.new.freeze
118
+
119
+ COERCE_BY_KIND = { "text" => :to_s, "symbol" => :to_sym }.freeze
120
+
121
+ # (context, word) OPENS_BLOCK pairs verified, by reading every
122
+ # real Ruby method, to do NOTHING beyond building the child and
123
+ # appending it — see this file's own header for the full account
124
+ # of what was excluded and why. Value: the ivar the built child
125
+ # is appended into. NOT derivable from `fills:` — every one of
126
+ # these Keyword rows carries `fills: ""`; the append target is
127
+ # implicit in the hand-written code today, never named by the
128
+ # table at all, so this is the one place slice 1 hand-names a
129
+ # fact the table doesn't yet carry, rather than guessing a
130
+ # pluralization rule that would silently mismatch a future word.
131
+ SAFE_OPENS_BLOCK = {
132
+ %w[Bluebook policy] => :policies,
133
+ %w[Bluebook process_manager] => :process_managers,
134
+ %w[Bluebook read_model] => :read_models
135
+ }.freeze
136
+
137
+ # `WordGate#method_missing`'s OWN bootstrap-window fallback,
138
+ # consulted ONLY while `MetaValidator.bootstrapping?` (the real
139
+ # table doesn't exist yet to read `keyword[:calls]` from). Names
140
+ # the SAME (context, word) -> method pairs the real table's own
141
+ # `calls:` column carries for these rows — kept in sync by hand,
142
+ # the one place in this whole arc that was worth it: it
143
+ # duplicates a METHOD NAME, never the method's own logic, so
144
+ # there is nothing here that could drift into a WRONG ANSWER,
145
+ # only (if ever forgotten) into `attribute` staying unreachable
146
+ # during bootstrap, the same loud `NoMethodError` failure this
147
+ # whole mechanism already had before slice 3 existed.
148
+ BOOTSTRAP_CALLS_FALLBACK = {
149
+ %w[Aggregate attribute] => :attribute_impl,
150
+ %w[Entity attribute] => :attribute_impl,
151
+ %w[Command attribute] => :attribute_impl,
152
+ %w[ValueObject attribute] => :attribute_impl,
153
+ %w[Query attribute] => :attribute_impl,
154
+ %w[PortOperation attribute] => :attribute_impl,
155
+ %w[Command role] => :role_impl,
156
+ # given/invariant/reference_to — slice 4b. Each is a SEPARATE
157
+ # per-builder implementation (not a shared mixin like
158
+ # attribute_impl), so every (context, word) pair below names
159
+ # its OWN builder's own method, even where several share a
160
+ # name.
161
+ %w[Aggregate given] => :given_impl,
162
+ %w[Entity given] => :given_impl,
163
+ %w[Command given] => :given_impl,
164
+ %w[Aggregate invariant] => :invariant_impl,
165
+ %w[Entity invariant] => :invariant_impl,
166
+ %w[ValueObject invariant] => :invariant_impl,
167
+ %w[Aggregate reference_to] => :reference_to_impl,
168
+ %w[Entity reference_to] => :reference_to_impl,
169
+ %w[Command reference_to] => :reference_to_impl,
170
+ %w[Query reference_to] => :reference_to_impl,
171
+ %w[ReadModel reference_to] => :reference_to_impl,
172
+ %w[PortOperation reference_to] => :reference_to_impl,
173
+ # `belongs_to` — genuinely NEW bootstrap-reachability, post-dating
174
+ # the "not bootstrap-reachable" determination above: has_many/
175
+ # has_one/belongs_to were retired everywhere when that check was
176
+ # made, so nothing core/attached used one to describe itself.
177
+ # Wave 6 (identity-and-relationships arc) un-deprecates all three
178
+ # for real, and syntax.bluebook's own Bluebook.Declare relationship
179
+ # (`belongs_to Bluebook`) now uses one describing itself — checked
180
+ # directly (only `belongs_to`, not `has_many`/`has_one`, is
181
+ # actually used this way by any core/attached chapter today).
182
+ %w[Aggregate belongs_to] => :belongs_to_impl,
183
+ # slice 4c — the remaining hand-written words a fresh survey
184
+ # found still un-migrated across every builder. Each checked
185
+ # for bootstrap-reachability individually (grepped directly
186
+ # against every core/attached chapter, not assumed); only the
187
+ # ones below actually are.
188
+ %w[Bluebook aggregate] => :aggregate_impl,
189
+ %w[Aggregate provenance] => :provenance_impl,
190
+ %w[Aggregate identified_by] => :identified_by_impl,
191
+ %w[Aggregate lifecycle] => :lifecycle_impl,
192
+ %w[Aggregate entity] => :entity_impl,
193
+ %w[Aggregate query] => :query_impl,
194
+ %w[Aggregate policy] => :policy_impl,
195
+ %w[Aggregate command] => :command_impl,
196
+ %w[Aggregate projects] => :projects_impl,
197
+ %w[Entity identified_by] => :identified_by_impl,
198
+ %w[Entity command] => :command_impl,
199
+ %w[Entity query] => :query_impl,
200
+ %w[Entity lifecycle] => :lifecycle_impl,
201
+ %w[Command provenance] => :provenance_impl,
202
+ %w[Command sets] => :sets_impl,
203
+ %w[Lifecycle transition] => :transition_impl,
204
+ %w[ReadModel where] => :where_impl,
205
+ %w[ReadModel order_by] => :order_by_impl,
206
+ %w[ReadModel include] => :include_impl,
207
+ %w[Query where] => :where_impl,
208
+ %w[Query order_by] => :order_by_impl,
209
+ %w[Entity entity] => :entity_impl,
210
+ %w[ValueObject member] => :member_impl,
211
+ # slice 5. `port`/`realm`/`latest` — real, closed-set words
212
+ # that sat unreachable behind Hecksagon/World's own class-level
213
+ # `method_missing` (see WordGate#word_gate_dispatch's own
214
+ # header), not bootstrap circularity as such, but the SAME
215
+ # fallback table serves them: this hash is looked up before
216
+ # `word_gate_dispatch` even runs, keyed by whichever context
217
+ # the caller's own class reports.
218
+ %w[Hecksagon port] => :port_impl,
219
+ %w[World realm] => :realm_impl,
220
+ %w[World latest] => :latest_impl,
221
+ # `["Type", word]` — ONE entry each covers `list_of`/`one_of`
222
+ # for EVERY calling context (Aggregate/Entity/Command/Query/
223
+ # PortOperation/ValueObject all use them in an attribute's own
224
+ # type position, and `self.class::GRAMMAR_CONTEXT` can never
225
+ # actually equal "Type" — see `word_gate_dispatch`'s own
226
+ # header). The bootstrap branch checks this key directly, the
227
+ # same way the ordinary `word_gate_dispatch` path's own
228
+ # "Type"-context fallback does.
229
+ %w[Type list_of] => :list_of_impl,
230
+ %w[Type one_of] => :one_of_impl
231
+ }.freeze
232
+
233
+ module_function
234
+
235
+ # THE STATIC PREDICATE — does this (context, word) pair fall
236
+ # within this slice's own verified scope, WITHOUT executing
237
+ # anything? The same row-shape checks `try` itself runs before
238
+ # ever touching a real argument, shared so a conformance spec
239
+ # (which has no real call, no real builder instance) can ask the
240
+ # SAME question `method_missing` answers live.
241
+ def handles?(context, word, rows: MetaValidator::SyntaxBoot.call)
242
+ !shape_for(context, word, rows).nil?
243
+ end
244
+
245
+ # `NOT_HANDLED` for anything outside this slice's own verified
246
+ # scope — the caller (`WordGate#method_missing`) falls through
247
+ # to its own existing "not yet implemented" refusal, UNCHANGED,
248
+ # the exact same message a word not yet migrated to any slice
249
+ # already gets today. A real `ArgumentError` — matching what a
250
+ # hand-written method of the same arity would raise — for a
251
+ # call whose SHAPE the grammar admits but whose actual argument
252
+ # count doesn't match; never a silent wrong answer.
253
+ def try(builder, context, word, args, kwargs, block, rows)
254
+ shape = shape_for(context, word, rows)
255
+ return NOT_HANDLED unless shape
256
+
257
+ case shape[:kind]
258
+ when :calls_through then try_calls_through(builder, shape[:calls], args, kwargs, block)
259
+ when :opens_block then try_opens_block(builder, shape[:keyword], args, kwargs, block)
260
+ when :zero_arg then try_zero_arg(builder, shape[:keyword], args)
261
+ when :single_fill then try_single_fill(builder, shape[:fills], shape[:argument], args, kwargs)
262
+ else
263
+ # `shape_for` names exactly four kinds and this case
264
+ # matches all four — a backstop against the day a fifth is
265
+ # added there without a matching arm here. Falling through
266
+ # silently would return bare `nil` from what the caller
267
+ # (`WordGate#method_missing`) reads as "handled" (anything
268
+ # other than NOT_HANDLED counts), so a self-hosted DSL word
269
+ # would silently execute as a no-op instead of raising the
270
+ # same "not yet implemented" refusal a genuinely unmigrated
271
+ # word already gets.
272
+ raise Runtime::WiringError, "no dispatcher handles shape #{shape[:kind].inspect} — add one before shape_for can produce it"
273
+ end
274
+ end
275
+
276
+ # THE ONE PLACE ROW SHAPE IS JUDGED — returns a small Hash naming
277
+ # which of the four safe shapes (context, word) is, or `nil` if
278
+ # it falls outside this slice's own verified scope. No argument
279
+ # values are read here; this only ever looks at the table.
280
+ def shape_for(context, word, rows)
281
+ keyword = rows[:keywords].find { |k| k[:context] == context && k[:word] == word && k[:status] != "retired" }
282
+ return nil unless keyword
283
+
284
+ calls = keyword[:calls].to_s
285
+ return { kind: :calls_through, calls: calls } unless calls.empty?
286
+
287
+ return { kind: :opens_block, keyword: keyword } if SAFE_OPENS_BLOCK.key?([context, word])
288
+
289
+ fills = keyword[:fills].to_s
290
+ return nil if fills.empty?
291
+
292
+ arguments = rows[:arguments].select { |a| a[:context] == context && a[:keyword] == word && a[:status] != "retired" }
293
+ return { kind: :zero_arg, keyword: keyword } if arguments.empty?
294
+
295
+ return nil unless arguments.size == 1
296
+
297
+ arg = arguments.first
298
+ return nil if arg[:variadic] == "true" || arg[:at] != "1" || !arg[:named].to_s.empty?
299
+ return nil unless COERCE_BY_KIND.key?(arg[:kind])
300
+
301
+ { kind: :single_fill, fills: fills, argument: arg }
302
+ end
303
+
304
+ # `keyword[:calls]` names a real Ruby method whose whole call —
305
+ # every positional, every kwarg, the block, all of it — forwards
306
+ # here UNCHANGED. No argument-shape interpretation at all,
307
+ # deliberately: the target method (`AttributeCollector#
308
+ # attribute_impl`, etc.) already does its own, real, hand-
309
+ # written argument handling; this is a pure, transparent `send`,
310
+ # the lowest-risk possible shape for a word whose own logic is
311
+ # too complex to re-derive from the table (type-quoting refusal,
312
+ # closed-set synthesis, pattern validation, ...).
313
+ def try_calls_through(builder, calls, args, kwargs, block)
314
+ builder.send(calls, *args, **kwargs, &block)
315
+ end
316
+
317
+ def try_opens_block(builder, keyword, args, kwargs, block)
318
+ return NOT_HANDLED unless kwargs.empty?
319
+
320
+ target_ivar = SAFE_OPENS_BLOCK.fetch([keyword[:context], keyword[:word]])
321
+ child_class = DSL.const_get("#{keyword[:opens]}Builder")
322
+
323
+ raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 1)" unless args.size == 1
324
+
325
+ child = child_class.build(args.first, &block)
326
+
327
+ ivar = :"@#{target_ivar}"
328
+ list = builder.instance_variable_get(ivar) || builder.instance_variable_set(ivar, [])
329
+ list << child
330
+ end
331
+
332
+ def try_zero_arg(builder, keyword, args)
333
+ raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 0)" unless args.empty?
334
+
335
+ rows = MetaValidator::SyntaxBoot.call[:keywords]
336
+ siblings = rows.count { |k| k[:context] == keyword[:context] && k[:fills] == keyword[:fills] && k[:status] != "retired" }
337
+ value = siblings > 1 ? keyword[:word].to_sym : true
338
+
339
+ builder.instance_variable_set(:"@#{keyword[:fills]}", value)
340
+ end
341
+
342
+ def try_single_fill(builder, fills, arg, args, kwargs)
343
+ return NOT_HANDLED unless kwargs.empty?
344
+
345
+ coerce = COERCE_BY_KIND.fetch(arg[:kind])
346
+
347
+ raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 1)" unless args.size == 1
348
+
349
+ value = arg[:coerce] == "false" ? args.first : args.first.public_send(coerce)
350
+
351
+ message = arg[:blank_message].to_s
352
+ raise Malformed, message if !message.empty? && value.to_s.empty?
353
+
354
+ ivar = :"@#{fills}"
355
+ current = builder.instance_variable_get(ivar)
356
+
357
+ if current.is_a?(Array)
358
+ current << value
359
+ else
360
+ builder.instance_variable_set(ivar, value)
361
+ end
362
+ end
363
+ end
364
+ end
365
+ end
366
+ end
@@ -0,0 +1,163 @@
1
+ require_relative "word_gate"
2
+ module Hecks
3
+ module Bluebook
4
+ module DSL
5
+ class HecksagonBuilder
6
+ GRAMMAR_CONTEXT = "Hecksagon"
7
+
8
+ include WordGate
9
+
10
+ class << self
11
+ attr_accessor :collector
12
+ end
13
+
14
+ attr_reader :binds, :subscriptions, :framework_members, :vendored_bluebooks
15
+
16
+ def initialize(domain)
17
+ @domain = domain
18
+ @binds = []
19
+ @subscriptions = []
20
+ @framework_members = []
21
+ @vendored_bluebooks = []
22
+ end
23
+
24
+ # An event this hecksagon takes from OUTSIDE the domain's own
25
+ # bluebook.
26
+ def subscribe(event) = @subscriptions << event.to_s
27
+
28
+ # A framework/ member this domain wants attached —
29
+ # Governance, Identity, whatever else lands beside them.
30
+ # Attaching one is a WIRING decision, the same kind `persisted_by`/
31
+ # `projected_by` already are, so it lives here rather than as a
32
+ # fact stated in the domain's own bluebook. Recorded onto THIS
33
+ # hecksagon, the same way `subscribe` records onto its own
34
+ # `subscriptions` — and loads the member's bluebook then its own
35
+ # hecksagon into whatever registry this one is loading into, see
36
+ # `Framework.load!`.
37
+ def uses_framework(name)
38
+ @framework_members << name.to_s
39
+ Hecks::Framework.load!(name)
40
+ end
41
+
42
+ # A VENDORED, EXTERNAL bluebook this domain wants attached — same
43
+ # wiring-decision shape `uses_framework` already is, one level
44
+ # further out: not a member shipped inside hecks's own lib/,
45
+ # but a separate package (embryonaut_bluebooks) vendored into THIS
46
+ # project's own checkout. See EmbryonautBluebook's own header for
47
+ # the full reasoning on why its ROOT can't be a fixed constant the
48
+ # way Framework::ROOT is, and for the recovery provenance.
49
+ #
50
+ # RECORDED ONTO @vendored_bluebooks, same shape `uses_framework`
51
+ # already gives @framework_members — a SEPARATE list on purpose:
52
+ # `framework_members` is load-bearing for `refuse_ungoverned_roles!`
53
+ # (below) and for Governance's own attachment check; conflating
54
+ # the two would make a vendored bluebook attachment satisfy a
55
+ # Governance check it has nothing to do with.
56
+ def uses_embryonaut_bluebook(name)
57
+ @vendored_bluebooks << name.to_s
58
+ Hecks::EmbryonautBluebook.load!(name)
59
+ end
60
+
61
+ # THE PRIMARY PORT, BARE AT THE ROOT — belongs to the CHAPTER as a
62
+ # whole, not one aggregate. `BindingProxy#port` is the aggregate-
63
+ # scoped sibling (`Payments::Payment.port("Gateway") do ... end`);
64
+ # this is what's left when a port isn't about any one record. The
65
+ # bluebook must already be built and registered, since a hecksagon
66
+ # loads after its bluebook, and this attaches to that real, final
67
+ # object directly rather than building a second copy MetaValidator
68
+ # would have to know how to reconstruct.
69
+ # RENAMED FROM `port` — item #13's full metaprogrammed dispatch
70
+ # (slice 5). Not bootstrap-reachable (checked directly — no
71
+ # core/attached chapter declares a Hecksagon of its own). Reached
72
+ # through `WordGate#method_missing`'s new `word_gate_dispatch`,
73
+ # called explicitly below since `HecksagonBuilder`'s own
74
+ # class-level `method_missing` (the open-verb catch-all beneath
75
+ # this) always wins over the module's — see `word_gate.rb`'s own
76
+ # header for the full mechanism.
77
+ def port_impl(name, &block)
78
+ bluebook_ir = Hecks.current_registry.bluebook(@domain) or
79
+ raise Malformed, "#{@domain} declares no such bluebook — a port needs one to belong to"
80
+
81
+ # See BindingProxy#port's own comment on why this resolver swap is
82
+ # needed — ConstShim's active resolver is one global for the whole
83
+ # dynamic extent, currently this file's own BindingProxy-minting
84
+ # one, which would turn a bare constant inside an operation's
85
+ # `reference_to`/`attribute` into another BindingProxy instead of
86
+ # a name.
87
+ built = ConstShim.with(->(const) { const }) { DomainPortBuilder.build(name, &block) }
88
+
89
+ # See BindingProxy#port's own comment on the same branch — a
90
+ # `verb`-shaped port is a plain `Port`, registered the same
91
+ # way `Hecks.port`'s top-level method already does, not attached
92
+ # to this bluebook's own IR the way an operations-shaped
93
+ # `DomainPort` is.
94
+ return Hecks.current_registry.add_port(built) if built.is_a?(Port)
95
+
96
+ bluebook_ir.add_port(built)
97
+ end
98
+
99
+ # NO ungoverned-role check here anymore — see
100
+ # Registry::Verification#refuse_ungoverned_roles!. Moved out of
101
+ # per-block `build`, recovered alongside `environment:`
102
+ # (Runtime::Loader.boot's comment has the provenance): a domain
103
+ # split across multiple hecksagon blocks (base + an
104
+ # `environments/<name>.hecksagon` overlay) would have every
105
+ # block but the one declaring `uses_framework "Governance"`
106
+ # refused HERE, even though `Registry#add_hecksagon` merges them
107
+ # into one Hecksagon before anything ever dispatches against it.
108
+ # Checking the MERGED result once, at verify! time — after every
109
+ # file for this domain has loaded — is both more permissive (no
110
+ # need to repeat `uses_framework` in every file) and strictly
111
+ # more correct (a check against an incomplete, not-yet-merged
112
+ # hecksagon can never see the real final shape).
113
+ def build
114
+ Hecksagon.new(domain: @domain, binds: @binds, subscriptions: @subscriptions,
115
+ framework_members: @framework_members, vendored_bluebooks: @vendored_bluebooks)
116
+ end
117
+
118
+ # DOMAIN-LEVEL DEFAULT BINDS — `persisted_by "Heki"` bare, at the top
119
+ # of a hecksagon block, applies to every aggregate in this domain
120
+ # that doesn't declare its own override. Mirrors `BindingProxy`'s own
121
+ # `method_missing` one level down (`aggregate:` filled in there,
122
+ # `nil` here) — generic over verb name, not hardcoded to
123
+ # `persisted_by`/`projected_by` specifically, so any future verb
124
+ # gets a domain-level default for free too. See `Hecksagon#bind_for`
125
+ # for the fallback lookup this feeds.
126
+ def method_missing(verb, *args, **kwargs, &block)
127
+ # A closed-set grammar word (`port`, today) gets first refusal
128
+ # — item #13's full metaprogrammed dispatch (slice 5); see
129
+ # `WordGate#word_gate_dispatch`'s own header for why this class
130
+ # needs to call it explicitly rather than including it the
131
+ # ordinary way. Only once THAT says "not admitted" does the
132
+ # genuinely open-ended `persisted_by "Heki"`-style bind
133
+ # vocabulary below get a turn.
134
+ result = word_gate_dispatch(verb, args, kwargs, block)
135
+ return result unless result.equal?(WordGate::NOT_ADMITTED)
136
+
137
+ return super unless args.first
138
+
139
+ @binds << Bind.new(aggregate: nil, verb: verb.to_s, adapter: args.first.to_s, role: kwargs[:role]&.to_s)
140
+ block&.call
141
+ self
142
+ end
143
+
144
+ def respond_to_missing?(_name, _include_private = false) = true
145
+
146
+ def self.build(domain, &block)
147
+ builder = new(domain)
148
+ resolver = ->(name) { BindingProxy.namespace(name, builder.binds) }
149
+
150
+ previous = collector
151
+ self.collector = builder.binds
152
+ begin
153
+ ConstShim.with(resolver) { builder.instance_eval(&block) } if block
154
+ ensure
155
+ self.collector = previous
156
+ end
157
+
158
+ builder.build
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end