hecks 0.2.0 → 1.0.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 (419) 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 +427 -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 +101 -0
  12. data/lib/hecks/adapters/driven/heki/journal.rb +56 -0
  13. data/lib/hecks/adapters/driven/heki/saga_store.rb +99 -0
  14. data/lib/hecks/adapters/driven/heki/snapshot.rb +65 -0
  15. data/lib/hecks/adapters/driven/heki.adapter +4 -0
  16. data/lib/hecks/adapters/driven/heki.rb +179 -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 +145 -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 +88 -0
  28. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +207 -0
  29. data/lib/hecks/adapters/driven/postgres.adapter +5 -0
  30. data/lib/hecks/adapters/driven/postgres.rb +438 -0
  31. data/lib/hecks/adapters/driven/postgres_era.adapter +17 -0
  32. data/lib/hecks/adapters/driven/prism.adapter +3 -0
  33. data/lib/hecks/adapters/driven/prism.rb +80 -0
  34. data/lib/hecks/adapters/driven/secure_random_identity.adapter +3 -0
  35. data/lib/hecks/adapters/driven/secure_random_identity.rb +14 -0
  36. data/lib/hecks/adapters/driven/sql_query_builder.rb +221 -0
  37. data/lib/hecks/adapters/driven/sqlite/codec.rb +80 -0
  38. data/lib/hecks/adapters/driven/sqlite/projection.rb +172 -0
  39. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +192 -0
  40. data/lib/hecks/adapters/driven/sqlite.adapter +9 -0
  41. data/lib/hecks/adapters/driven/sqlite.rb +306 -0
  42. data/lib/hecks/adapters/driven/system_clock.adapter +3 -0
  43. data/lib/hecks/adapters/driven/system_clock.rb +14 -0
  44. data/lib/hecks/adapters/driven.rb +54 -0
  45. data/lib/hecks/adapters.rb +6 -0
  46. data/lib/hecks/behaviors/dsl.rb +125 -0
  47. data/lib/hecks/behaviors/expectations.rb +340 -0
  48. data/lib/hecks/behaviors/ir.rb +31 -0
  49. data/lib/hecks/behaviors/rspec.rb +42 -0
  50. data/lib/hecks/behaviors/runner.rb +96 -0
  51. data/lib/hecks/behaviors.rb +25 -0
  52. data/lib/hecks/bluebook/aggregate.rb +108 -0
  53. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +134 -0
  54. data/lib/hecks/bluebook/assembly/build.rb +48 -0
  55. data/lib/hecks/bluebook/assembly/contract.rb +112 -0
  56. data/lib/hecks/bluebook/assembly/contracts.rb +438 -0
  57. data/lib/hecks/bluebook/assembly/marks.rb +228 -0
  58. data/lib/hecks/bluebook/assembly/specializer.rb +70 -0
  59. data/lib/hecks/bluebook/assembly.rb +91 -0
  60. data/lib/hecks/bluebook/attribute.rb +96 -0
  61. data/lib/hecks/bluebook/behaviour/aggregate.rb +83 -0
  62. data/lib/hecks/bluebook/behaviour/attribute.rb +27 -0
  63. data/lib/hecks/bluebook/behaviour/chapter.rb +72 -0
  64. data/lib/hecks/bluebook/behaviour/command.rb +116 -0
  65. data/lib/hecks/bluebook/behaviour/domain_port.rb +25 -0
  66. data/lib/hecks/bluebook/behaviour/entity.rb +59 -0
  67. data/lib/hecks/bluebook/behaviour/hexagon.rb +50 -0
  68. data/lib/hecks/bluebook/behaviour/lifecycle.rb +68 -0
  69. data/lib/hecks/bluebook/behaviour/policy.rb +52 -0
  70. data/lib/hecks/bluebook/behaviour/process_manager.rb +51 -0
  71. data/lib/hecks/bluebook/behaviour/query.rb +10 -0
  72. data/lib/hecks/bluebook/behaviour/read_model.rb +29 -0
  73. data/lib/hecks/bluebook/behaviour/traits.rb +81 -0
  74. data/lib/hecks/bluebook/behaviour/value_object.rb +33 -0
  75. data/lib/hecks/bluebook/chapter.rb +78 -0
  76. data/lib/hecks/bluebook/command.rb +124 -0
  77. data/lib/hecks/bluebook/domain_port.rb +102 -0
  78. data/lib/hecks/bluebook/dsl/adapter_builder.rb +34 -0
  79. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +1018 -0
  80. data/lib/hecks/bluebook/dsl/attribute_collector.rb +348 -0
  81. data/lib/hecks/bluebook/dsl/binding_proxy.rb +71 -0
  82. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +1087 -0
  83. data/lib/hecks/bluebook/dsl/command_builder.rb +714 -0
  84. data/lib/hecks/bluebook/dsl/const_shim.rb +81 -0
  85. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +79 -0
  86. data/lib/hecks/bluebook/dsl/entity_builder.rb +430 -0
  87. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +366 -0
  88. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +163 -0
  89. data/lib/hecks/bluebook/dsl/identity_declaration.rb +191 -0
  90. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +44 -0
  91. data/lib/hecks/bluebook/dsl/malformed.rb +7 -0
  92. data/lib/hecks/bluebook/dsl/policy_builder.rb +135 -0
  93. data/lib/hecks/bluebook/dsl/port_builder.rb +39 -0
  94. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +142 -0
  95. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +306 -0
  96. data/lib/hecks/bluebook/dsl/query_builder.rb +113 -0
  97. data/lib/hecks/bluebook/dsl/read_model_builder.rb +233 -0
  98. data/lib/hecks/bluebook/dsl/rule_reference.rb +173 -0
  99. data/lib/hecks/bluebook/dsl/translation_builder.rb +243 -0
  100. data/lib/hecks/bluebook/dsl/value_object_builder.rb +178 -0
  101. data/lib/hecks/bluebook/dsl/word_gate.rb +228 -0
  102. data/lib/hecks/bluebook/dsl/world_builder.rb +117 -0
  103. data/lib/hecks/bluebook/dsl.rb +45 -0
  104. data/lib/hecks/bluebook/entity.rb +103 -0
  105. data/lib/hecks/bluebook/expression/canonical_form.rb +123 -0
  106. data/lib/hecks/bluebook/expression/evaluator.rb +304 -0
  107. data/lib/hecks/bluebook/expression/projection.json +218 -0
  108. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +233 -0
  109. data/lib/hecks/bluebook/expression/resolver.rb +781 -0
  110. data/lib/hecks/bluebook/expression.rb +13 -0
  111. data/lib/hecks/bluebook/hexagon.rb +60 -0
  112. data/lib/hecks/bluebook/lifecycle.rb +42 -0
  113. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +54 -0
  114. data/lib/hecks/bluebook/meta_validator/judge.rb +621 -0
  115. data/lib/hecks/bluebook/meta_validator/plan.rb +332 -0
  116. data/lib/hecks/bluebook/meta_validator/port_judge.rb +51 -0
  117. data/lib/hecks/bluebook/meta_validator/readings.rb +360 -0
  118. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +351 -0
  119. data/lib/hecks/bluebook/meta_validator/shapes.rb +266 -0
  120. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +255 -0
  121. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +138 -0
  122. data/lib/hecks/bluebook/meta_validator/world_judge.rb +78 -0
  123. data/lib/hecks/bluebook/meta_validator.rb +542 -0
  124. data/lib/hecks/bluebook/model_check.rb +445 -0
  125. data/lib/hecks/bluebook/pattern_subset.rb +184 -0
  126. data/lib/hecks/bluebook/policy.rb +41 -0
  127. data/lib/hecks/bluebook/process_manager.rb +128 -0
  128. data/lib/hecks/bluebook/project_discovery.rb +30 -0
  129. data/lib/hecks/bluebook/project_loader.rb +40 -0
  130. data/lib/hecks/bluebook/project_register.rb +82 -0
  131. data/lib/hecks/bluebook/query.rb +61 -0
  132. data/lib/hecks/bluebook/read_model.rb +109 -0
  133. data/lib/hecks/bluebook/reference.rb +74 -0
  134. data/lib/hecks/bluebook/smoke_test.rb +166 -0
  135. data/lib/hecks/bluebook/synthesizer.rb +95 -0
  136. data/lib/hecks/bluebook/translation.rb +92 -0
  137. data/lib/hecks/bluebook/value_object.rb +66 -0
  138. data/lib/hecks/bluebook.rb +74 -0
  139. data/lib/hecks/codemod.rb +342 -0
  140. data/lib/hecks/construct.rb +71 -0
  141. data/lib/hecks/deploy/bluebook/deploy.bluebook +219 -0
  142. data/lib/hecks/deploy/bluebook/deploy.hecksagon +4 -0
  143. data/lib/hecks/deploy/oidc.json +18 -0
  144. data/lib/hecks/doc/reference.rb +410 -0
  145. data/lib/hecks/embryonaut_bluebook.rb +75 -0
  146. data/lib/hecks/facade/cli_door.rb +119 -0
  147. data/lib/hecks/facade/cli_runner.rb +190 -0
  148. data/lib/hecks/facade/command_request.rb +105 -0
  149. data/lib/hecks/facade/handle.rb +173 -0
  150. data/lib/hecks/facade/json_door.rb +166 -0
  151. data/lib/hecks/facade/surface/aggregate_door.rb +185 -0
  152. data/lib/hecks/facade/surface/chapter.rb +107 -0
  153. data/lib/hecks/facade/surface.rb +48 -0
  154. data/lib/hecks/facade.rb +44 -0
  155. data/lib/hecks/forms/app.rb +341 -0
  156. data/lib/hecks/forms/command_form_renderer.rb +113 -0
  157. data/lib/hecks/forms/examples/banking_console.bluebook +3 -0
  158. data/lib/hecks/forms/field_renderer.rb +177 -0
  159. data/lib/hecks/forms/field_shape.rb +232 -0
  160. data/lib/hecks/forms/html.rb +84 -0
  161. data/lib/hecks/forms/index_renderer.rb +35 -0
  162. data/lib/hecks/forms/page.rb +157 -0
  163. data/lib/hecks/forms/params.rb +161 -0
  164. data/lib/hecks/forms/port_argument.rb +46 -0
  165. data/lib/hecks/forms/query_form_renderer.rb +114 -0
  166. data/lib/hecks/forms/record_renderer.rb +119 -0
  167. data/lib/hecks/forms/record_table.rb +68 -0
  168. data/lib/hecks/forms/reference_options.rb +30 -0
  169. data/lib/hecks/forms/value_object_shape.rb +46 -0
  170. data/lib/hecks/forms.rb +54 -0
  171. data/lib/hecks/fqn.rb +94 -0
  172. data/lib/hecks/framework/bluebook/compliance.bluebook +1 -0
  173. data/lib/hecks/framework/bluebook/console_settings.bluebook +489 -0
  174. data/lib/hecks/framework/bluebook/framework.hecksagon +32 -0
  175. data/lib/hecks/framework/bluebook/governance.bluebook +145 -0
  176. data/lib/hecks/framework/bluebook/identity.bluebook +90 -0
  177. data/lib/hecks/framework/oidc.json +39 -0
  178. data/lib/hecks/framework.rb +90 -0
  179. data/lib/hecks/freezer.rb +67 -0
  180. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +527 -0
  181. data/lib/hecks/fuzzing/invalid_value_generator.rb +86 -0
  182. data/lib/hecks/fuzzing/isolated_boot.rb +286 -0
  183. data/lib/hecks/fuzzing/properties.rb +1192 -0
  184. data/lib/hecks/fuzzing/replay.rb +668 -0
  185. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +93 -0
  186. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +80 -0
  187. data/lib/hecks/fuzzing/sequence_generator/picker.rb +96 -0
  188. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +250 -0
  189. data/lib/hecks/fuzzing/sequence_generator.rb +131 -0
  190. data/lib/hecks/fuzzing/value_generator.rb +200 -0
  191. data/lib/hecks/fuzzing.rb +12 -0
  192. data/lib/hecks/grammar/evolve.rb +324 -0
  193. data/lib/hecks/grammar/expression.bluebook +420 -0
  194. data/lib/hecks/grammar/expression_operators.json +1648 -0
  195. data/lib/hecks/grammar/grammar.hecksagon +20 -0
  196. data/lib/hecks/grammar/oidc.json +69 -0
  197. data/lib/hecks/grammar/translation.bluebook +203 -0
  198. data/lib/hecks/grammar.rb +178 -0
  199. data/lib/hecks/ir.rb +126 -0
  200. data/lib/hecks/language/adapter.bluebook +116 -0
  201. data/lib/hecks/language/bluebook/aggregate.bluebook +581 -0
  202. data/lib/hecks/language/bluebook/attaches/paging.bluebook +76 -0
  203. data/lib/hecks/language/bluebook/bluebook.bluebook +256 -0
  204. data/lib/hecks/language/bluebook/bluebook.hecksagon +24 -0
  205. data/lib/hecks/language/bluebook/command.bluebook +471 -0
  206. data/lib/hecks/language/bluebook/entity.bluebook +392 -0
  207. data/lib/hecks/language/bluebook/policy.bluebook +189 -0
  208. data/lib/hecks/language/bluebook/process_manager.bluebook +381 -0
  209. data/lib/hecks/language/bluebook/projection.bluebook +267 -0
  210. data/lib/hecks/language/bluebook/query.bluebook +245 -0
  211. data/lib/hecks/language/bluebook/shape.bluebook +292 -0
  212. data/lib/hecks/language/bluebook/syntax.bluebook +448 -0
  213. data/lib/hecks/language/bluebook/vocabulary.bluebook +379 -0
  214. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +51 -0
  215. data/lib/hecks/language/hecksagon/domain_port.bluebook +76 -0
  216. data/lib/hecks/language/hecksagon/hecksagon.bluebook +131 -0
  217. data/lib/hecks/language/hecksagon/port_operation.bluebook +102 -0
  218. data/lib/hecks/language/oidc.json +333 -0
  219. data/lib/hecks/language/port.bluebook +120 -0
  220. data/lib/hecks/language/translation/translation.bluebook +110 -0
  221. data/lib/hecks/language/translation/translation_aggregate.bluebook +267 -0
  222. data/lib/hecks/language/world/wiring.bluebook +62 -0
  223. data/lib/hecks/language/world/world.bluebook +84 -0
  224. data/lib/hecks/literal.rb +125 -0
  225. data/lib/hecks/naming.rb +174 -0
  226. data/lib/hecks/ports/access_control.port +9 -0
  227. data/lib/hecks/ports/access_control.rb +62 -0
  228. data/lib/hecks/ports/agent/answers.rb +104 -0
  229. data/lib/hecks/ports/agent.port +8 -0
  230. data/lib/hecks/ports/agent.rb +167 -0
  231. data/lib/hecks/ports/authentication.port +6 -0
  232. data/lib/hecks/ports/authentication.rb +50 -0
  233. data/lib/hecks/ports/authorization.port +7 -0
  234. data/lib/hecks/ports/authorization.rb +62 -0
  235. data/lib/hecks/ports/clock.port +5 -0
  236. data/lib/hecks/ports/clock.rb +62 -0
  237. data/lib/hecks/ports/extraction.port +5 -0
  238. data/lib/hecks/ports/extraction.rb +37 -0
  239. data/lib/hecks/ports/identity_assignment.port +5 -0
  240. data/lib/hecks/ports/identity_assignment.rb +45 -0
  241. data/lib/hecks/ports/identity_generation.port +5 -0
  242. data/lib/hecks/ports/identity_generation.rb +49 -0
  243. data/lib/hecks/ports/identity_resolution.port +5 -0
  244. data/lib/hecks/ports/identity_resolution.rb +40 -0
  245. data/lib/hecks/ports/loading.port +4 -0
  246. data/lib/hecks/ports/loading.rb +13 -0
  247. data/lib/hecks/ports/persistence/append_only.rb +138 -0
  248. data/lib/hecks/ports/persistence/binding_policy.rb +56 -0
  249. data/lib/hecks/ports/persistence/execution.rb +23 -0
  250. data/lib/hecks/ports/persistence/null_saga_store.rb +25 -0
  251. data/lib/hecks/ports/persistence/plugin.rb +54 -0
  252. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +169 -0
  253. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +128 -0
  254. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +161 -0
  255. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +61 -0
  256. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +304 -0
  257. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +171 -0
  258. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +190 -0
  259. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +478 -0
  260. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +166 -0
  261. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +314 -0
  262. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +168 -0
  263. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +170 -0
  264. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +134 -0
  265. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +137 -0
  266. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +89 -0
  267. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +85 -0
  268. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +43 -0
  269. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +132 -0
  270. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +74 -0
  271. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +758 -0
  272. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +120 -0
  273. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +31 -0
  274. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +46 -0
  275. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +102 -0
  276. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +46 -0
  277. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +70 -0
  278. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +72 -0
  279. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +120 -0
  280. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +183 -0
  281. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +41 -0
  282. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +28 -0
  283. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +30 -0
  284. data/lib/hecks/ports/persistence/plugins/era/translation.rb +11 -0
  285. data/lib/hecks/ports/persistence/plugins/era.rb +48 -0
  286. data/lib/hecks/ports/persistence/remote_runtime.rb +42 -0
  287. data/lib/hecks/ports/persistence/repository_factory.rb +30 -0
  288. data/lib/hecks/ports/persistence.port +4 -0
  289. data/lib/hecks/ports/persistence.rb +39 -0
  290. data/lib/hecks/ports/projection.port +4 -0
  291. data/lib/hecks/ports/projection.rb +96 -0
  292. data/lib/hecks/ports/query/in_memory.rb +60 -0
  293. data/lib/hecks/ports/query/ordering.rb +41 -0
  294. data/lib/hecks/ports/query.rb +36 -0
  295. data/lib/hecks/ports.rb +27 -0
  296. data/lib/hecks/projections/diagrams.rb +642 -0
  297. data/lib/hecks/projections/ir.rb +18 -0
  298. data/lib/hecks/projections/model/deviations.rb +98 -0
  299. data/lib/hecks/projections/model.rb +145 -0
  300. data/lib/hecks/projections/oidc.rb +110 -0
  301. data/lib/hecks/projections/parser_table.rb +159 -0
  302. data/lib/hecks/projections/reference.rb +38 -0
  303. data/lib/hecks/projections/shape.rb +44 -0
  304. data/lib/hecks/projections/statements.rb +110 -0
  305. data/lib/hecks/projections/vocabulary.rb +100 -0
  306. data/lib/hecks/projections.rb +32 -0
  307. data/lib/hecks/projector/cli_projector.rb +446 -0
  308. data/lib/hecks/projector/docs_projector.rb +321 -0
  309. data/lib/hecks/projector/exporter.rb +158 -0
  310. data/lib/hecks/projector/ir_projector.rb +18 -0
  311. data/lib/hecks/projector/narrate_projector.rb +243 -0
  312. data/lib/hecks/projector/target.rb +97 -0
  313. data/lib/hecks/projector.rb +186 -0
  314. data/lib/hecks/query_ir.rb +411 -0
  315. data/lib/hecks/query_specification/common/authorization_spec.rb +9 -0
  316. data/lib/hecks/query_specification/common/comparators.rb +25 -0
  317. data/lib/hecks/query_specification/common/comparison.rb +174 -0
  318. data/lib/hecks/query_specification/common/cursor_spec.rb +9 -0
  319. data/lib/hecks/query_specification/common/dsl.rb +58 -0
  320. data/lib/hecks/query_specification/common/inspection_spec.rb +9 -0
  321. data/lib/hecks/query_specification/common/limit_spec.rb +9 -0
  322. data/lib/hecks/query_specification/common/null_policy.rb +92 -0
  323. data/lib/hecks/query_specification/common/null_semantics.rb +11 -0
  324. data/lib/hecks/query_specification/common/offset_spec.rb +9 -0
  325. data/lib/hecks/query_specification/common/options.rb +32 -0
  326. data/lib/hecks/query_specification/common/order_by.rb +9 -0
  327. data/lib/hecks/query_specification/common/specification.rb +10 -0
  328. data/lib/hecks/query_specification/common/where_clause.rb +9 -0
  329. data/lib/hecks/query_specification/field_path.rb +107 -0
  330. data/lib/hecks/query_specification/hop_path.rb +132 -0
  331. data/lib/hecks/query_specification/read_model/specification.rb +18 -0
  332. data/lib/hecks/query_specification.rb +14 -0
  333. data/lib/hecks/rendering.rb +48 -0
  334. data/lib/hecks/router/namespace_installer.rb +157 -0
  335. data/lib/hecks/router.rb +70 -0
  336. data/lib/hecks/runtime/aggregate_lock.rb +45 -0
  337. data/lib/hecks/runtime/boot_gates.rb +41 -0
  338. data/lib/hecks/runtime/caller.rb +66 -0
  339. data/lib/hecks/runtime/capability_graph.rb +44 -0
  340. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +135 -0
  341. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +260 -0
  342. data/lib/hecks/runtime/command_interpreter.rb +497 -0
  343. data/lib/hecks/runtime/command_rules/admissibility.rb +357 -0
  344. data/lib/hecks/runtime/command_rules/arithmetic.rb +260 -0
  345. data/lib/hecks/runtime/command_rules/authorization.rb +65 -0
  346. data/lib/hecks/runtime/command_rules/emission.rb +34 -0
  347. data/lib/hecks/runtime/command_rules/references.rb +189 -0
  348. data/lib/hecks/runtime/command_rules.rb +28 -0
  349. data/lib/hecks/runtime/dependency_planning.rb +245 -0
  350. data/lib/hecks/runtime/dispatcher.rb +301 -0
  351. data/lib/hecks/runtime/entity_element.rb +253 -0
  352. data/lib/hecks/runtime/entity_interpreter.rb +299 -0
  353. data/lib/hecks/runtime/errors.rb +122 -0
  354. data/lib/hecks/runtime/event.rb +51 -0
  355. data/lib/hecks/runtime/identity.rb +156 -0
  356. data/lib/hecks/runtime/instance.rb +175 -0
  357. data/lib/hecks/runtime/interpreting.rb +90 -0
  358. data/lib/hecks/runtime/loader.rb +184 -0
  359. data/lib/hecks/runtime/policy_interpreter.rb +366 -0
  360. data/lib/hecks/runtime/port_operation_interpreter.rb +210 -0
  361. data/lib/hecks/runtime/query_interpreter.rb +286 -0
  362. data/lib/hecks/runtime/reaction_invocation.rb +253 -0
  363. data/lib/hecks/runtime/read_model_interpreter.rb +341 -0
  364. data/lib/hecks/runtime/rebuild_sweep.rb +74 -0
  365. data/lib/hecks/runtime/reference_hop.rb +99 -0
  366. data/lib/hecks/runtime/refusal_wording.rb +126 -0
  367. data/lib/hecks/runtime/registry/saga_persistence.rb +142 -0
  368. data/lib/hecks/runtime/registry/verification.rb +246 -0
  369. data/lib/hecks/runtime/registry.rb +279 -0
  370. data/lib/hecks/runtime/remote_dispatcher.rb +143 -0
  371. data/lib/hecks/runtime/routing.rb +96 -0
  372. data/lib/hecks/runtime/saga_interpreter/correlation.rb +97 -0
  373. data/lib/hecks/runtime/saga_interpreter.rb +503 -0
  374. data/lib/hecks/runtime/saga_pending_dispatch.rb +45 -0
  375. data/lib/hecks/runtime/tenant_check.rb +84 -0
  376. data/lib/hecks/runtime/tenant_scope.rb +55 -0
  377. data/lib/hecks/runtime/value/admission.rb +130 -0
  378. data/lib/hecks/runtime/value/coercion.rb +565 -0
  379. data/lib/hecks/runtime/value/invariant_violation.rb +5 -0
  380. data/lib/hecks/runtime/value.rb +125 -0
  381. data/lib/hecks/runtime.rb +107 -0
  382. data/lib/hecks/storehouse.rb +632 -0
  383. data/lib/hecks/version.rb +16 -0
  384. data/lib/hecks/vocabulary.rb +218 -0
  385. data/lib/hecks.rb +123 -6
  386. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +90 -0
  387. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +128 -0
  388. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +160 -0
  389. metadata +412 -222
  390. data/bin/hecks +0 -7
  391. data/bin/hecks-package +0 -65
  392. data/bin/hecks_console +0 -12
  393. data/bin/hecks_serverless +0 -6
  394. data/lib/cli/build.rb +0 -14
  395. data/lib/cli/command_runner.rb +0 -28
  396. data/lib/cli/console.rb +0 -10
  397. data/lib/cli/generate.rb +0 -37
  398. data/lib/cli/hecks-cli.rb +0 -27
  399. data/lib/cli/test.rb +0 -57
  400. data/lib/console/commands.rb +0 -8
  401. data/lib/console/hecks-console.rb +0 -1
  402. data/lib/packager/README.md +0 -0
  403. data/lib/packager/app_runner.rb +0 -21
  404. data/lib/packager/args.rb +0 -26
  405. data/lib/packager/compatibility/fixnum.rb +0 -6
  406. data/lib/packager/hecks.rb +0 -39
  407. data/lib/packager/query_runner.rb +0 -21
  408. data/lib/packager/resources/Dockerfile +0 -11
  409. data/lib/packager/resources/app_binary +0 -7
  410. data/lib/packager/resources/bundle_config +0 -3
  411. data/lib/packager/resources/traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz +0 -0
  412. data/lib/packager/resources/traveling-ruby-20150715-2.2.2-osx.tar.gz +0 -0
  413. data/lib/serverless/Domain +0 -32
  414. data/lib/serverless/cli.rb +0 -75
  415. data/lib/serverless/resources/command_name.js +0 -5
  416. data/lib/serverless/resources/environment.js +0 -7
  417. data/lib/serverless/resources/handler.js.tt +0 -28
  418. data/lib/serverless/resources/run_binary.js +0 -22
  419. data/lib/serverless/resources/serverless.yml +0 -20
