hecks 2.8.0 → 3.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 (886) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +50 -7
  3. data/lib/hecks/adapters/driven/claude_code.rb +4 -104
  4. data/lib/hecks/adapters/driven/d1.rb +44 -237
  5. data/lib/hecks/adapters/driven/folder.rb +17 -76
  6. data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
  7. data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
  8. data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
  9. data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
  10. data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
  11. data/lib/hecks/adapters/driven/heki.rb +13 -42
  12. data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
  13. data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
  14. data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
  15. data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
  16. data/lib/hecks/adapters/driven/lambda.rb +10 -84
  17. data/lib/hecks/adapters/driven/local_storage.rb +5 -40
  18. data/lib/hecks/adapters/driven/memory.rb +32 -100
  19. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
  20. data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
  21. data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
  22. data/lib/hecks/adapters/driven/postgres/reconnect.rb +10 -32
  23. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
  24. data/lib/hecks/adapters/driven/postgres/shared_connection.rb +180 -0
  25. data/lib/hecks/adapters/driven/postgres.rb +149 -136
  26. data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
  27. data/lib/hecks/adapters/driven/prism.rb +48 -38
  28. data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
  29. data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
  30. data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
  31. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
  32. data/lib/hecks/adapters/driven/sqlite.rb +128 -65
  33. data/lib/hecks/adapters/driven/tenant_provisioner.rb +76 -62
  34. data/lib/hecks/adapters/driven.rb +5 -36
  35. data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
  36. data/lib/hecks/behaviors/dsl.rb +7 -25
  37. data/lib/hecks/behaviors/expectations.rb +32 -142
  38. data/lib/hecks/behaviors/ir.rb +7 -20
  39. data/lib/hecks/behaviors/rspec.rb +6 -17
  40. data/lib/hecks/behaviors/runner.rb +10 -34
  41. data/lib/hecks/behaviors.rb +4 -8
  42. data/lib/hecks/bench/cli.rb +62 -0
  43. data/lib/hecks/bench/environment.rb +71 -0
  44. data/lib/hecks/bench/postgres_probe.rb +30 -0
  45. data/lib/hecks/bench/report.rb +76 -0
  46. data/lib/hecks/bench/ruby_runner.rb +93 -0
  47. data/lib/hecks/bench/run.rb +55 -0
  48. data/lib/hecks/bench/rust_runner.rb +101 -0
  49. data/lib/hecks/bench/stats.rb +46 -0
  50. data/lib/hecks/bench/suite.rb +98 -0
  51. data/lib/hecks/bench/workload.rb +89 -0
  52. data/lib/hecks/bench.rb +17 -0
  53. data/lib/hecks/bluebook/aggregate.rb +9 -75
  54. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
  55. data/lib/hecks/bluebook/assembly/build.rb +4 -15
  56. data/lib/hecks/bluebook/assembly/contract.rb +15 -136
  57. data/lib/hecks/bluebook/assembly/contracts.rb +56 -174
  58. data/lib/hecks/bluebook/assembly/marks.rb +31 -223
  59. data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
  60. data/lib/hecks/bluebook/assembly.rb +6 -45
  61. data/lib/hecks/bluebook/attribute.rb +12 -61
  62. data/lib/hecks/bluebook/behaviour/aggregate.rb +39 -39
  63. data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
  64. data/lib/hecks/bluebook/behaviour/chapter.rb +14 -42
  65. data/lib/hecks/bluebook/behaviour/command.rb +14 -66
  66. data/lib/hecks/bluebook/behaviour/domain_port.rb +11 -20
  67. data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
  68. data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
  69. data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
  70. data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
  71. data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
  72. data/lib/hecks/bluebook/behaviour/read_model.rb +25 -31
  73. data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
  74. data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
  75. data/lib/hecks/bluebook/capabilities.rb +17 -49
  76. data/lib/hecks/bluebook/chapter.rb +16 -50
  77. data/lib/hecks/bluebook/command.rb +23 -81
  78. data/lib/hecks/bluebook/domain_port.rb +49 -67
  79. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
  80. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
  81. data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
  82. data/lib/hecks/bluebook/dsl/binding_proxy.rb +16 -69
  83. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +96 -708
  84. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +63 -169
  85. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +3 -1
  86. data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
  87. data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
  88. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +42 -89
  89. data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
  90. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
  91. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +148 -197
  92. data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
  93. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
  94. data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
  95. data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
  96. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
  97. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
  98. data/lib/hecks/bluebook/dsl/query_builder.rb +38 -43
  99. data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
  100. data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
  101. data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
  102. data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
  103. data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
  104. data/lib/hecks/bluebook/dsl/world_builder.rb +46 -111
  105. data/lib/hecks/bluebook/entity.rb +13 -71
  106. data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
  107. data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
  108. data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
  109. data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
  110. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
  111. data/lib/hecks/bluebook/expression/resolver.rb +39 -661
  112. data/lib/hecks/bluebook/hexagon.rb +18 -33
  113. data/lib/hecks/bluebook/lifecycle.rb +5 -16
  114. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
  115. data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
  116. data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
  117. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
  118. data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
  119. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +25 -176
  120. data/lib/hecks/bluebook/meta_validator/shapes.rb +53 -267
  121. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -306
  122. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
  123. data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +246 -0
  124. data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
  125. data/lib/hecks/bluebook/meta_validator.rb +87 -352
  126. data/lib/hecks/bluebook/model_check/client_profile.rb +6 -21
  127. data/lib/hecks/bluebook/model_check.rb +122 -596
  128. data/lib/hecks/bluebook/pattern_subset.rb +49 -69
  129. data/lib/hecks/bluebook/process_manager.rb +13 -83
  130. data/lib/hecks/bluebook/project_loader.rb +3 -39
  131. data/lib/hecks/bluebook/project_register.rb +12 -60
  132. data/lib/hecks/bluebook/query.rb +27 -51
  133. data/lib/hecks/bluebook/read_model.rb +57 -81
  134. data/lib/hecks/bluebook/reference.rb +7 -41
  135. data/lib/hecks/bluebook/smoke_test.rb +9 -99
  136. data/lib/hecks/bluebook/synthesizer.rb +13 -62
  137. data/lib/hecks/bluebook/translation.rb +26 -62
  138. data/lib/hecks/bluebook/value_object.rb +11 -36
  139. data/lib/hecks/bluebook.rb +5 -22
  140. data/lib/hecks/cache_dir.rb +4 -23
  141. data/lib/hecks/canonical_json.rb +30 -0
  142. data/lib/hecks/chapters.rb +102 -0
  143. data/lib/hecks/cli/behaviors.rb +61 -0
  144. data/lib/hecks/cli/canonicalise.rb +25 -0
  145. data/lib/hecks/cli/check_engine_agreement.rb +32 -0
  146. data/lib/hecks/cli/check_era.rb +88 -0
  147. data/lib/hecks/cli/console.rb +66 -0
  148. data/lib/hecks/cli/deploy_template_diff.rb +40 -0
  149. data/lib/hecks/cli/doc_coverage.rb +32 -0
  150. data/lib/hecks/cli/document.rb +5 -23
  151. data/lib/hecks/cli/expression_projection.rb +41 -0
  152. data/lib/hecks/cli/follow.rb +88 -0
  153. data/lib/hecks/cli/history.rb +44 -0
  154. data/lib/hecks/cli/ir.rb +4 -6
  155. data/lib/hecks/cli/mcp.rb +5 -6
  156. data/lib/hecks/cli/model_check.rb +24 -88
  157. data/lib/hecks/cli/pattern_cases.rb +47 -0
  158. data/lib/hecks/cli/present.rb +39 -0
  159. data/lib/hecks/cli/project_cli.rb +223 -64
  160. data/lib/hecks/cli/project_diagrams.rb +4 -10
  161. data/lib/hecks/cli/project_glossary.rb +44 -0
  162. data/lib/hecks/cli/reference.rb +46 -0
  163. data/lib/hecks/cli/refresh_projections.rb +44 -0
  164. data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +150 -0
  165. data/lib/hecks/cli/release.rb +70 -0
  166. data/lib/hecks/cli/release_gem.rb +59 -0
  167. data/lib/hecks/cli/rspec_io_parallel_files.rb +137 -0
  168. data/lib/hecks/cli/rspec_shard_files.rb +66 -0
  169. data/lib/hecks/cli/run.rb +15 -61
  170. data/lib/hecks/cli/seed_semantics_corpus.rb +71 -0
  171. data/lib/hecks/cli/serve_query_ir_mcp.rb +30 -0
  172. data/lib/hecks/cli/shape.rb +70 -0
  173. data/lib/hecks/cli/smoke_http.rb +230 -0
  174. data/lib/hecks/cli/smoke_test.rb +7 -19
  175. data/lib/hecks/cli/spec_example.rb +27 -0
  176. data/lib/hecks/cli/statements.rb +32 -0
  177. data/lib/hecks/cli/stores.rb +4 -6
  178. data/lib/hecks/cli/stress_concurrency_specs.rb +177 -0
  179. data/lib/hecks/cli.rb +216 -73
  180. data/lib/hecks/codemod.rb +324 -0
  181. data/lib/hecks/construct.rb +8 -34
  182. data/lib/hecks/corpus.rb +423 -0
  183. data/lib/hecks/deploy/bluebook/deploy.bluebook +617 -158
  184. data/lib/hecks/deploy/bluebook/deploy.hecksagon +41 -11
  185. data/lib/hecks/deploy/oidc.json +82 -2
  186. data/lib/hecks/doc/reference.rb +351 -0
  187. data/lib/hecks/doors/cli_door.rb +196 -0
  188. data/lib/hecks/doors/cli_runner.rb +297 -0
  189. data/lib/hecks/{facade → doors}/command_request.rb +14 -34
  190. data/lib/hecks/doors/handle.rb +206 -0
  191. data/lib/hecks/doors/json_door.rb +132 -0
  192. data/lib/hecks/doors/launcher_options.rb +129 -0
  193. data/lib/hecks/{cli → doors}/mcp_door.rb +25 -120
  194. data/lib/hecks/doors/mcp_door_scope.rb +97 -0
  195. data/lib/hecks/doors/ruby_door/aggregate_door.rb +162 -0
  196. data/lib/hecks/doors/ruby_door/chapter.rb +72 -0
  197. data/lib/hecks/doors/ruby_door.rb +77 -0
  198. data/lib/hecks/doors.rb +61 -0
  199. data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
  200. data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
  201. data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
  202. data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
  203. data/lib/hecks/embryonaut_bluebook.rb +5 -72
  204. data/lib/hecks/engine_agreement.rb +156 -0
  205. data/lib/hecks/facade.rb +23 -51
  206. data/lib/hecks/forms/app.rb +21 -76
  207. data/lib/hecks/forms/banking_presentation.rb +50 -0
  208. data/lib/hecks/forms/command_form_renderer.rb +10 -29
  209. data/lib/hecks/forms/field_renderer.rb +17 -156
  210. data/lib/hecks/forms/field_shape.rb +31 -222
  211. data/lib/hecks/forms/html.rb +12 -47
  212. data/lib/hecks/forms/index_renderer.rb +1 -4
  213. data/lib/hecks/forms/page.rb +3 -9
  214. data/lib/hecks/forms/params.rb +14 -60
  215. data/lib/hecks/forms/port_argument.rb +2 -19
  216. data/lib/hecks/forms/query_form_renderer.rb +4 -79
  217. data/lib/hecks/forms/record_renderer.rb +8 -75
  218. data/lib/hecks/forms/record_table.rb +7 -50
  219. data/lib/hecks/forms/reference_options.rb +3 -30
  220. data/lib/hecks/forms/value_object_shape.rb +8 -35
  221. data/lib/hecks/forms.rb +5 -33
  222. data/lib/hecks/fqn.rb +5 -12
  223. data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
  224. data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
  225. data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
  226. data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
  227. data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
  228. data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
  229. data/lib/hecks/framework.rb +11 -80
  230. data/lib/hecks/freezer.rb +5 -39
  231. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +393 -0
  232. data/lib/hecks/fuzzing/combination_miner.rb +86 -0
  233. data/lib/hecks/fuzzing/concurrent_dispatch.rb +214 -0
  234. data/lib/hecks/fuzzing/coverage_campaign.rb +143 -0
  235. data/lib/hecks/fuzzing/differential.rb +156 -0
  236. data/lib/hecks/fuzzing/domain_generator.rb +615 -0
  237. data/lib/hecks/fuzzing/era_boundary.rb +71 -0
  238. data/lib/hecks/fuzzing/form_census.rb +136 -0
  239. data/lib/hecks/fuzzing/generated_domain_check.rb +93 -0
  240. data/lib/hecks/fuzzing/invalid_value_generator.rb +64 -0
  241. data/lib/hecks/fuzzing/isolated_boot.rb +301 -0
  242. data/lib/hecks/fuzzing/nondeterministic.rb +51 -0
  243. data/lib/hecks/fuzzing/outside_world.rb +45 -0
  244. data/lib/hecks/fuzzing/persistence_parity.rb +102 -0
  245. data/lib/hecks/fuzzing/properties/corrections.rb +88 -0
  246. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +314 -0
  247. data/lib/hecks/fuzzing/properties/guards.rb +190 -0
  248. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +300 -0
  249. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +93 -0
  250. data/lib/hecks/fuzzing/properties/outbox.rb +89 -0
  251. data/lib/hecks/fuzzing/properties/querying.rb +175 -0
  252. data/lib/hecks/fuzzing/properties.rb +162 -0
  253. data/lib/hecks/fuzzing/qa_settings.rb +123 -0
  254. data/lib/hecks/fuzzing/replay.rb +505 -0
  255. data/lib/hecks/fuzzing/rotation_priority.rb +48 -0
  256. data/lib/hecks/fuzzing/rust_gap_manifest.rb +108 -0
  257. data/lib/hecks/fuzzing/self_consistency.rb +339 -0
  258. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +385 -0
  259. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +132 -0
  260. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +95 -0
  261. data/lib/hecks/fuzzing/sequence_generator/picker.rb +77 -0
  262. data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +109 -0
  263. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +237 -0
  264. data/lib/hecks/fuzzing/sequence_generator.rb +189 -0
  265. data/lib/hecks/fuzzing/shrinker.rb +166 -0
  266. data/lib/hecks/fuzzing/structural_skips.rb +33 -0
  267. data/lib/hecks/fuzzing/sweep_depth.rb +43 -0
  268. data/lib/hecks/fuzzing/target_capabilities.rb +163 -0
  269. data/lib/hecks/fuzzing/value_generator.rb +216 -0
  270. data/lib/hecks/fuzzing.rb +23 -0
  271. data/lib/hecks/grammar/evolve.rb +336 -0
  272. data/lib/hecks/grammar/expression.bluebook +15 -40
  273. data/lib/hecks/grammar/translation.bluebook +3 -6
  274. data/lib/hecks/grammar.rb +16 -41
  275. data/lib/hecks/hecks/adapters/codebase/codemods.rb +45 -0
  276. data/lib/hecks/hecks/adapters/codebase/conformance.rb +71 -0
  277. data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +202 -0
  278. data/lib/hecks/hecks/adapters/codebase/gem_registry.rb +80 -0
  279. data/lib/hecks/hecks/adapters/codebase/kernel_tables.rb +54 -0
  280. data/lib/hecks/hecks/adapters/codebase/language.rb +240 -0
  281. data/lib/hecks/hecks/adapters/codebase/npm_registry.rb +102 -0
  282. data/lib/hecks/hecks/adapters/codebase/publishing.rb +142 -0
  283. data/lib/hecks/hecks/adapters/codebase/regeneration.rb +67 -0
  284. data/lib/hecks/hecks/adapters/codebase/release_facts.rb +90 -0
  285. data/lib/hecks/hecks/adapters/codebase/ruby_child.rb +83 -0
  286. data/lib/hecks/hecks/adapters/codebase/secret_vault.rb +36 -0
  287. data/lib/hecks/hecks/adapters/codebase/source_tree.adapter +7 -0
  288. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +189 -0
  289. data/lib/hecks/hecks/adapters/codebase/sqlite_fixture.rb +71 -0
  290. data/lib/hecks/hecks/adapters/codebase/style.rb +171 -0
  291. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +55 -0
  292. data/lib/hecks/hecks/adapters/codebase/test_suite.rb +165 -0
  293. data/lib/hecks/hecks/adapters/codebase/tree.rb +111 -0
  294. data/lib/hecks/hecks/adapters/console_capture.rb +79 -0
  295. data/lib/hecks/hecks/adapters/deploy_toolchain.adapter +7 -0
  296. data/lib/hecks/hecks/adapters/deploy_toolchain.rb +108 -0
  297. data/lib/hecks/hecks/adapters/git.adapter +7 -0
  298. data/lib/hecks/hecks/adapters/git.rb +102 -0
  299. data/lib/hecks/hecks/adapters/host_http.adapter +7 -0
  300. data/lib/hecks/hecks/adapters/host_http.rb +65 -0
  301. data/lib/hecks/hecks/adapters/in_process_boot.adapter +7 -0
  302. data/lib/hecks/hecks/adapters/in_process_boot.rb +197 -0
  303. data/lib/hecks/hecks/adapters/in_process_operations.rb +202 -0
  304. data/lib/hecks/hecks/adapters/journal_store/changes.rb +143 -0
  305. data/lib/hecks/hecks/adapters/journal_store/compaction.rb +145 -0
  306. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +132 -0
  307. data/lib/hecks/hecks/adapters/journal_store/examination.rb +135 -0
  308. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +163 -0
  309. data/lib/hecks/hecks/adapters/journal_store/readings.rb +187 -0
  310. data/lib/hecks/hecks/adapters/journal_store.adapter +7 -0
  311. data/lib/hecks/hecks/adapters/journal_store.rb +64 -0
  312. data/lib/hecks/hecks/adapters/local_files.adapter +7 -0
  313. data/lib/hecks/hecks/adapters/local_files.rb +46 -0
  314. data/lib/hecks/hecks/adapters/pg_admin.adapter +7 -0
  315. data/lib/hecks/hecks/adapters/pg_admin.rb +245 -0
  316. data/lib/hecks/hecks/adapters/process_pool.adapter +7 -0
  317. data/lib/hecks/hecks/adapters/process_pool.rb +119 -0
  318. data/lib/hecks/hecks/adapters/rust_toolchain.adapter +7 -0
  319. data/lib/hecks/hecks/adapters/rust_toolchain.rb +179 -0
  320. data/lib/hecks/hecks/adapters/rust_workspace.rb +150 -0
  321. data/lib/hecks/hecks/adapters/shell.adapter +7 -0
  322. data/lib/hecks/hecks/adapters/shell.rb +49 -0
  323. data/lib/hecks/hecks/adapters/terminal.adapter +7 -0
  324. data/lib/hecks/hecks/adapters/terminal.rb +74 -0
  325. data/lib/hecks/hecks/codebase.behaviors +172 -0
  326. data/lib/hecks/hecks/codebase.bluebook +2453 -0
  327. data/lib/hecks/hecks/context_map.hecksagon +13 -0
  328. data/lib/hecks/hecks/custodian.behaviors +179 -0
  329. data/lib/hecks/hecks/custodian.bluebook +1847 -0
  330. data/lib/hecks/hecks/deploy.behaviors +74 -0
  331. data/lib/hecks/hecks/deploy.world +12 -0
  332. data/lib/hecks/hecks/environments/memory.world +10 -0
  333. data/lib/hecks/hecks/governance.world +7 -0
  334. data/lib/hecks/hecks/hecks.behaviors +62 -0
  335. data/lib/hecks/hecks/hecks.bluebook +124 -0
  336. data/lib/hecks/hecks/hecks.hecksagon +390 -0
  337. data/lib/hecks/hecks/hecks.world +42 -0
  338. data/lib/hecks/ir.rb +14 -83
  339. data/lib/hecks/kernel_capabilities.rb +194 -0
  340. data/lib/hecks/language/adapter.bluebook +2 -7
  341. data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
  342. data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
  343. data/lib/hecks/language/bluebook/bluebook.bluebook +26 -83
  344. data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
  345. data/lib/hecks/language/bluebook/command.bluebook +27 -144
  346. data/lib/hecks/language/bluebook/entity.bluebook +24 -97
  347. data/lib/hecks/language/bluebook/policy.bluebook +16 -67
  348. data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
  349. data/lib/hecks/language/bluebook/projection.bluebook +126 -60
  350. data/lib/hecks/language/bluebook/query.bluebook +19 -43
  351. data/lib/hecks/language/bluebook/shape.bluebook +23 -73
  352. data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
  353. data/lib/hecks/language/bluebook/vocabulary.bluebook +83 -198
  354. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
  355. data/lib/hecks/language/hecksagon/domain_port.bluebook +14 -19
  356. data/lib/hecks/language/hecksagon/hecksagon.bluebook +26 -25
  357. data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
  358. data/lib/hecks/language/oidc.json +35 -0
  359. data/lib/hecks/language/port.bluebook +4 -17
  360. data/lib/hecks/language/translation/translation.bluebook +3 -9
  361. data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
  362. data/lib/hecks/language/world/wiring.bluebook +1 -3
  363. data/lib/hecks/language/world/world.bluebook +5 -7
  364. data/lib/hecks/literal.rb +8 -50
  365. data/lib/hecks/mcp_stdio_guard.rb +4 -41
  366. data/lib/hecks/naming.rb +29 -137
  367. data/lib/hecks/persistence_legacy_fixture/regenerate.rb +161 -0
  368. data/lib/hecks/persistence_legacy_fixture.rb +113 -0
  369. data/lib/hecks/ports/access_control.rb +7 -23
  370. data/lib/hecks/ports/agent/answers.rb +5 -23
  371. data/lib/hecks/ports/agent.rb +47 -172
  372. data/lib/hecks/ports/authentication.rb +12 -39
  373. data/lib/hecks/ports/authorization.rb +16 -43
  374. data/lib/hecks/ports/clock.rb +5 -45
  375. data/lib/hecks/ports/extraction.rb +7 -12
  376. data/lib/hecks/ports/identity_assignment.rb +8 -29
  377. data/lib/hecks/ports/identity_generation.rb +6 -29
  378. data/lib/hecks/ports/identity_resolution.rb +2 -10
  379. data/lib/hecks/ports/key_vault.rb +9 -45
  380. data/lib/hecks/ports/persistence/append_only.rb +61 -64
  381. data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
  382. data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
  383. data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
  384. data/lib/hecks/ports/persistence/plugin.rb +13 -42
  385. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +44 -144
  386. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
  387. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +20 -85
  388. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +6 -25
  389. data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +18 -24
  390. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
  391. data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
  392. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
  393. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
  394. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
  395. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
  396. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
  397. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
  398. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +19 -76
  399. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
  400. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
  401. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
  402. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
  403. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
  404. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +43 -127
  405. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
  406. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +131 -555
  407. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
  408. data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +227 -0
  409. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
  410. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
  411. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
  412. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
  413. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
  414. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +50 -47
  415. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -124
  416. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
  417. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
  418. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
  419. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
  420. data/lib/hecks/ports/persistence/plugins/era/translation.rb +1 -0
  421. data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
  422. data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
  423. data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
  424. data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
  425. data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
  426. data/lib/hecks/ports/persistence/state_codec.rb +47 -108
  427. data/lib/hecks/ports/persistence.rb +7 -14
  428. data/lib/hecks/ports/projection.rb +42 -84
  429. data/lib/hecks/ports/query/in_memory.rb +10 -58
  430. data/lib/hecks/ports/query/ordering.rb +11 -32
  431. data/lib/hecks/ports/query.rb +14 -37
  432. data/lib/hecks/ports.rb +2 -8
  433. data/lib/hecks/projection_files.rb +285 -0
  434. data/lib/hecks/projections/bootstrap_table.rb +12 -44
  435. data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
  436. data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
  437. data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
  438. data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
  439. data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
  440. data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
  441. data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
  442. data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
  443. data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
  444. data/lib/hecks/projections/deploy/fargate.rb +40 -207
  445. data/lib/hecks/projections/deploy/lambda.rb +191 -708
  446. data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
  447. data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
  448. data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
  449. data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
  450. data/lib/hecks/projections/deploy/preview/script.rb +2 -14
  451. data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
  452. data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
  453. data/lib/hecks/projections/deploy/preview/template.rb +3 -59
  454. data/lib/hecks/projections/deploy/preview.rb +2 -67
  455. data/lib/hecks/projections/deploy/scripts/deploy-service.sh.tmpl +1 -1
  456. data/lib/hecks/projections/deploy/scripts/expected-era.header +1 -1
  457. data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +3 -3
  458. data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
  459. data/lib/hecks/projections/deploy/scripts/smoke-after-deploy.sh.tmpl +1 -1
  460. data/lib/hecks/projections/deploy/scripts.rb +4 -57
  461. data/lib/hecks/projections/deploy/shared.rb +48 -147
  462. data/lib/hecks/projections/deploy/smoke.rb +4 -61
  463. data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
  464. data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
  465. data/lib/hecks/projections/deploy/template_diff.rb +5 -57
  466. data/lib/hecks/projections/diagrams.rb +22 -584
  467. data/lib/hecks/projections/glossary/html.rb +14 -130
  468. data/lib/hecks/projections/glossary/markdown.rb +8 -69
  469. data/lib/hecks/projections/glossary/mermaid.rb +9 -66
  470. data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
  471. data/lib/hecks/projections/glossary/sentences.rb +14 -159
  472. data/lib/hecks/projections/glossary.rb +30 -222
  473. data/lib/hecks/projections/ir.rb +3 -10
  474. data/lib/hecks/projections/model/deviations.rb +16 -43
  475. data/lib/hecks/projections/model.rb +12 -51
  476. data/lib/hecks/projections/oidc.rb +12 -56
  477. data/lib/hecks/projections/parser_table.rb +13 -32
  478. data/lib/hecks/projections/reference.rb +4 -18
  479. data/lib/hecks/projections/rust_vocabulary.rb +13 -251
  480. data/lib/hecks/projections/shape.rb +3 -29
  481. data/lib/hecks/projections/statements.rb +7 -86
  482. data/lib/hecks/projections/vocabulary.rb +6 -22
  483. data/lib/hecks/projections.rb +2 -16
  484. data/lib/hecks/projector/cli_projector.rb +154 -400
  485. data/lib/hecks/projector/docs_projector.rb +10 -201
  486. data/lib/hecks/projector/exporter.rb +42 -134
  487. data/lib/hecks/projector/ir_projector.rb +2 -9
  488. data/lib/hecks/projector/narrate_projector.rb +15 -189
  489. data/lib/hecks/projector/target.rb +13 -76
  490. data/lib/hecks/projector.rb +30 -121
  491. data/lib/hecks/quality_control/adapters/agent.adapter +7 -0
  492. data/lib/hecks/quality_control/adapters/agent.rb +58 -0
  493. data/lib/hecks/quality_control/adapters/angle_tools.adapter +7 -0
  494. data/lib/hecks/quality_control/adapters/angle_tools.rb +15 -0
  495. data/lib/hecks/quality_control/adapters/clearance_recorder.rb +36 -0
  496. data/lib/hecks/quality_control/adapters/clearance_tools.adapter +7 -0
  497. data/lib/hecks/quality_control/adapters/clearance_tools.rb +17 -0
  498. data/lib/hecks/quality_control/adapters/git_pr.adapter +7 -0
  499. data/lib/hecks/quality_control/adapters/git_pr.rb +226 -0
  500. data/lib/hecks/quality_control/adapters/github_checks.adapter +9 -0
  501. data/lib/hecks/quality_control/adapters/github_checks.rb +83 -0
  502. data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +56 -0
  503. data/lib/hecks/quality_control/adapters/github_issues.adapter +7 -0
  504. data/lib/hecks/quality_control/adapters/github_issues.rb +49 -0
  505. data/lib/hecks/quality_control/adapters/qa_tool.rb +59 -0
  506. data/lib/hecks/quality_control/adapters/sweep_tools.adapter +7 -0
  507. data/lib/hecks/quality_control/adapters/sweep_tools.rb +51 -0
  508. data/lib/hecks/quality_control/adapters/target_tools.adapter +7 -0
  509. data/lib/hecks/quality_control/adapters/target_tools.rb +43 -0
  510. data/lib/hecks/quality_control/cli/child.rb +45 -0
  511. data/lib/hecks/quality_control/cli/qa_concurrency_racer.rb +45 -0
  512. data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +248 -0
  513. data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +163 -0
  514. data/lib/hecks/quality_control/cli/qa_generated_domains.rb +450 -0
  515. data/lib/hecks/quality_control/cli/qa_log_bug.rb +195 -0
  516. data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +220 -0
  517. data/lib/hecks/quality_control/cli/qa_open_pr.rb +305 -0
  518. data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +154 -0
  519. data/lib/hecks/quality_control/cli/qa_postgres_role.rb +159 -0
  520. data/lib/hecks/quality_control/cli/qa_pr_check.rb +232 -0
  521. data/lib/hecks/quality_control/cli/qa_seed_angles.rb +142 -0
  522. data/lib/hecks/quality_control/cli/qa_seed_targets.rb +69 -0
  523. data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +280 -0
  524. data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +329 -0
  525. data/lib/hecks/quality_control/cli/qa_sweep/dials.rb +92 -0
  526. data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +117 -0
  527. data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +175 -0
  528. data/lib/hecks/quality_control/cli/qa_sweep/release_mode.rb +60 -0
  529. data/lib/hecks/quality_control/cli/qa_sweep.rb +611 -0
  530. data/lib/hecks/quality_control/cli/qa_tick.rb +274 -0
  531. data/lib/hecks/quality_control/quality_control.bluebook +2224 -0
  532. data/lib/hecks/quality_control/quality_control.hecksagon +13 -0
  533. data/lib/hecks/quality_control/quality_control.ports.hecksagon +54 -0
  534. data/lib/hecks/query_ir.rb +346 -0
  535. data/lib/hecks/query_ir_mcp.rb +198 -0
  536. data/lib/hecks/query_specification/common/comparators.rb +5 -26
  537. data/lib/hecks/query_specification/common/comparison.rb +35 -143
  538. data/lib/hecks/query_specification/common/dsl.rb +8 -24
  539. data/lib/hecks/query_specification/common/null_policy.rb +20 -70
  540. data/lib/hecks/query_specification/common/options.rb +2 -6
  541. data/lib/hecks/query_specification/common/where_clause.rb +2 -10
  542. data/lib/hecks/query_specification/field_path.rb +37 -77
  543. data/lib/hecks/query_specification/hop_path.rb +12 -76
  544. data/lib/hecks/release/gem_pin.rb +2 -26
  545. data/lib/hecks/release/runner/ci_publisher.rb +5 -8
  546. data/lib/hecks/release/runner/clean_tree.rb +42 -0
  547. data/lib/hecks/release/runner/commands.rb +2 -4
  548. data/lib/hecks/release/runner/console.rb +6 -0
  549. data/lib/hecks/release/runner/gem_publisher.rb +15 -9
  550. data/lib/hecks/release/runner/npm_publisher.rb +9 -53
  551. data/lib/hecks/release/runner/preflight.rb +29 -20
  552. data/lib/hecks/release/runner/published.rb +8 -26
  553. data/lib/hecks/release/runner/tagger.rb +31 -23
  554. data/lib/hecks/release/runner.rb +60 -38
  555. data/lib/hecks/rendering.rb +4 -26
  556. data/lib/hecks/router/namespace_installer.rb +15 -39
  557. data/lib/hecks/router.rb +4 -8
  558. data/lib/hecks/runtime/adapter_lookup.rb +124 -0
  559. data/lib/hecks/runtime/aggregate_lock.rb +8 -33
  560. data/lib/hecks/runtime/boot_gates.rb +3 -18
  561. data/lib/hecks/runtime/caller.rb +19 -59
  562. data/lib/hecks/runtime/capability_graph.rb +5 -21
  563. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
  564. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +27 -160
  565. data/lib/hecks/runtime/command_interpreter.rb +124 -306
  566. data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
  567. data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
  568. data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
  569. data/lib/hecks/runtime/command_rules/emission.rb +8 -21
  570. data/lib/hecks/runtime/command_rules/references.rb +23 -202
  571. data/lib/hecks/runtime/dependency_planning.rb +50 -104
  572. data/lib/hecks/runtime/dispatcher.rb +134 -243
  573. data/lib/hecks/runtime/entity_element.rb +40 -462
  574. data/lib/hecks/runtime/entity_interpreter.rb +64 -219
  575. data/lib/hecks/runtime/errors.rb +32 -115
  576. data/lib/hecks/runtime/event.rb +3 -25
  577. data/lib/hecks/runtime/identity.rb +18 -154
  578. data/lib/hecks/runtime/instance.rb +18 -150
  579. data/lib/hecks/runtime/interpreting.rb +14 -70
  580. data/lib/hecks/runtime/invocation.rb +28 -164
  581. data/lib/hecks/runtime/loader.rb +109 -194
  582. data/lib/hecks/runtime/outbox.rb +39 -262
  583. data/lib/hecks/runtime/policy_interpreter.rb +43 -202
  584. data/lib/hecks/runtime/port_operation_interpreter.rb +28 -97
  585. data/lib/hecks/runtime/query_interpreter.rb +122 -187
  586. data/lib/hecks/runtime/reaction_invocation.rb +36 -138
  587. data/lib/hecks/runtime/reaction_outcome.rb +89 -0
  588. data/lib/hecks/runtime/read_model_interpreter.rb +117 -208
  589. data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
  590. data/lib/hecks/runtime/reference_hop.rb +8 -81
  591. data/lib/hecks/runtime/refusal_wording.rb +28 -87
  592. data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
  593. data/lib/hecks/runtime/registry/verification.rb +213 -227
  594. data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
  595. data/lib/hecks/runtime/registry.rb +156 -247
  596. data/lib/hecks/runtime/remote_dispatcher.rb +68 -154
  597. data/lib/hecks/runtime/routing.rb +4 -15
  598. data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
  599. data/lib/hecks/runtime/saga_interpreter.rb +79 -263
  600. data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
  601. data/lib/hecks/runtime/tenant_check.rb +6 -68
  602. data/lib/hecks/runtime/tenant_scope.rb +3 -28
  603. data/lib/hecks/runtime/value/admission.rb +16 -67
  604. data/lib/hecks/runtime/value/coercion.rb +162 -760
  605. data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
  606. data/lib/hecks/runtime/value/field_checks.rb +172 -0
  607. data/lib/hecks/runtime/value.rb +15 -84
  608. data/lib/hecks/runtime.rb +35 -69
  609. data/lib/hecks/rust_build/conformance.rb +158 -0
  610. data/lib/hecks/rust_build/conformance_fuzz.rb +71 -0
  611. data/lib/hecks/rust_build/coverage.rb +218 -0
  612. data/lib/hecks/rust_build/native_build.rb +124 -0
  613. data/lib/hecks/rust_build/project_rust/root_mod.rb +120 -0
  614. data/lib/hecks/rust_build/project_rust.rb +332 -0
  615. data/lib/hecks/rust_build/wasm.rb +105 -0
  616. data/lib/hecks/rust_build/wasm_browser.rb +113 -0
  617. data/lib/hecks/rust_build.rb +144 -0
  618. data/lib/hecks/storehouse.rb +155 -582
  619. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +10 -34
  620. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
  621. data/lib/hecks/three_zero/forms.yml +127 -0
  622. data/lib/hecks/three_zero.rb +12 -0
  623. data/lib/hecks/tools/argument_gate_matrix.rb +316 -0
  624. data/lib/hecks/tools/comment_style.rb +1070 -0
  625. data/lib/hecks/tools/corpus_report.rb +87 -0
  626. data/lib/hecks/tools/deploy_recipe.rb +255 -0
  627. data/lib/hecks/tools/deploy_recipe_lint.rb +282 -0
  628. data/lib/hecks/tools/drop_implicit_append_fields.rb +95 -0
  629. data/lib/hecks/tools/era_projection_backfill.rb +94 -0
  630. data/lib/hecks/tools/era_reattest.rb +146 -0
  631. data/lib/hecks/tools/evolve_run.rb +189 -0
  632. data/lib/hecks/tools/fuzz_sweep.rb +373 -0
  633. data/lib/hecks/tools/heki_compaction.rb +100 -0
  634. data/lib/hecks/tools/hoist_local_givens.rb +246 -0
  635. data/lib/hecks/tools/journal_compaction.rb +89 -0
  636. data/lib/hecks/tools/oidc_manifests.rb +70 -0
  637. data/lib/hecks/tools/query_ir_run.rb +81 -0
  638. data/lib/hecks/tools/regeneration_run.rb +166 -0
  639. data/lib/hecks/tools/rust_comment_style.rb +642 -0
  640. data/lib/hecks/tools/sequence_script.rb +62 -0
  641. data/lib/hecks/tools/tail_merge.rb +117 -0
  642. data/lib/hecks/tools/tenant_provisioning.rb +142 -0
  643. data/lib/hecks/tools/translation_audit.rb +208 -0
  644. data/lib/hecks/tools/translation_scaffold.rb +131 -0
  645. data/lib/hecks/tools.rb +86 -0
  646. data/lib/hecks/vendoring/git_environment.rb +2 -8
  647. data/lib/hecks/vendoring/git_source.rb +4 -10
  648. data/lib/hecks/vendoring.rb +7 -46
  649. data/lib/hecks/version.rb +3 -14
  650. data/lib/hecks.rb +52 -90
  651. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
  652. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
  653. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
  654. data/qa/settings.yml +66 -0
  655. data/rust/.cargo/config.toml +6 -0
  656. data/rust/.gitignore +2 -0
  657. data/rust/Cargo.lock +54 -0
  658. data/rust/Cargo.toml +61 -0
  659. data/rust/build/.cargo/config.toml +3 -0
  660. data/rust/build/.gitignore +1 -0
  661. data/rust/build/Cargo.lock +7 -0
  662. data/rust/build/Cargo.toml +19 -0
  663. data/rust/build/src/build_artifact.rs +47 -0
  664. data/rust/build/src/cargo_sync.rs +248 -0
  665. data/rust/build/src/json.rs +421 -0
  666. data/rust/build/src/lineage_pass.rs +285 -0
  667. data/rust/build/src/main.rs +51 -0
  668. data/rust/build/src/optional_pass.rs +150 -0
  669. data/rust/build/src/pipeline.rs +264 -0
  670. data/rust/build/src/reserved_names.rs +76 -0
  671. data/rust/build/src/resolve.rs +124 -0
  672. data/rust/build/src/root.rs +25 -0
  673. data/rust/build/src/sidecars.rs +73 -0
  674. data/rust/build/src/subprocess.rs +51 -0
  675. data/rust/build/src/tmp.rs +31 -0
  676. data/rust/codegen/.cargo/config.toml +3 -0
  677. data/rust/codegen/.gitignore +1 -0
  678. data/rust/codegen/Cargo.lock +7 -0
  679. data/rust/codegen/Cargo.toml +20 -0
  680. data/rust/codegen/src/attr.rs +32 -0
  681. data/rust/codegen/src/bridging.rs +481 -0
  682. data/rust/codegen/src/commands.rs +1226 -0
  683. data/rust/codegen/src/constraints.rs +109 -0
  684. data/rust/codegen/src/dependency_planning.rs +209 -0
  685. data/rust/codegen/src/domain_generator.rs +1288 -0
  686. data/rust/codegen/src/exemplar.rs +230 -0
  687. data/rust/codegen/src/expr_emitter.rs +87 -0
  688. data/rust/codegen/src/fielded.rs +192 -0
  689. data/rust/codegen/src/hecks_naming.rs +33 -0
  690. data/rust/codegen/src/json.rs +335 -0
  691. data/rust/codegen/src/json_codec.rs +697 -0
  692. data/rust/codegen/src/literal.rs +207 -0
  693. data/rust/codegen/src/main.rs +290 -0
  694. data/rust/codegen/src/manifest.rs +227 -0
  695. data/rust/codegen/src/mutations.rs +784 -0
  696. data/rust/codegen/src/naming.rs +286 -0
  697. data/rust/codegen/src/ports.rs +208 -0
  698. data/rust/codegen/src/prelude.rs +116 -0
  699. data/rust/codegen/src/queries.rs +786 -0
  700. data/rust/codegen/src/reactions.rs +532 -0
  701. data/rust/codegen/src/read_models.rs +697 -0
  702. data/rust/codegen/src/reference_specs.rs +40 -0
  703. data/rust/codegen/src/registry.rs +966 -0
  704. data/rust/codegen/src/reserved_names.rs +76 -0
  705. data/rust/codegen/src/shared.rs +93 -0
  706. data/rust/codegen/src/skip_reason.rs +25 -0
  707. data/rust/codegen/src/types.rs +362 -0
  708. data/rust/host/.cargo/config.toml +3 -0
  709. data/rust/host/.gitignore +1 -0
  710. data/rust/host/Cargo.lock +4297 -0
  711. data/rust/host/Cargo.toml +61 -0
  712. data/rust/host/HECKS_RELEASE +1 -0
  713. data/rust/host/rds-ca-bundle.pem +2736 -0
  714. data/rust/host/src/api.rs +1596 -0
  715. data/rust/host/src/approval.rs +652 -0
  716. data/rust/host/src/auth.rs +1287 -0
  717. data/rust/host/src/bin/expr_harness.rs +46 -0
  718. data/rust/host/src/bin/lineage_harness.rs +119 -0
  719. data/rust/host/src/bin/mint_harness.rs +135 -0
  720. data/rust/host/src/checkout.rs +265 -0
  721. data/rust/host/src/dispatch.rs +1443 -0
  722. data/rust/host/src/expr_json.rs +1117 -0
  723. data/rust/host/src/field_hints.rs +52 -0
  724. data/rust/host/src/ir.rs +733 -0
  725. data/rust/host/src/journal.rs +874 -0
  726. data/rust/host/src/lambda_client.rs +378 -0
  727. data/rust/host/src/log.rs +147 -0
  728. data/rust/host/src/main.rs +474 -0
  729. data/rust/host/src/mint.rs +1865 -0
  730. data/rust/host/src/payments/keystore.rs +330 -0
  731. data/rust/host/src/payments/tests.rs +1400 -0
  732. data/rust/host/src/payments.rs +767 -0
  733. data/rust/host/src/presentation.rs +698 -0
  734. data/rust/host/src/presentation_write.rs +1431 -0
  735. data/rust/host/src/query_step.rs +149 -0
  736. data/rust/host/src/rate_limit.rs +904 -0
  737. data/rust/host/src/reference_transform.rs +241 -0
  738. data/rust/host/src/reference_validate.rs +338 -0
  739. data/rust/host/src/resend.rs +296 -0
  740. data/rust/host/src/secrets.rs +106 -0
  741. data/rust/host/src/server.rs +663 -0
  742. data/rust/host/src/storage_shape.rs +175 -0
  743. data/rust/host/src/test_pg.rs +40 -0
  744. data/rust/host/src/ui_schema.rs +1351 -0
  745. data/rust/host/src/wasm_runner.rs +191 -0
  746. data/rust/host/src/web/newsletter/cooldown.rs +126 -0
  747. data/rust/host/src/web/newsletter/tests.rs +104 -0
  748. data/rust/host/src/web/newsletter.rs +310 -0
  749. data/rust/host/src/web/newsletter_send.rs +357 -0
  750. data/rust/host/src/web/registrations.rs +1505 -0
  751. data/rust/host/src/web.rs +2937 -0
  752. data/rust/lsp/.gitignore +1 -0
  753. data/rust/lsp/Cargo.lock +7 -0
  754. data/rust/lsp/Cargo.toml +16 -0
  755. data/rust/lsp/README.md +133 -0
  756. data/rust/lsp/src/diagnostics.rs +165 -0
  757. data/rust/lsp/src/json.rs +385 -0
  758. data/rust/lsp/src/main.rs +399 -0
  759. data/rust/lsp/src/outline.rs +177 -0
  760. data/rust/lsp/src/rpc.rs +67 -0
  761. data/rust/parser/.cargo/config.toml +5 -0
  762. data/rust/parser/.gitignore +1 -0
  763. data/rust/parser/Cargo.lock +7 -0
  764. data/rust/parser/Cargo.toml +21 -0
  765. data/rust/parser/src/build/closed_sets.rs +27 -0
  766. data/rust/parser/src/build/identity.rs +276 -0
  767. data/rust/parser/src/build/mod.rs +12 -0
  768. data/rust/parser/src/build/naming.rs +141 -0
  769. data/rust/parser/src/build/pattern_subset.rs +161 -0
  770. data/rust/parser/src/build/query_derive.rs +72 -0
  771. data/rust/parser/src/build/query_inference.rs +269 -0
  772. data/rust/parser/src/build/query_options.rs +100 -0
  773. data/rust/parser/src/build/read_model.rs +94 -0
  774. data/rust/parser/src/build/references.rs +32 -0
  775. data/rust/parser/src/canonical.rs +114 -0
  776. data/rust/parser/src/diag.rs +55 -0
  777. data/rust/parser/src/emit.rs +953 -0
  778. data/rust/parser/src/expr/ast_json.rs +147 -0
  779. data/rust/parser/src/expr/evaluator.rs +81 -0
  780. data/rust/parser/src/expr/mod.rs +84 -0
  781. data/rust/parser/src/expr/resolver.rs +497 -0
  782. data/rust/parser/src/ir.rs +387 -0
  783. data/rust/parser/src/keywords.rs +585 -0
  784. data/rust/parser/src/lex.rs +662 -0
  785. data/rust/parser/src/main.rs +252 -0
  786. data/rust/parser/src/parse/aggregate.rs +612 -0
  787. data/rust/parser/src/parse/chapter.rs +517 -0
  788. data/rust/parser/src/parse/command.rs +637 -0
  789. data/rust/parser/src/parse/domain_port.rs +127 -0
  790. data/rust/parser/src/parse/entity.rs +527 -0
  791. data/rust/parser/src/parse/file.rs +67 -0
  792. data/rust/parser/src/parse/hecksagon.rs +231 -0
  793. data/rust/parser/src/parse/lifecycle.rs +162 -0
  794. data/rust/parser/src/parse/mod.rs +1262 -0
  795. data/rust/parser/src/parse/policy.rs +87 -0
  796. data/rust/parser/src/parse/process_manager.rs +305 -0
  797. data/rust/parser/src/parse/query.rs +100 -0
  798. data/rust/parser/src/parse/read_model.rs +214 -0
  799. data/rust/parser/src/parse/value_object.rs +250 -0
  800. data/rust/parser/src/ruby_value.rs +422 -0
  801. data/rust/project/bridging.rb +257 -0
  802. data/rust/project/commands.rb +877 -0
  803. data/rust/project/constraints.rb +86 -0
  804. data/rust/project/dependency_planning.rb +178 -0
  805. data/rust/project/domain_generator.rb +980 -0
  806. data/rust/project/exemplar.rb +148 -0
  807. data/rust/project/expr_emitter.rb +72 -0
  808. data/rust/project/fielded.rb +141 -0
  809. data/rust/project/json_codec.rb +641 -0
  810. data/rust/project/mutations.rb +721 -0
  811. data/rust/project/naming.rb +205 -0
  812. data/rust/project/ports.rb +65 -0
  813. data/rust/project/queries.rb +493 -0
  814. data/rust/project/reactions.rb +317 -0
  815. data/rust/project/read_models.rb +690 -0
  816. data/rust/project/reference_specs.rb +27 -0
  817. data/rust/project/registry.rb +396 -0
  818. data/rust/project/skip_reason.rb +29 -0
  819. data/rust/project/types.rb +225 -0
  820. data/rust/project/write_if_changed.rb +83 -0
  821. data/rust/project.rb +30 -0
  822. data/rust/project_rust_pipeline.rb +383 -0
  823. data/rust/src/exemplar/commands.rs +279 -0
  824. data/rust/src/exemplar/constraints.rs +18 -0
  825. data/rust/src/exemplar/fielded.rs +280 -0
  826. data/rust/src/exemplar/json.rs +277 -0
  827. data/rust/src/exemplar/mod.rs +17 -0
  828. data/rust/src/exemplar/mutations.rs +80 -0
  829. data/rust/src/exemplar/queries.rs +33 -0
  830. data/rust/src/exemplar/reactions.rs +88 -0
  831. data/rust/src/exemplar/read_models.rs +48 -0
  832. data/rust/src/exemplar/registry.rs +166 -0
  833. data/rust/src/exemplar/types.rs +44 -0
  834. data/rust/src/kernel/attribute_shapes/composite.rs +88 -0
  835. data/rust/src/kernel/attribute_shapes/list.rs +18 -0
  836. data/rust/src/kernel/attribute_shapes/mod.rs +44 -0
  837. data/rust/src/kernel/attribute_shapes/optional.rs +9 -0
  838. data/rust/src/kernel/attribute_shapes/scalar.rs +39 -0
  839. data/rust/src/kernel/cli.rs +585 -0
  840. data/rust/src/kernel/dispatch.rs +1090 -0
  841. data/rust/src/kernel/expr.rs +458 -0
  842. data/rust/src/kernel/expression_operators/arithmetic.rs +128 -0
  843. data/rust/src/kernel/expression_operators/comparison.rs +48 -0
  844. data/rust/src/kernel/expression_operators/enumeration.rs +232 -0
  845. data/rust/src/kernel/expression_operators/logical.rs +13 -0
  846. data/rust/src/kernel/expression_operators/membership.rs +18 -0
  847. data/rust/src/kernel/expression_operators/mod.rs +68 -0
  848. data/rust/src/kernel/expression_operators/pattern_match.rs +73 -0
  849. data/rust/src/kernel/expression_operators/positional.rs +126 -0
  850. data/rust/src/kernel/expression_operators/presence.rs +101 -0
  851. data/rust/src/kernel/expression_operators/sign_test.rs +16 -0
  852. data/rust/src/kernel/expression_operators/sized.rs +35 -0
  853. data/rust/src/kernel/expression_operators/text.rs +79 -0
  854. data/rust/src/kernel/expression_operators/to_string.rs +18 -0
  855. data/rust/src/kernel/json.rs +779 -0
  856. data/rust/src/kernel/mod.rs +133 -0
  857. data/rust/src/kernel/named_query.rs +219 -0
  858. data/rust/src/kernel/orchestrate.rs +1810 -0
  859. data/rust/src/kernel/pattern.rs +307 -0
  860. data/rust/src/kernel/query_comparators.rs +206 -0
  861. data/rust/src/kernel/query_ordering.rs +103 -0
  862. data/rust/src/kernel/read_model.rs +914 -0
  863. data/rust/src/kernel/reference_lookup.rs +149 -0
  864. data/rust/src/kernel/repository.rs +468 -0
  865. data/rust/src/kernel/routing.rs +612 -0
  866. data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +118 -0
  867. data/rust/src/kernel/vocab/entity_dispatch_order.rs +114 -0
  868. data/rust/src/kernel/vocab/field_hint.rs +70 -0
  869. data/rust/src/kernel/vocab/mod.rs +20 -0
  870. data/rust/src/kernel/vocab/query_comparator.rs +65 -0
  871. data/rust/src/kernel/vocab/refusal_template.rs +1592 -0
  872. data/rust/src/lib.rs +8 -0
  873. data/rust/src/main.rs +16 -0
  874. data/rust/web/.gitignore +1 -0
  875. data/rust/web/Cargo.lock +119 -0
  876. data/rust/web/Cargo.toml +18 -0
  877. data/rust/web/src/lib.rs +8 -0
  878. metadata +478 -12
  879. data/lib/hecks/facade/cli_door.rb +0 -178
  880. data/lib/hecks/facade/cli_runner.rb +0 -271
  881. data/lib/hecks/facade/handle.rb +0 -293
  882. data/lib/hecks/facade/json_door.rb +0 -247
  883. data/lib/hecks/facade/surface/aggregate_door.rb +0 -222
  884. data/lib/hecks/facade/surface/chapter.rb +0 -116
  885. data/lib/hecks/facade/surface.rb +0 -61
  886. data/lib/hecks/mcp_door_scope.rb +0 -176
