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,143 @@
1
+ require_relative "dispatcher"
2
+ require_relative "instance"
3
+ require_relative "event"
4
+ require_relative "errors"
5
+ require_relative "../naming"
6
+ require_relative "../adapters/driven/lambda/client"
7
+ require_relative "../ports/persistence/binding_policy"
8
+ require_relative "../ports/persistence/remote_runtime"
9
+
10
+ module Hecks
11
+ module Runtime
12
+ # THE WRITE-SIDE HALF OF LAMBDA ROUTING — `Runtime::Loader.boot`
13
+ # constructs this INSTEAD OF `Dispatcher` when the booted domain's
14
+ # own `.world` declares Lambda routing (see loader.rb's own
15
+ # `dispatcher_class_for`). Matches `Dispatcher`'s public shape
16
+ # closely enough that everything built ON TOP of a dispatcher —
17
+ # `Handle`, `AggregateDoor`, `Facade::Surface` — needs no changes
18
+ # at all: `Handle#run`'s entire contract is
19
+ # `@dispatcher.dispatch("#{fqn}.#{command}", **identity, **args).instance.state`,
20
+ # and both classes answer that identically.
21
+ #
22
+ # READS DELEGATE, WRITES DON'T. `query`/`reference_query` hand off
23
+ # to a REAL `Dispatcher` built over the SAME registry — since that
24
+ # registry's own repositories are ALREADY Lambda-backed
25
+ # (`Adapters::Lambda`, `persisted_by("Lambda")`, Phase 2's other
26
+ # half), the inherited query machinery (`QueryInterpreter`,
27
+ # `Ports::Query::InMemory.execute`) works completely unchanged, no
28
+ # query logic duplicated here. `dispatch` can't delegate the same
29
+ # way: command validation (givens, constraints) has to actually
30
+ # run in Rust for a Lambda-routed domain, not get pre-checked here
31
+ # against incomplete local state and then merely persisted.
32
+ class RemoteDispatcher
33
+ Result = Struct.new(:verb, :instance, :events, keyword_init: true) do
34
+ def id = instance.id
35
+ def state = instance.to_h
36
+ end
37
+
38
+ attr_reader :registry
39
+
40
+ def initialize(registry, region: "us-east-1")
41
+ @registry = registry
42
+ # `File.basename(registry.root)`, not `bluebooks.keys.first` —
43
+ # matches `Adapters::Lambda`'s own function-name resolution
44
+ # exactly (see its own comment on why: one merged Lambda per
45
+ # deploy, not one per attached chapter, and `root` is the one
46
+ # signal every bluebook in this registry shares regardless of
47
+ # which one attached it) — INCLUDING that same adapter's own
48
+ # `ENV["DOMAIN_NAME"]`-first fix: `root` is always `/var/task`
49
+ # inside a deployed Lambda, giving "task" instead of the real
50
+ # domain name (a real, live AccessDeniedException on
51
+ # "hecks-task" caught this).
52
+ @client = Adapters::Lambda::Client.new(domain: ENV["DOMAIN_NAME"] || File.basename(registry.root), region: region)
53
+ # READ-SIDE DELEGATE ONLY (see class comment) — never dispatched
54
+ # through; a real Dispatcher's own `query`/`reference_query`
55
+ # already resolve generically via `registry.repository(...)`,
56
+ # so building one here reuses that instead of duplicating it.
57
+ @local = Dispatcher.new(registry)
58
+ end
59
+
60
+ def dispatch(verb, saga_correlation: nil, **args)
61
+ domain, aggregate_name, = Naming.split_verb(verb) ||
62
+ raise(UnknownVerb,
63
+ RefusalWording.render("UnknownVerb", "not_fully_qualified", verb: verb.inspect))
64
+ aggregate = @registry.bluebook(domain)&.aggregate(aggregate_name) ||
65
+ raise(UnknownVerb,
66
+ RefusalWording.render("UnknownVerb", "no_aggregate", domain: domain, aggregate: aggregate_name.inspect))
67
+
68
+ # NOT EVERY AGGREGATE IN A LAMBDA-ROUTED DOMAIN IS ITSELF
69
+ # LAMBDA-BOUND — Member's real name->email rekey carries a
70
+ # `compute` rule (era_check.rb's own `check_compute_rules!`),
71
+ # which can only ever run against Postgres, permanently. Its
72
+ # OWN `.hecksagon` bind stays "Postgres" even when
73
+ # `dispatched_by("Lambda")` is on for everything else — checked
74
+ # here by real CAPABILITY (`Ports::Persistence::RemoteRuntime`,
75
+ # §1), not by comparing the adapter's own name to the string
76
+ # "Lambda" — a bind resolves to whatever adapter CLASS actually
77
+ # backs it, and only a class shaped like "the real interpreter
78
+ # lives behind a call boundary" forwards here; anything else
79
+ # (Postgres, Memory, any future local adapter) falls through to
80
+ # the real local Dispatcher instead of being forwarded to a
81
+ # Lambda that has no way to represent its lineage history at
82
+ # all.
83
+ adapter_name = Ports::Persistence::BindingPolicy.resolve(@registry, domain, aggregate).adapter
84
+ return @local.dispatch(verb, saga_correlation: saga_correlation, **args) unless @registry.adapter_class(adapter_name) <= Ports::Persistence::RemoteRuntime
85
+
86
+ response = @client.dispatch(verb, args)
87
+
88
+ refusal = response.fetch("refusals", []).find { |r| r["verb"] == verb }
89
+ raise RemoteRefusal, "#{verb} refused: #{refusal['error']}" if refusal
90
+
91
+ # THIS STEP'S OWN mutations — `mutations` is one entry per
92
+ # replayed step (rust/host's rehydrate-and-replay design,
93
+ # Phase 1), so `.last` is exactly the step just dispatched.
94
+ # Matched by fully-qualified aggregate name, not just "the
95
+ # first mutation" — a command whose reaction ALSO mutates a
96
+ # different aggregate (a policy, a saga leg) puts more than
97
+ # one mutation in the same step, and the direct effect of
98
+ # THIS verb is the one this dispatch's own caller expects
99
+ # `.instance` to be.
100
+ fqn = "#{domain}::#{aggregate.hecks_name}"
101
+ mutation = response.fetch("mutations", []).last&.find { |m| m["aggregate"] == fqn } ||
102
+ raise(WiringError,
103
+ "#{verb} was accepted but rust/host reported no mutation for #{fqn} — response: #{response.inspect}")
104
+
105
+ instance = Instance.new(aggregate: aggregate, id: mutation["id"],
106
+ state: JSON.parse(JSON.generate(mutation["state"]), symbolize_names: true))
107
+
108
+ Result.new(verb: verb, instance: instance, events: step_events(response))
109
+ end
110
+
111
+ def query(verb, **args) = @local.query(verb, **args)
112
+ def reference_query(verb, **args) = @local.reference_query(verb, **args)
113
+
114
+ # THE FULL DOMAIN'S EVENT HISTORY, on every call — `{"read":
115
+ # true}` replays the whole journal (Phase 1's `dispatch::read`),
116
+ # so its own `events` array already IS the complete log, the
117
+ # same thing `@registry.event_log` would answer for a local
118
+ # dispatch. Not cached: `AggregateDoor.events`/`Handle#events`
119
+ # are not called in this codebase's own hot paths today: if that
120
+ # changes, caching belongs here, not in every caller.
121
+ def events
122
+ @client.read.fetch("events", []).map { |e| build_event(e) }
123
+ end
124
+
125
+ private
126
+
127
+ def step_events(response)
128
+ response.fetch("events", []).map { |e| build_event(e) }
129
+ end
130
+
131
+ # Rust's own event JSON (kernel/cli.rs's `event_to_json`) carries
132
+ # `name`/`aggregate`/`id`/`payload` only — no `occurred_at`
133
+ # (nothing in the kernel tracks wall-clock time; every
134
+ # replay is deterministic and timestamp-free by design). `nil`
135
+ # here, not a synthesized `Time.now` that would silently lie
136
+ # about when something actually happened.
137
+ def build_event(json)
138
+ Event.new(name: json["name"], aggregate: json["aggregate"], id: json["id"],
139
+ payload: JSON.parse(JSON.generate(json["payload"]), symbolize_names: true), occurred_at: nil)
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,96 @@
1
+ require_relative "errors"
2
+ require_relative "refusal_wording"
3
+
4
+ module Hecks
5
+ module Runtime
6
+ # The invocation address is not part of a command's domain payload.
7
+ # Aggregate commands carry one receiver identity; entity commands carry
8
+ # the aggregate receiver followed by one identity for every entity hop.
9
+ module Routing
10
+ Envelope = Struct.new(:aggregate, :entities, keyword_init: true) do
11
+ def initialize(aggregate:, entities: [])
12
+ super(aggregate: aggregate.to_s, entities: Array(entities).map(&:to_s).freeze)
13
+ freeze
14
+ end
15
+ end
16
+
17
+ module_function
18
+
19
+ def envelope(to, entity_depth: 0)
20
+ return nil if to.nil?
21
+
22
+ aggregate, entities = if to.is_a?(Hash)
23
+ hash = to.transform_keys(&:to_sym)
24
+ unknown = hash.keys - %i[aggregate entity entities]
25
+ unless unknown.empty?
26
+ raise TypeMismatch, "to: does not recognize #{unknown.sort.join(', ')}"
27
+ end
28
+
29
+ [hash[:aggregate], entity_identities(hash)]
30
+ else
31
+ [to, []]
32
+ end
33
+
34
+ if aggregate.nil? || aggregate.to_s.empty?
35
+ raise TypeMismatch, "to: must name the receiving aggregate identity"
36
+ end
37
+ if entities.size != entity_depth
38
+ raise TypeMismatch,
39
+ "to: for an entity command needs #{entity_depth} entity " \
40
+ "#{entity_depth == 1 ? 'identity' : 'identities'} after the aggregate — got #{entities.size}"
41
+ end
42
+ if entities.any? { |identity| identity.nil? || identity.to_s.empty? }
43
+ raise TypeMismatch, "to: contains a blank entity identity"
44
+ end
45
+
46
+ Envelope.new(aggregate: aggregate, entities: entities)
47
+ end
48
+
49
+ # `with:` is deliberately strict. Compatibility-only calls still pass
50
+ # loose keyword arguments through the old addressing gate, but a caller
51
+ # choosing the explicit envelope cannot smuggle receiver identity back
52
+ # into the payload.
53
+ def payload(command, with:, legacy:)
54
+ if with && !legacy.empty?
55
+ raise TypeMismatch, "dispatch takes command facts in with:, not both with: and loose keyword arguments"
56
+ end
57
+
58
+ return legacy unless with
59
+ unless with.is_a?(Hash)
60
+ raise TypeMismatch, "with: must be a hash of command facts"
61
+ end
62
+
63
+ offered = with.transform_keys(&:to_sym)
64
+ declared = command.attributes.map { |attribute| attribute.name.to_sym }
65
+ unknown = (offered.keys - declared).sort
66
+ unless unknown.empty?
67
+ reading = declared.empty? ? "none" : declared.join(", ")
68
+ raise UnknownArgument,
69
+ RefusalWording.render("UnknownArgument", "unknown_args",
70
+ command: command.hecks_name, unknown: unknown.join(", "),
71
+ declared: reading)
72
+ end
73
+
74
+ absent = command.attributes.reject(&:optional?).map { |attribute| attribute.name.to_sym } - offered.keys
75
+ unless absent.empty?
76
+ reading = declared.empty? ? "none" : declared.join(", ")
77
+ raise AbsentArgument,
78
+ RefusalWording.render("AbsentArgument", "absent_args",
79
+ command: command.hecks_name, absent: absent.sort.join(", "),
80
+ declared: reading)
81
+ end
82
+
83
+ offered
84
+ end
85
+
86
+ def entity_identities(hash)
87
+ if hash.key?(:entities) && hash.key?(:entity)
88
+ raise TypeMismatch, "to: takes entity: or entities:, not both"
89
+ end
90
+
91
+ hash.key?(:entities) ? Array(hash[:entities]) : Array(hash[:entity])
92
+ end
93
+ private_class_method :entity_identities
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,97 @@
1
+ require_relative "../value"
2
+
3
+ module Hecks
4
+ module Runtime
5
+ class SagaInterpreter
6
+ # How a saga decides WHICH CONVERSATION an event belongs to — three
7
+ # tiers, each one a lesson.
8
+ module Correlation
9
+ private
10
+
11
+ # A DOTTED PATH NAMES THE SCALAR FIELD, rather than asking a value object
12
+ # to stand in for one. `correlates_by :end_to_end` would key a saga on
13
+ # the whole ExternalTransfer::EndToEndReference — and what a non-scalar
14
+ # correlation key even IS is representation-dependent (the object
15
+ # itself? its serialised text?). `:"end_to_end.value"` reads the one
16
+ # field with a single unambiguous rendering.
17
+ def saga_correlation(pm, event)
18
+ path = pm.correlates_by.to_s.split(".")
19
+ # A LATER EVENT MAY ALREADY HOLD THE SCALAR. `reference.value` digs a
20
+ # value object's field out of a FRESH declaration (TransferRequested's
21
+ # `reference` IS a TransferReference) — but a downstream event this
22
+ # same value was smuggled through as a passthrough argument
23
+ # (AccountDebited's `reference:`, resolved by `dispatch_args` to the
24
+ # bare correlation string) carries it as a scalar already, with
25
+ # nothing left to dig. `"xfer-1".respond_to?(:[])` is true — String
26
+ # has its OWN `[]` (substring indexing) — so checking for keyed
27
+ # lookup explicitly, rather than "responds to `[]` at all", is what
28
+ # stops the second segment from being read as a symbol index into a
29
+ # string that has already arrived.
30
+ value = path.reduce(event.payload) do |held, segment|
31
+ held.is_a?(Hash) || held.is_a?(Value) ? held[segment.to_sym] : held
32
+ end
33
+ return value unless value.to_s.empty?
34
+
35
+ # THE STAMP — `deliver_saga_dispatch` marks its own event before this
36
+ # saga's next step ever asks, for a leg whose command declares
37
+ # NEITHER the correlation field itself nor the emitting aggregate's
38
+ # own reference key (the two tiers above). command_interpreter/
39
+ # argument_gate.rb names the old payload-only lookup "the weakest
40
+ # part of the gate" : a correlation key arriving on a command only
41
+ # because `correlation_keys` widens the undeclared-argument
42
+ # allow-list domain-wide. This is the additive fix — a leg that
43
+ # carries nothing correlation-shaped at all still correlates,
44
+ # because the saga that dispatched it already knows the answer.
45
+ # Keyed by `correlation_head`
46
+ # rather than a bare scalar so an event stamped by one saga cannot be
47
+ # misread by an unrelated one correlating on a different field.
48
+ stamped = event.correlation && event.correlation[pm.correlation_head.to_s]
49
+ return stamped unless stamped.nil? || stamped.to_s.empty?
50
+
51
+ # A SELF-REFERENCING LEG carries the correlation forward under its
52
+ # own emitting record's identity — `event.id`, not a field dug back
53
+ # out of the payload. This used to read `event.payload[own_key]`
54
+ # (`own_key` the aggregate's own reference-key convention, "wire",
55
+ # "transfer"), which only ever held a value because LEGACY dispatch
56
+ # left the self-addressing key riding along in the payload
57
+ # unfiltered. Routing separated from payload (`to:`/`with:`, the
58
+ # facade's own `Handle#run` always uses it) closed exactly that
59
+ # leak — correctly, since an addressing key is not a fact the
60
+ # payload should carry — which left this tier reading an empty
61
+ # Hash for any self-referencing leg with no OTHER declared
62
+ # attributes (`OnboardingCase.Clear`, `.Decline` — no `attribute`
63
+ # lines at all): the saga silently stopped advancing, forever, for
64
+ # exactly the leg this tier exists to correlate.
65
+ #
66
+ # `event.id` says the identical thing this tier always meant —
67
+ # "the record that just emitted this event, by its own identity" —
68
+ # and unlike a payload dig it is populated by the record itself,
69
+ # not by which dispatch convention the caller happened to use.
70
+ #
71
+ # GATED, still — a manually-dispatched command on a wholly
72
+ # UNRELATED aggregate can share an event NAME this pm happens to
73
+ # handle (`Drawer.Take` also emits "Taken", the same name a
74
+ # SAGA-DISPATCHED leg uses) with nothing this saga should read as
75
+ # its own conversation. What makes a leg genuinely
76
+ # self-referencing — the one fact worth trusting `event.id`
77
+ # for — is that `correlates_by`'s own head field IS this event's
78
+ # OWN aggregate's declared identity, not merely a same-shaped
79
+ # name: `OnboardingCase.identity_heads` really does include
80
+ # `:reference`, `correlates_by :"reference.value"`'s own head ;
81
+ # `Drawer.identity_heads` is `[:number]`, nowhere close.
82
+ self_identified?(pm, event) ? event.id : nil
83
+ end
84
+
85
+ def self_identified?(pm, event)
86
+ domain, bare_name = event.aggregate.to_s.split("::", 2)
87
+ return false unless bare_name
88
+
89
+ construct = @registry.bluebook(domain)&.aggregate(bare_name)
90
+ return false unless construct
91
+
92
+ construct.identity_heads.map(&:to_s).include?(pm.correlation_head.to_s)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end