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,379 @@
1
+ Hecks.bluebook "Bluebook" do
2
+ aggregate "Vocabulary" do
3
+ # These are DECLARATIONS, not runtime state — a language's admitted sets are
4
+ # fixed when the language is defined, which is what one_of means. They carry
5
+ # no commands on purpose : nothing dispatches a vocabulary, the conformance
6
+ # check READS them from the IR and holds the runtime's hand-typed tables to them.
7
+ #
8
+ # Every one of these is a set the runtime must agree with, and every one has
9
+ # already drifted or leaked at least once :
10
+ # Comparison went disjoint from the grammar chapter's operator table
11
+ # NormalisationStrategy is the third, unchecked copy of the canonical-form table
12
+ # Primitive is what "primitives live in value objects only" is ABOUT
13
+ # DomainRefusal is the boundary three raw Ruby TypeErrors crossed tonight
14
+ description "The closed sets the language admits — the whole of what any runtime may accept, declared once."
15
+
16
+ # ITS NAME, and nothing else. A vocabulary hangs under no other thing — the
17
+ # closed sets are the language's own, declared once — so one path is the whole
18
+ # identity.
19
+ identified_by VocabularyName, as: :name
20
+
21
+
22
+ value_object "VocabularyName" do
23
+ attribute :value, String
24
+ invariant("a vocabulary is named") { !value.to_s.empty? }
25
+ end
26
+
27
+ # Expression::Evaluator::COMPARISONS — six operators, all reduced by the
28
+ # evaluator to two primitives (less_than, equal) combined with a small boolean
29
+ # algebra: compares_less_than and compares_equal choose which primitive(s) OR
30
+ # together, negated inverts the result. `compare` reads this table instead of
31
+ # hardcoding a six-way case statement — see Evaluator::COMPARISONS.
32
+ value_object "Comparison" do
33
+ attribute :symbol, String
34
+ attribute :compares_less_than, String
35
+ attribute :compares_equal, String
36
+ attribute :negated, String
37
+
38
+ member symbol: ">=", compares_less_than: "true", compares_equal: "false", negated: "true"
39
+ member symbol: "<=", compares_less_than: "true", compares_equal: "true", negated: "false"
40
+ member symbol: "<", compares_less_than: "true", compares_equal: "false", negated: "false"
41
+ member symbol: ">", compares_less_than: "true", compares_equal: "true", negated: "true"
42
+ member symbol: "==", compares_less_than: "false", compares_equal: "true", negated: "false"
43
+ member symbol: "!=", compares_less_than: "false", compares_equal: "true", negated: "true"
44
+ end
45
+
46
+ # Expression::Resolver::SIGN_TESTS
47
+ # Each sign test is comparing against the literal 0, using an operator
48
+ # Comparison already declares — compares_via names which one, so a sign
49
+ # test is sugar for an existing operator rather than a second algebra
50
+ # beside it. `positive?` = value > 0, `negative?` = value < 0, `zero?` =
51
+ # value == 0.
52
+ value_object "SignTest" do
53
+ attribute :name, String
54
+ attribute :compares_via, String
55
+
56
+ member name: "positive?", compares_via: ">"
57
+ member name: "negative?", compares_via: "<"
58
+ member name: "zero?", compares_via: "=="
59
+ end
60
+
61
+ # `.include?`'s haystack type decides its behaviour : Array does
62
+ # membership (the same equal? primitive Comparison's == uses), String
63
+ # does an exact substring match and refuses a non-String needle. Anything
64
+ # else is always false — not declared here, since it is the fallback
65
+ # every OTHER haystack type shares, not a case of its own.
66
+ value_object "IncludeHaystack" do
67
+ attribute :type, String
68
+ attribute :strategy, String
69
+
70
+ member type: "Array", strategy: "membership"
71
+ member type: "String", strategy: "substring"
72
+ end
73
+
74
+ # `.to_s` admits exactly these scalar types, and every one of them uses
75
+ # the SAME rule (Ruby's own to_s — nil renders "", a bool its name, a
76
+ # number its digits, a string itself) — a closed set to admit into, not a
77
+ # table of different rules per type.
78
+ value_object "ToStringType" do
79
+ attribute :type, String, one_of: ["String", "Integer", "Float", "TrueClass", "FalseClass", "NilClass"]
80
+ end
81
+
82
+ # `.size` and `.empty?` admit exactly the same closed set — a list, a
83
+ # string, or an open map — and each just calls the one Ruby method
84
+ # already named for it. One declaration for both, since the set itself is
85
+ # the only thing either needed to say.
86
+ value_object "SizedType" do
87
+ attribute :type, String, one_of: ["Array", "String", "Hash"]
88
+ end
89
+
90
+ # Attribute::PRIMITIVES — the scalars a value object may bottom out in
91
+ value_object "Primitive" do
92
+ attribute :name, String, one_of: ["String", "Integer", "Float", "TrueClass", "FalseClass"]
93
+ end
94
+
95
+ # Expression::CanonicalForm::STRATEGIES
96
+ value_object "NormalisationStrategy" do
97
+ attribute :name, String, one_of: ["collapse_whitespace", "replace"]
98
+ end
99
+
100
+ # the ops Runtime::CommandInterpreter applies. `sign` is the arithmetic
101
+ # delta increment/decrement share one primitive by — CommandRules#arithmetic
102
+ # applies `current + sign *
103
+ # amount`, differing only in which sign. set and append do no arithmetic,
104
+ # so they carry no sign — ABSENT IS NOT EMPTY, same reading as elsewhere in
105
+ # this file.
106
+ value_object "MutationOp" do
107
+ attribute :name, String
108
+ attribute :sign, String
109
+
110
+ member name: "set", sign: ""
111
+ member name: "append", sign: ""
112
+ member name: "increment", sign: "1"
113
+ member name: "decrement", sign: "-1"
114
+ # Vendored addition, not (yet) upstream hecks (migration plan
115
+ # task 4, i106 in-DSL math — CommandRules::Arithmetic#multiply/
116
+ # #clamp): multiply scales (`current * amount`), clamp bounds
117
+ # (`current.clamp(min, max)`) — neither is an add/subtract, so
118
+ # neither carries a sign, same reading as set/append above.
119
+ member name: "multiply", sign: ""
120
+ member name: "clamp", sign: ""
121
+ # Vendored addition, not (yet) upstream hecks (migration plan
122
+ # task 4): remove — the list-removal counterpart to append,
123
+ # matching an element by value. No sign, same reading as append.
124
+ member name: "remove", sign: ""
125
+ # Vendored addition, not (yet) upstream hecks — CommandBuilder
126
+ # #delegates_to's own comment gives the full reasoning: an
127
+ # aggregate-level command's synchronous, single-dispatch handoff
128
+ # into one nested entity command, rather than a policy/saga's own
129
+ # commit-then-react reentry. Rides the SAME multi-binding wire
130
+ # shape append does (`with: {...}` is a field map, same as
131
+ # append's own `fields:`), so it carries no sign, same reading.
132
+ member name: "delegate", sign: ""
133
+ # CommandBuilder#corrects_impl's own comment gives the full
134
+ # reasoning — a command declaring a past event it amends, rather
135
+ # than a fresh mutation of its own. Rides the SAME multi-binding
136
+ # wire shape append/delegate do (`as:`/`reason:`/`reverses:`,
137
+ # assembled into one `source` hash by hand, same as `with:` is),
138
+ # so it carries no sign either.
139
+ member name: "corrects", sign: ""
140
+ end
141
+
142
+ # QuerySpecification::Common::Comparators::COMPARATORS — a where-clause's
143
+ # admitted operators. Unlike Comparison, these do not reduce to one shared
144
+ # boolean algebra (eq/ne compare values, gt/gte/lt/lte order them, in/contains
145
+ # test membership in opposite directions), so this stays a flat closed set —
146
+ # the same shape MutationOp had before it grew a sign.
147
+ # `none_in_state` (the last member) is a vendored addition, not (yet)
148
+ # upstream hecks (migration plan task 4) — see
149
+ # query_specification/common/comparators.rb's own comment on
150
+ # none_in_state. Both closed sets (the Ruby COMPARATORS constant and
151
+ # this self-hosted grammar entry) must agree, the same two-places-
152
+ # must-agree discipline MutationOp/multiply/clamp already required
153
+ # earlier this pass.
154
+ value_object "QueryComparator" do
155
+ attribute :name, String, one_of: ["eq", "ne", "gt", "gte", "lt", "lte", "in", "contains", "none_in_state"]
156
+ end
157
+
158
+ # Adapters::Driven::Folder::DOMAIN_ORDER — declarations load in this order
159
+ value_object "LoadOrder" do
160
+ attribute :glob, String,
161
+ one_of: ["*.port", "*.adapter", "*.bluebook", "translations/*.bluebook", "*.hecksagon", "*.world"]
162
+ end
163
+
164
+ # CommandInterpreter#call — an aggregate command's
165
+ # own interpretation, ending at the events it emits. Reaction (policies,
166
+ # sagas) is a structurally separate phase and is not part
167
+ # of this : CommandInterpreter#call returns before it runs, in a
168
+ # different class — reaction is
169
+ # what a command's OWN emitted events cause, not what interpreting
170
+ # the command does. Two conditional steps — assign_creation_attributes only
171
+ # fires for a creating command, advance_lifecycle only when a transition
172
+ # applies — so this is the order a command that does both follows,
173
+ # confirmed by tracing a real dispatch, not read off the source.
174
+ value_object "AggregateDispatchOrder" do
175
+ attribute :step, String,
176
+ one_of: ["refuse_unknown_arguments", "refuse_absent_arguments", "normalize_args",
177
+ "refuse_role_mismatch", "resolve_references", "hydrate", "enforce_givens",
178
+ "admissible_transition", "assign_creation_attributes", "apply_mutations",
179
+ "advance_lifecycle", "delegate_to_entity", "enforce_ensures", "enforce_invariants",
180
+ "save", "emit"]
181
+ end
182
+
183
+ # EntityInterpreter#call — the same shape
184
+ # one level down, on a piece an aggregate holds rather than the aggregate
185
+ # itself. `refuse_unknown_arguments`/`refuse_absent_arguments` lead it,
186
+ # the same position they hold in AggregateDispatchOrder — bug audit H1
187
+ # (docs/audits/2026-08-10-main-bug-audit.md): an entity command used to
188
+ # run NEITHER at all, on a since-corrected comment claiming it "inherits
189
+ # its aggregate's own gate" — nothing on this path ever ran one, and a
190
+ # bogus argument or a silently-nil'd absent one both went straight
191
+ # through. The only real difference from AggregateDispatchOrder now is
192
+ # that an entity is never CREATED through this path (no
193
+ # assign_creation_attributes) — hydrating the parent and locating the
194
+ # element replace a single hydrate. resolve_references stayed, though —
195
+ # an entity command can declare a reference-typed attribute the same way
196
+ # an aggregate command can (CommandRules#resolve_references is shared by
197
+ # both interpreters), even though nothing in the real corpus does yet.
198
+ value_object "EntityDispatchOrder" do
199
+ attribute :step, String,
200
+ one_of: ["refuse_unknown_arguments", "refuse_absent_arguments", "normalize_args",
201
+ "refuse_role_mismatch", "resolve_references", "hydrate_parent",
202
+ "locate_element", "enforce_givens", "admissible_transition", "apply_mutations",
203
+ "advance_lifecycle", "enforce_ensures", "enforce_invariants", "save", "emit"]
204
+ end
205
+
206
+ # Runtime::Errors::DOMAIN_REFUSALS — what counts as the domain judging,
207
+ # as opposed to the runtime breaking. Anything outside this set that reaches
208
+ # a refusal list is a bug wearing a refusal's clothes.
209
+ value_object "DomainRefusal" do
210
+ attribute :name, String,
211
+ one_of: ["AbsentArgument", "AlreadyExists", "AttributeAbsent", "EnsuresNotMet", "GivenNotMet",
212
+ "InvariantViolation", "LifecycleRefused", "NothingToCorrect", "NotFound", "ProjectionAbsent",
213
+ "RemoteRefusal", "TypeMismatch", "Unauthorized", "UnknownArgument", "UnknownVerb"]
214
+ end
215
+
216
+ # THE WORDING ITSELF, for every DomainRefusal site that is not already
217
+ # data — `given`/`ensures`/a declared `invariant` already carry their own
218
+ # description, read at dispatch time off the command or value object that
219
+ # declared them. Everything here is different in kind: a LANGUAGE-LEVEL
220
+ # refusal, the same wording for every domain, not authored per-bluebook —
221
+ # closer to Comparison/SignTest beside it than to a given. So it follows
222
+ # THEIR pattern, not given's: declared here for a human to read and a
223
+ # conformance spec to hold equal, and a hand-typed table
224
+ # (RefusalWording) is what a dispatch
225
+ # actually reads — the same reason Evaluator::SIGN_TEST_OPERATORS is
226
+ # hand-typed rather than read live off this very chapter at every call.
227
+ #
228
+ # `{name}` markers are placeholders — plain text substitution, not
229
+ # expression syntax ; a template is read, never evaluated. Two call
230
+ # sites that happen to raise the same sentence share one `site` row
231
+ # (entity_interpreter.rb and command_interpreter.rb's own "not found"
232
+ # messages, for instance) rather than being declared as two facts that
233
+ # would have to be kept identical by hand.
234
+ value_object "RefusalTemplate" do
235
+ attribute :refusal, String, admits: "Vocabulary::DomainRefusal"
236
+ attribute :site, String
237
+ attribute :template, String
238
+
239
+ member refusal: "NotFound", site: "creating_no_identity",
240
+ template: "{command} creates a {aggregate} — pass {identity}:"
241
+ member refusal: "AlreadyExists", site: "creating_duplicate",
242
+ template: "{command} creates a {aggregate} that already exists — {identity} {offered}"
243
+ member refusal: "AlreadyExists", site: "entity_duplicate",
244
+ template: "a {entity} already exists on {aggregate} — {identity} {offered}"
245
+ member refusal: "NotFound", site: "acting_no_identity",
246
+ template: "{command} acts on an existing {aggregate} — pass {identity}:"
247
+ member refusal: "NotFound", site: "record_missing",
248
+ template: "no {aggregate} with {identity} {offered}"
249
+ member refusal: "NotFound", site: "entity_parent_no_identity",
250
+ template: "{command} acts on a {aggregate}'s {entity} — pass {identity}:"
251
+ member refusal: "UnknownVerb", site: "entity_unknown",
252
+ template: "{aggregate} has no entity {entity}"
253
+ member refusal: "NotFound", site: "entity_element_no_identity",
254
+ template: "{command} acts on one {entity} — pass {identity}:"
255
+ member refusal: "NotFound", site: "entity_element_missing",
256
+ template: "no {entity} with {identity} {wants} on {aggregate} {parent_id}"
257
+ member refusal: "NotFound", site: "reference_target_missing",
258
+ template: "no {target} with {heads} {key}"
259
+ member refusal: "NotFound", site: "read_model_reference_missing",
260
+ template: "no {aggregate} with reference {offered}"
261
+ member refusal: "TypeMismatch", site: "read_model_object_reference",
262
+ template: "{query} refused — a reference is an id, and {field} arrived as an object"
263
+ member refusal: "UnknownVerb", site: "no_query",
264
+ template: "{aggregate} has no query {query}"
265
+ member refusal: "UnknownVerb", site: "entity_query_missing",
266
+ template: "{entity} has no query {query}"
267
+ member refusal: "UnknownVerb", site: "entity_holds_no_list",
268
+ template: "{aggregate} holds no list of {entity}"
269
+ member refusal: "UnknownVerb", site: "entity_no_command",
270
+ template: "{entity} has no command {command}"
271
+ member refusal: "UnknownVerb", site: "aggregate_no_command",
272
+ template: "{aggregate} has no command {command}"
273
+ member refusal: "UnknownVerb", site: "port_no_operation",
274
+ template: "{port} has no operation {operation}"
275
+ member refusal: "UnknownVerb", site: "no_domain",
276
+ template: "no domain {domain} loaded (verb {verb})"
277
+ member refusal: "UnknownVerb", site: "no_read_model",
278
+ template: "{domain} has no read model {query}"
279
+ member refusal: "UnknownVerb", site: "not_fully_qualified",
280
+ template: "{verb} is not a fully-qualified verb (Domain::Aggregate.Command)"
281
+ member refusal: "UnknownVerb", site: "no_aggregate",
282
+ template: "{domain} has no aggregate {aggregate}"
283
+ member refusal: "LifecycleRefused", site: "transition_blocked",
284
+ template: "{command} refused — {field} is {current}, and {command} moves it only from {allowed}"
285
+ member refusal: "TypeMismatch", site: "value_object_shape",
286
+ template: "{name} is a {type} — pass its fields as an object, not {offered}"
287
+ member refusal: "TypeMismatch", site: "reference_as_object",
288
+ template: "{command} refused — a reference is an id, and {attribute} arrived as an object{known_by}"
289
+ member refusal: "TypeMismatch", site: "multi_field_scalar",
290
+ template: "{type} has multiple fields and cannot stand in for a scalar"
291
+ member refusal: "TypeMismatch", site: "composite_identity",
292
+ template: "{type} is a composite identity — an identity must have exactly one field"
293
+ member refusal: "TypeMismatch", site: "numeric_field",
294
+ template: "{type}.{field} expects {expected}, got {offered}"
295
+ member refusal: "TypeMismatch", site: "non_finite_field",
296
+ template: "{type}.{field} must be a finite number, got {offered}"
297
+ member refusal: "TypeMismatch", site: "pattern_mismatch",
298
+ template: "{type}.{field} must match {pattern}, got {offered}"
299
+ member refusal: "TypeMismatch", site: "arithmetic_amount",
300
+ template: "{op} of {target} needs an Integer, got {offered}"
301
+ member refusal: "TypeMismatch", site: "arithmetic_current",
302
+ template: "{op} of {target} needs an Integer {target}, got {offered}"
303
+ member refusal: "TypeMismatch", site: "arithmetic_shared_field",
304
+ template: "{op} of {target} needs a value object with one shared Integer field"
305
+ member refusal: "UnknownArgument", site: "unknown_args",
306
+ template: "{command} does not declare {unknown} — it takes {declared}"
307
+ member refusal: "AbsentArgument", site: "absent_args",
308
+ template: "{command} was not given {absent} — it takes {declared}"
309
+ member refusal: "InvariantViolation", site: "closed_set_member",
310
+ template: "{type} admits {admitted} — got {offered}"
311
+ member refusal: "InvariantViolation", site: "value_object_invariant",
312
+ template: "{name} invariant violated — {description} (given {offered})"
313
+ member refusal: "InvariantViolation", site: "admits_declared_set",
314
+ template: "{name} admits {admits} — {admitted} — got {offered}"
315
+ member refusal: "InvariantViolation", site: "undeclared_set",
316
+ template: "{name} admits {admits}, which this chapter does not declare — a closed set is named " \
317
+ "Aggregate::SetName, and it must be one the bluebook actually holds"
318
+ member refusal: "Unauthorized", site: "tenant_required",
319
+ template: "{query} declares authorize with tenant: {field} — pass {field}: to name which " \
320
+ "{field} this ask is scoped to"
321
+ member refusal: "Unauthorized", site: "role_mismatch",
322
+ template: "{command} refused — role: {role}, and the caller stated {caller_role}"
323
+ member refusal: "AttributeAbsent", site: "absent_read",
324
+ template: "{aggregate} {field} is absent on this record — declared, not optional, and " \
325
+ "added since it was written. Backfill it in a translation (backfill :{field}, " \
326
+ "default: ...), or declare it optional: true"
327
+ # S12, ADR 0025 — the same silent-wrong-answer class AttributeAbsent
328
+ # above refuses, one line up: a `projects` field this record predates,
329
+ # or that no rebuild sweep has populated yet, read by a rule as
330
+ # though it were a real value rather than one nobody has copied over.
331
+ member refusal: "ProjectionAbsent", site: "absent_read",
332
+ template: "{aggregate} {field} is not yet projected on this record — declared via " \
333
+ "projects :{field}, but no rebuild sweep has populated it. Run the sweep, " \
334
+ "or read {reference}.{remote_field} directly if this rule cannot wait"
335
+ end
336
+
337
+ # SagaInterpreter::REFUSED.
338
+ #
339
+ # A leg answers an EVENT — `on "AccountDebited"` — or it answers one of these,
340
+ # which are not events at all: no aggregate announces that a leg the procedure
341
+ # dispatched was declined. `on :refused` is the compensating leg, and without
342
+ # this declaration the word lived only as a magic string in the interpreter,
343
+ # and a reader of the language could not discover the
344
+ # trigger existed.
345
+ value_object "Trigger" do
346
+ attribute :name, String, one_of: ["refused"]
347
+ end
348
+
349
+ # Hecks::Forms::FieldShape's own EMAIL_HINT/URL_HINT/
350
+ # TEL_HINT/TEXTAREA_HINT (lib/hecks/forms/field_shape.rb)
351
+ # — the regexes `text_field` matches a text attribute's own NAME
352
+ # against (case-insensitively) to guess an HTML input type or a
353
+ # textarea kind, when nothing more specific (a `pattern:`, an
354
+ # `admits:`, a closed set) already answered the question. Declared
355
+ # here for the same reason RefusalTemplate is: a LANGUAGE-LEVEL
356
+ # rendering convention, the same guess for every domain, not
357
+ # authored per-bluebook — closer to Comparison/SignTest than to a
358
+ # given. `pattern` is the regex SOURCE, no delimiters or flags
359
+ # (Ruby's own `Regexp#source`) — spec/field_hint_conformance_spec.rb
360
+ # holds FieldShape's four hand-typed constants equal to this, both
361
+ # directions, the same conformance shape refusal_wording_
362
+ # conformance_spec.rb already holds RefusalTemplate to.
363
+ #
364
+ # `resolves_to` names WHICH Field attribute a match sets — `html_type`
365
+ # for email/url/tel (three candidates, only one wins, checked in that
366
+ # order), `kind` for textarea (checked separately, and only once
367
+ # html_type has already fallen through to "text").
368
+ value_object "FieldHint" do
369
+ attribute :name, String
370
+ attribute :pattern, String
371
+ attribute :resolves_to, String
372
+
373
+ member name: "email", pattern: 'email', resolves_to: "html_type"
374
+ member name: "url", pattern: '\b(url|uri|website|link)\b', resolves_to: "html_type"
375
+ member name: "tel", pattern: 'phone|\btel(ephone)?\b', resolves_to: "html_type"
376
+ member name: "textarea", pattern: '\b(text|body|note|notes|description|message|comment)\b', resolves_to: "kind"
377
+ end
378
+ end
379
+ end
@@ -0,0 +1,51 @@
1
+ Hecks.bluebook "Hecksagon" do
2
+ aggregate "AdapterBinding" do
3
+ description "One aggregate-to-adapter binding inside a hecksagon — the verb it answers, the adapter it names. Its own root because a hecksagon's binds are an open set of verbs (one per declared port), which no value object can hold — the same reasoning Wiring carries for a world's settings."
4
+
5
+ # The retained parent edge is structural state. `hecksagon` below is
6
+ # separately the text component of this binding's own compound identity,
7
+ # so the relationship keeps the same explicit `_ref` distinction World::
8
+ # Wiring uses for its parent edge.
9
+ belongs_to Hecksagon, as: :hecksagon_ref
10
+
11
+ # THE HECKSAGON IT IS IN, THE AGGREGATE IT NAMES, THE VERB IT ANSWERS.
12
+ # One hecksagon binds one adapter per (aggregate, verb) pair — that is
13
+ # what a binding IS — so the triple identifies it.
14
+ identified_by :hecksagon, :aggregate, :verb
15
+
16
+ attribute :hecksagon, BindingText
17
+ attribute :aggregate, BindingText
18
+ attribute :verb, BindingText
19
+ attribute :adapter, BindingText
20
+ attribute :role, BindingText, optional: true
21
+
22
+ value_object "BindingText" do
23
+ attribute :value, String
24
+ end
25
+
26
+ command "Bind" do
27
+ role "Deployment"
28
+ goal "Name the adapter one aggregate answers one verb through"
29
+
30
+ # A creating command receives the parent's identity as an ordinary
31
+ # value fact. It does not declare a behavioral relationship or use the
32
+ # parent as a hidden receiver.
33
+ attribute :hecksagon_ref, HecksagonName
34
+ attribute :aggregate, BindingText
35
+ attribute :verb, BindingText
36
+ attribute :adapter, BindingText
37
+ attribute :role, BindingText, optional: true
38
+
39
+ given("a binding names its verb") { !verb.value.to_s.empty? }
40
+
41
+ sets :hecksagon_ref
42
+ sets :hecksagon
43
+ sets :aggregate
44
+ sets :verb
45
+ sets :adapter
46
+ sets :role
47
+
48
+ emits "Bound"
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,76 @@
1
+ Hecks.bluebook "Hecksagon" do
2
+ aggregate "DomainPort" do
3
+ description "A primary port — the boundary between a domain and its adapters, in hexagonal terms, is exactly what a hecksagon already IS for every other port. Root-level (belongs to the chapter) or aggregate-scoped (reached the same way persisted_by is, through the open Const.verb(...) door). One of two shapes, never both: a list of operations translating an inbound fact into this domain's own events, or a bare verb naming a swappable resource port (the same Hecks.port a project's own .port file declares, reached from inside the hecksagon instead)."
4
+
5
+ identified_by PortName, as: :name
6
+
7
+ attribute :verb, PortVerb, optional: true
8
+
9
+ value_object "PortName" do
10
+ attribute :value, String
11
+ invariant("a port is named") { !value.to_s.empty? }
12
+ end
13
+
14
+ value_object "PortVerb" do
15
+ attribute :value, String
16
+ invariant("a verb is named") { !value.to_s.empty? }
17
+ end
18
+
19
+ # HOW DOMAINPORT IS SPELLED. These rows live with the concept
20
+ # they describe; SyntaxBoot discovers every aggregate-local seed table.
21
+ # Contexts represented here: DomainPort.
22
+ value_object "KeywordSeed" do
23
+ attribute :word, String
24
+ attribute :context, String, admits: "Syntax::Context"
25
+ attribute :body, String, admits: "Syntax::Body"
26
+ attribute :inner, String
27
+ attribute :opens, String
28
+ attribute :fills, String
29
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
30
+ attribute :was, String
31
+ attribute :resolves_via, String, default: "", admits: "Syntax::ResolutionScope"
32
+ attribute :disambiguator, String, default: "", admits: "Syntax::Disambiguator"
33
+
34
+ member word: "operation", context: "DomainPort", body: "keywords", inner: "PortOperation", opens: "PortOperation", fills: "", calls: "tells_impl"
35
+ member word: "tells", context: "DomainPort", body: "keywords", inner: "PortOperation", opens: "PortOperation", fills: "", calls: "tells_impl"
36
+ member word: "asks", context: "DomainPort", body: "keywords", inner: "PortOperation", opens: "PortOperation", fills: "", calls: "asks_impl"
37
+ member word: "verb", context: "DomainPort", body: "none", inner: "", opens: "", fills: "verb"
38
+
39
+ end
40
+
41
+ value_object "ArgumentSeed" do
42
+ attribute :keyword, String
43
+ attribute :context, String, admits: "Syntax::Context"
44
+ attribute :at, String
45
+ attribute :named, String
46
+ attribute :kind, String, admits: "Syntax::ArgumentKind"
47
+ attribute :required, String
48
+ attribute :fills, String
49
+ attribute :selects, String
50
+ attribute :pair_key_fills, String
51
+ attribute :pair_value_fills, String
52
+ attribute :pairs_shape, String, admits: "Syntax::PairsShape"
53
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
54
+ attribute :variadic, String
55
+ attribute :coerce, String
56
+ attribute :blank_message, String
57
+
58
+ member keyword: "operation", context: "DomainPort", at: "1", named: "", kind: "text", required: "true", fills: "name"
59
+ member keyword: "tells", context: "DomainPort", at: "1", named: "", kind: "text", required: "true", fills: "name"
60
+ member keyword: "asks", context: "DomainPort", at: "1", named: "", kind: "text", required: "true", fills: "name"
61
+ member keyword: "verb", context: "DomainPort", at: "1", named: "", kind: "text", required: "true", fills: "verb"
62
+
63
+ # THE RECEIVING AGGREGATE — PortOperationBuilder's own `reference_to`
64
+ # (inside the block) is refused (#335); this is the sanctioned
65
+ # replacement, named directly on the word that opens the block
66
+ # rather than a statement inside it. `kind: "constant"`, matching
67
+ # `reference_to`'s own first positional argument
68
+ # (port_operation.bluebook) — same bareword-constant resolution,
69
+ # just moved.
70
+ member keyword: "operation", context: "DomainPort", at: "", named: "to", kind: "constant", required: "false", fills: "to"
71
+ member keyword: "tells", context: "DomainPort", at: "", named: "to", kind: "constant", required: "false", fills: "to"
72
+ member keyword: "asks", context: "DomainPort", at: "", named: "to", kind: "constant", required: "false", fills: "to"
73
+
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,131 @@
1
+ Hecks.bluebook "Hecksagon" do
2
+ aggregate "Hecksagon" do
3
+ description "One .hecksagon — the events a domain subscribes to, and the root every binding hangs off. A sibling artifact to the bluebook, not part of it."
4
+
5
+ identified_by HecksagonName, as: :domain
6
+
7
+ attribute :subscriptions, list_of(Subscription)
8
+ attribute :framework_members, list_of(FrameworkMember)
9
+ attribute :vendored_bluebooks, list_of(VendoredBluebook)
10
+
11
+ value_object "HecksagonName" do
12
+ attribute :value, String
13
+ invariant("a hecksagon names its domain") { !value.to_s.empty? }
14
+ end
15
+
16
+ value_object "Subscription" do
17
+ attribute :value, String
18
+ invariant("a subscription names an event") { !value.to_s.empty? }
19
+ end
20
+
21
+ # A `framework/bluebook/` member this hecksagon attaches — Governance,
22
+ # Identity, whatever else lands beside them. Same shape as
23
+ # `Subscription` beside it, one word over.
24
+ value_object "FrameworkMember" do
25
+ attribute :value, String
26
+ invariant("a framework member is named") { !value.to_s.empty? }
27
+ end
28
+
29
+ # A vendored, external bluebook this hecksagon attaches — one level
30
+ # further out than `FrameworkMember`: not a member shipped inside
31
+ # hecks's own lib/, but a separate package vendored into the
32
+ # consuming project's own checkout. Same shape as `FrameworkMember`
33
+ # beside it, one word over — see EmbryonautBluebook's own header.
34
+ value_object "VendoredBluebook" do
35
+ attribute :value, String
36
+ invariant("a vendored bluebook is named") { !value.to_s.empty? }
37
+ end
38
+
39
+ command "Declare" do
40
+ role "Deployment"
41
+ goal "Open a hecksagon for a domain"
42
+
43
+ attribute :domain, HecksagonName
44
+
45
+ sets :domain
46
+
47
+ emits "HecksagonDeclared"
48
+ end
49
+
50
+ command "Subscribe" do
51
+ role "Deployment"
52
+ goal "Take a hecksagon's own event, from outside the domain's own bluebook"
53
+
54
+ attribute :event, Subscription
55
+
56
+ sets :subscriptions, append: { value: :event }
57
+
58
+ emits "SubscriptionAdded"
59
+ end
60
+
61
+ command "UsesFramework" do
62
+ role "Deployment"
63
+ goal "Attach a framework/bluebook/ member to this hecksagon"
64
+
65
+ attribute :member, FrameworkMember
66
+
67
+ sets :framework_members, append: { value: :member }
68
+
69
+ emits "FrameworkMemberAttached"
70
+ end
71
+
72
+ command "UsesEmbryonautBluebook" do
73
+ role "Deployment"
74
+ goal "Attach a vendored, external bluebook to this hecksagon"
75
+
76
+ attribute :package, VendoredBluebook
77
+
78
+ sets :vendored_bluebooks, append: { value: :package }
79
+
80
+ emits "VendoredBluebookAttached"
81
+ end
82
+
83
+ # HOW HECKSAGON IS SPELLED. These rows live with the concept
84
+ # they describe; SyntaxBoot discovers every aggregate-local seed table.
85
+ # Contexts represented here: File, Hecksagon.
86
+ value_object "KeywordSeed" do
87
+ attribute :word, String
88
+ attribute :context, String, admits: "Syntax::Context"
89
+ attribute :body, String, admits: "Syntax::Body"
90
+ attribute :inner, String
91
+ attribute :opens, String
92
+ attribute :fills, String
93
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
94
+ attribute :was, String
95
+ attribute :resolves_via, String, default: "", admits: "Syntax::ResolutionScope"
96
+ attribute :disambiguator, String, default: "", admits: "Syntax::Disambiguator"
97
+
98
+ member word: "hecksagon", context: "File", body: "keywords", inner: "Hecksagon", opens: "Hecksagon", fills: ""
99
+ member word: "subscribe", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "subscriptions"
100
+ member word: "uses_framework", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "framework_members"
101
+ member word: "uses_embryonaut_bluebook", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "vendored_bluebooks"
102
+ member word: "port", context: "Hecksagon", body: "keywords", inner: "DomainPort", opens: "DomainPort", fills: "", calls: "port_impl"
103
+
104
+ end
105
+
106
+ value_object "ArgumentSeed" do
107
+ attribute :keyword, String
108
+ attribute :context, String, admits: "Syntax::Context"
109
+ attribute :at, String
110
+ attribute :named, String
111
+ attribute :kind, String, admits: "Syntax::ArgumentKind"
112
+ attribute :required, String
113
+ attribute :fills, String
114
+ attribute :selects, String
115
+ attribute :pair_key_fills, String
116
+ attribute :pair_value_fills, String
117
+ attribute :pairs_shape, String, admits: "Syntax::PairsShape"
118
+ attribute :status, String, default: "admitted", admits: "Syntax::Status"
119
+ attribute :variadic, String
120
+ attribute :coerce, String
121
+ attribute :blank_message, String
122
+
123
+ member keyword: "hecksagon", context: "File", at: "1", named: "", kind: "text", required: "true", fills: "domain"
124
+ member keyword: "subscribe", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "subscriptions"
125
+ member keyword: "uses_framework", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "framework_members"
126
+ member keyword: "uses_embryonaut_bluebook", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "vendored_bluebooks"
127
+ member keyword: "port", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "name"
128
+
129
+ end
130
+ end
131
+ end