@@ -1,5 +1,6 @@
1
1
  require_relative "errors"
2
2
  require_relative "refusal_wording"
3
+ require_relative "reaction_outcome"
3
4
  require_relative "caller"
4
5
  require_relative "invocation"
5
6
  require_relative "command_rules"
@@ -14,36 +15,49 @@ require_relative "../naming"
14
15
 
15
16
  module Hecks
16
17
  module Runtime
17
- # The runtime's single dispatch entry point for one booted registry:
18
- # routes a "Domain::Aggregate.Command"-shaped verb to the right
19
- # sub-interpreter (command, entity, port operation, query, read
20
- # model), then runs every policy and saga reaction the resulting
21
- # events trigger. Also the door reactions dispatch back through
22
- # (#reenter), and the one place reaction-cascade depth is tracked, to
23
- # keep a policy/saga loop from re-triggering itself without bound.
18
+ # Routes a "Domain::Aggregate.Command" verb to its interpreter, then runs the policy
19
+ # and saga reactions its events trigger; tracks reaction depth to bound cascades.
24
20
  class Dispatcher
25
21
  MAX_REACTION_DEPTH = 5
26
22
 
27
- Result = Struct.new(:verb, :instance, :events, :execution_plan, :persistence_outcome, keyword_init: true) do
28
- # Reads the identity of the record the dispatch settled on.
23
+ Result = Struct.new(:verb, :instance, :events, :execution_plan, :persistence_outcome,
24
+ :refused_reactions, :blocking_reactions, :reaction_defects,
25
+ keyword_init: true) do
26
+ # Lists the policy reactions this dispatch caused that the domain refused.
27
+ #
28
+ # A policy's trigger that a `given` or invariant refuses does not undo the command that
29
+ # fired it, which has already persisted, so the outcome above stays a success. The
30
+ # refusal is recorded here instead of vanishing into the reaction log.
31
+ #
32
+ # @return [Array<Hash{Symbol => Object}>] one `{ policy:, trigger:, reason: }` per refused
33
+ # reaction, oldest first; empty when every reaction was delivered
34
+ def refused_reactions = self[:refused_reactions] || []
35
+
36
+ # Lists the refused reactions that block the run, as opposed to a benign non-match.
37
+ #
38
+ # See `ReactionOutcome`: a refusal is benign when a sibling reaction to the same event
39
+ # delivered another command on the same aggregate. `--wait` exits 1 on any that remain.
40
+ #
41
+ # @return [Array<Hash{Symbol => Object}>] the subset of `refused_reactions` that blocks
42
+ def blocking_reactions = self[:blocking_reactions] || []
43
+
44
+ # Lists the reactions that crashed, as opposed to being refused by the domain.
29
45
  #
