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,392 @@
1
+ Hecks.bluebook "Bluebook" do
2
+ aggregate "Entity" do
3
+ description "One entity inside an aggregate — an element with its own identity, state machine, commands and queries. Its own root because it repeats the aggregate's whole shape one level down."
4
+
5
+ reference_to Aggregate
6
+
7
+ # THE AGGREGATE IT IS IN, AND ITS NAME. Note this is the identity of the RECORD
8
+ # describing a piece, which is a different thing from the identity that piece
9
+ # itself declares (`identified_by`, the list below).
10
+ identified_by :aggregate, :name
11
+
12
+ attribute :owner, EntityText
13
+ attribute :name, EntityName
14
+ attribute :description, EntityName
15
+ # SEVERAL PATHS, joined — a piece spells an identity exactly as a head does,
16
+ # which is the whole point of it being its own root.
17
+ attribute :identified_by, list_of(IdentityPath)
18
+ attribute :attributes, list_of(PieceField)
19
+ # ADR 0028 — A PRECONDITION SHARED ACROSS THIS PIECE'S OWN COMMANDS,
20
+ # DECLARED ONCE — the SAME Rule shape Aggregate's own `preconditions`
21
+ # already carries (that file's own comment on why it's declared
22
+ # again here rather than shared: a value object is aggregate-scoped
23
+ # in this self-hosting domain).
24
+ attribute :preconditions, list_of(Rule)
25
+ # A PIECE'S OWN SHAPE RULE — the SAME Rule shape, checked (round 7)
26
+ # against EVERY INSTANCE this piece's own aggregate holds, not the
27
+ # aggregate's own flat state — `ValueObject#invariants`'s own
28
+ # relationship to ITS OWN instances, one construct over.
29
+ attribute :invariants, list_of(Rule)
30
+ attribute :state_field, EntityText, optional: true
31
+ attribute :state_start, EntityText, optional: true
32
+ attribute :transitions, list_of(PieceTransition)
33
+
34
+ value_object "EntityName" do
35
+ attribute :value, String
36
+ invariant("an entity is named") { !value.to_s.empty? }
37
+ end
38
+
39
+ value_object "EntityText" do
40
+ attribute :value, String
41
+ end
42
+
43
+ # See Aggregate's own "Rule" value object — the identical shape,
44
+ # declared again here rather than shared (that file's own comment
45
+ # on why).
46
+ value_object "Rule" do
47
+ attribute :description, String
48
+ attribute :canonical, String
49
+ end
50
+
51
+ # A piece's identity is made of parts the same way a head's is, so it holds
52
+ # the same shape. Declared here rather than shared because a value object
53
+ # belongs to the aggregate that uses it.
54
+ value_object "IdentityPath" do
55
+ attribute :value, String
56
+ end
57
+
58
+ value_object "PieceField" do
59
+ attribute :name, String
60
+ attribute :type, String
61
+ attribute :list, String
62
+ attribute :optional, String, optional: true
63
+ attribute :pattern, String, optional: true
64
+ attribute :default, String
65
+ # The closed set this value must belong to — see Aggregate::Field.
66
+ attribute :admits, String, optional: true
67
+ attribute :relationship, String, optional: true
68
+ end
69
+
70
+ value_object "PieceTransition" do
71
+ attribute :command, String
72
+ attribute :from_state, String
73
+ attribute :to_state, String
74
+ end
75
+
76
+ # The way back: everything DECLARED IN the aggregate above. The parent
77
+ # reference IS the query.
78
+ # WHERE IT SITS AMONG ITS SIBLINGS. Declaration order is a FACT ABOUT THE
79
+ # SOURCE — the IR is a contract read straight from this file,
80
+ # field for field AND INDEX FOR INDEX. So the language HOLDS it, instead of
81
+ # inheriting it from whatever order a store happens to iterate: an ask that
82
+ # does not say how it is ordered is answered in identity order, which is
83
+ # right for every other ask and fatal for the one that is the SOURCE.
84
+ value_object "Position" do
85
+ attribute :value, Integer
86
+ end
87
+
88
+ attribute :position, Position
89
+
90
+ query "DeclaredIn" do
91
+ attribute :aggregate, EntityText
92
+ where(aggregate: :aggregate)
93
+ order_by :position
94
+ end
95
+ command "Declare" do
96
+ role "Language"
97
+ goal "Open an entity inside an aggregate"
98
+
99
+ reference_to Aggregate
100
+ attribute :owner, EntityText
101
+ attribute :name, EntityName
102
+ attribute :description, EntityName, optional: true
103
+
104
+ attribute :position, Position, optional: true
105
+ sets :aggregate
106
+ sets :owner
107
+ sets :name
108
+ sets :description
109
+ sets :position
110
+ emits PieceDeclared
111
+ end
112
+
113
+ # ONE PART OF THE PIECE'S IDENTITY, attached exactly as an aggregate's is.
114
+ #
115
+ # A PIECE MUST SAY WHAT IT IS KNOWN BY — the rule, where the language keeps
116
+ # its rules. An entity is an element with an identity of ITS OWN ; that is
117
+ # the whole difference between a piece and a value object, so a command
118
+ # acting on one must be able to say which one. Undeclared, every reader
119
+ # has to invent its own answer — fall through to nothing, or assume
120
+ # `id` — and inventions agree only because every entity in the corpus happened
121
+ # to declare it: a divergence the
122
+ # declaration was masking. Requiring it removes the default there was to
123
+ # disagree about. That requirement now sits on Seal, where a whole-document
124
+ # rule belongs ; what stays here is the shape of each part.
125
+ command "Identify" do
126
+ role "Language"
127
+ goal "Attach one part of the entity's identity"
128
+
129
+ attribute :path, IdentityPath
130
+
131
+ # See Aggregate.Identify, where the same rule is written out in full —
132
+ # the builder resolves the real shape (dotted-unwrap, reference, or
133
+ # bare scalar) before a part ever reaches here.
134
+ given("an identity part names something") { !path.value.to_s.empty? }
135
+
136
+ sets :identified_by, append: { value: :path }
137
+ emits PieceIdentified
138
+ end
139
+
140
+ command "Seal" do
141
+ role "Language"
142
+ goal "Close an entity — the checks that need every declaration present"
143
+
144
+ # A piece gets the whole-document shape a head has, for the same reason :
145
+ # "it said SOMETHING" cannot be asked while the parts are still arriving.
146
+
147
+ given("an entity says what it is known by") { !identified_by.empty? }
148
+
149
+ emits PieceSealed
150
+ end
151
+
152
+ command "Attribute" do
153
+ role "Language"
154
+ goal "Attach one attribute to the entity"
155
+
156
+ # THE TYPE IS A REFERENCE TO THE VALUE OBJECT IT NAMES — the same rule
157
+ # Aggregate.Attribute enforces one construct over (see that command's own
158
+ # comment). An entity declares no value objects of its own (Entity never
159
+ # answers `value_object` — entity.rb's own comment says why); its
160
+ # attributes read the SAME pool its enclosing aggregate declares, so this
161
+ # still resolves as a reference, not free text. An entity attribute naming
162
+ # an undeclared value object failed to fail: `type` rode as plain text, so
163
+ # reference resolution never ran and a typo'd or invented type boots clean.
164
+ reference_to ValueObject, as: :type
165
+ attribute :name, EntityText
166
+ attribute :list, EntityText
167
+ attribute :optional, EntityText, optional: true
168
+ attribute :pattern, EntityText, optional: true
169
+ attribute :default, EntityText, optional: true
170
+ attribute :admits, EntityText, optional: true
171
+ attribute :relationship, EntityText, optional: true
172
+
173
+ sets :attributes, append: { name: :name, type: :type, list: :list, default: :default, optional: :optional, pattern: :pattern, admits: :admits, relationship: :relationship }
174
+
175
+ emits PieceAttributeAttached
176
+ end
177
+
178
+ # An attribute that points at ANOTHER AGGREGATE'S HEAD — the SAME
179
+ # construct Aggregate.Reference is, one level down (see that
180
+ # command's own comment for why the type cannot be text): `belongs_to`/
181
+ # `has_one`/`has_many`/`reference_to` are declared on an entity by the
182
+ # same DSL (`EntityBuilder`/`AttributeCollector`) an aggregate uses,
183
+ # and a real fixture already exercises it (`spec/relationship_
184
+ # declaration_spec.rb`'s "uses the same relationship declarations on
185
+ # an entity", `docs/reference/entity.md`). Without this verb such an
186
+ # attribute fell to the SAME `Attribute` verb above, which reads
187
+ # `type` as a value-object reference — so a cross-aggregate reference
188
+ # declared on a piece failed reference resolution against the wrong
189
+ # pool the moment entity attributes started being checked at all.
190
+ command "Reference" do
191
+ role "Language"
192
+ goal "Attach an attribute that points at another aggregate's head"
193
+
194
+ reference_to Aggregate, as: :points_at
195
+ attribute :name, EntityText
196
+ attribute :list, EntityText
197
+ attribute :optional, EntityText, optional: true
198
+ attribute :pattern, EntityText, optional: true
199
+ attribute :default, EntityText, optional: true
200
+ attribute :admits, EntityText, optional: true
201
+ attribute :relationship, EntityText, optional: true
202
+
203
+ sets :attributes, append: { name: :name, type: :points_at, list: :list, default: :default, optional: :optional, pattern: :pattern, admits: :admits, relationship: :relationship }
204
+
205
+ emits PieceReferenceAttached
206
+ end
207
+
208
+ # An attribute whose type names a PIECE NESTED INSIDE THIS ONE — the
209
+ # SAME construct Aggregate.Holds is, one level down (see that
210
+ # command's own comment): `attribute :dispatches, list_of(Dispatch)`
211
+ # inside `entity "Handler"` (S17, ADR 0026's own two-level chain) is
212
+ # exactly `Account#ledger` one level further in. Without this verb
213
+ # such an attribute fell to the SAME `Attribute` verb above, which
214
+ # reads `type` as a value-object reference — so a piece nested inside
215
+ # a piece failed reference resolution against the wrong pool the
216
+ # moment entity attributes started being checked at all (found live:
217
+ # the meta-grammar's own `Handler.dispatches` naming `Dispatch`,
218
+ # nested inside Handler itself).
219
+ command "Holds" do
220
+ role "Language"
221
+ goal "Attach an attribute whose type is a piece nested inside this one"
222
+
223
+ reference_to Entity, as: :holds
224
+ attribute :name, EntityText
225
+ attribute :list, EntityText
226
+ attribute :optional, EntityText, optional: true
227
+ attribute :pattern, EntityText, optional: true
228
+ attribute :default, EntityText, optional: true
229
+ attribute :admits, EntityText, optional: true
230
+ attribute :relationship, EntityText, optional: true
231
+
232
+ sets :attributes, append: { name: :name, type: :holds, list: :list, default: :default, optional: :optional, pattern: :pattern, admits: :admits, relationship: :relationship }
233
+
234
+ emits PieceHeld
235
+ end
236
+
237
+
238
+ # A PRECONDITION SHARED ACROSS THIS PIECE'S OWN COMMANDS, DECLARED
239
+ # ONCE (ADR 0028) — see Aggregate.Precondition, the identical shape
240
+ # one level down: the piece's own named `given`, referenced back by
241
+ # one of its own commands rather than re-typed.
242
+ command "Precondition" do
243
+ role "Language"
244
+ goal "Declare one precondition this piece's own commands can reference by name"
245
+
246
+ attribute :description, EntityText, optional: true
247
+ attribute :canonical, EntityText
248
+
249
+ given("a rule says what it means") { !description.value.to_s.empty? }
250
+ given("a rule survives extraction") { !canonical.value.to_s.empty? }
251
+
252
+ sets :preconditions, append: { description: :description, canonical: :canonical }
253
+
254
+ emits PiecePreconditionAttached
255
+ end
256
+
257
+ # A PIECE'S OWN SHAPE RULE, DECLARED ONCE (round 7) — see
258
+ # Aggregate.Invariant, the identical shape one level down: checked
259
+ # against every instance of this piece, not this ONE aggregate's
260
+ # own flat state.
261
+ command "Invariant" do
262
+ role "Language"
263
+ goal "Attach one shape rule this piece's own instances must hold"
264
+
265
+ attribute :description, EntityText, optional: true
266
+ attribute :canonical, EntityText
267
+
268
+ given("a rule says what it means") { !description.value.to_s.empty? }
269
+ given("a rule survives extraction") { !canonical.value.to_s.empty? }
270
+
271
+ sets :invariants, append: { description: :description, canonical: :canonical }
272
+
273
+ emits PieceInvariantAttached
274
+ end
275
+
276
+ command "Lifecycle" do
277
+ role "Language"
278
+ goal "Name the field this entity's state machine runs on"
279
+
280
+
281
+ sets :state_field
282
+ sets :state_start
283
+
284
+ emits PieceLifecycleNamed
285
+ end
286
+
287
+ command "Transition" do
288
+ role "Language"
289
+ goal "Attach one transition to the entity's state machine"
290
+
291
+ attribute :command, EntityText
292
+ attribute :from_state, EntityText, optional: true
293
+ attribute :to_state, EntityText
294
+
295
+ sets :transitions, append: { command: :command, from_state: :from_state, to_state: :to_state }
296
+
297
+ emits PieceTransitionAttached
298
+ end
299
+
300
+ # HOW ENTITY IS SPELLED. These rows live with the concept
301
+ # they describe; SyntaxBoot discovers every aggregate-local seed table.
302
+ # Contexts represented here: Entity.
303
+ value_object "KeywordSeed" do
304
+ attribute :word, String
305
+ attribute :context, String, admits: "Syntax::Context"
306
+ attribute :body, String, admits: "Syntax::Body"
307
+ attribute :inner, String
308
+ attribute :opens, String
309
+ attribute :fills, String
310
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
311
+ attribute :was, String
312
+ attribute :resolves_via, String, default: "", admits: "Syntax::ResolutionScope"
313
+ attribute :disambiguator, String, default: "", admits: "Syntax::Disambiguator"
314
+
315
+ member word: "description", context: "Entity", body: "none", inner: "", opens: "", fills: "description"
316
+ member word: "identified_by", context: "Entity", body: "keywords", inner: "ValueObject", opens: "ValueObject", fills: "identified_by", calls: "identified_by_impl"
317
+ member word: "identified_by", context: "Entity", body: "none", inner: "", opens: "", fills: "identified_by", calls: "identified_by_impl"
318
+ member word: "given", context: "Entity", body: "source", inner: "", opens: "", fills: "preconditions", resolves_via: "owner_keyed", disambiguator: "declared_by", calls: "given_impl"
319
+ member word: "invariant", context: "Entity", body: "source", inner: "", opens: "", fills: "invariants", calls: "invariant_impl"
320
+ member word: "command", context: "Entity", body: "keywords", inner: "Command", opens: "Command", fills: "", calls: "command_impl"
321
+ member word: "query", context: "Entity", body: "keywords", inner: "Query", opens: "Query", fills: "", calls: "query_impl"
322
+ member word: "lifecycle", context: "Entity", body: "keywords", inner: "Lifecycle", opens: "", fills: "state_field", calls: "lifecycle_impl"
323
+ member word: "attribute", context: "Entity", body: "none", inner: "", opens: "", fills: "attributes", calls: "attribute_impl"
324
+ member word: "reference_to", context: "Entity", body: "none", inner: "", opens: "", fills: "attributes", calls: "reference_to_impl"
325
+ member word: "has_many", context: "Entity", body: "none", inner: "", opens: "", fills: "attributes", calls: "has_many_impl"
326
+ member word: "has_one", context: "Entity", body: "none", inner: "", opens: "", fills: "attributes", calls: "has_one_impl"
327
+ member word: "belongs_to", context: "Entity", body: "none", inner: "", opens: "", fills: "attributes", calls: "belongs_to_impl"
328
+ member word: "entity", context: "Entity", body: "keywords", inner: "Entity", opens: "Entity", fills: "", calls: "entity_impl"
329
+
330
+ end
331
+
332
+ value_object "ArgumentSeed" do
333
+ attribute :keyword, String
334
+ attribute :context, String, admits: "Syntax::Context"
335
+ attribute :at, String
336
+ attribute :named, String
337
+ attribute :kind, String, admits: "Syntax::ArgumentKind"
338
+ attribute :required, String
339
+ attribute :fills, String
340
+ attribute :selects, String
341
+ attribute :pair_key_fills, String
342
+ attribute :pair_value_fills, String
343
+ attribute :pairs_shape, String, admits: "Syntax::PairsShape"
344
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
345
+ attribute :variadic, String
346
+ attribute :minimum, String
347
+ attribute :coerce, String
348
+ attribute :blank_message, String
349
+
350
+ member keyword: "description", context: "Entity", at: "1", named: "", kind: "text", required: "true", fills: "description", coerce: "false"
351
+ member keyword: "given", context: "Entity", at: "1", named: "", kind: "text", required: "true", fills: "description"
352
+ # PLAIN TEXT, not `kind: "constant"` — unlike `Aggregate`'s own
353
+ # `declared_by:` (which names a real aggregate constant), a piece
354
+ # has no first-class, independently-addressable reference anywhere
355
+ # in this language. "AggregateName.EntityName" ships as a string,
356
+ # the same way `admits:` shipped textual before its own
357
+ # constant-bridge existed — see `EntityBuilder#given_impl`'s own
358
+ # comment for why this is a deliberate, not temporary-by-oversight,
359
+ # divergence.
360
+ member keyword: "given", context: "Entity", at: "", named: "declared_by", kind: "text", required: "false", fills: "declared_by"
361
+ member keyword: "invariant", context: "Entity", at: "1", named: "", kind: "text", required: "true", fills: "description"
362
+ member keyword: "identified_by", context: "Entity", at: "1", named: "", kind: "symbol", required: "false", fills: "identified_by", variadic: "true", minimum: "2"
363
+ member keyword: "identified_by", context: "Entity", at: "1", named: "", kind: "constant", required: "false", fills: "type"
364
+ member keyword: "identified_by", context: "Entity", at: "", named: "as", kind: "symbol", required: "false", fills: "name"
365
+ member keyword: "command", context: "Entity", at: "1", named: "", kind: "text", required: "true", fills: "name"
366
+ member keyword: "command", context: "Entity", at: "", named: "from", kind: "literal", required: "false", fills: "from"
367
+ member keyword: "query", context: "Entity", at: "1", named: "", kind: "text", required: "true", fills: "name"
368
+ member keyword: "entity", context: "Entity", at: "1", named: "", kind: "text", required: "true", fills: "name"
369
+ member keyword: "lifecycle", context: "Entity", at: "1", named: "", kind: "symbol", required: "true", fills: "state_field"
370
+ member keyword: "lifecycle", context: "Entity", at: "", named: "default", kind: "literal", required: "true", fills: "state_start"
371
+ member keyword: "attribute", context: "Entity", at: "1", named: "", kind: "symbol", required: "true", fills: "name"
372
+ member keyword: "attribute", context: "Entity", at: "2", named: "", kind: "constant", required: "true", fills: "type"
373
+ member keyword: "attribute", context: "Entity", at: "", named: "default", kind: "literal", required: "false", fills: "default"
374
+ member keyword: "attribute", context: "Entity", at: "", named: "optional", kind: "flag", required: "false", fills: "optional"
375
+ member keyword: "attribute", context: "Entity", at: "", named: "pattern", kind: "text", required: "false", fills: "pattern"
376
+ member keyword: "attribute", context: "Entity", at: "", named: "admits", kind: "text", required: "false", fills: "admits"
377
+ member keyword: "attribute", context: "Entity", at: "", named: "one_of", kind: "list", required: "false", fills: "one_of"
378
+ member keyword: "reference_to", context: "Entity", at: "1", named: "", kind: "constant", required: "true", fills: "type"
379
+ member keyword: "reference_to", context: "Entity", at: "", named: "as", kind: "symbol", required: "false", fills: "name"
380
+ member keyword: "reference_to", context: "Entity", at: "", named: "optional", kind: "flag", required: "false", fills: "optional"
381
+ member keyword: "has_many", context: "Entity", at: "1", named: "", kind: "constant", required: "true", fills: "type"
382
+ member keyword: "has_many", context: "Entity", at: "", named: "as", kind: "symbol", required: "false", fills: "name"
383
+ member keyword: "has_one", context: "Entity", at: "1", named: "", kind: "constant", required: "true", fills: "type"
384
+ member keyword: "has_one", context: "Entity", at: "", named: "as", kind: "symbol", required: "false", fills: "name"
385
+ member keyword: "has_one", context: "Entity", at: "", named: "optional", kind: "flag", required: "false", fills: "optional"
386
+ member keyword: "belongs_to", context: "Entity", at: "1", named: "", kind: "constant", required: "true", fills: "type"
387
+ member keyword: "belongs_to", context: "Entity", at: "", named: "as", kind: "symbol", required: "false", fills: "name"
388
+ member keyword: "belongs_to", context: "Entity", at: "", named: "optional", kind: "flag", required: "false", fills: "optional"
389
+
390
+ end
391
+ end
392
+ end
@@ -0,0 +1,189 @@
1
+ Hecks.bluebook "Bluebook" do
2
+ aggregate "Policy" do
3
+ description "One policy — the event it watches, the command it fires, and the domain that command belongs to."
4
+
5
+ reference_to Bluebook
6
+
7
+ # THE CHAPTER IT IS IN, AND ITS NAME. A policy hangs off the chapter rather
8
+ # than an aggregate, so the chapter is the part above it.
9
+ identified_by :bluebook, :name
10
+
11
+ attribute :name, PolicyName
12
+ # WHICH HEAD DECLARED IT, empty for a reaction the chapter owns.
13
+ #
14
+ # A policy written inside an aggregate is hoisted onto the chapter by the
15
+ # builder, and the chapter is where the runtime reads it — so nothing was ever
16
+ # lost at runtime. What was lost is where it was WRITTEN, which is a fact about
17
+ # the source, and facts about the source are what this language holds.
18
+ # `Aggregate#to_h` does not carry it and does not need to: the wire format is
19
+ # a contract, and the language may hold more than it.
20
+ attribute :aggregate, PolicyText
21
+ attribute :on_event, PolicyText
22
+ attribute :trigger_command, PolicyText
23
+ attribute :target_domain, PolicyText
24
+ # THE GUARD, CARRIED AS TEXT — same discipline `Command.givens`
25
+ # already holds: the block that wrote it is never called at
26
+ # runtime, only its EXTRACTED SOURCE is (Ports::Extraction), so
27
+ # what the language holds is the string, not a live Proc no wire
28
+ # format could carry. Optional — most policies fire unconditionally.
29
+ attribute :where, PolicyText, optional: true
30
+ # THE FAN-OUT SOURCE — a query verb ("Aggregate.query_name" or
31
+ # "Domain::Aggregate.query_name"), same text shape as
32
+ # `trigger_command`/`target_domain` beside it. Optional — most
33
+ # policies fire once, not once per row.
34
+ attribute :for_each, PolicyText, optional: true
35
+ # WHAT THE TRIGGER IS GIVEN, when the event's own shape is not it.
36
+ # Empty means the whole payload forwards verbatim — what every policy
37
+ # did before this existed, and still the right default for a trigger
38
+ # shaped like its event.
39
+ #
40
+ # The same `Binding` list a saga's own `Dispatch` carries, for the
41
+ # same reason: a reaction crosses an aggregate boundary, and the
42
+ # event on one side is under no obligation to be shaped like the
43
+ # command on the other. Without it the target has to declare every
44
+ # field the event happens to carry — banking's own `FreezeAccount`
45
+ # grew an attribute it never reads, and Account grew two duplicated
46
+ # value objects to type it, before this word existed.
47
+ attribute :with_spec, list_of(Binding)
48
+
49
+ value_object "PolicyName" do
50
+ attribute :value, String
51
+ invariant("a policy is named") { !value.to_s.empty? }
52
+ end
53
+
54
+ value_object "PolicyText" do
55
+ attribute :value, String
56
+ end
57
+
58
+ # DECLARED HERE RATHER THAN SHARED WITH `Dispatch`'s own — a value
59
+ # object belongs to the aggregate that uses it, and everything that
60
+ # walks an aggregate's own scope has nowhere else to look.
61
+ value_object "Binding" do
62
+ attribute :key, String
63
+ attribute :value, String
64
+ end
65
+
66
+ # The way back: everything DECLARED IN the chapter above. The parent
67
+ # reference IS the query.
68
+ # WHERE IT SITS AMONG ITS SIBLINGS. Declaration order is a FACT ABOUT THE
69
+ # SOURCE — the IR is a contract read straight from this file,
70
+ # field for field AND INDEX FOR INDEX. So the language HOLDS it, instead of
71
+ # inheriting it from whatever order a store happens to iterate: an ask that
72
+ # does not say how it is ordered is answered in identity order, which is
73
+ # right for every other ask and fatal for the one that is the SOURCE.
74
+ value_object "Position" do
75
+ attribute :value, Integer
76
+ end
77
+
78
+ attribute :position, Position
79
+
80
+ query "DeclaredIn" do
81
+ attribute :bluebook, PolicyText
82
+ where(bluebook: :bluebook)
83
+ order_by :position
84
+ end
85
+ command "Declare" do
86
+ role "Language"
87
+ goal "Declare a policy on a chapter"
88
+
89
+ reference_to Bluebook
90
+ attribute :name, PolicyName
91
+ attribute :aggregate, PolicyText, optional: true
92
+ attribute :on_event, PolicyText
93
+ attribute :trigger_command, PolicyText
94
+ attribute :target_domain, PolicyText, optional: true
95
+ attribute :where, PolicyText, optional: true
96
+ attribute :for_each, PolicyText, optional: true
97
+
98
+ attribute :position, Position, optional: true
99
+ sets :bluebook
100
+ sets :name
101
+ sets :aggregate
102
+ sets :on_event
103
+ sets :trigger_command
104
+ sets :target_domain
105
+ sets :where
106
+ sets :for_each
107
+ sets :position
108
+ emits ReactionDeclared
109
+ end
110
+
111
+ command "Bind" do
112
+ role "Language"
113
+ goal "Bind one argument of the triggered command"
114
+
115
+ attribute :key, PolicyText
116
+ attribute :value, PolicyText
117
+
118
+ sets :with_spec, append: { key: :key, value: :value }
119
+
120
+ emits TriggerBindingAttached
121
+ end
122
+
123
+ # HOW POLICY IS SPELLED. These rows live with the concept
124
+ # they describe; SyntaxBoot discovers every aggregate-local seed table.
125
+ # Contexts represented here: Policy.
126
+ #
127
+ # `on`'s ArgumentSeed gained a `kind: "constant"` row alongside its
128
+ # existing `kind: "text"` one (ADR 0025, S6 — "events first-class"),
129
+ # same shape `trigger`'s own pair already carries — `on
130
+ # Account::AccountFrozen`, a bare constant, now parses the same way
131
+ # `trigger Account::Debit` does. `calls: "on_impl"` routes the word
132
+ # through a hand-written method (`PolicyBuilder#on_impl`) instead of
133
+ # the generic single-fill coercion, mirroring `trigger`'s own
134
+ # `calls: "trigger_impl"` on the row below. UNLIKE `trigger`,
135
+ # `on_impl` does NOT refuse the quoted-text form outside
136
+ # `shadow_parse` — command references were safe to refuse that way
137
+ # only because they're 100% migrated across the live corpus; event
138
+ # names (`emits`/`on`) are not (only Account's `AccountFrozen` is,
139
+ # this pass), so refusing the old spelling here would break every
140
+ # live `.bluebook` site this pass didn't touch. Both forms stay
141
+ # admitted until a full corpus migration lands.
142
+ value_object "KeywordSeed" do
143
+ attribute :word, String
144
+ attribute :context, String, admits: "Syntax::Context"
145
+ attribute :body, String, admits: "Syntax::Body"
146
+ attribute :inner, String
147
+ attribute :opens, String
148
+ attribute :fills, String
149
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
150
+ attribute :was, String
151
+ attribute :resolves_via, String, default: "", admits: "Syntax::ResolutionScope"
152
+ attribute :disambiguator, String, default: "", admits: "Syntax::Disambiguator"
153
+
154
+ member word: "on", context: "Policy", body: "none", inner: "", opens: "", fills: "on_event", calls: "on_impl"
155
+ member word: "trigger", context: "Policy", body: "none", inner: "", opens: "", fills: "trigger_command", calls: "trigger_impl"
156
+ member word: "across", context: "Policy", body: "none", inner: "", opens: "", fills: "target_domain"
157
+ member word: "where", context: "Policy", body: "source", inner: "", opens: "", fills: "where"
158
+ member word: "for_each", context: "Policy", body: "none", inner: "", opens: "", fills: "for_each"
159
+
160
+ end
161
+
162
+ value_object "ArgumentSeed" do
163
+ attribute :keyword, String
164
+ attribute :context, String, admits: "Syntax::Context"
165
+ attribute :at, String
166
+ attribute :named, String
167
+ attribute :kind, String, admits: "Syntax::ArgumentKind"
168
+ attribute :required, String
169
+ attribute :fills, String
170
+ attribute :selects, String
171
+ attribute :pair_key_fills, String
172
+ attribute :pair_value_fills, String
173
+ attribute :pairs_shape, String, admits: "Syntax::PairsShape"
174
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
175
+ attribute :variadic, String
176
+ attribute :coerce, String
177
+ attribute :blank_message, String
178
+
179
+ member keyword: "on", context: "Policy", at: "1", named: "", kind: "constant", required: "true", fills: "on_event"
180
+ member keyword: "on", context: "Policy", at: "1", named: "", kind: "text", required: "true", fills: "on_event"
181
+ member keyword: "trigger", context: "Policy", at: "1", named: "", kind: "constant", required: "true", fills: "trigger_command"
182
+ member keyword: "trigger", context: "Policy", at: "1", named: "", kind: "text", required: "true", fills: "trigger_command"
183
+ member keyword: "across", context: "Policy", at: "1", named: "", kind: "text", required: "true", fills: "target_domain"
184
+ member keyword: "for_each", context: "Policy", at: "1", named: "", kind: "text", required: "true", fills: "for_each"
185
+ member keyword: "trigger", context: "Policy", at: "", named: "with", kind: "pairs", required: "false", fills: "with_spec", pairs_shape: "verbatim"
186
+
187
+ end
188
+ end
189
+ end