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
@@ -8,11 +8,8 @@ require_relative "../bluebook/expression/evaluator"
8
8
 
9
9
  module Hecks
10
10
  module Runtime
11
- # Fires the declared `policy` reactions triggered by one just-emitted
12
- # event: scans every loaded bluebook (a policy commonly lives in a
13
- # different domain than the event it reacts to), checks each
14
- # candidate's `where` guard, and re-enters the dispatcher for each
15
- # delivery — recording every outcome on the reaction log.
11
+ # Fires the declared `policy` reactions triggered by one just-emitted event,
12
+ # recording every outcome on the reaction log.
16
13
  class PolicyInterpreter
17
14
  attr_reader :registry
18
15
 
@@ -26,61 +23,35 @@ module Hecks
26
23
  end
27
24
 
28
25
  # Fires every declared policy `event` triggers, recording each outcome on
29
- # the registry's reaction log.
30
- #
31
- # `deliver` returns `nil` for a policy whose `where` did not hold —
32
- # silently, the same as a policy `policies_for` never selected at all
33
- # (an `event_qualifier` miss carries no reaction_log entry either) —
34
- # so nothing is appended for it. A `for_each` policy answers an array
35
- # (one record per matched row) rather than one record ; `Array(...)`
36
- # is wrong here (it would explode a plain record Hash into its own
37
- # key/value pairs), so the two shapes are told apart explicitly.
38
- # `only:` — one `[policy, home_domain]` pair, the outbox relay's
39
- # way of running exactly the consumer a row names (`Runtime::
40
- # Outbox::Relay#run_consumer`) instead of every policy that
41
- # matches the event. Selection is otherwise identical.
26
+ # the registry's reaction log. A policy whose `where` does not hold logs nothing.
42
27
  #
43
28
  # @param event [Runtime::Event] the just-emitted event to react to
44
29
  # @param domain [String, Symbol] the domain `event`'s own aggregate belongs
45
30
  # to, the emitting domain's policies fire first
46
31
  # @param only [Array(Bluebook::Policy, String), nil] one `[policy, home_domain]`
47
- # pair to run exactly, instead of scanning every loaded bluebook for candidates
32
+ # pair to run exactly (the outbox relay's consumer), instead of scanning every
33
+ # loaded bluebook for candidates
34
+ # @param event_uid [String, nil] the outbox uid every consumer of this event shares, when the
35
+ # event was rebuilt from an outbox row; otherwise the event object itself is the identity
48
36
  # @return [void]
49
- def react(event, domain, only: nil)
37
+ def react(event, domain, only: nil, event_uid: nil)
50
38
  selected = only ? [only] : policies_for(event, domain)
51
39
  selected.each do |policy, home_domain|
52
40
  result = deliver(policy, event, home_domain)
53
41
  next if result.nil?
54
42
 
55
- (result.is_a?(Array) ? result : [result]).each { |record| @registry.reaction_log << record }
43
+ # A for_each policy answers an array; Array(...) would explode a record Hash.
44
+ identity = event_uid || event.object_id
45
+ (result.is_a?(Array) ? result : [result]).each { |record| @registry.log_reaction(record, event: identity) }
56
46
  end
57
47
  end
58
48
 
59
49
  private
60
50
 