30
- # `instance` is nil for a port operation dispatched by verb (below)
31
- # — nothing was hydrated or saved, the same reason
32
- # `PortOperationInterpreter#emit`'s own comment gives for sourcing
33
- # `id:` off the operation's reference attribute instead. `&.`, not
34
- # a raised error: a caller that dispatches a port verb and then
35
- # asks this Result for `.id`/`.state` made a category error the
36
- # domain itself already told it about (there is no record here),
37
- # not a crash-worthy one.
46
+ # A crash is warned and never re-raised, since the emitting command has persisted; it is
47
+ # recorded here so `--wait` can fail on a chain that stopped halfway.
38
48
  #
39
- # @return [String, nil] the record's identity; nil for a port operation, which
40
- # hydrates no record
49
+ # @return [Array<Hash{Symbol => Object}>] `{ policy:, trigger:, reason:, error_class: }`
50
+ # per crashed reaction; empty when none crashed
51
+ def reaction_defects = self[:reaction_defects] || []
52
+
53
+ # Reads the identity of the record the dispatch settled on.
54
+ #
55
+ # @return [String, nil] the record's identity; nil for a port operation (no record)
41
56
  def id = instance&.id
42
57
 
43
- # Reads the settled record's attributes as one Hash, for the same nil-safe reason as `id`.
58
+ # Reads the settled record's attributes as one Hash.
44
59
  #