@@ -0,0 +1,381 @@
1
+ Hecks.bluebook "Bluebook" do
2
+ aggregate "ProcessManager" do
3
+ description "One process manager — what correlates its instances, what starts and ends it, and the states it moves through."
4
+
5
+ reference_to Bluebook
6
+
7
+ # THE CHAPTER IT IS IN, AND ITS NAME — the same shape a policy takes, and for
8
+ # the same reason.
9
+ identified_by :bluebook, :name
10
+
11
+ attribute :name, ProcessManagerName
12
+ attribute :correlates_by, ProcessManagerText
13
+ attribute :starts_on, ProcessManagerText
14
+ attribute :ends_on, ProcessManagerText
15
+ attribute :states, list_of(SagaState)
16
+ # S17, ADR 0026 — Handler nested here (see `entity "Handler"`, below),
17
+ # an entity rather than its own root aggregate. `list_of(Handler)`
18
+ # forward-references it the same way banking's own `attribute :ledger,
19
+ # list_of(LedgerEntry)` names LedgerEntry before it is declared.
20
+ attribute :handlers, list_of(Handler)
21
+
22
+ value_object "ProcessManagerName" do
23
+ attribute :value, String
24
+ invariant("a process manager is named") { !value.to_s.empty? }
25
+ end
26
+
27
+ value_object "ProcessManagerText" do
28
+ attribute :value, String
29
+ end
30
+
31
+ value_object "SagaState" do
32
+ attribute :name, String
33
+ end
34
+
35
+ # S17, ADR 0026 — HandlerText/DispatchText/Binding, hoisted up from
36
+ # the old standalone `aggregate "Handler"`/`aggregate "Dispatch"`. An
37
+ # entity cannot declare its own `value_object` (EntityBuilder has no
38
+ # such method — a piece borrows its owning aggregate's, the same way
39
+ # LedgerEntry borrows Account's Money), so these live here now, at
40
+ # the ROOT, where BOTH `entity "Handler"` and its own nested `entity
41
+ # "Dispatch"` can still reach them — a piece mints no value objects
42
+ # of its own AT ANY DEPTH, so there is exactly one pool however deep
43
+ # the nesting goes (`EntityBuilder#entity`'s own comment).
44
+ value_object "HandlerText" do
45
+ attribute :value, String
46
+ end
47
+
48
+ value_object "DispatchText" do
49
+ attribute :value, String
50
+ end
51
+
52
+ value_object "Binding" do
53
+ attribute :key, String
54
+ attribute :value, String
55
+ end
56
+
57
+ # ONE DISPATCH'S OWN ORDER AMONG ITS HANDLER'S SIBLINGS — named
58
+ # DispatchPosition rather than reusing ProcessManager's own `Position`
59
+ # four lines below (same discipline as `MemberPosition`/shape.bluebook's
60
+ # own comment on the identical choice): that one orders process
61
+ # managers among a CHAPTER's siblings ; this one orders dispatches
62
+ # within ONE handler. Same shape, different fact.
63
+ #
64
+ # Part of `identified_by`, below, alongside `command_name` — a real
65
+ # handler fans the SAME command out more than once with different
66
+ # `with:` bindings each leg (item #151's own real example: one
67
+ # BodyPulse handler dispatching Signal.FireSignal once per organ),
68
+ # and `command_name` alone collided the instant it did: the Judge's
69
+ # own `entity_duplicate` check raised the moment a second dispatch of
70
+ # the same command was declared, an uncaught crash for a legitimate,
71
+ # common pattern. `position` names WHICH send this is and is safe to
72
+ # fold into identity exactly where it would not be for Handler's own
73
+ # `from_state` (a real business value) — a Dispatch is declared once,
74
+ # at load time, and never re-addressed by identity afterward.
75
+ value_object "DispatchPosition" do
76
+ attribute :value, Integer
77
+ end
78
+
79
+ # The way back: everything DECLARED IN the chapter above. The parent
80
+ # reference IS the query.
81
+ # WHERE IT SITS AMONG ITS SIBLINGS. Declaration order is a FACT ABOUT THE
82
+ # SOURCE — the IR is a contract read straight from this file,
83
+ # field for field AND INDEX FOR INDEX. So the language HOLDS it, instead of
84
+ # inheriting it from whatever order a store happens to iterate: an ask that
85
+ # does not say how it is ordered is answered in identity order, which is
86
+ # right for every other ask and fatal for the one that is the SOURCE.
87
+ value_object "Position" do
88
+ attribute :value, Integer
89
+ end
90
+
91
+ attribute :position, Position
92
+
93
+ query "DeclaredIn" do
94
+ attribute :bluebook, ProcessManagerText
95
+ where(bluebook: :bluebook)
96
+ order_by :position
97
+ end
98
+ command "Declare" do
99
+ role "Language"
100
+ goal "Open a process manager on a chapter"
101
+
102
+ reference_to Bluebook
103
+ attribute :name, ProcessManagerName
104
+ attribute :correlates_by, ProcessManagerText
105
+ attribute :starts_on, ProcessManagerText
106
+ # A PROCEDURE NEED NOT DECLARE AN ENDING. The runtime has always held
107
+ # this optional — ProcessManagerBuilder defaults `@ends_on` to nil,
108
+ # validates only correlates_by/starts_on/states/handlers,
109
+ # and fills it only if the line is written. The
110
+ # language was the one saying it was required, and nothing in the corpus
111
+ # had to disagree because every procedure in it happens to end.
112
+ attribute :ends_on, ProcessManagerText, optional: true
113
+
114
+ attribute :position, Position, optional: true
115
+ sets :bluebook
116
+ sets :name
117
+ sets :correlates_by
118
+ sets :starts_on
119
+ sets :ends_on
120
+ sets :position
121
+ emits SagaDeclared
122
+ end
123
+
124
+ command "State" do
125
+ role "Language"
126
+ goal "Attach one state to the process manager"
127
+
128
+ attribute :name, ProcessManagerText
129
+
130
+ sets :states, append: { name: :name }
131
+
132
+ emits SagaStateAttached
133
+ end
134
+
135
+ # THE HANDLER'S OWN CREATION. S17, ADR 0026 — Handler is a genuine
136
+ # ENTITY now (`entity "Handler"`, below), and an entity is never
137
+ # created through its own dotted verb — banking's own LedgerEntry is
138
+ # created by `Account.LogEntry`, an ordinary append on the OWNER,
139
+ # never by a `LedgerEntry.Declare` of its own
140
+ # (`EntityInterpreter#element_of` only LOCATES an element already on
141
+ # the list — it has no path that creates one). So Handler's creation
142
+ # moved here, onto ProcessManager, mirroring `State` beside it: a
143
+ # bare, aggregate-level append.
144
+ command "Handler" do
145
+ role "Language"
146
+ goal "Open a handler inside a process manager"
147
+
148
+ attribute :event_type, HandlerText
149
+ # A LEG ALWAYS SAYS WHERE IT MOVES FROM. There is no wildcard leg to be
150
+ # optional for: `on "Event", transition: { from => to }` is the only
151
+ # spelling the runtime reads, and it refuses anything else —
152
+ # `single_transition` raises unless the hash holds exactly one from => to
153
+ # pair, so a leg without one
154
+ # is never built at all. `optional: true` here was
155
+ # the language admitting a leg the runtime cannot parse.
156
+ attribute :from_state, HandlerText
157
+ attribute :to_state, HandlerText
158
+
159
+ sets :handlers, append: { event_type: :event_type, from_state: :from_state, to_state: :to_state }
160
+
161
+ emits LegDeclared
162
+ end
163
+
164
+ # S17, ADR 0026 — ONE HANDLER, nested rather than its own root
165
+ # aggregate. No `saga` field. It named the old word for a process
166
+ # manager, held nothing — ProcessManagerHandler has no such reader,
167
+ # so every Handler record's saga was empty — and repeated the parent
168
+ # that its own containment already carries. A field that names the
169
+ # wrong thing, holds nothing, and duplicates the reference beside it.
170
+ #
171
+ # `event_type` is an event name, or one of the Trigger vocabulary's
172
+ # members when the leg answers something no aggregate announces — but
173
+ # NOT, alone, Handler's own identity any more (items #151/#152's own
174
+ # finding): a state machine legitimately answers the SAME event
175
+ # differently depending on which state it is currently in — one event
176
+ # name, several distinct legs (a BodyPulse handler that moves
177
+ # `attentive -> attentive` and, separately, `sleeping_light ->
178
+ # sleeping_light`) — and `event_type` alone collided the instant a
179
+ # real corpus declared that shape: the Judge's own `entity_duplicate`
180
+ # check raised `AlreadyExists` the moment the second leg was declared,
181
+ # an uncaught crash, not a refusal, for a common, legitimate pattern.
182
+ # `from_state` joins it below for exactly this reason — a real
183
+ # business value, not a stand-in for missing meaning, the same
184
+ # distinction `DispatchPosition`'s own comment (above) draws for its
185
+ # sibling `Dispatch`. The process manager this leg belongs to stays
186
+ # structural (which list this element sits in), never a stored field.
187
+ entity "Handler" do
188
+ description "One handler inside a process manager — the event it answers, the state move it makes, and the commands it sends. Nested under the process manager because a handler holds nested dispatches, which hold nested bindings."
189
+
190
+ attribute :event_type, HandlerText
191
+ attribute :from_state, HandlerText
192
+ attribute :to_state, HandlerText
193
+ # S17, ADR 0026 — Dispatch nested here too (see `entity "Dispatch"`,
194
+ # below), one level further in than Handler itself.
195
+ attribute :dispatches, list_of(Dispatch)
196
+
197
+ # BOTH FIELDS TOGETHER — see the class-level comment above.
198
+ identified_by :event_type, :from_state
199
+
200
+ # THE DISPATCH'S OWN CREATION — same reason Handler's own creation
201
+ # lives on ProcessManager, one level up: an entity is never created
202
+ # through its own dotted verb. Reached as a DOTTED verb itself
203
+ # (`ProcessManager.Handler.Dispatch`) since Handler, the owner
204
+ # doing the creating here, is an entity too, not a real aggregate
205
+ # with a bare verb of its own to dispatch into.
206
+ command "Dispatch" do
207
+ role "Language"
208
+ goal "Open a dispatch inside a handler"
209
+
210
+ attribute :command_name, DispatchText
211
+ # THE WALK INDEX, never author-supplied — the same generic
212
+ # POSITION handling `ValueObject.Member`'s own creating command
213
+ # already relies on (`Judge#appends`), which fills this from
214
+ # where the walk found the dispatch, not from a field the row
215
+ # happens to hold. No real `.bluebook` author ever calls this
216
+ # verb directly; only the Judge's own replay does.
217
+ attribute :position, DispatchPosition
218
+
219
+ sets :dispatches, append: { command_name: :command_name, position: :position }
220
+
221
+ emits SendDeclared
222
+ end
223
+
224
+ # S17, ADR 0026 — ONE COMMAND A HANDLER DISPATCHES, nested two
225
+ # levels in rather than its own root aggregate — "no life outside
226
+ # its Handler" (the ADR's own words). The bindings are an open
227
+ # map, which no value object can hold — that was always a reason
228
+ # it could not be one, never a reason it could not be an entity.
229
+ # `command_name` ALONE used to be Dispatch's own identity, the same
230
+ # shape Handler's own `event_type` took one level up — and collided
231
+ # the same way, for the same real reason (item #151): one handler
232
+ # fanning the SAME command out several times with different `with:`
233
+ # bindings each time (one BodyPulse handler dispatching
234
+ # Signal.FireSignal once per organ). `position` joins it below —
235
+ # see `DispatchPosition`'s own comment for why that field, unlike
236
+ # Handler's `from_state`, is safe to fold into identity.
237
+ entity "Dispatch" do
238
+ description "One command a handler dispatches, with the arguments it binds. Nested under the handler because the bindings are an open map, which no value object can hold."
239
+
240
+ attribute :command_name, DispatchText
241
+ attribute :position, DispatchPosition
242
+
243
+ identified_by :command_name, :position
244
+
245
+ attribute :with_spec, list_of(Binding)
246
+
247
+ command "Bind" do
248
+ role "Language"
249
+ goal "Bind one argument of the dispatched command"
250
+
251
+ attribute :key, DispatchText
252
+ attribute :value, DispatchText
253
+
254
+ sets :with_spec, append: { key: :key, value: :value }
255
+
256
+ emits BindingAttached
257
+ end
258
+
259
+ # THE COMPENSATING DISPATCH THIS ONE COMPENSATES FOR, IF ANY —
260
+ # FLAT FIELDS on THIS SAME entity, mirroring `command_name`/
261
+ # `with_spec` above one-for-one, rather than a nested (or
262
+ # self-referential) second `Dispatch`: an entity's own attribute
263
+ # type has to resolve against a value object, and neither a
264
+ # self-reference to `Dispatch` (written from inside its own
265
+ # block, before it exists to reference) nor a plain nested
266
+ # entity reference passes that check the way `Handler.
267
+ # dispatches: list_of(Dispatch)` does — that one resolves a
268
+ # SIBLING already fully built by the time deferred construction
269
+ # (ADR 0028) finishes; a dispatch compensating for itself has no
270
+ # such sibling. `compensates_command_name` absent means no
271
+ # compensation; present, together with whatever
272
+ # `compensates_with_spec` holds, is everything
273
+ # `Reconstruction#dispatch` needs to assemble the SAME
274
+ # `DispatchSpec` shape `compensates` (the real, author-facing
275
+ # word) fills.
276
+ attribute :compensates_command_name, DispatchText, optional: true
277
+ attribute :compensates_with_spec, list_of(Binding)
278
+
279
+ command "Compensates" do
280
+ role "Language"
281
+ goal "Name the command this dispatch compensates for"
282
+
283
+ attribute :compensates_command_name, DispatchText
284
+
285
+ sets :compensates_command_name
286
+
287
+ emits "CompensationDeclared"
288
+ end
289
+
290
+ command "BindCompensation" do
291
+ role "Language"
292
+ goal "Bind one argument of the compensation's own dispatched command"
293
+
294
+ attribute :key, DispatchText
295
+ attribute :value, DispatchText
296
+
297
+ sets :compensates_with_spec, append: { key: :key, value: :value }
298
+
299
+ emits "CompensationBindingAttached"
300
+ end
301
+ end
302
+ end
303
+
304
+ # HOW PROCESSMANAGER IS SPELLED. These rows live with the concept
305
+ # they describe; SyntaxBoot discovers every aggregate-local seed table.
306
+ # Contexts represented here: ProcessManager, Handler.
307
+ value_object "KeywordSeed" do
308
+ attribute :word, String
309
+ attribute :context, String, admits: "Syntax::Context"
310
+ attribute :body, String, admits: "Syntax::Body"
311
+ attribute :inner, String
312
+ attribute :opens, String
313
+ attribute :fills, String
314
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
315
+ attribute :was, String
316
+ attribute :resolves_via, String, default: "", admits: "Syntax::ResolutionScope"
317
+ attribute :disambiguator, String, default: "", admits: "Syntax::Disambiguator"
318
+
319
+ member word: "correlates_by", context: "ProcessManager", body: "none", inner: "", opens: "", fills: "correlates_by"
320
+ # BARE CONSTANT ACCEPTED (ADR 0025, S6 — "events first-class"),
321
+ # `starts_on Transfer::TransferRequested` / `ends_on
322
+ # Transfer::TransferSettled`, same `kind: "constant"` + `kind:
323
+ # "text"` ArgumentSeed pair `emits`/policy's own `on` already
324
+ # carry (this row's own comment there). Now `calls:`-routed
325
+ # (`starts_on_impl`/`ends_on_impl`, hand-written — GenericDispatch's
326
+ # own `COERCE_BY_KIND` has no "constant" entry, so a bare
327
+ # constant needs the same `Naming.event_ref` resolution `on_impl`/
328
+ # `transition_impl` already do, not the plain `.to_s` a single
329
+ # `kind: "text"` row used to get for free).
330
+ member word: "starts_on", context: "ProcessManager", body: "none", inner: "", opens: "", fills: "", calls: "starts_on_impl"
331
+ member word: "ends_on", context: "ProcessManager", body: "none", inner: "", opens: "", fills: "", calls: "ends_on_impl"
332
+ member word: "transition", context: "ProcessManager", body: "keywords", inner: "Handler", opens: "Handler", fills: "", calls: "transition_impl"
333
+ member word: "transition", context: "ProcessManager", body: "none", inner: "", opens: "", fills: "", calls: "transition_impl"
334
+ # TWO ROWS, the SAME PAIR SHAPE `transition` takes just above —
335
+ # `body: "none"` was already the only row (`opens: "Dispatch"`
336
+ # already anticipated a block, unused until now); `body:
337
+ # "keywords"` is the new one, opening `compensates` on the
338
+ # dispatch it sits inside (per-dispatch saga compensation — see
339
+ # `ProcessManagerBuilder::HandlerBuilder#dispatch_impl`'s own
340
+ # comment).
341
+ member word: "dispatch", context: "Handler", body: "keywords", inner: "Dispatch", opens: "Dispatch", fills: "", calls: "dispatch_impl"
342
+ member word: "dispatch", context: "Handler", body: "none", inner: "", opens: "Dispatch", fills: "", calls: "dispatch_impl"
343
+ member word: "compensates", context: "Dispatch", body: "none", inner: "", opens: "", fills: "", calls: "compensates_impl"
344
+
345
+ end
346
+
347
+ value_object "ArgumentSeed" do
348
+ attribute :keyword, String
349
+ attribute :context, String, admits: "Syntax::Context"
350
+ attribute :at, String
351
+ attribute :named, String
352
+ attribute :kind, String, admits: "Syntax::ArgumentKind"
353
+ attribute :required, String
354
+ attribute :fills, String
355
+ attribute :selects, String
356
+ attribute :pair_key_fills, String
357
+ attribute :pair_value_fills, String
358
+ attribute :pairs_shape, String, admits: "Syntax::PairsShape"
359
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
360
+ attribute :variadic, String
361
+ attribute :coerce, String
362
+ attribute :blank_message, String
363
+
364
+ member keyword: "correlates_by", context: "ProcessManager", at: "1", named: "", kind: "symbol", required: "true", fills: "correlates_by"
365
+ member keyword: "starts_on", context: "ProcessManager", at: "1", named: "", kind: "constant", required: "true", fills: "starts_on"
366
+ member keyword: "starts_on", context: "ProcessManager", at: "1", named: "", kind: "text", required: "true", fills: "starts_on"
367
+ member keyword: "ends_on", context: "ProcessManager", at: "1", named: "", kind: "constant", required: "true", fills: "ends_on"
368
+ member keyword: "ends_on", context: "ProcessManager", at: "1", named: "", kind: "text", required: "true", fills: "ends_on"
369
+ member keyword: "transition", context: "ProcessManager", at: "1", named: "", kind: "pairs", required: "true", fills: "", pair_key_fills: "event_type", pair_value_fills: "to_state", pairs_shape: "fields"
370
+ member keyword: "transition", context: "ProcessManager", at: "", named: "from", kind: "text", required: "true", fills: "from_state"
371
+ member keyword: "transition", context: "ProcessManager", at: "", named: "from", kind: "list", required: "false", fills: "from_state"
372
+ member keyword: "dispatch", context: "Handler", at: "1", named: "", kind: "constant", required: "true", fills: "command_name"
373
+ member keyword: "dispatch", context: "Handler", at: "1", named: "", kind: "text", required: "true", fills: "command_name"
374
+ member keyword: "dispatch", context: "Handler", at: "", named: "with", kind: "pairs", required: "false", fills: "with_spec", pairs_shape: "verbatim"
375
+ member keyword: "compensates", context: "Dispatch", at: "1", named: "", kind: "constant", required: "true", fills: "command_name"
376
+ member keyword: "compensates", context: "Dispatch", at: "1", named: "", kind: "text", required: "true", fills: "command_name"
377
+ member keyword: "compensates", context: "Dispatch", at: "", named: "with", kind: "pairs", required: "false", fills: "with_spec", pairs_shape: "verbatim"
378
+
379
+ end
380
+ end
381
+ end
@@ -0,0 +1,267 @@
1
+ Hecks.bluebook "Bluebook" do
2
+ aggregate "ReadModel" do
3
+ description "One read model — the aggregate heads it gathers and the reference it hangs from."
4
+
5
+ reference_to Bluebook
6
+
7
+ # THE CHAPTER IT IS IN, AND ITS NAME.
8
+ identified_by :bluebook, :name
9
+
10
+ attribute :name, ReadModelName
11
+ attribute :description, ProjectionPurpose
12
+ attribute :query_name, ReadModelText
13
+ attribute :reference_name, ReadModelText
14
+ attribute :reference_target, ReadModelText
15
+ attribute :aggregate_heads, list_of(Head)
16
+ # The same open map a query carries — see Query's AskOption. A read model
17
+ # inherits every specification option an ask has, so it holds them the same way.
18
+ attribute :options, list_of(ProjectionOption)
19
+ # WHICH of the eligible head's own fields to nest its rows under, in
20
+ # declared order. Rows, not a single value object with N fields — an
21
+ # arbitrary NUMBER of fields, the same reason `aggregate_heads`/
22
+ # `options` are lists rather than fixed attributes.
23
+ attribute :group_by, list_of(GroupByField)
24
+ # `count`/`median_field` are the OTHER two reductions a read model
25
+ # may declare over its one eligible head, siblings of `group_by`
26
+ # rather than of `options` — same permissive `ReadModelText` shape,
27
+ # and the same UNmarked-optional spelling `reference_name`/
28
+ # `reference_target` already use just above (permissiveness lives
29
+ # in `ReadModelText`'s own lack of an invariant, not in an
30
+ # `optional:` flag this chapter's aggregate-level attributes never
31
+ # carry) — "true"/"" for `count`, a field name or "" for
32
+ # `median_field`, both legitimately absent on a read model that
33
+ # declares neither.
34
+ attribute :count, ReadModelText, optional: true
35
+ attribute :median_field, ReadModelText, optional: true
36
+
37
+ value_object "ReadModelName" do
38
+ attribute :value, String
39
+ invariant("a read model is named") { !value.to_s.empty? }
40
+ end
41
+
42
+ value_object "ReadModelText" do
43
+ # deliberately permissive : query_name / ref_name / ref_target are
44
+ # legitimately empty on a read model that has not named them yet
45
+ attribute :value, String
46
+ end
47
+
48
+ value_object "ProjectionPurpose" do
49
+ attribute :value, String
50
+ invariant("a description says something") { !value.to_s.empty? }
51
+ end
52
+
53
+ value_object "Head" do
54
+ attribute :aggregate, String
55
+ attribute :as, String
56
+ attribute :many, String
57
+ end
58
+
59
+ value_object "ProjectionOption" do
60
+ attribute :option, String
61
+ attribute :key, String
62
+ attribute :value, String
63
+ attribute :at, String
64
+ end
65
+
66
+ value_object "GroupByField" do
67
+ attribute :field, String
68
+ invariant("a group_by field is named") { !field.to_s.empty? }
69
+ end
70
+
71
+ # The way back: everything DECLARED IN the chapter above. The parent
72
+ # reference IS the query.
73
+ # WHERE IT SITS AMONG ITS SIBLINGS. Declaration order is a FACT ABOUT THE
74
+ # SOURCE — the IR is a contract read straight from this file,
75
+ # field for field AND INDEX FOR INDEX. So the language HOLDS it, instead of
76
+ # inheriting it from whatever order a store happens to iterate: an ask that
77
+ # does not say how it is ordered is answered in identity order, which is
78
+ # right for every other ask and fatal for the one that is the SOURCE.
79
+ value_object "Position" do
80
+ attribute :value, Integer
81
+ end
82
+
83
+ attribute :position, Position
84
+
85
+ query "DeclaredIn" do
86
+ attribute :bluebook, ReadModelText
87
+ where(bluebook: :bluebook)
88
+ order_by :position
89
+ end
90
+ command "Declare" do
91
+ role "Language"
92
+ goal "Open a read model on a chapter"
93
+
94
+ reference_to Bluebook
95
+ attribute :name, ReadModelName
96
+ attribute :description, ProjectionPurpose, optional: true
97
+ attribute :query_name, ReadModelText
98
+ # Both optional now — a ROOTLESS read model (no `reference_to`
99
+ # declared at all) has neither. Permanently empty, not "not yet
100
+ # set" — see Gather's own comment below for why that distinction
101
+ # matters.
102
+ attribute :reference_name, ReadModelText, optional: true
103
+ attribute :reference_target, ReadModelText, optional: true
104
+
105
+ attribute :position, Position, optional: true
106
+ sets :bluebook
107
+ sets :name
108
+ sets :description
109
+ sets :query_name
110
+ sets :reference_name
111
+ sets :reference_target
112
+ sets :position
113
+ emits ProjectionDeclared
114
+ end
115
+
116
+ command "Gather" do
117
+ role "Language"
118
+ goal "Attach one aggregate head to the read model"
119
+
120
+ # A HEAD IS THE AGGREGATE IT NAMES. There is no head with nothing gathered:
121
+ # `add_aggregate_head` is only ever reached from an `include Target`,
122
+ # so the builder cannot produce one
123
+ # without it — the field is a plain
124
+ # required, non-empty name. `as` and
125
+ # `many` are both DERIVED from it when the author does not spell them, which
126
+ # is the clearest statement that it is the part that cannot be missing.
127
+ attribute :aggregate, ReadModelText
128
+ attribute :as, ReadModelText
129
+ attribute :many, ReadModelText
130
+
131
+ # NOT "reference_target must already be set" anymore — reference_target
132
+ # is fixed forever at Declare time (nothing ever changes it later), so
133
+ # that rule was really "this read model must have SOME reference, ever"
134
+ # — exactly the constraint a ROOTLESS read model (bulk, no root,
135
+ # `group_by`'s own real use) deliberately doesn't meet, permanently,
136
+ # on purpose, not by omission. Removed rather than relaxed: there is
137
+ # no runtime fact left here that distinguishes "forgot to declare a
138
+ # reference" from "declared rootless on purpose" — both look
139
+ # identical (`reference_target` empty) by the time Gather is judged.
140
+
141
+ sets :aggregate_heads, append: { aggregate: :aggregate, as: :as, many: :many }
142
+
143
+ emits HeadGathered
144
+ end
145
+
146
+ command "GroupBy" do
147
+ role "Language"
148
+ goal "Nest one collection's own rows by one of its own fields"
149
+
150
+ attribute :field, ReadModelText
151
+
152
+ given("a group_by field is named") { !field.value.to_s.empty? }
153
+
154
+ sets :group_by, append: { field: :field }
155
+
156
+ emits GroupByFieldAdded
157
+ end
158
+
159
+ # `count`/`median` are LATE-SET scalars, the same shape `Lifecycle`'s
160
+ # own `state_field`/`state_start` already are on `Aggregate`
161
+ # (aggregate.bluebook) — a command carrying its own value and a bare
162
+ # `sets field, to: field` copying it onto the record, rather
163
+ # than an `append:` (they are not lists, and there is only ever one
164
+ # of each). `count`/`median_field` are declared here, not folded
165
+ # into `Declare`, for the same reason `GroupBy` is its own command
166
+ # above: neither is known until the DSL body runs past `include`.
167
+ command "Count" do
168
+ role "Language"
169
+ goal "Mark the read model as a bare row count over its one eligible collection"
170
+
171
+
172
+ sets :count
173
+
174
+ emits CountDeclared
175
+ end
176
+
177
+ command "Median" do
178
+ role "Language"
179
+ goal "Mark the read model as the median of one numeric field across its one eligible collection"
180
+
181
+
182
+ given("a median field is named") { !median_field.value.to_s.empty? }
183
+
184
+ sets :median_field
185
+
186
+ emits MedianFieldSet
187
+ end
188
+
189
+ command "Option" do
190
+ role "Language"
191
+ goal "Attach one part of one specification option to the read model"
192
+
193
+ attribute :option, ReadModelText
194
+ attribute :key, ReadModelText
195
+ # Same reading as Query.Option above — an option key may stand alone.
196
+ attribute :value, ReadModelText, optional: true
197
+ attribute :at, ReadModelText, optional: true
198
+
199
+ given("an option is named") { !option.value.to_s.empty? }
200
+
201
+ sets :options, append: { option: :option, key: :key, value: :value, at: :at }
202
+
203
+ emits OptionAttached
204
+ end
205
+
206
+ # HOW READMODEL IS SPELLED. These rows live with the concept
207
+ # they describe; SyntaxBoot discovers every aggregate-local seed table.
208
+ # Contexts represented here: ReadModel.
209
+ value_object "KeywordSeed" do
210
+ attribute :word, String
211
+ attribute :context, String, admits: "Syntax::Context"
212
+ attribute :body, String, admits: "Syntax::Body"
213
+ attribute :inner, String
214
+ attribute :opens, String
215
+ attribute :fills, String
216
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
217
+ attribute :was, String
218
+ attribute :resolves_via, String, default: "", admits: "Syntax::ResolutionScope"
219
+ attribute :disambiguator, String, default: "", admits: "Syntax::Disambiguator"
220
+
221
+ member word: "description", context: "ReadModel", body: "none", inner: "", opens: "", fills: "description"
222
+ member word: "reference_to", context: "ReadModel", body: "none", inner: "", opens: "", fills: "reference_target", calls: "reference_to_impl"
223
+ member word: "include", context: "ReadModel", body: "none", inner: "", opens: "", fills: "aggregate_heads", calls: "include_impl"
224
+ member word: "group_by", context: "ReadModel", body: "none", inner: "", opens: "", fills: "group_by", calls: "group_by_impl"
225
+ member word: "count", context: "ReadModel", body: "none", inner: "", opens: "", fills: "count"
226
+ member word: "median", context: "ReadModel", body: "none", inner: "", opens: "", fills: "median_field"
227
+ member word: "where", context: "ReadModel", body: "none", inner: "", opens: "", fills: "options", calls: "where_impl"
228
+ member word: "order_by", context: "ReadModel", body: "none", inner: "", opens: "", fills: "options", calls: "order_by_impl"
229
+ member word: "authorize", context: "ReadModel", body: "none", inner: "", opens: "", fills: "options", calls: "authorize_impl"
230
+ member word: "inspect_query", context: "ReadModel", body: "none", inner: "", opens: "", fills: "options"
231
+
232
+ end
233
+
234
+ value_object "ArgumentSeed" do
235
+ attribute :keyword, String
236
+ attribute :context, String, admits: "Syntax::Context"
237
+ attribute :at, String
238
+ attribute :named, String
239
+ attribute :kind, String, admits: "Syntax::ArgumentKind"
240
+ attribute :required, String
241
+ attribute :fills, String
242
+ attribute :selects, String
243
+ attribute :pair_key_fills, String
244
+ attribute :pair_value_fills, String
245
+ attribute :pairs_shape, String, admits: "Syntax::PairsShape"
246
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
247
+ attribute :variadic, String
248
+ attribute :coerce, String
249
+ attribute :blank_message, String
250
+
251
+ member keyword: "description", context: "ReadModel", at: "1", named: "", kind: "text", required: "true", fills: "description", coerce: "false"
252
+ member keyword: "reference_to", context: "ReadModel", at: "1", named: "", kind: "constant", required: "true", fills: "reference_target"
253
+ member keyword: "reference_to", context: "ReadModel", at: "", named: "as", kind: "symbol", required: "false", fills: "reference_name"
254
+ member keyword: "include", context: "ReadModel", at: "1", named: "", kind: "constant", required: "true", fills: "aggregate"
255
+ member keyword: "include", context: "ReadModel", at: "", named: "as", kind: "symbol", required: "false", fills: "as"
256
+ member keyword: "group_by", context: "ReadModel", at: "1", named: "", kind: "symbol", required: "true", fills: "group_by", variadic: "true"
257
+ member keyword: "median", context: "ReadModel", at: "1", named: "", kind: "symbol", required: "true", fills: "median_field"
258
+ member keyword: "where", context: "ReadModel", at: "1", named: "", kind: "pairs", required: "true", fills: ""
259
+ member keyword: "order_by", context: "ReadModel", at: "1", named: "", kind: "symbol", required: "true", fills: "field"
260
+ member keyword: "order_by", context: "ReadModel", at: "2", named: "", kind: "symbol", required: "false", fills: "direction"
261
+ member keyword: "authorize", context: "ReadModel", at: "1", named: "", kind: "symbol", required: "true", fills: "policy"
262
+ member keyword: "authorize", context: "ReadModel", at: "", named: "tenant", kind: "symbol", required: "false", fills: "tenant"
263
+ member keyword: "inspect_query", context: "ReadModel", at: "1", named: "", kind: "symbol", required: "false", fills: "mode"
264
+
265
+ end
266
+ end
267
+ end