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,81 @@
1
+ module Hecks
2
+ module Bluebook
3
+ module DSL
4
+ module ConstShim
5
+ class << self
6
+ attr_accessor :resolver
7
+
8
+ def with(resolver)
9
+ previous = @resolver
10
+ @resolver = resolver
11
+ yield
12
+ ensure
13
+ @resolver = previous
14
+ end
15
+
16
+ def active? = !@resolver.nil?
17
+ end
18
+
19
+ # THE SCOPED-CONSTANT BRIDGE (ADR 0025, docs/dsl-work-slices.md's
20
+ # S0b) — a Symbol cannot answer `::`, so `Account::Debit` and
21
+ # `admits: Account::LedgerDirection` could never resolve past
22
+ # their FIRST segment while `Account` returned a bare Symbol
23
+ # (`resolver = ->(const) { const }`, bluebook_builder.rb's own
24
+ # comment on why that was right for a BARE name): Ruby's `::`
25
+ # operator raises `TypeError` on the returned value before any
26
+ # DSL code runs at all, unless that value is itself a Module.
27
+ #
28
+ # A REAL `Module` subclass, not a decorated Symbol, for exactly
29
+ # that reason — nothing else answers `::`. Every existing
30
+ # consumer keeps working duck-typed, not because nothing
31
+ # changed: `Attribute#spell`'s `type.is_a?(Module)` branch now
32
+ # fires where it used to fall to `type.to_s`, and
33
+ # `Naming.demodulise` (`path.split("::").last`) gives the
34
+ # IDENTICAL string either way for a single segment — the two
35
+ # branches were already equivalent for a name with no `::` in
36
+ # it, which is every bareword before this.
37
+ class ScopedConstant < Module
38
+ def self.for(path) = new(path.to_s)
39
+
40
+ def initialize(path)
41
+ super()
42
+ @path = path
43
+ end
44
+
45
+ # ONE MORE SEGMENT, the same way an unresolved const anywhere
46
+ # else does — `Account::Debit::Anything` keeps chaining rather
47
+ # than refusing, since nothing here knows how deep a reference
48
+ # is meant to go; the DSL keyword that finally reads `.to_s`
49
+ # is the one place that does.
50
+ def const_missing(name) = ScopedConstant.for("#{@path}::#{name}")
51
+
52
+ def to_s = @path
53
+ def to_sym = @path.to_sym
54
+ def inspect = @path
55
+ def hecks_path = @path
56
+
57
+ def ==(other) = other.is_a?(ScopedConstant) ? @path == other.hecks_path : @path.to_sym == other
58
+ alias eql? ==
59
+ def hash = @path.hash
60
+ end
61
+
62
+ # A SCOPED NAME IS WRITTEN AS TEXT, NOT AS A CONSTANT PATH — see the
63
+ # note on `admits:` in AttributeCollector. A resolver returning a
64
+ # Module (so that `Vocabulary::QueryComparator` reaches a second
65
+ # `const_missing`) was tried and cannot be made to hold : `Facade::
66
+ # Surface` installs EVERY aggregate name as a top-level constant, so
67
+ # once any facade is built, `Vocabulary` resolves to that real module
68
+ # and never reaches this hook at all. A spelling that works only
69
+ # before a facade exists is worse than one that always works.
70
+ module Hook
71
+ def const_missing(name)
72
+ resolver = ConstShim.resolver
73
+ resolver ? resolver.call(name) : super
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ Object.singleton_class.prepend(Hecks::Bluebook::DSL::ConstShim::Hook)
@@ -0,0 +1,79 @@
1
+ require_relative "word_gate"
2
+ module Hecks
3
+ module Bluebook
4
+ module DSL
5
+ class DomainPortBuilder
6
+ GRAMMAR_CONTEXT = "DomainPort"
7
+
8
+ include WordGate
9
+
10
+ def initialize(name, owner: nil)
11
+ @name = name
12
+ @owner = owner
13
+ @operations = []
14
+ end
15
+
16
+ # WHAT THE OUTSIDE TELLS US — an external fact arriving, translated
17
+ # into this domain's own word for it. Spelled `operation` before it
18
+ # had a twin, and `operation` still works: the corpus is full of it,
19
+ # and renaming a word costs every chapter that uses it for no gain a
20
+ # reader can feel.
21
+ #
22
+ # RENAMED FROM `tells` — item #13's full metaprogrammed dispatch
23
+ # (slice 4c). `operation`/`tells` are TWO separate Keyword rows
24
+ # (a word admitting two forms) that both name `calls: "tells_impl"`
25
+ # — the routing between the two spellings now lives in the table,
26
+ # not in a Ruby `alias`. Not bootstrap-reachable (checked
27
+ # directly), so no BOOTSTRAP_CALLS_FALLBACK entry needed.
28
+ def tells_impl(name, to: nil, &block)
29
+ @operations << PortOperationBuilder.build(name, to: to, owner: @owner, direction: :inbound, &block)
30
+ end
31
+
32
+ # WHAT WE ASK OF THE OUTSIDE — the direction this language did not
33
+ # have. Before this, a domain could be CALLED by an adapter and never
34
+ # call one. An `asks` is dispatched like any other port operation, so
35
+ # a `policy` can trigger it off an event, and it comes back as one of
36
+ # the two events it named — which is what makes the outside world
37
+ # something the model can reason about rather than a place exceptions
38
+ # come from.
39
+ #
40
+ # RENAMED FROM `asks` — item #13's full metaprogrammed dispatch
41
+ # (slice 4c), same reasoning as tells_impl above.
42
+ def asks_impl(name, to: nil, &block)
43
+ @operations << PortOperationBuilder.build(name, to: to, owner: @owner, direction: :outbound, &block)
44
+ end
45
+
46
+ # THE DRIVEN HALF OF THE SAME WORD. `operation`/`emits` translates an
47
+ # inbound fact into this domain's own event vocabulary — there is no
48
+ # channel back to a caller beyond the events it emits. `verb` is the
49
+ # opposite direction: the domain calling OUT to a swappable adapter
50
+ # and getting a real value back (a checkout URL, a fetched document),
51
+ # exactly what `Hecks.port "name" do verb "x" end` already builds —
52
+ # this is that same `Port`, reached from the same `port` call
53
+ # `operation` already lives under, so a project's own resource ports
54
+ # read next to their binding instead of in a separate file. One port,
55
+ # one shape or the other — never both.
56
+ # `verb` — item #13's full metaprogrammed dispatch, slice 1
57
+ # (whole-project table-unification survey): a bare, kind-driven
58
+ # coerce-and-assign with nothing else, now executed by
59
+ # `GenericDispatch`.
60
+
61
+ def build
62
+ raise Malformed, "#{@name} declares both a verb and operations — a port is one or the other, not both" if @verb && !@operations.empty?
63
+
64
+ return Port.new(name: @name, verb: @verb, signal: :reply) if @verb
65
+
66
+ raise Malformed, "#{@name} declares no verb and no operations" if @operations.empty?
67
+
68
+ DomainPort.new(name: @name, operations: @operations)
69
+ end
70
+
71
+ def self.build(name, owner: nil, &block)
72
+ builder = new(name, owner: owner)
73
+ builder.instance_eval(&block) if block
74
+ builder.build
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,305 @@
1
+ require_relative "word_gate"
2
+ module Hecks
3
+ module Bluebook
4
+ module DSL
5
+ class EntityBuilder
6
+ GRAMMAR_CONTEXT = "Entity"
7
+
8
+ include AttributeCollector
9
+ include IdentityDeclaration
10
+ include RuleReference
11
+ include WordGate
12
+
13
+ def initialize(name, owner_value_objects: [], owner_named_givens: {},
14
+ identity_name_prefix: nil, identity_value_object_installer: nil)
15
+ @name = name
16
+ @commands = []
17
+ @queries = []
18
+ @entities = []
19
+ @named_givens = {}
20
+ @invariants = []
21
+ @owner_value_objects = owner_value_objects
22
+ @identity_name_prefix = identity_name_prefix || Naming.demodulise(name)
23
+ @identity_value_object_installer = identity_value_object_installer
24
+ # THE AGGREGATE-WIDE cross-entity given pool — ONE hash, the
25
+ # SAME object, threaded unchanged through every piece nested
26
+ # under one aggregate however deep (the identical shape
27
+ # `@owner_value_objects` already threads — see this class'
28
+ # own `entity` comment). `given`'s own block form writes
29
+ # through to it; a SIBLING piece's bare command-level
30
+ # reference reads from it via `CommandBuilder#
31
+ # reference_named_given`.
32
+ @owner_named_givens = owner_named_givens
33
+ # DEFERRED CONSTRUCTION — see `AggregateBuilder#drain_pending!`'s
34
+ # own comment; the identical mechanism, one level down, so a
35
+ # nested piece's own commands (Dispatch inside Handler) see
36
+ # every SIBLING entity/command/query this piece goes on to
37
+ # declare, not just whatever came before it textually.
38
+ @pending_entities = []
39
+ @pending_commands = []
40
+ @pending_queries = []
41
+ end
42
+
43
+ def description(value) = @description = value
44
+
45
+ # THE SAME FIELD AggregateBuilder's OWN reference_to BUILDS — a
46
+ # piece can hold a reference to another root exactly the way its
47
+ # own head can (Card.assignee_id, a Team's own id), just never
48
+ # to another PIECE, since there's no cross-piece addressing
49
+ # anywhere in this language to resolve one against.
50
+ # RENAMED FROM `reference_to` — item #13's full metaprogrammed
51
+ # dispatch (slice 4b). Bootstrap-reachable, in
52
+ # GenericDispatch::BOOTSTRAP_CALLS_FALLBACK.
53
+ def reference_to_impl(type, as: nil, optional: false)
54
+ target = Naming.demodulise(type)
55
+ relationship_attribute(target, :reference_to,
56
+ as || default_reference_name(target), optional: optional)
57
+ end
58
+
59
+ # has_many_impl/has_one_impl are DSL declaration keywords a domain
60
+ # author writes as bare has_many/has_one (matching belongs_to_impl
61
+ # alongside them) — not real predicates, so renaming to many?/one?
62
+ # per Naming/PredicatePrefix would break every bluebook that
63
+ # declares one. New on Entity (Wave 6, identity-and-relationships
64
+ # arc) — pieces never had relationship words before; named
65
+ # `*_impl` to match AggregateBuilder's own siblings, item #13's
66
+ # full metaprogrammed dispatch convention.
67
+ # rubocop:disable Naming/PredicatePrefix
68
+ def has_many_impl(type, as: nil, **options)
69
+ unless options.empty?
70
+ raise Malformed, "#{@name}.has_many takes no #{options.keys.first}: — an empty list already means none"
71
+ end
72
+
73
+ plural = Naming.demodulise(type)
74
+ relationship_attribute(Naming.singularize(plural), :has_many,
75
+ as || Naming.snake(plural).to_sym, list: true)
76
+ end
77
+
78
+ def has_one_impl(type, as: nil, optional: false)
79
+ target = Naming.demodulise(type)
80
+ relationship_attribute(target, :has_one, as || Naming.snake(target).to_sym, optional: optional)
81
+ end
82
+ # rubocop:enable Naming/PredicatePrefix
83
+
84
+ def belongs_to_impl(type, as: nil, optional: false)
85
+ target = Naming.demodulise(type)
86
+ relationship_attribute(target, :belongs_to, as || Naming.snake(target).to_sym, optional: optional)
87
+ end
88
+
89
+ # A PIECE is known by a field, not by a whole value object.
90
+ # `identified_by :sequence` names the SCALAR inside it, which is
91
+ # what an id actually is — a LedgerEntry is entry 3, not entry
92
+ # {"value":3}. `identified_by` itself is AttributeCollector's own
93
+ # shared method (S9) — the two constructs cannot drift apart in
94
+ # how they spell an identity, including composite
95
+ # (`identified_by :branch_code, :box_number`), which a piece may
96
+ # declare for the same reason a head may.
97
+
98
+ # `from:` — see `AggregateBuilder#command`'s own comment; the
99
+ # SAME guard, checked against this PIECE's own lifecycle field
100
+ # (S10, ADR 0025 — a piece's own state machine is checkable the
101
+ # same way a head's is).
102
+ # RENAMED FROM `command`/`query`/`entity`/`lifecycle` (all below)
103
+ # — item #13's full metaprogrammed dispatch (slice 4c), same
104
+ # reasoning as AggregateBuilder's own siblings: bootstrap-
105
+ # reachable, in BOOTSTRAP_CALLS_FALLBACK.
106
+ def command_impl(name, from: nil, &block)
107
+ @pending_commands << [name, from, block]
108
+ end
109
+
110
+ def query_impl(name, &block)
111
+ @pending_queries << [name, block]
112
+ end
113
+
114
+ # S17, ADR 0026 — A PIECE NESTED INSIDE A PIECE. "A `Dispatch`
115
+ # [has] no life outside its `Handler`" (the ADR's own words) —
116
+ # the same reason `Member` nests inside `ValueObject`, one level
117
+ # further in. `owner_value_objects` passes straight through
118
+ # unchanged, not re-derived from this entity's own attributes —
119
+ # a piece mints no value objects of its own at any depth, so a
120
+ # NESTED piece's bare `identified_by :field` still resolves
121
+ # against the SAME root aggregate's value objects an outer
122
+ # piece's already does (`AggregateBuilder#entity`'s own comment
123
+ # names this pool ; there is exactly one of them, however deep
124
+ # the nesting goes).
125
+ def entity_impl(name, &block)
126
+ @pending_entities << [name, block]
127
+ end
128
+
129
+ def lifecycle_impl(field, default:, &block)
130
+ @lifecycle = LifecycleBuilder.build(field, default: default, &block)
131
+ end
132
+
133
+ # A PRECONDITION SHARED ACROSS THIS PIECE'S OWN COMMANDS, DECLARED
134
+ # ONCE — the same move `AggregateBuilder#given` already makes,
135
+ # one level down. Real, live redundancy this closes: banking's
136
+ # own `LedgerEntry.Amend`/`LedgerEntry.Reverse` each repeated
137
+ # `given("customer is active") { parent.customer.status ==
138
+ # "active" }` and `given("account is open") { parent.status ==
139
+ # "open" }`, byte for byte, because a piece had no way to declare
140
+ # either once and reference it back — only the AGGREGATE could.
141
+ # DECLARE BEFORE THE COMMANDS THAT REFERENCE IT, the same
142
+ # ordering `AggregateBuilder#given`'s own comment names — though
143
+ # since ADR 0028, `command` only queues a descriptor and actually
144
+ # builds at `#drain_pending!` time, well after this whole block
145
+ # (including every `given` in it) has already run, so textual
146
+ # order within the block no longer actually matters here; named
147
+ # for the reader anyway, since `given`'s own resolution logic
148
+ # (`CommandBuilder#reference_named_given`) still reads whatever
149
+ # `@named_givens` holds AT THE COMMAND'S OWN BUILD TIME, not by
150
+ # magic.
151
+ # RENAMED FROM `given` — item #13's full metaprogrammed dispatch
152
+ # (slice 4b), same reasoning as reference_to_impl above.
153
+ def given_impl(description, &predicate)
154
+ named = build_rule(Given, description, predicate, owner_name: @name, word: "given",
155
+ extraction_failure: "its source could not be read, so no other runtime could ever evaluate it")
156
+ @named_givens[description] = named
157
+ # WRITE-THROUGH, first-declared-wins (`||=`) — a SECOND piece
158
+ # under the same aggregate independently declaring the exact
159
+ # same description stays purely local to itself (no silent
160
+ # overwrite of whatever the first piece already shared;
161
+ # real, live case a fuzzer or a future codemod could easily
162
+ # surface: two pieces phrasing an UNRELATED rule identically
163
+ # by coincidence, same as an aggregate-level given already
164
+ # tolerates today).
165
+ @owner_named_givens[description] ||= named
166
+ end
167
+
168
+ # A PIECE'S OWN SHAPE RULE (S10, ADR 0025's own "Rules" shape,
169
+ # one level down from `ValueObjectBuilder#invariant`, whose
170
+ # extraction/error pattern this mirrors) — checked against
171
+ # EVERY INSTANCE of this piece the aggregate holds, not once
172
+ # against the aggregate's own flat state
173
+ # (`Admissibility#enforce_invariants`'s own recursive walk).
174
+ # No reference-by-name form (unlike `given`) — no known corpus
175
+ # need for a piece's own invariant to be shared with a SIBLING
176
+ # piece yet; if that need shows up, it is `given`'s own
177
+ # cross-entity write-through pattern to extend, not a reason to
178
+ # invent a second one here speculatively.
179
+ # RENAMED FROM `invariant` — item #13's full metaprogrammed
180
+ # dispatch (slice 4b), same reasoning as given_impl above.
181
+ def invariant_impl(description, &predicate)
182
+ @invariants << build_rule(Invariant, description, predicate, owner_name: @name, word: "invariant",
183
+ extraction_failure: "it would be a rule the IR cannot carry")
184
+ end
185
+
186
+ def build
187
+ drain_pending!
188
+ resolve_pending_identity!
189
+ seal_lifecycle_guards
190
+ install_closed_sets!
191
+ Entity.declare(
192
+ name: @name,
193
+ description: @description,
194
+ identified_by: @identity_paths,
195
+ attributes: attributes,
196
+ commands: @commands,
197
+ queries: @queries,
198
+ entities: @entities,
199
+ preconditions: @named_givens.values,
200
+ invariants: @invariants,
201
+ lifecycle: @lifecycle
202
+ )
203
+ end
204
+
205
+ def self.build(name, owner_value_objects: [], owner_named_givens: {},
206
+ identity_name_prefix: nil, identity_value_object_installer: nil, &block)
207
+ builder = new(name, owner_value_objects: owner_value_objects, owner_named_givens: owner_named_givens,
208
+ identity_name_prefix: identity_name_prefix,
209
+ identity_value_object_installer: identity_value_object_installer)
210
+ builder.instance_eval(&block) if block
211
+ builder.build
212
+ end
213
+
214
+ private
215
+
216
+ # A PIECE'S OWN `one_of` LANDS ON ITS AGGREGATE. A type-position
217
+ # `one_of("never_moved", "moved")` on an entity attribute
218
+ # synthesizes a closed-set value object — and until this, that
219
+ # object was built and then DROPPED: `Entity.declare` carries no
220
+ # value objects, so the synthesized set existed nowhere in the
221
+ # finished graph. The attribute stayed typed "Moved" with nothing
222
+ # to resolve it: runtime admission had no closed set to enforce
223
+ # (the one_of was decorative), and the fuzzer's ValueGenerator
224
+ # crashed every run on the first domain to declare one — a chess
225
+ # King/Rook's own castling flag — with `does not know primitive
226
+ # type "Moved"`. Installed through the SAME hook an entity's own
227
+ # identity value object already rides to the aggregate
228
+ # (`identity_value_object_installer`, threaded unchanged through
229
+ # nested pieces). Two sibling pieces synthesizing the same set
230
+ # (King's and Rook's own `moved`) install it once; the same NAME
231
+ # with a DIFFERENT member list is refused as the collision it is,
232
+ # never first-wins silently.
233
+ def install_closed_sets!
234
+ return unless @identity_value_object_installer
235
+
236
+ closed_sets.each do |value_object|
237
+ existing = @owner_value_objects.find { |candidate| candidate.hecks_name == value_object.hecks_name }
238
+ if existing
239
+ next if existing.to_h == value_object.to_h
240
+
241
+ raise Malformed,
242
+ "#{@name}'s one_of synthesizes #{value_object.hecks_name.inspect}, but the aggregate already " \
243
+ "holds a different #{value_object.hecks_name.inspect} — name the closed set's field differently"
244
+ end
245
+
246
+ @identity_value_object_installer.call(value_object)
247
+ end
248
+ end
249
+
250
+ # See `AggregateBuilder#drain_pending!`'s own comment — the
251
+ # identical mechanism, one level down. Entities first and fully
252
+ # built (so a nested command's own `append:` resolution can read
253
+ # a sibling piece's `.attributes`), then commands, then queries.
254
+ def drain_pending!
255
+ @entities = @pending_entities.map do |name, block|
256
+ EntityBuilder.build(name, owner_value_objects: @owner_value_objects,
257
+ owner_named_givens: @owner_named_givens,
258
+ identity_name_prefix: "#{@identity_name_prefix}#{Naming.demodulise(name)}",
259
+ identity_value_object_installer: @identity_value_object_installer,
260
+ &block)
261
+ end
262
+
263
+ @commands = @pending_commands.map do |name, from, block|
264
+ CommandBuilder.build(name, owner: @name, from: from, named_givens: @named_givens,
265
+ owner_attributes: attributes,
266
+ owner_constructs: @owner_value_objects + @entities,
267
+ entity_shared_givens: @owner_named_givens, &block)
268
+ end
269
+
270
+ @queries = @pending_queries.map do |name, block|
271
+ QueryBuilder.build(name, owner_attributes: attributes, &block)
272
+ end
273
+ end
274
+
275
+ # See `AggregateBuilder#seal_lifecycle_guards`'s own comment —
276
+ # the identical check, one level down.
277
+ def seal_lifecycle_guards
278
+ return if @lifecycle
279
+
280
+ @commands.each do |command|
281
+ next unless command.from
282
+
283
+ raise Malformed,
284
+ "#{@name}.#{command.hecks_name} guards from: #{Array(command.from).inspect}, but " \
285
+ "#{@name} declares no lifecycle — from: checks a lifecycle field, and there is " \
286
+ "none here to check"
287
+ end
288
+ end
289
+
290
+ # `identified_by`'s own resolution pool (AttributeCollector#resolve_
291
+ # pending_identity!'s hook, S9) — a piece mints no value objects of
292
+ # its own, so a bare field's own type resolves against its OWNER
293
+ # aggregate's, passed in at declaration (`AggregateBuilder#entity`).
294
+ def identity_pool = @owner_value_objects
295
+
296
+ def identity_value_object_name = "#{@identity_name_prefix}Identity"
297
+
298
+ def install_identity_value_object!(value_object)
299
+ @identity_value_object_installer&.call(value_object)
300
+ @owner_value_objects << value_object unless @owner_value_objects.include?(value_object)
301
+ end
302
+ end
303
+ end
304
+ end
305
+ end