45
- # @return [Hash{Symbol => Object}, nil] the record's state with `:id` merged in
46
- # last; nil for a port operation, which hydrates no record
60
+ # @return [Hash{Symbol => Object}, nil] the record's state; nil for a port operation
47
61
  def state = instance&.to_h
48
62
 
49
63
  def to_s
@@ -56,8 +70,7 @@ module Hecks
56
70
 
57
71
  attr_reader :registry
58
72
 
59
- # @param registry [Runtime::Registry] the booted registry every interpreter reads; its
60
- # outbox is attached to this dispatcher's policy and saga interpreters
73
+ # @param registry [Runtime::Registry] the booted registry every interpreter reads
61
74
  def initialize(registry)
62
75
  @registry = registry
63
76
  rules = CommandRules.new(registry)
@@ -68,108 +81,72 @@ module Hecks
68
81
  @read_models = ReadModelInterpreter.new(registry)
69
82
  @policies = PolicyInterpreter.new(registry, door: self)
70
83
  @sagas = SagaInterpreter.new(registry, door: self)
71
- # The relay is the registry's, not this dispatcher's — the
72
- # interpreters enqueue through `@registry.outbox` from inside
73
- # the save transaction, and this dispatcher drains through the
74
- # same object, so there is exactly one relay per registry no
75
- # matter how many dispatchers front it. What it borrows from
76
- # here is the pair of interpreters a consumer runs through.
84
+ # One relay per registry: interpreters enqueue through it inside the save transaction.
77
85
  @registry.outbox.attach(policies: @policies, sagas: @sagas)