61
- # Scans every loaded bluebook, not just the emitting command's own —
62
- # a policy commonly lives in the consumer's bluebook, reacting
63
- # passively to an event a different domain's aggregate emits (the
64
- # corpus-standard shape : `world/conception/bluebook/domain_cell.bluebook`'s
65
- # ConceiveOnAbsorption reacts `on "DomainAbsorbed"`, an event
66
- # `body/organs/bluebook/gut.bluebook`'s Gut.Absorb emits — two
67
- # different bluebooks, joined only by the event's name). Restricting
68
- # the scan to the emitting domain's own bluebook (the previous
69
- # shape) silently drops every cross-domain reaction : the policy is
70
- # never even a candidate, no refusal, no log entry, nothing —
71
- # confirmed against the corpus's own .behaviors fixtures, several of
72
- # which encode this exact cross-bluebook cascade as their contract.
73
- #
74
- # Returns [policy, home_domain] pairs rather than bare policies —
75
- # `deliver`/`deliver_for_each` fall back to the reacting policy's
76
- # own domain (not the emitting one) when a trigger or for_each route
77
- # is bare, and that fallback has to travel with each match now that
78
- # a single event can surface policies from several different homes.
79
- #
80
- # The emitting domain's own policies first, in declaration order,
81
- # then other bluebooks' in load order (C10.2) — the same order the
82
- # outbox lays its rows in (`Outbox::Fanout.policies`) and the Rust
83
- # kernel runs (`react_policies`: its own table, then cross-domain).
51
+ # Scans every loaded bluebook, since a policy commonly lives in a different
52
+ # domain than the event it reacts to. Returns [policy, home_domain] pairs: the
53
+ # home domain is the fallback for a bare trigger or for_each route. Order is the
54
+ # emitting domain first, then load order, matching Outbox::Fanout and the Rust kernel.
84
55
  def policies_for(event, domain)
85
56
  emitting = Naming.demodulise(event.aggregate)
86
57
 
@@ -93,17 +64,9 @@ module Hecks
93
64
  end
94
65
  end
95
66
 
96
- # The guard, evaluated against the triggering event's own payload —
97
- # a policy has no aggregate instance of its own to read state from,
98
- # so `state` is empty and every bare name a `where` resolves comes
99
- # from `attrs` (Expression::Resolver#fetch checks `attrs` before
100
- # `state`, so this is exactly the shape `enforce_givens` already
101
- # gives a command's own given, minus the settled-record half a
102
- # policy simply has none of). Called from inside `deliver`'s own
103
- # rescue-guarded body (both callers, below) — never guarded here —
104
- # so an EvaluationError (an unresolvable field, a bad comparison) is
105
- # caught the same way any other reaction defect is, not swallowed as
106
- # though the policy had merely declined to fire.
67
+ # Evaluated against the event payload alone (a policy has no aggregate state).
68
+ # Not rescued here: an EvaluationError must reach `deliver`'s defect rescue, not
69
+ # read as a policy that declined to fire.
107
70
  def where_holds?(policy, event)
108
71
  return true if policy.where.to_s.empty?
109
72
 
@@ -111,11 +74,7 @@ module Hecks
111
74
  end
112
75
 
113
76
  def deliver(policy, event, domain)
114
- # `record` assigned before any branch that can raise, same reason
115
- # `deliver_for_each`'s own header gives : both rescue clauses below
116
- # call `.merge` on it, and a defect raised before it existed would
117
- # be caught here only to raise a second, different NoMethodError
118
- # trying to record the first one.
77
+ # `record` must exist before anything can raise: both rescues call `.merge` on it.
119
78
  target = "#{policy.target_domain || domain}::#{policy.trigger_command}"
120
79
  record = { policy: policy.name, on: event.name, trigger: target }
121
80
 
@@ -131,66 +90,26 @@ module Hecks
131
90
  @door.reenter(target, **reaction_invocation(target, args, policy, event))
132
91
  record.merge(delivered: true)
133
92
  rescue *DOMAIN_REFUSALS => e
134
- # The target refused — a fact about the domain, recorded and not
135
- # fatal to the command that emitted the event.
136
93
  record.merge(delivered: false, reason: e.message)
137
94
  rescue StandardError => e