78
86
  end
79
87
 
80
- # Exposes the registry's outbox relay, the object this dispatcher drains reactions through.
88
+ # Exposes the registry's outbox relay, through which this dispatcher drains reactions.
81
89
  #
82
- # `runtime.outbox.rows`, `.rows(status: "claimed")`, `.redrive!`,
83
- # `.log` — see `Runtime::Outbox`.
84
- #
85
- # @return [Runtime::Outbox::Relay] the registry's one relay, shared by every dispatcher
86
- # fronting that registry
90
+ # @return [Runtime::Outbox::Relay] the registry's one relay
87
91
  def outbox = @registry.outbox
88
92
 
89
- # Exposes every event emitted through this registry since boot or the last reset.
93
+ # Exposes every event emitted through this registry, oldest first.
90
94
  #
91
- # @return [Array<Runtime::Event>] the registry's live event log, oldest first
95
+ # @return [Array<Runtime::Event>]
92
96
  def events = @registry.event_log
93
97
 
94
- # Exposes one record per policy reaction that was delivered, refused or left undelivered.
98
+ # Exposes one record per policy reaction delivered, refused or left undelivered.
95
99
  #
96
- # @return [Array<Hash{Symbol => Object}>] the registry's live reaction log, oldest first
100
+ # @return [Array<Hash{Symbol => Object}>]
97
101
  def reactions = @registry.reaction_log