138
- # A defect, not a refusal — a NoMethodError in an interpreter, a
139
- # NameError from a missing constant, a TypeError from a bad
140
- # assumption : exactly the class of thing DOMAIN_REFUSALS
141
- # (errors.rb, see the comment above that constant) deliberately
142
- # excludes, and for the reason that comment gives at length —
143
- # folding a crash into the same `delivered: false` shape as an
144
- # ordinary refusal makes a broken runtime read as normal operation
145
- # in the log. This clause does not reopen that hole: it is a
146
- # second, narrower rescue, tried only once the first one above has
147
- # already declined to match, so a legitimate refusal still takes
148
- # the branch above and a defect always takes this one.
149
- #
150
- # Catching it here is safe for a fact this method's caller cannot
151
- # see from where it sits: by the time `react` runs, the command
152
- # that emitted `event` has already succeeded and persisted —
153
- # `Dispatcher#dispatch` calls `@policies.react` only after its own
154
- # `announced` events are already in hand. Letting this exception
155
- # keep propagating would not undo that command (nothing here is
156
- # transactional across aggregates) — it would only blow up the
157
- # original caller's `dispatch` call for a failure that happened in
158
- # a different command, one the caller never asked to run and has no
159
- # way to compensate for. So the defect is recorded, distinguishably
160
- # (`defect: true`, plus the error's own class — nothing here is
161
- # allowed to read like an ordinary refusal), warned to STDERR so it
162
- # is never silent, and left exactly where it happened for a human
163
- # to find — never re-raised, and never swallowed either.
95
+ # A defect, not a refusal: recorded with `defect: true` and warned, never
96
+ # re-raised. The emitting command has already persisted, so propagating would
97
+ # only fail an unrelated caller. See DOMAIN_REFUSALS for why the two stay apart.
164
98
  warn "[hecks] defect in reaction — policy #{policy.name} on #{event.name} " \
165
99
  "firing #{target}: #{e.class}: #{e.message}"
166
100
  record.merge(delivered: false, reason: e.message, defect: true, error_class: e.class.name)
167
101
  end
168
102
 
169
- # **The fan-out** — `policy.for_each` names a query ; this runs it
170
- # against the triggering event's own payload (the same source
171
- # `deliver`'s own ordinary path forwards to `trigger` wholesale) and
172
- # fires `trigger` once per row, merging each row's own id into the
173
- # forwarded payload under whichever key the target command itself
174
- # expects to be addressed by (`Behaviour::Command#addressing_key_for`
175
- # — never a guessed, one-size mint: `Account.Freeze`, addressed by
176
- # `account` because it is declared on Account and self-references
177
- # it, refused every dispatch for as long as this hardcoded
178
- # `<aggregate>_id` instead — a real bug, found wiring `for_each`
179
- # into a real domain for the first time, not a hypothetical). A
180
- # refusal is recorded per row and the fan-out continues ; a crash
181
- # resolving the query itself, or the target command's own inability
182
- # to address this aggregate at all (`addressing_key_for` answering
183
- # `nil` — a domain-authoring mistake, not a data problem), is a
184
- # single top-level defect for the policy, the same shape `deliver`'s
185
- # own outer rescue already gives every other reaction.
103
+ # Runs the `for_each` query against the event payload and fires the trigger once
104
+ # per row, addressing each row by `addressing_key_for`. A refusal is recorded per
105
+ # row and the fan-out continues; a crash resolving the query or an unaddressable
106
+ # target is one top-level defect for the policy.
186
107
  def deliver_for_each(policy, event, domain, target, record)
187
108
  return nil unless where_holds?(policy, event)
188
109
 
189
110
  query_domain, aggregate_name, query_name = policy.for_each_route(domain)
190
111
  aggregate = resolve_query_aggregate(query_domain, aggregate_name, policy.for_each)
191
- # The query reads the event, never the projection — `with:` says
192
- # what the trigger is given, and the fan-out's query is asking a
193
- # different question (which rows) in the event's own vocabulary.
112
+ # The query reads the event, never the `with:` projection: it asks which rows.
194
113
  query_args = for_each_query_args(aggregate.query(query_name), event)
195
114
  rows = QueryInterpreter.new(@registry).call(query_domain, aggregate, query_name, query_args)
196
115
  reference_key = addressing_key_for(target, aggregate_name)
@@ -206,24 +125,9 @@ module Hecks
206
125
  record.merge(delivered: false, reason: e.message, defect: true, error_class: e.class.name)
207
126
  end
208
127
 
209
- # The event's own identity is a fact too, not only its payload. A
210
- # for_each query commonly filters by the emitting record's own
211
- # identity (`OpenForCustomer`'s own `reference:`, scoping by the
212
- # very customer who was just suspended) — a fact routing keeps
213
- # separate from payload (`to:`/`with:`, what the facade's own
214
- # bang-methods always use), so `event.payload` alone does not carry
215
- # it. Without this, the query would silently see neither the field
216
- # it needs nor any error saying why — an empty result read as
217
- # "nothing to freeze" instead of "the customer" the whole reaction
218
- # exists to catch.
219
- #
220
- # Merged in only when the query declares an argument by that exact
221
- # name and the emitting aggregate's own identity is genuinely what
222
- # that name means (`construct.identity_heads`) — the same guard
223
- # `SagaInterpreter::Correlation#self_identified?` uses for the
224
- # identical shape one call away, so an unrelated aggregate sharing
225
- # an argument name by coincidence never gets misread as this one.
226
- # Never overrides a value the payload already supplied.
128
+ # The event's own identity is not in its payload, so a query argument named
129
+ # after an identity head of the emitting aggregate is filled from `event.id`.
130
+ # Without it the query silently sees nothing. Never overrides a payload value.
227
131
  def for_each_query_args(query, event)
228
132
  args = event.payload.transform_keys(&:to_sym)
229
133
  return args unless query
@@ -242,26 +146,10 @@ module Hecks
242
146
  args
243
147
  end
244
148
 
245
- # **What the trigger is given**. Undeclared, the event's whole payload
246
- # forwards verbatim — the behaviour every policy had before `with:`
247
- # existed, and still the right default for a trigger shaped like
248
- # its event.
249
- #
250
- # Declared, it is the same reading a saga's own `dispatch ...,
251
- # with:` gets (`SagaInterpreter#dispatch_args`): a Symbol names a
252
- # field on the source below, anything else is a literal the policy
253
- # supplies itself. A saga additionally resolves against its own
254
- # memory and correlation key; a policy has neither — it holds
255
- # nothing between events — so the source is the event, plus:
256
- #
257
- # `extra` is a fan-out's row key, merged into the source before the
258
- # projection rather than after it. That is what lets a `for_each`
259
- # policy name the row it is acting on — `with: { account: :account }`
260
- # — and therefore what lets one send the row and nothing else. A
261
- # trigger needing only which record to act on is the ordinary case
262
- # for a fan-out, and before this it could not be written: the whole
263
- # event rode along, and the target had to declare every field of it
264
- # whether it read them or not.
149
+ # What the trigger is given: the whole event payload verbatim when no `with:` is
150
+ # declared, otherwise the projection (a Symbol names a payload field, anything else
151
+ # is a literal). `extra` is a fan-out's row key, merged into the source before the
152
+ # projection so a `with:` can name the row it acts on.
265
153
  def trigger_args(policy, event, extra = {})
266
154
  payload = event.payload.transform_keys(&:to_sym).merge(extra)
267
155
  return payload unless ReactionInvocation.projection_declared?(policy)
@@ -274,44 +162,16 @@ module Hecks
274
162
  label: "#{policy.name}'s trigger"
275
163
  )
276
164
 
277
- # The raw inputs `args` was resolved from — same additive,
278
- # Ruby-only shape SagaInterpreter#deliver_saga_dispatch's own
279
- # saga_dispatch_log gets, for Properties.dispatch_binding_
280
- # fidelity's own independent re-derivation of Policy#with_spec's
281
- # 2-branch resolution (Symbol → payload lookup, anything else →
282
- # literal — a policy holds no correlation and no memory, so
283
- # `payload` — the merged event-payload-plus-fan-out-row source —
284
- # is the whole source, unlike a saga's own 4-branch one).
165
+ # Raw inputs kept for Properties.dispatch_binding_fidelity's re-derivation.
285
166
  @registry.policy_dispatch_log << { policy: policy.name, on: event.name, payload: payload,
286
167
  with_spec: policy.with_spec, args: args }