98
102
 
99
103
  # Exposes one record per process-manager step: a start, an advance, a delivery, a refusal.
100
104
  #
101
- # @return [Array<Hash{Symbol => Object}>] the registry's live saga log, oldest first
105
+ # @return [Array<Hash{Symbol => Object}>]
102
106
  def sagas = @registry.saga_log
103
107
 
104
- # Exposes the raw inputs each saga dispatch bound its arguments from, a Ruby-only log.
108
+ # Exposes the raw inputs each saga dispatch bound its arguments from (Ruby-only).
105
109
  #
106
- # @return [Array<Hash{Symbol => Object}>] the registry's live saga dispatch log, oldest first
110
+ # @return [Array<Hash{Symbol => Object}>]
107
111
  def saga_dispatches = @registry.saga_dispatch_log
108
112
 
109
- # Exposes the raw inputs each policy trigger bound its arguments from, a Ruby-only log.
113
+ # Exposes the raw inputs each policy trigger bound its arguments from (Ruby-only).
110
114
  #
111
- # @return [Array<Hash{Symbol => Object}>] the registry's live policy dispatch log, with
112
- # keys `:policy`, `:on`, `:payload`, `:with_spec` and `:args`
115
+ # @return [Array<Hash{Symbol => Object}>] entries keyed `:policy`, `:on`, `:payload`,
116
+ # `:with_spec` and `:args`
113
117
  def policy_dispatches = @registry.policy_dispatch_log
114
118
 
115
119
  # Lists every verb the loaded bluebooks declare.
116
120
  #
117
- # @return [Array<String>] the verbs of every loaded bluebook, sorted
121
+ # @return [Array<String>] sorted
118
122
  def verbs = @registry.verbs
119
123
 
120
- # Runs one command, entity command or port operation, then every policy and saga reaction
121
- # its events are owed.
122
- #
123
- # The receiver in `to:`, the facts in `with:`, and nothing else.
124
- # Loose keyword facts — `dispatch(verb, amount: 5)`, one bag holding
125
- # both the route and the payload — were deprecated in 1.3.x and are
126
- # gone: Ruby now refuses them itself, by name ("unknown keyword:
127
- # :amount"). Code holding a bag of data rather than written keywords
128
- # calls `dispatch_flat` below; that door is not going anywhere.
124
+ # Runs one command, entity command or port operation, then the reactions its events owe.
129
125
  #
130
- # @param verb [String] the fully qualified verb: `"Domain::Aggregate.Command"`,
131
- # `"Domain::Aggregate.Entity.Command"` or `"Domain::Aggregate.Port.Operation"`
132
- # @param to [String, Hash, nil] the receiver: an aggregate identity, or an entity route
133
- # Hash with `:aggregate` and one of `:entity`/`:entities`; nil when the facts carry
134
- # the identity themselves
135
- # @param with [Hash, nil] the command's facts, keyed by argument name (String or Symbol)
136
- # @param saga_correlation [Hash, nil] correlation head => value, stamped on every
137
- # emitted event when a saga leg causes this dispatch; nil otherwise
138
- # @return [Runtime::Dispatcher::Result] the verb, settled instance (nil for a port
139
- # operation), emitted events, execution plan and persistence outcome
140
- # @raise [Runtime::UnknownVerb] if the verb is not fully qualified, or names a domain,
141
- # aggregate, command, entity or port operation that is not declared
142
- # @raise [StandardError] any class in `Runtime::DOMAIN_REFUSALS` when the domain refuses
143
- # the call (`GivenNotMet`, `TypeMismatch`, `Unauthorized`, `NotFound`, …)
144
- # @raise [Runtime::StaleWrite] if concurrent writers beat this one through every retry
145
- # @raise [Runtime::WiringError] if the aggregate's repository cannot be resolved
126
+ # @param verb [String] `"Domain::Aggregate.Command"`, `"Domain::Aggregate.Entity.Command"`
127
+ # or `"Domain::Aggregate.Port.Operation"`
128
+ # @param to [String, Hash, nil] the receiver: an aggregate identity, or an entity route Hash
129
+ # with `:aggregate` and `:entity`/`:entities`
130
+ # @param with [Hash, nil] the command's facts, keyed by argument name
131
+ # @param saga_correlation [Hash, nil] stamped on emitted events when a saga leg dispatches
132
+ # @return [Runtime::Dispatcher::Result] the instance is nil for a port operation
133
+ # @raise [Runtime::UnknownVerb] if the verb is malformed or names something undeclared
134
+ # @raise [StandardError] a `Runtime::DOMAIN_REFUSALS` class when the domain refuses
135
+ # @raise [Runtime::StaleWrite] if concurrent writers win every retry
146
136
  def dispatch(verb, to: nil, with: nil, saga_correlation: nil)
147
137
  dispatch_invocation(verb, to: to, with: with, saga_correlation: saga_correlation, flat: {})
148
138
  end
149
139
 
150
140
  # Dispatches a verb whose receiver and facts arrive together in one flat Hash.
151
141
  #