287
168
  args
288
169
  end
289
170
 
290
- # The emitting record's own identity is a fact a projection may read
291
- # — the same reasoning `for_each_query_args` gives one method up,
292
- # extended from the fan-out's query to the trigger's own `with:`.
293
- # Routing separated from payload (`to:`/`with:`) stopped carrying
294
- # the emitting aggregate's identity in the payload, which is right
295
- # for the event (a KnightCaptured is a fact about a knight, not a
296
- # re-statement of which game) but left a cross-aggregate reaction
297
- # with no way to say which record to address: chess's Graveyard is
298
- # one-per-game, fed by policy from every piece's own Captured
299
- # event, and its burials had no way to name the game — the
300
- # dispatcher fell through to the captured piece's `id` as the
301
- # graveyard's identity and refused every one ("no Graveyard with
302
- # label.value \"bb\""). Same-aggregate targets were already covered
303
- # (`ReactionInvocation.source_receiver_for` lifts Event.id), so
304
- # this is the other aggregate's half of that.
305
- #
306
- # Offered under the emitting aggregate's own identity heads, only
307
- # to an explicit projection (a legacy wholesale forward keeps its
308
- # exact old payload), and never over a value the payload itself
309
- # carries. `event.id` is the scalar the identity resolves to, so a
310
- # projection naming it as the target's own identity head routes it
311
- # as the receiver (`Identity.of` coerces a scalar against a
312
- # single-field VO head), and one naming it as a declared attribute
313
- # carries it as a fact. The build-time validator admits the same
314
- # names (`BluebookBuilder.check_with_spec!`).
171
+ # The emitting record's identity, offered to an explicit `with:` projection under
172
+ # the emitting aggregate's identity heads (never over a payload value). Without it
173
+ # a cross-aggregate reaction cannot say which record to address. The build-time
174
+ # validator admits the same names (`BluebookBuilder.check_with_spec!`).
315
175
  def emitter_identity(event)
316
176
  return {} if event.id.nil? || event.id.to_s.empty?
317
177
 
@@ -322,18 +182,9 @@ module Hecks
322
182
  construct.identity_heads.to_h { |head| [head.to_sym, event.id] }
323
183
  end
324
184
 
325
- # Resolves `target` ("Domain::Aggregate.Command", the same shape
326
- # `deliver`'s own caller already built) back to its own declared
327
- # command, then asks it how it expects to be addressed by a row of
328
- # `aggregate_name` — see `Behaviour::Command#addressing_key_for`'s
329
- # own comment for the two shapes that answers. Raises (caught by
330
- # `deliver_for_each`'s own outer `rescue StandardError`, the same
331
- # "a defect, not a refusal" treatment `resolve_query_aggregate`'s
332
- # own `UnknownVerb` already gets one level up) rather than
333
- # silently falling back on a guess when the target command cannot
334
- # be resolved, or genuinely cannot be addressed by this aggregate
335
- # at all — either is a domain-authoring mistake worth surfacing
336
- # loudly, not a row this fan-out simply skips.
185
+ # Resolves `target` back to its declared command and asks it how a row of
186
+ # `aggregate_name` addresses it. Raises rather than guessing when the command is
187
+ # unresolvable or cannot be addressed: a domain-authoring mistake to surface.
337
188
  def addressing_key_for(target, aggregate_name)
338
189
  target_domain, target_aggregate_name, target_command_name = Naming.split_verb(target)
339
190
  command = @registry.bluebook(target_domain)&.aggregate(target_aggregate_name)&.command(target_command_name)
@@ -355,9 +206,7 @@ module Hecks
355
206
  reason: "reaction depth #{@door.max_reaction_depth} reached")
356
207
  end
357
208
 
358
- # Already merged, by `trigger_args` — the row key belongs in the
359
- # source a `with:` projection reads from, not bolted onto its
360
- # result, or a projection could never name the row it acts on.
209
+ # The row key is already merged by `trigger_args`, so a projection can name it.
361
210
  @door.reenter(target, **reaction_invocation(target, args, policy, event))
362
211
  row_record.merge(delivered: true)
363
212
  rescue *DOMAIN_REFUSALS => e
@@ -374,14 +223,6 @@ module Hecks
374
223
  )
375
224
  end
376
225
 
377
- # `for_each`'s own query route moved onto the Policy itself
378
- # (Behaviour::Policy#for_each_route) — one reading the interpreter
379
- # and the fuzzer's fan-out property both call, rather than the
380
- # same split spelled twice. The reference-key the dispatch itself
381
- # uses is `addressing_key_for`, above — a property of the target
382
- # command, not of the policy, so it lives on `Behaviour::Command`
383
- # instead.
384
-
385
226
  def resolve_query_aggregate(domain, aggregate_name, verb)
386
227
  bluebook = @registry.bluebook(domain) ||
387
228
  raise(UnknownVerb, RefusalWording.render_site("UnknownVerb", "no_domain", domain: domain, verb: verb))
@@ -1,3 +1,4 @@
1
+ require_relative "adapter_lookup"
1
2
  require_relative "interpreting"
2
3
  require_relative "command_interpreter/argument_gate"
3
4
  require_relative "event"
@@ -6,15 +7,8 @@ require_relative "../naming"
6
7
 
7
8
  module Hecks
8
9
  module Runtime
9
- # The dispatch pipeline for a port operation — called by an adapter living
10
- # outside the bluebook entirely, never by the domain itself. Deliberately
11
- # a trimmed CommandInterpreter: the same payload gate and coercion
12
- # (ArgumentGate, Interpreting#normalize_args), but no `given`, no
13
- # `mutations`, no lifecycle, no save. A port operation does not act on an
14
- # aggregate instance — it translates an external call into an event in
15
- # this domain's own vocabulary, and whatever mutation follows happens
16
- # wherever a `policy` reacts to that event, exactly as it would for any
17
- # command-emitted one.
10
+ # Dispatch pipeline for a port operation, called by an adapter outside the bluebook.
11
+ # A trimmed CommandInterpreter: argument gate and coercion, but no `given`, mutations or save.
18
12
  class PortOperationInterpreter
19
13
  include Interpreting
20
14
  include CommandInterpreter::ArgumentGate
@@ -34,24 +28,17 @@ module Hecks
34
28
  @rules = rules
35
29
  end
36
30
 
37
- # `invocation` — the `Runtime::Invocation` `Dispatcher` built;
38
- # `ctx.args` is its `to_args`, `ctx.route` its `target`.
39
- #
31
+ # `ctx.args` is the invocation's `to_args`, `ctx.route` its `target`.
40
32
  # @param domain [String] the domain the aggregate belongs to
41
33
  # @param aggregate [Bluebook::Aggregate] the aggregate the port operation belongs to
42
34
  # @param operation [Bluebook::PortOperation] the port operation to dispatch
43
35
  # @param invocation [Runtime::Invocation] the invocation `Dispatcher` built for this call
44
- # @return [Array<Runtime::Event>] the events recorded: the operation's own `emits` for
45
- # an inbound operation, or a single `answers`/`refuses` event for an outbound one
46
- # (an adapter failure is recorded as a `refuses` event, not raised)
47
- # @raise [Runtime::UnknownArgument] if `invocation` offers an argument the operation
48
- # does not declare
49
- # @raise [Runtime::AbsentArgument] if `invocation` omits a non-optional declared
50
- # argument
51
- # @raise [Runtime::TypeMismatch] if an offered argument does not coerce to its declared
52
- # type
53
- # @raise [Runtime::NotFound] if an offered reference or the operation's own receiving
54
- # record cannot be found
36
+ # @return [Array<Runtime::Event>] `emits` (inbound), or one `answers`/`refuses`
37
+ # event (outbound; an adapter failure is recorded as `refuses`, not raised)
38
+ # @raise [Runtime::UnknownArgument] if `invocation` offers an undeclared argument
39
+ # @raise [Runtime::AbsentArgument] if `invocation` omits a non-optional declared argument
40
+ # @raise [Runtime::TypeMismatch] if an offered argument does not coerce to its declared type
41
+ # @raise [Runtime::NotFound] if an offered reference or the receiving record is missing
55
42
  def call(domain, aggregate, operation, invocation)