152
- # **The flat-facts wire form** — one Hash, not keywords: the shape
153
- # `spec/corpus/*.json` steps, the Rust kernel's `cli.rs` contract, a
154
- # reaction without a `with:` projection, and the self-hosted
155
- # meta-domain all carry, where the receiver's identity is one of the
156
- # keys because that is how the wire spells it. Routes exactly as the
157
- # removed keyword door did: a Symbol `:to`, `:with` or
158
- # `:saga_correlation` key is lifted out as that keyword, everything
159
- # else is a fact (so a String "to" key stays a fact, as it did).
160
- # Framework code that replays data calls this; application code
161
- # calls `dispatch(verb, to:, with:)`.
142
+ # The wire form: Symbol keys `:to`, `:with` and `:saga_correlation` are lifted out as
143
+ # the keywords of `dispatch`; every other key, including a String "to", is a fact.
162
144
  #
163
145
  # @param verb [String] the fully qualified verb, in any shape `dispatch` accepts
164
- # @param args [Hash] the facts, plus optional Symbol keys `:to`, `:with` and
165
- # `:saga_correlation`, read as `dispatch`'s keywords of the same names; not mutated
146
+ # @param args [Hash] the facts plus the optional Symbol keys above; not mutated
166
147
  # @return [Runtime::Dispatcher::Result] the same result `dispatch` returns
167
- # @raise [Runtime::UnknownVerb] if the verb is not fully qualified, or names a domain,
168
- # aggregate, command, entity or port operation that is not declared
169
- # @raise [StandardError] any class in `Runtime::DOMAIN_REFUSALS` when the domain refuses
170
- # the call
171
- # @raise [Runtime::StaleWrite] if concurrent writers beat this one through every retry
172
- # @raise [Runtime::WiringError] if the aggregate's repository cannot be resolved
148
+ # @raise [Runtime::UnknownVerb] if the verb is malformed or names something undeclared
149
+ # @raise [StandardError] a `Runtime::DOMAIN_REFUSALS` class when the domain refuses
173
150
  def dispatch_flat(verb, args = {})
174
151
  facts = args.dup
175
152
  to = facts.delete(:to)
@@ -179,6 +156,14 @@ module Hecks
179
156
  end
180
157
 
181
158
  def dispatch_invocation(verb, to:, with:, saga_correlation:, flat:)
159
+ @registry.collecting_reactions do |reactions|
160
+ dispatch_collecting(verb, reactions, to: to, with: with, saga_correlation: saga_correlation, flat: flat)
161
+ end
162
+ end
163
+ private :dispatch_invocation
164
+
165
+ # One dispatch, with `reactions` receiving every reaction its events cause.
166
+ def dispatch_collecting(verb, reactions, to:, with:, saga_correlation:, flat:)
182
167
  domain, aggregate_name, command_name = parse(verb)
183
168
  aggregate = resolve_aggregate(domain, aggregate_name, verb)
184
169
 
@@ -186,17 +171,8 @@ module Hecks
186
171
  if command_name.include?(".")
187
172
  head, sub = command_name.split(".", 2)
188
173
  port = aggregate.port(head)
189
- # A port operation, reached by the same verb shape an entity
190
- # command already uses ("Domain::Aggregate.Head.Rest") — ports
191
- # are checked first, so an aggregate that ever declared both a
192
- # port and an entity of the same name would resolve to the
193
- # port; no domain in this corpus does, and `dispatch_port`'s
194
- # own header already named this as an open wire-spelling
195
- # question this resolves, not silently avoids. No `instance`
196
- # comes back — nothing is hydrated or saved by a port
197
- # operation (`PortOperationInterpreter`'s own header) — so
198
- # `Result#id`/`#state` are nil-safe (above) for exactly this
199
- # path.
174
+ # Ports are checked before entities, so a port wins a name an entity also declares.
175
+ # No instance comes back: a port operation hydrates and saves nothing.
200
176
  if port
201
177
  operation = port.operation(sub) ||