56
43
  ctx = Context.new(domain, aggregate, operation, invocation.to_args)
57
44
  ctx.invocation = invocation
@@ -89,37 +76,13 @@ module Hecks
89
76
  ctx.result = step(:emit) { ctx.operation.outbound? ? ask(ctx) : emit(ctx) }
90
77
  end
91
78
 
92
- # The domain calling out, and both endings recorded.
93
- #
94
- # The adapter is found the same way every other port's is — by name,
95
- # across whatever adapters this boot loaded — so an `asks` is bound by
96
- # an adapter declaring `port "IssueTracker"` and nothing new to learn.
97
- #
98
- # Every failure is an answer. A raise from the far side of a boundary is
99
- # not an exception in this domain's terms, it is the outside saying no,
100
- # and the chapter already named the word for that. So the rescue is
101
- # deliberately wide: a timeout, a bad credential, an adapter that does
102
- # not exist, a nil where a number was wanted — all of them become the
103
- # `refuses` event, carrying what was said. A policy reacts to it, a
104
- # retry counter reads it, and nothing has to catch anything.
105
- #
106
- # An ask is handed the record it is about.
107
- #
108
- # An inbound operation deliberately cannot read state — it is the
109
- # anti-corruption boundary, translating a fact from outside, and letting
110
- # it read the aggregate would make it a second place rules live. That
111
- # rule was written for that direction and does not survive the crossing.
79
+ # The domain calling out. Any failure, however wide (timeout, bad credential, missing
80
+ # adapter), becomes the `refuses` event rather than a raise, so a policy can react to it.
81
+ # The adapter is found by port name across the adapters this boot loaded.
112
82
  #
113
- # An outbound one almost always needs the record. `asks "File"` names
114
- # `reference_to Ticket` and the adapter needs the ticket's repository,
115
- # title and body — which are on the ticket, and which the policy that
116
- # triggered this cannot supply because a command's event payload is its
117
- # arguments, not its state. Without this, every ask would have to have
118
- # its data re-passed through the command that fired it, so the same text
119
- # would live in two places and could differ.
120
- #
121
- # Arguments win over state, because an argument is what this call said
122
- # and state is what the record happens to hold.
83
+ # Unlike an inbound operation, an ask is handed the record's held state: the adapter
84
+ # needs data that lives on the record, and an event payload carries only arguments.
85
+ # Arguments win over state.
123
86
  def ask(ctx)
124
87
  payload = held_state(ctx).merge(materialise(ctx.args))
125
88
  answer = adapter_for(ctx).public_send(Naming.snake(ctx.operation.hecks_name), **payload)
@@ -128,21 +91,10 @@ module Hecks
128
91
  announce(ctx, ctx.operation.refuses, ctx.args.merge(refusal: { value: "#{e.class}: #{e.message}" }))
129
92
  end
130
93
 
131
- # The answer is spread, not nested — and that is what makes the loop
132
- # close. A policy re-enters its target with the event payload verbatim;
133
- # it cannot reach inside a key. So an answer tucked under `answered:`
134
- # can be read by a human and by nothing else, and the command that
135
- # should record the issue number never gets one.
136
- #
137
- # Spread, the adapter's own keys are the arguments of whatever command
138
- # reacts to the answering event. Which is a real contract on the adapter
139
- # — it must return what that command takes, in the shape the runtime
140
- # coerces (`{ number: { value: 43 } }`, not `43`) — and naming it here
141
- # is cheaper than a mapping layer nobody could see into.
142
- #
143
- # A non-Hash answer keeps the old shape: a port that returns a URL
144
- # string has nothing to spread, and `answered:` is the honest word for
145
- # a single unnamed value.
94
+ # The answer is spread, not nested: a policy re-enters its target with the event
95
+ # payload verbatim and cannot reach inside a key. The adapter's keys are therefore the
96
+ # arguments of the reacting command, in the shape the runtime coerces
97
+ # (`{ number: { value: 43 } }`, not `43`). A non-Hash answer is kept under `answered:`.
146
98
  def spread(answer)
147
99
  return { answered: answer } unless answer.is_a?(Hash)
148
100
 
@@ -157,21 +109,16 @@ module Hecks
157
109
  end
158
110
  end
159
111
 
160
- # The record, if there is one. A record that does not exist yet is not
161
- # an error here — the ask still goes, carrying only its arguments, and
162
- # whatever the adapter makes of that is its own business. Refusing
163
- # would put a second existence check behind the one `resolve_references`
164
- # already performed.
112
+ # The record, if there is one. A missing record is not an error here: the ask still
113
+ # goes with only its arguments, since `resolve_references` already checked existence.
165
114
  def held_state(ctx)
166
115
  ctx.instance ? Value.materialize(ctx.instance.state) : {}
167
116
  rescue StandardError
168
117
  {}
169
118
  end
170
119
 
171
- # The port this operation belongs to, found by asking the aggregate
172
- # rather than threading it through the call — the dispatcher already
173
- # resolved it once to get here, and a second parameter carried purely so
174
- # this method can read it would be a parameter every other step ignores.
120
+ # The port this operation belongs to, found through the aggregate rather than
121
+ # threaded through the call.
175
122
  def port_name_for(ctx)
176
123
  owning = ctx.aggregate.ports.find { |port| port.operations.any? { |op| op.equal?(ctx.operation) } }
177
124
  owning&.name or raise WiringError,
@@ -179,21 +126,10 @@ module Hecks
179
126
  end
180
127
 
181
128
  def adapter_for(ctx)
182
- name = port_name_for(ctx)
183
- implementations = @registry.adapters.values.select { |adapter| adapter.port == name }
184
-
185
- case implementations.size
186
- when 1 then Adapters.const_get(implementations.first.name).new
187
- when 0 then raise WiringError, "no adapter implements the #{name} port — nothing can answer #{ctx.operation.hecks_name}"
188
- else raise WiringError,
189
- "#{implementations.size} adapters implement the #{name} port " \
190
- "(#{implementations.map(&:name).sort.join(', ')}) — the runtime will not choose for you"
191
- end
129
+ AdapterLookup.call(@registry, port_name_for(ctx), asked: ctx.operation.hecks_name)
192
130
  end
193
131
 
194
- # A Value never crosses the boundary — an adapter is somebody else's
195
- # code and should be handed plain data, the same reasoning `JsonDoor`
196
- # gives for materialising before it hands anything to an HTTP caller.
132
+ # Adapters are handed plain data, never a Value.
197
133
  def materialise(args) = Value.materialize(args)
198
134
 
199
135
  def announce(ctx, event_name, payload)
@@ -208,13 +144,8 @@ module Hecks
208
144
  [event]
209
145
  end
210
146
 
211
- # The one place this differs from CommandRules::Emission — there is no
212
- # mutated instance to read an id off, because nothing was hydrated or
213
- # saved. The record this event is about is named by whichever attribute
214
- # is a reference to the owning aggregate (PortOperationBuilder#build
215
- # already refused to build an operation with none), so its coerced
216
- # value — already a plain id, never an object, per
217
- # Value::Coercion#refuse_object_reference — is what stamps the event.
147
+ # Unlike CommandRules::Emission there is no mutated instance to read an id off; the
148
+ # event is stamped with the coerced reference to the owning aggregate (already a plain id).
218
149
  def emit(ctx)
219
150
  ctx.operation.emits.map do |event_name|
220
151
  event = Event.new(