202
178
  raise(UnknownVerb, RefusalWording.render_site("UnknownVerb", "port_no_operation",
@@ -218,37 +194,31 @@ module Hecks
218
194
  @commands.call(domain, aggregate, command, invocation, saga_correlation)
219
195
  end
220
196
 
221
- # Correlation is set when each event is constructed, not merged on
222
- # here — it is part of the transaction, known from this method's
223
- # own argument before a single event exists. Stamping it onto
224
- # already-emitted events would keep an event mutable after it had
225
- # happened.
226
- #
227
- # The ordering that depends on it holds for the same reason:
228
- # `SagaInterpreter#advance` runs on this domain's `announced`
229
- # events within this very call, and finds the correlation already
230
- # there because it was never absent.
197
+ # Correlation is stamped as each event is built, so emitted events are never mutated.
231
198
 
232
199
  react(announced, domain, aggregate, outbox_rows)
233
200
 
234
201
  Result.new(verb: verb, instance: instance, events: announced,
235
- execution_plan: execution_plan, persistence_outcome: persistence_outcome)
202
+ execution_plan: execution_plan, persistence_outcome: persistence_outcome,
203
+ refused_reactions: refused_from(reactions),
204
+ blocking_reactions: ReactionOutcome.blocking(reactions, event_of: @registry.method(:reaction_event)),
205
+ reaction_defects: ReactionOutcome.defects(reactions))
236
206
  end
207
+ private :dispatch_collecting
237
208
 
238
- # **The one body both doors run** — `dispatch` (keywords) and
239
- # `dispatch_flat` (one Hash) differ only in how the call's parts are
240
- # spelled, never in what happens next.
241
- private :dispatch_invocation
209
+ # The reactions among `logged` that the domain refused, as plain facts.
210
+ #
211
+ # A crash in a reaction is a defect, not a refusal, and is warned where it happens.
212
+ def refused_from(logged)
213
+ logged.select { |entry| entry[:delivered] == false && !entry[:defect] }
214
+ .map { |entry| entry.slice(:policy, :trigger, :reason) }
215
+ end
216
+ private :refused_from
242
217
 
243
- # **Everything owed because `announced` committed** — policies first,
244
- # then sagas, the order this method always ran them in. The
245
- # command/entity interpreters hand back the outbox rows they
246
- # enqueued inside the save transaction (`Interpreting#
247
- # run_dispatch_order`); a port operation saves nothing, so its
248
- # rows are enqueued here, after the fact (`:enqueue`) — durable
249
- # still, just not transactional with anything, because there is
250
- # nothing for them to be transactional with. `nil` rows mean the
251
- # repository has no outbox: react directly, exactly as before.
218
+ # Runs the policy and saga reactions owed because `announced` committed.
219
+ #
220
+ # A port operation saves nothing, so its outbox rows are enqueued here (`:enqueue`);
221
+ # nil rows mean the repository has no outbox and reactions run directly.
252
222
  def react(announced, domain, aggregate, outbox_rows)
253
223
  return if announced.empty?
254
224
 
@@ -260,38 +230,16 @@ module Hecks
260
230
 
261
231
  # Answers whether a command would succeed right now, without saving, emitting or reacting.
262
232
  #
263
- # "If this were dispatched right now, would it succeed" — the same
264
- # pipeline #dispatch itself runs (arguments coerced, givens checked,
265
- # mutations applied in memory, ensures checked against the settled
266
- # result), except `step_save`/`step_emit` never run, and neither do
267
- # policies or sagas afterward: nothing here is committed, so nothing
268
- # should react to it. Built for exactly the shape a whole-board
269
- # postcondition needs to be tested against (a downstream project's
270
- # own chess domain, checking "does this move leave my own king in
271
- # check" — the alternative was dispatching a real, unrelated piece's
272
- # own move purely to trigger the check, which then had to avoid
273
- # interfering with the very position being tested).
274
- #
275
- # Raises the same refusals #dispatch does — a DomainRefusal
276
- # subclass propagates normally, so a caller checking "would this be
277
- # legal" writes the identical rescue clause a real dispatch already
278
- # needs; this returns `true` only when nothing was refused.
279
- #
280
- # **Never a port verb** — `PortOperationInterpreter`'s own side effects
281
- # (an external gateway call, say) have no meaningful in-memory-only
282
- # form, so this refuses one outright rather than silently running
283
- # it for real, which "dry" would otherwise quietly lie about.
233
+ # Runs the dispatch pipeline in memory only; refusals raise exactly as `dispatch` raises
234
+ # them. A port verb is refused: its side effects have no in-memory form.
284
235
  #
285
236
  # @param verb [String] the fully qualified aggregate or entity command verb
286
- # @param args [Hash{Symbol => Object}] the command's facts as flat keywords; a key named
287
- # `to` or `with` is an ordinary fact here, never routing (BUG#131)
288
- # @return [true] whenever nothing refused; a refusal is raised, never returned as false
289
- # @raise [Runtime::WiringError] if the verb names a port operation, or the aggregate's
290
- # repository cannot be resolved
291
- # @raise [Runtime::UnknownVerb] if the verb is not fully qualified, or names a domain,
292
- # aggregate, command or entity that is not declared
293
- # @raise [StandardError] any class in `Runtime::DOMAIN_REFUSALS` that the real dispatch
294
- # would raise
237
+ # @param args [Hash{Symbol => Object}] the facts as flat keywords; `to` and `with` are
238
+ # ordinary facts here, never routing
239
+ # @return [true] whenever nothing refused
240
+ # @raise [Runtime::WiringError] if the verb names a port operation
241
+ # @raise [Runtime::UnknownVerb] if the verb is malformed or names something undeclared
242
+ # @raise [StandardError] any `Runtime::DOMAIN_REFUSALS` class the real dispatch would raise
295
243
  def dry_run?(verb, **args)
296
244
  domain, aggregate_name, command_name = parse(verb)
297
245
  aggregate = resolve_aggregate(domain, aggregate_name, verb)
@@ -304,8 +252,7 @@ module Hecks
304
252
  "only for aggregate and entity commands"
305
253
  end
306
254
 
307
- # `to:`/`with:` are not keywords of this method — a key named
308
- # either is an ordinary fact here (BUG#131), so both go in as nil.
255
+ # `to:`/`with:` are not keywords here; a key named either is an ordinary fact.
309
256
  resolution = nil
310
257
  invocation = Invocation.from_call(verb, to: nil, with: nil, flat: args, receiver: :entity) do
311
258
  (resolution = EntityInterpreter::Resolution.of(aggregate, command_name)).command
@@ -320,36 +267,18 @@ module Hecks
320
267
  true
321
268
  end
322
269
 
323
- # Runs one port operation named by its parts, then the reactions its events are owed.
270
+ # Runs one port operation named by its parts, then the reactions its events owe.
324
271
  #
325
- # The door an adapter outside the bluebook calls through — never the
326
- # domain itself. `port_name`/`operation_name` are separate arguments
327
- # rather than one packed verb string on purpose: there is no established
328
- # wire spelling for "domain, aggregate, port, operation" yet, and
329
- # inventing one is a bigger decision than this call needs to make.
272
+ # The door for an adapter outside the bluebook; the parts are separate arguments because
273
+ # no wire spelling for a packed port verb exists.
330
274
  #
331
- # No adapter-to-port binding lookup happens here — that is
332
- # `Hecks.adapter`'s existing job (unchanged by this), and wiring "which
333
- # adapter may call this port" through is the next piece, not this one.
334
- #
335
- # @param domain [String, Symbol] name of the domain the aggregate belongs to
336
- # @param aggregate_name [String, Symbol] name of the aggregate that declares the port
337
- # @param port_name [String] name of the port, as the aggregate declares it
338
- # @param operation_name [String] name of the operation on that port
339
- # @param to [String, Hash, nil] the receiving aggregate's identity; when nil it is read
340
- # from the facts, by the operation's reference or identity attribute
275
+ # @param to [String, Hash, nil] the receiver; when nil it is read from the facts
341
276
  # @param with [Hash, nil] the operation's facts, keyed by argument name
342
- # @param flat [Hash] the wire form `dispatch_flat` takes, for the driving adapter
343
- # holding a decoded webhook rather than written keywords; it is where the operation's
344
- # own reference attribute is read from and lifted into `to:` when `to:` is nil
345
- # @return [Array<Runtime::Event>] the events the operation announced: one per declared
346
- # `emits` for an inbound operation, the one answering or refusing event for an
347
- # outbound one
348
- # @raise [Runtime::UnknownVerb] if the domain, aggregate, port or operation is not declared
349
- # @raise [Runtime::TypeMismatch] if no receiving identity can be found, or `to:`/`with:`
350
- # is malformed
351
- # @raise [Runtime::NotFound] if the receiving aggregate record does not exist
352
- # @raise [Runtime::WiringError] if the aggregate's repository cannot be resolved
277
+ # @param flat [Hash] the `dispatch_flat` wire form, for an adapter holding a decoded webhook
278
+ # @return [Array<Runtime::Event>] the events the operation announced
279
+ # @raise [Runtime::UnknownVerb] if the domain, aggregate, port or operation is undeclared
280
+ # @raise [Runtime::TypeMismatch] if no receiving identity is found, or `to:`/`with:` is bad
281
+ # @raise [Runtime::NotFound] if the receiving record does not exist
353
282
  def dispatch_port(domain, aggregate_name, port_name, operation_name, to: nil, with: nil, flat: {})
354
283
  aggregate = resolve_aggregate(domain, aggregate_name, "#{domain}::#{aggregate_name}.#{port_name}.#{operation_name}")
355
284
  port = aggregate.port(port_name) ||
@@ -369,22 +298,16 @@ module Hecks
369
298
 
370
299
  # Answers a declared query: an aggregate query, an entity query, or a read model.
371
300
  #
372
- # The verb's shape picks the interpreter. `"Domain.ReadModel"` — no `::` before the
373
- # dot — is a read model; `"Domain::Aggregate.Query"` is an aggregate query, and
374
- # `"Domain::Aggregate.Entity.Query"` an entity query.
301
+ # `"Domain.ReadModel"` (no `::`) is a read model; `"Domain::Aggregate.Query"` and
302
+ # `"Domain::Aggregate.Entity.Query"` are aggregate and entity queries.
375
303
  #
376
304
  # @param verb [String, Symbol] the query's verb, in one of the three shapes above
377
305
  # @param args [Hash{Symbol => Object}] the query's declared arguments
378
- # @return [Array<Hash>] for an aggregate query, one deep-frozen Hash per matching record,
379
- # its state with `:id` merged in last; for an entity query, one Hash per matching
380
- # element with the parent's reference key merged in first; for a read model, a
306
+ # @return [Array<Hash>] one Hash per matching record or element; a read model returns a
381
307
  # one-element Array holding a Hash of head name to projected rows
382
- # @raise [Runtime::UnknownVerb] if the verb is not fully qualified, or names a domain,
383
- # aggregate, entity, query or read model that is not declared
308
+ # @raise [Runtime::UnknownVerb] if the verb is malformed or names something undeclared
384
309
  # @raise [Runtime::NotFound] if a read model's root reference names no record
385
310
  # @raise [Runtime::TypeMismatch] if an argument cannot be coerced to its declared type
386
- # @raise [KeyError] if a rooted read model is asked without its reference argument
387
- # @raise [Runtime::WiringError] if the aggregate's repository cannot be resolved
388
311
  def query(verb, **args)
389
312
  domain, query_name = verb.to_s.split(".", 2)
390
313
  if query_name && !domain.include?("::")
@@ -404,20 +327,14 @@ module Hecks
404
327
 
405
328
  # Answers an aggregate or entity query through the reference interpreter alone.
406
329
  #
407
- # The same ask as `#query`, never answered by the bound adapter's
408
- # native hook. Read models have no reference twin, so only the
409
- # `"Domain::Aggregate.Query"` forms answer here; the fuzzer's
410
- # query oracle diffs this against `#query`'s answer.
330
+ # Never answered by the bound adapter's native hook; the fuzzer's query oracle diffs it
331
+ # against `#query`. Read models have no reference twin.
411
332
  #
412
- # @param verb [String] the fully qualified query verb, `"Domain::Aggregate.Query"` or
413
- # `"Domain::Aggregate.Entity.Query"`
333
+ # @param verb [String] `"Domain::Aggregate.Query"` or `"Domain::Aggregate.Entity.Query"`
414
334
  # @param args [Hash{Symbol => Object}] the query's declared arguments
415
- # @return [Array<Hash>] one Hash per matching record, its state with `:id` merged in
416
- # last; for an entity query, one Hash per matching element
417
- # @raise [Runtime::UnknownVerb] if the verb is not fully qualified, or names a domain,
418
- # aggregate, entity or query that is not declared
335
+ # @return [Array<Hash>] one Hash per matching record or element
336
+ # @raise [Runtime::UnknownVerb] if the verb is malformed or names something undeclared
419
337
  # @raise [Runtime::TypeMismatch] if an argument cannot be coerced to its declared type
420
- # @raise [Runtime::WiringError] if the aggregate's repository cannot be resolved
421
338
  def reference_query(verb, **args)
422
339
  domain, aggregate_name, query_name = parse(verb)
423
340
  aggregate = resolve_aggregate(domain, aggregate_name, verb)
@@ -425,43 +342,18 @@ module Hecks
425
342
  @queries.reference_call(domain, aggregate, query_name, args)
426
343
  end
427
344
 
428
- # Dispatches a reaction's command one level deeper in the cascade, as the system rather
429
- # than as the triggering caller.
430
- #
431
- # A reaction is the system acting, not the caller who happened to be
432
- # on the stack when the triggering command ran — the ambient caller
433
- # is cleared for the reaction's own dispatch, so a triggering
434
- # caller's role can neither satisfy nor block a reaction command it
435
- # has nothing to do with (Runtime::Caller.without).
436
- #
437
- # `Thread.current[:hecks_reaction_depth]`, not a plain ivar — this
438
- # `Dispatcher` instance is a single object shared by every thread
439
- # dispatching through it (a Puma worker pool, say), so a plain ivar
440
- # here is exactly the known Puma-concurrency bug class: two
441
- # concurrent top-level dispatches on different threads would
442
- # increment/decrement the same counter, letting one thread's nested
443
- # reaction depth leak into another thread's unrelated dispatch. A
444
- # `Mutex` is not the answer either — a reaction cascade re-enters
445
- # `reenter` on the same thread (see `SagaInterpreter#advance_saga`'s
446
- # own comment on why a non-reentrant `Mutex` can't guard this).
447
- # `Thread.current`-backed, saved/restored around the call with a
448
- # plain local + `ensure`, is the same idiom `Runtime::Caller`
449
- # (`caller.rb`) already established for exactly this shape of
450
- # per-thread ambient state.
345
+ # Dispatches a reaction's command one level deeper in the cascade, as the system.
451
346
  #
452
- # The depth is not checked here: a reacting interpreter asks
453
- # `reaction_depth_reached?` first and records an undelivered reaction
454
- # instead of calling this.
347
+ # The ambient caller is cleared (Runtime::Caller.without) so the triggering caller's role
348
+ # neither satisfies nor blocks the reaction. Depth lives in `Thread.current`, not an ivar
349
+ # or Mutex: the dispatcher is shared across threads and cascades re-enter on one thread.
350
+ # The depth limit is checked by the reacting interpreter, not here.
455
351
  #
456
352
  # @param verb [String] the fully qualified verb of the reaction's target command
457
- # @param saga_correlation [Hash{String => Object}, nil] correlation head => value when a
458
- # saga leg dispatches; nil for a policy
459
- # @param args [Hash{Symbol => Object}] the flat facts, read exactly as `dispatch_flat`
460
- # reads them, so `:to` and `:with` keys route rather than count as facts
461
- # @return [Runtime::Dispatcher::Result] the result of the nested dispatch
462
- # @raise [Runtime::UnknownVerb] if the verb names nothing declared
463
- # @raise [StandardError] any class in `Runtime::DOMAIN_REFUSALS` when the target
464
- # refuses; the policy and saga interpreters rescue these as recorded outcomes
353
+ # @param saga_correlation [Hash{String => Object}, nil] set when a saga leg dispatches
354
+ # @param args [Hash{Symbol => Object}] flat facts, read as `dispatch_flat` reads them
355
+ # @return [Runtime::Dispatcher::Result] the nested dispatch's result
356
+ # @raise [StandardError] any `Runtime::DOMAIN_REFUSALS` class; interpreters rescue these
465
357
  def reenter(verb, saga_correlation: nil, **args)
466
358
  depth = Thread.current[:hecks_reaction_depth].to_i
467
359
  Thread.current[:hecks_reaction_depth] = depth + 1
@@ -472,13 +364,12 @@ module Hecks
472
364
 
473
365
  # Answers whether the calling thread's reaction cascade is as deep as it may go.
474
366
  #
475
- # @return [Boolean] true once this thread's nested `reenter` calls number
476
- # `MAX_REACTION_DEPTH` or more; other threads' cascades are not counted
367
+ # @return [Boolean] true once nested `reenter` calls on this thread reach the limit
477
368
  def reaction_depth_reached? = Thread.current[:hecks_reaction_depth].to_i >= MAX_REACTION_DEPTH
478
369
 
479
- # Reads the cascade limit, for the reason an interpreter records when it declines to react.
370
+ # Reads the cascade limit an interpreter records when it declines to react.
480
371
  #
481
- # @return [Integer] `MAX_REACTION_DEPTH`, the number of nested reactions allowed
372
+ # @return [Integer] `MAX_REACTION_DEPTH`
482
373
  def max_reaction_depth = MAX_REACTION_DEPTH
483
374
 
484
375
  private