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
@@ -14,88 +14,43 @@ require_relative "command_interpreter/argument_gate"
14
14
 
15
15
  module Hecks
16
16
  module Runtime
17
- # Interprets a command dispatched against a nested entity (a dotted
18
- # verb like "Handler.Dispatch.Bind") rather than an aggregate root
19
- # directly: walks the entity chain off the parent aggregate, applies
20
- # the command's own DISPATCH_ORDER of steps against the located
21
- # element, then saves and emits through the same parent record a
22
- # plain aggregate command would. CommandInterpreter's sibling for
23
- # entity-owned commands.
17
+ # Interprets a command dispatched against a nested entity (a dotted verb
18
+ # like "Handler.Dispatch.Bind") rather than an aggregate root directly.
19
+ # CommandInterpreter's sibling for entity-owned commands.
24
20
  class EntityInterpreter
25
21
  include Interpreting
26
- # The same payload gate aggregate commands and port operations already
27
- # run — bug audit H1 (docs/audits/2026-08-10-main-bug-audit.md): without
28
- # this, this class runs neither refuse_unknown_arguments nor
29
- # refuse_absent_arguments, on a comment claiming "an entity inherits
30
- # its aggregate's own gate." Nothing on the entity dispatch path ever
31
- # ran one — confirmed live, `LedgerEntry.Reverse` accepted an
32
- # unrecognized `bogus_arg:` outright, and dispatching it with no
33
- # `narrative:` silently overwrote the stored narrative with `nil`
34
- # (`sets :narrative`'s bare self-referential form reads `args[:narrative]`
35
- # unconditionally). See `step_refuse_unknown_arguments`/
36
- # `step_refuse_absent_arguments`, below, for how the shared gate is
37
- # reused rather than reimplemented.
22
+ # Same argument gate aggregate commands and port operations run —
23
+ # without it, entity commands skip unknown/absent-argument checks.
38
24
  include CommandInterpreter::ArgumentGate
39
25
 
40
26
  attr_reader :registry
41
27
 
42
- # **The declared order** — Vocabulary::EntityDispatchOrder
43
- # (language/bluebook/vocabulary.bluebook), read off the generated table
44
- # the same way CommandInterpreter's own DISPATCH_ORDER is.
45
- # `refuse_unknown_arguments`/`refuse_absent_arguments` now lead it, same
46
- # position `AggregateDispatchOrder` holds them at (H1, above) — the only
47
- # remaining difference from the aggregate order is no
48
- # `assign_creation_attributes` (an entity is never created through this
49
- # path).
28
+ # The command-execution steps, in order, generated from
29
+ # Vocabulary::EntityDispatchOrder. Never includes
30
+ # `assign_creation_attributes` — an entity is never created directly.
50
31
  DISPATCH_ORDER = Hecks::Vocabulary.symbols("EntityDispatchOrder")
51
32
 
52
- # Same safety valve as `CommandInterpreter::MAX_STALE_WRITE_RETRIES` —
53
- # see that constant's own comment.
33
+ # Retry cap for a stale write — same reasoning as
34
+ # `CommandInterpreter::MAX_STALE_WRITE_RETRIES`.
54
35
  MAX_STALE_WRITE_RETRIES = 5
55
36
 
56
- # `instance` is the parent aggregate record (what gets saved and
57
- # returned) ; `element`/`view` are the entity piece itself — `view`
58
- # wraps `element` as it stood at `locate_element`, pre-mutation, and
59
- # `enforce_ensures` builds its own settled wrapper off `element` as it
60
- # stands after, the same split the original sequential code made.
61
- #
62
- # `chain` — S17, ADR 0026 — every entity the dotted verb passes
63
- # through, root-first (`[Handler, Dispatch]` for `Handler.Dispatch.
64
- # Bind`) ; `entity`/`entity_name` stay the chain's own last entry,
65
- # the one a command actually belongs to and a mutation actually
66
- # targets, so every step written before this ADR (enforce_givens,
67
- # apply_mutations, advance_lifecycle, element_identity, ...) reads
68
- # exactly as it always has. Only `locate_element` walks the chain.
69
- # `:chain` shadows Enumerable#chain on purpose — every read is
70
- # `ctx.chain` fetching the field (an Array of entities), never
71
- # `ctx.chain(other)` combining enumerables. Verified before disabling
72
- # this cop for it.
37
+ # `chain` holds every entity a dotted verb passes through, root-first
38
+ # (ADR 0026); `entity`/`entity_name` are always its last entry, the one
39
+ # a command targets. `instance` is the parent aggregate record;
40
+ # `element`/`view` are the entity piece itself, pre- and
41
+ # post-mutation. `:chain` intentionally shadows Enumerable#chain —
42
+ # every read is the struct field, never enumerable-combining.
73
43
  # rubocop:disable-next Lint/StructNewOverride
74
44
  Context = Struct.new(:domain, :aggregate, :entity, :entity_name, :command, :command_name,
75
45
  :args, :repository, :instance, :chain, :element, :view, :transition,
76
46
  :old_element, :result, :route, :plan, :persistence_outcome, :dry_run, :outbox_rows,
77
47
  :correction_bindings, :invocation)
78
48
 
79
- # A dotted entity verb resolved against its aggregate. `Resolution.of`
80
- # lives here rather than as a second public verb on the interpreter
81
- # (spec/runtime/command_rules_spec.rb holds each interpreter to one),
82
- # so `Dispatcher` can resolve it at the point `Invocation.from_call`
83
- # reads the declaring command — after `to:` is parsed, before the
84
- # facts are.
49
+ # A dotted entity verb resolved against its aggregate: the entity
50
+ # chain it names and the command located at the end of it.
85
51
  Resolution = Data.define(:entity_names, :chain, :command_name, :command) do
86
- # Resolves a dotted entity verb against `aggregate` into the entity
87
- # chain it walks and the command it names.
88
- #
89
- # Refuses UnknownVerb for an unknown entity or command.
90
- #
91
- # @param aggregate [Bluebook::Aggregate] the root aggregate the dotted verb
92
- # is resolved against
93
- # @param dotted [String, Symbol] the entity verb, with the leading
94
- # "Domain::Aggregate." already stripped (e.g. `"Handler.Dispatch.Bind"`)
95
- # @return [EntityInterpreter::Resolution] the resolved entity names, chain,
96
- # command name and command class
97
- # @raise [Runtime::UnknownVerb] if `dotted` names no entity, or the located
98
- # entity declares no such command
52
+ # Resolves a dotted entity verb into its entity chain and command,
53
+ # raising UnknownVerb if either segment doesn't exist.
99
54
  def self.of(aggregate, dotted)
100
55
  *entity_names, command_name = dotted.to_s.split(".")
101
56
  if entity_names.empty?
@@ -110,14 +65,8 @@ module Hecks
110
65
  new(entity_names: entity_names, chain: chain, command_name: command_name, command: command)
111
66
  end
112
67
 
113
- # **One hop per dotted segment** — `ProcessManager.Handler.Dispatch.Bind`
114
- # (once the dispatcher has already stripped "Domain::Aggregate.")
115
- # walks Handler off the aggregate, then Dispatch off Handler, each
116
- # step reading `.entities` exactly the way the single-level case
117
- # always did — a nested entity is "structurally interchangeable
118
- # with an aggregate" (Entity's own header) for precisely this
119
- # reason. Two levels is what Handler/Dispatch need today ; nothing
120
- # here assumes it stops at two.
68
+ # Walks one hop per dotted segment, resolving each entity name off
69
+ # the previous one — not limited to two levels.
121
70
  def self.walk(aggregate, entity_names)
122
71
  owner = aggregate
123
72
  entity_names.map do |name|
@@ -139,38 +88,18 @@ module Hecks
139
88
  @rules = rules
140
89
  end
141
90
 
142
- # `dry_run:` — CommandInterpreter#call's own twin, see that method's
143
- # comment for the shared reasoning (Dispatcher#dry_run?'s own entry
144
- # point). `step_save`/`step_emit` are the only two steps here that
145
- # read it either.
146
- # Retries the whole method body on `StaleWrite` — same reasoning as
147
- # `CommandInterpreter#call`'s own retry: a fresh `ctx`, a fresh
148
- # `step_hydrate_parent`/`step_locate_element` re-reading current
149
- # state.
150
- #
151
- # `resolution` is #resolve's answer; `invocation` the
152
- # `Runtime::Invocation` `Dispatcher` built — `ctx.args` is its
153
- # `to_args`, `ctx.route` its `target`.
154
- #
91
+ # Runs the entity dispatch order for one command, saving and emitting
92
+ # through the parent record. Retries once on `StaleWrite` with a fresh
93
+ # `ctx`, re-reading current state.
155
94
  # @param domain [String, Symbol] the domain `aggregate` belongs to
156
- # @param aggregate [Bluebook::Aggregate] the root aggregate owning the entity
157
- # chain the command targets
158
- # @param resolution [EntityInterpreter::Resolution] the resolved entity chain
159
- # and command, as `Resolution.of` builds it
160
- # @param invocation [Runtime::Invocation] the invocation `Dispatcher` built for
161
- # this call
162
- # @param dry_run [Boolean] whether to run every step through validation without
163
- # saving, emitting or enqueueing
164
- # @return [Array(Runtime::Instance, Array<Runtime::Event>,
165
- # Runtime::DependencyPlanning::Plan, Ports::Persistence::Execution,
166
- # Array<Runtime::Outbox::Row>)] the settled parent aggregate instance, emitted
167
- # events, execution plan, persistence outcome and outbox rows — the last
168
- # three nil on a dry run, which skips save/emit/outbox
169
- # @raise [StandardError] any class in `Runtime::DOMAIN_REFUSALS` when a
170
- # given/ensures/invariant/authorization/admissibility rule refuses
171
- # @raise [Runtime::StaleWrite] if concurrent writers beat this one through every
172
- # retry (`MAX_STALE_WRITE_RETRIES`)
173
- # @raise [Runtime::WiringError] if the aggregate's repository cannot be resolved
95
+ # @param aggregate [Bluebook::Aggregate] the root aggregate owning the entity chain
96
+ # @param resolution [EntityInterpreter::Resolution] the resolved entity chain and command
97
+ # @param invocation [Runtime::Invocation] the invocation `Dispatcher` built
98
+ # @param dry_run [Boolean] validate every step without saving, emitting or enqueueing
99
+ # @return [Array] instance, events, plan, persistence outcome, outbox rows — last three
100
+ # nil on a dry run
101
+ # @raise [StandardError] any `Runtime::DOMAIN_REFUSALS` class when a rule refuses
102
+ # @raise [Runtime::StaleWrite, Runtime::WiringError] every retry loses, or resolve fails
174
103
  def call(domain, aggregate, resolution, invocation, dry_run: false)
175
104
  chain = resolution.chain
176
105
  entity = chain.last
@@ -185,16 +114,12 @@ module Hecks
185
114
  ctx.chain = chain
186
115
  ctx.route = route
187
116
  ctx.dry_run = dry_run
188
- # `root_aggregate:` — `entity` is the immediate owner (what
189
- # `owner_fields` inside the Analyzer means), but a `parent.X`
190
- # read inside this command's own given/ensures means the root
191
- # aggregate's own field, not the entity's — `aggregate` here is
192
- # that root (this method's own first parameter, never the
193
- # entity). See DependencyPlanning::Analyzer.call's own header
194
- # for the bug this closes.
117
+ # `root_aggregate:` is the true root aggregate (this method's first
118
+ # parameter), never `entity` — a `parent.X` read in this command's
119
+ # given/ensures means the root's field, not the entity's.
195
120
  ctx.plan = DependencyPlanning::Analyzer.call(aggregate: entity, command: command, root_aggregate: aggregate)
196
- # **Resolved here, once** — see CommandInterpreter#call's own comment;
197
- # `step_hydrate_parent` reads `ctx.repository` without re-fetching.
121
+ # Resolved once, here — `step_hydrate_parent` reuses `ctx.repository`
122
+ # rather than re-fetching it.
198
123
  ctx.repository = @registry.repository(domain, aggregate)
199
124
  lock_id = Identity.best_effort(aggregate, args, route)
200
125
  run_dispatch_order_with_isolation(DISPATCH_ORDER, ctx, lock_key_id: lock_id)
@@ -208,18 +133,12 @@ module Hecks
208
133
 
209
134
  private
210
135
 
211
- # **A no-op, and untraced** — Vocabulary::EntityDispatchOrder's
212
- # decode_arguments. See CommandInterpreter#step_decode_arguments.
136
+ # No-op — entities have no `decode_arguments` step of their own.
213
137
  def step_decode_arguments(_ctx); end
214
138
 
215
- # `extra_identity_heads:` — every entity `ctx.chain` walks through, not
216
- # just the root aggregate `ArgumentGate` already knows about. A
217
- # two-hop dispatch (`Handler.Dispatch.Bind`) is addressed by both
218
- # hops' own identity, each read straight out of `args` by
219
- # `EntityElement#element_of` — refusing those as unknown would refuse
220
- # every legitimate nested-entity dispatch there is, the same reasoning
221
- # `ArgumentGate#refuse_unknown_arguments`'s own header gives for `:id`/
222
- # the root's `identity_heads`.
139
+ # `extra_identity_heads:` covers every entity in `ctx.chain`, not just
140
+ # the root — each hop is addressed by its own identity fields, which
141
+ # would otherwise be refused as unknown arguments.
223
142
  def step_refuse_unknown_arguments(ctx)
224
143
  step(:refuse_unknown_arguments) do
225
144
  refuse_unknown_arguments(ctx.domain, ctx.aggregate, ctx.command, ctx.args,
@@ -227,12 +146,8 @@ module Hecks
227
146
  end
228
147
  end
229
148
 
230
- # No `aggregate:` exemption to pass — that kwarg exists only for a
231
- # port operation's own self-address (`ArgumentGate#refuse_absent_
232
- # arguments`'s own comment); an entity command's chain identity never
233
- # reaches `command.attributes` in the first place (resolved as
234
- # addressing above, not as a declared fact), so there is nothing here
235
- # for the exemption to need to strip.
149
+ # No `aggregate:` exemption needed — an entity command's chain identity
150
+ # never reaches `command.attributes` in the first place.
236
151
  def step_refuse_absent_arguments(ctx)
237
152
  step(:refuse_absent_arguments) { refuse_absent_arguments(ctx.command, ctx.args) }
238
153
  end
@@ -268,61 +183,10 @@ module Hecks
268
183
  state: ctx.element)
269
184
  end
270
185
 
271
- # BUG#30 — the entity-level half of `CommandInterpreter#step_enforce_
272
- # givens`'s own structural-before-declared ordering (see that
273
- # method's comment for the shared reasoning): "does the fact this
274
- # command's `corrects` names even exist" is checked here too, once,
275
- # before the entity's own `given`s.
276
- #
277
- # Admissibility is checked against the parent/root, not the entity —
278
- # deliberately `ctx.instance`/`ctx.aggregate` (the parent aggregate
279
- # record and the root aggregate construct), never `ctx.view`/
280
- # `ctx.entity` (the entity's own pre-mutation view/construct). This
281
- # is not a simplification; it is the only choice that lines up with
282
- # how the event being corrected was actually recorded: an entity has
283
- # no event stream of its own — `CommandRules::Emission#emit` (called
284
- # from this class's own `step_emit`, and from `CommandInterpreter`'s
285
- # `step_emit` for an aggregate-level command alike) always stamps an
286
- # emitted event with the root aggregate's own qualified name
287
- # (`"#{domain}::#{aggregate.hecks_name}"`) and the parent record's
288
- # own id (`ctx.instance.id`), regardless of which level dispatched
289
- # it. `enforce_correction_target` (CommandRules::Admissibility)
290
- # looks a correction target up by exactly those two fields plus the
291
- # event name — asking it in terms of the entity instead would search
292
- # for an event key/id that no emitted event could ever actually
293
- # carry, and every entity-level correction would refuse
294
- # (NothingToCorrect) even against a real, already-emitted event.
295
- # `qa/stress_domains/corrections`' own `Entry.Amend` (corrects
296
- # "EntryRecorded", which `Ledger.Record` — an aggregate-level
297
- # command — actually emits) is exactly this shape: the corrected
298
- # event's `aggregate`/`id` are the ledger's, never the Entry's own
299
- # (an Entry has no id an event could be filed under in the first
300
- # place). `Fuzzing::Properties::Corrections#corrections_reference_
301
- # an_emitted_event` independently encodes the identical rule
302
- # (`aggregate_key` built off the outer aggregate for both the
303
- # `corrects` target and the `emits` produced event, regardless of
304
- # entity nesting depth) — this is that property's dispatch-time
305
- # enforcement counterpart, not a new invention.
306
- #
307
- # One structural consequence, worth being explicit about for a
308
- # Rust port: because the lookup is scoped to the parent record
309
- # (not to any one entity element within it), an entity-level
310
- # `corrects` only proves "this parent record has emitted the named
311
- # event at some point" — it does not, and cannot, further narrow
312
- # to "...specifically for THIS entity element" (a Ledger with three
313
- # Entries all satisfy the same `EntryRecorded`-was-emitted check).
314
- # That is not a gap this fix introduces: it is the same granularity
315
- # the aggregate-level check already has (one record, one event
316
- # history), just observed from one level down. A command wanting a
317
- # tighter, element-specific correlation has to encode it itself, in
318
- # its own `given`s, off `correction`-bound payload fields.
319
- #
320
- # `correction:` bindings computed here are threaded through to both
321
- # halves of the same command's admissibility, same as the
322
- # aggregate-level path: `ctx.correction_bindings` is read again by
323
- # `step_enforce_ensures`, below, so an `as:`-named binding is
324
- # visible to a settled-record `ensures` exactly as freely as it is
325
- # here, pre-mutation.
186
+ # Enforces this command's `given`s and correction-target admissibility.
187
+ # Checked against the parent aggregate, never the entity view — every
188
+ # emitted event is stamped with the root aggregate's name and the
189
+ # parent record's id, regardless of dispatch level.
326
190
  def step_enforce_givens(ctx)
327
191
  step(:enforce_givens) do
328
192
  ctx.correction_bindings = @rules.enforce_correction_target(ctx.instance, ctx.aggregate, ctx.command, domain: ctx.domain)
@@ -338,7 +202,7 @@ module Hecks
338
202
  def step_apply_mutations(ctx)
339
203
  ctx.old_element = ctx.element.dup unless ctx.command.ensures.empty?
340
204
  step(:apply_mutations) do
341
- pre = ctx.element.dup # C4.2 — the update set reads the element as it was
205
+ pre = ctx.element.dup # the update set reads the element as it stood before mutation
342
206
  ctx.command.mutations.each do |mutation|
343
207
  EntityElement.apply_to_element(@rules, ctx.aggregate, ctx.entity, ctx.element, mutation, ctx.args, pre)
344
208
  end
@@ -357,46 +221,33 @@ module Hecks
357
221
  def step_enforce_ensures(ctx)
358
222
  step(:enforce_ensures) do
359
223
  settled = Instance.new(aggregate: ctx.entity, id: ctx.view.id, state: ctx.element)
360
- # `correction:` — same `as:`-bound corrected-event payload
361
- # `step_enforce_givens` already located, above; `|| {}` covers
362
- # a command with no `corrects` mutation at all, where
363
- # `ctx.correction_bindings` is `{}` from that call already, or
364
- # (belt-and-braces, matching `CommandInterpreter#step_enforce_
365
- # ensures`'s own identical `|| {}`) never set.
224
+ # `correction:` reuses the `as:`-bound bindings `step_enforce_givens`
225
+ # already located; `|| {}` covers a command with no `corrects`
226
+ # mutation, where `ctx.correction_bindings` may be unset.
366
227
  @rules.enforce_ensures(settled, ctx.command, ctx.args, old: ctx.old_element, domain: ctx.domain, parent: ctx.instance,
367
228
  correction: ctx.correction_bindings || {})
368
229
  end
369
230
  end
370
231
 
371
- # The parent aggregate's own invariants — `ctx.instance` is the
372
- # parent record an entity mutation writes into (this file's own
373
- # `Context` comment), the same boundary an aggregate-level
374
- # invariant guards regardless of which interpreter changed it. No
375
- # separate "entity invariant" exists (S10, ADR 0025 scopes
376
- # `invariant` to the aggregate only) — see `Admissibility#
377
- # enforce_invariants`'s own comment.
232
+ # Enforces the parent aggregate's own invariants — there is no separate
233
+ # "entity invariant" concept (ADR 0025 scopes `invariant` to the aggregate).
378
234
  def step_enforce_invariants(ctx)
379
235
  step(:enforce_invariants) { @rules.enforce_invariants(ctx.instance, ctx.aggregate, domain: ctx.domain) }
380
236
  end
381
237
 
382
- # `dry_run:` skips the write half of this step — see
383
- # CommandInterpreter#step_save's own comment (BUG#127): the
384
- # reference-existence check stays unconditional, only the actual
385
- # persist is behind the early return.
238
+ # `dry_run:` skips only the persist — the reference-existence check
239
+ # above stays unconditional either way.
386
240
  def step_save(ctx)
387
241
  step(:save) { @rules.resolve_state_references(ctx.domain, ctx.aggregate, ctx.instance.state) }
388
242
 
389
243
  return if ctx.dry_run
390
244
 
391
245
  step(:save) do
392
- # `expected_version:` — see CommandInterpreter#step_save's own
393
- # comment: nil for a repository that isn't CAS-capable, or an
394
- # instance never read from storage, either of which falls
395
- # through to a plain save inside `AppendOnly#save`.
246
+ # `expected_version:` is nil for a non-CAS repository or an instance
247
+ # never read from storage — either falls through to a plain save.
396
248
  ctx.persistence_outcome = ctx.repository.save(ctx.instance, expected_version: ctx.instance.version)
397
249
  if ctx.persistence_outcome.status == :stale
398
- # Not a `RefusalWording.render` call — see
399
- # `CommandInterpreter#step_save`'s identical branch and
250
+ # Intentionally not a `RefusalWording.render` call — see
400
251
  # `Runtime::StaleWrite`'s own comment.
401
252
  raise(StaleWrite,
402
253
  "#{ctx.command.hecks_name} on #{ctx.aggregate.hecks_name} " \
@@ -414,10 +265,8 @@ module Hecks
414
265
  ctx.result = step(:emit) { @rules.emit(ctx.command, ctx.domain, ctx.aggregate, ctx.instance, ctx.args, ctx.repository) }
415
266
  end
416
267
 
417
- # The parent aggregate, addressed exactly as `CommandInterpreter#hydrate`
418
- # addresses one acting on itself — derive from the declared identity first
419
- # (`Identity.of`), and let a bare `id:` name an already-derived record when
420
- # the identity itself is not what the caller is holding.
268
+ # Finds the parent aggregate: the declared identity first, then a bare
269
+ # `id:` for a record the caller derived itself.
421
270
  def parent(repository, aggregate, entity_name, command_name, args, route = nil)
422
271
  parent_id = route&.aggregate ||
423
272
  Identity.of(aggregate, args) ||
@@ -433,13 +282,9 @@ module Hecks
433
282
  found.dup
434
283
  end
435
284
 
436
- # `locate_chain`/`element_of`/`element_identity`/`apply_to_element` and
437
- # their own helpers live in `Runtime::EntityElement`
438
- # (see that file's own header), shared rather than kept here, so
439
- # `CommandInterpreter`'s own `delegate_to_entity` step can locate and
440
- # mutate the same element the same way, against an aggregate record
441
- # already held in memory. `call`, above, and every `step_*` method
442
- # reach them through that module.
285
+ # Entity element helpers (`locate_chain`, `element_of`, `element_identity`,
286
+ # `apply_to_element`) live in `Runtime::EntityElement`, shared with
287
+ # `CommandInterpreter#delegate_to_entity`.
443
288
  end
444
289
  end
445
290
  end
@@ -7,38 +7,27 @@ module Hecks
7
7
  # everything downstream of a `.bluebook`/`.hecksagon`/`.world` declaration.
8
8
  # See `lib/hecks/runtime.rb` for the module's own facade and boot entry points.
9
9
  module Runtime
10
+ # A dispatched verb names no aggregate, entity or command.
10
11
  class UnknownVerb < StandardError; end
12
+ # A settled record failed a command's `ensures`.
11
13
  class EnsuresNotMet < StandardError; end
12
14
 
13
- # `detail` — the failing comparison's own resolved operands, "left: X,
14
- # right: Y" — set only when the given's top-level shape is a bare
15
- # comparison (`Evaluator.comparison_detail`'s own comment has the full
16
- # scoping); nil otherwise. Deliberately not folded into `#message`:
17
- # that string is pinned byte-for-byte across this corpus's own specs
18
- # (`raise_error(GivenNotMet, "...")`, command_rules_spec.rb and every
19
- # domain that vendors this gem) as contract, so changing its shape by
20
- # default would be a breaking change for every one of them. Riding on
21
- # `#detailed_message` instead (Ruby 3.2+, what irb/a Rails console's
22
- # own unhandled-exception banner already calls to show more than
23
- # `#message`) means the detail actually reaches a human staring at a
24
- # live refusal, without moving the string anything else asserts on.
15
+ # A command's `given` refused. `detail` holds the failing comparison's resolved operands
16
+ # ("left: X, right: Y") when the given is a bare comparison, else nil.
17
+ #
18
+ # `detail` rides on `#detailed_message`; `#message` stays byte-for-byte, as specs pin it.
25
19
  class GivenNotMet < StandardError
26
20
  attr_reader :detail
27
21
 
28
- # @param message [String, nil] the refusal text, pinned byte-for-byte across specs
29
- # @param detail [String, nil] the failing comparison's resolved operands ("left: X,
30
- # right: Y"), or nil when the given's top-level shape is not a bare comparison
22
+ # @param message [String, nil] the refusal text
23
+ # @param detail [String, nil] the failing comparison's resolved operands, if any
31
24
  def initialize(message = nil, detail: nil)
32
25
  super(message)
33
26
  @detail = detail
34
27
  end
35
28
 
36
- # Renders `message` with `detail` appended, for a human reading an unhandled refusal.
29
+ # Overrides Ruby's own error formatting to append the refusal's detail.
37
30
  #
38
- # @param highlight [Boolean] unused; accepted for compatibility with `Exception#
39
- # detailed_message`'s own signature
40
- # @param opts [Hash] unused; accepted for compatibility with `Exception#
41
- # detailed_message`'s own signature
42
31
  # @return [String] `message`, with `" (#{detail})"` appended when `detail` is present
43
32
  def detailed_message(highlight: false, **opts)
44
33
  base = super
@@ -46,117 +35,45 @@ module Hecks
46
35
  end
47
36
  end
48
37
 
38
+ # A command addressed a record that does not exist.
49
39
  class NotFound < StandardError; end
40
+ # A command is not admissible from the record's current lifecycle state.
50
41
  class LifecycleRefused < StandardError; end
42
+ # An argument carries the wrong kind of value for its declared type.
51
43
  class TypeMismatch < StandardError; end
52
- # An argument the command does not declare. Sibling of TypeMismatch : that one
53
- # is the right name carrying the wrong thing, this one is a name the command
54
- # never had. Both are the payload gate refusing before any rule runs.
44
+ # An argument the command does not declare.
55
45
  class UnknownArgument < StandardError; end
56
- # The third of the trio, and the one that was missing : a name the command does
57
- # declare, absent. TypeMismatch is the right name carrying the wrong thing,
58
- # UnknownArgument a name that was never declared, AbsentArgument a declared name
59
- # that never arrived. Between them they say a command takes exactly the
60
- # arguments it declares — no others, and all of them.
46
+ # An argument the command declares but the call omitted.
61
47
  class AbsentArgument < StandardError; end
62
- # A creating command whose derived identity already names a record. The
63
- # record it would have overwritten stands ; the dispatch that tried to
64
- # mint a second one over it is what refuses.
48
+ # A creating command whose derived identity already names a record.
65
49
  class AlreadyExists < StandardError; end
66
- # A declared, non-optional attribute a record predates — added since
67
- # it was written, with no default: to fill it and no translation
68
- # declaring what an old record should read there. `GuardState`
69
- # (command_rules/admissibility.rb) is the one place this is raised: a
70
- # `given`/`ensures`/`invariant` that reads the field would otherwise
71
- # evaluate against a value nobody wrote, which is the same silent-
72
- # wrong-answer class as an unpopulated projection reading "not
73
- # active" (ADR 0025, "Added attributes and absence"). An optional
74
- # attribute in the same spot reads nil instead — that is what
75
- # optional means, and this refusal is deliberately narrower than the
76
- # nil-read it sits beside, not a replacement for it.
50
+ # A required attribute the stored record predates, with no default or translation to fill it.
51
+ # Raised only by `GuardState`; an optional attribute reads nil instead (ADR 0025).
77
52
  class AttributeAbsent < StandardError; end
78
- # The same silent-wrong-answer class as above, one line up — a
79
- # `projects` field (S12, ADR 0025) this record predates, or that no
80
- # rebuild sweep has populated yet, read by a `given`/`ensures`/
81
- # `invariant` as though it carried a real value. `GuardState` is
82
- # the one place this is raised, the same way AttributeAbsent is —
83
- # a declared field the record does not yet carry, distinguished
84
- # from that one only in why: an ordinary attribute is absent
85
- # because nobody backfilled it, a projected field is absent
86
- # because nobody has swept it yet.
53
+ # A `projects` field the record predates or no rebuild sweep has populated yet.
54
+ # Raised by `GuardState`.
87
55
  class ProjectionAbsent < StandardError; end
88
- # A query or read model declares `authorize policy, tenant: :field` and
89
- # the caller did not pass that field — the one half of `authorize` this
90
- # runtime can enforce without a caller-identity system: the boundary
91
- # itself, not whether the caller actually holds `policy`. See
92
- # Runtime::TenantScope.
56
+ # A query or read model declares `authorize policy, tenant: :field` and the caller omitted it.
93
57
  class Unauthorized < StandardError; end
94
- # `corrects` names a past event this record must have already emitted
95
- # (CommandBuilder#corrects_impl's own comment) — a fact the expression
96
- # evaluator cannot check (it is not a predicate over the record's own
97
- # fields, it is "did this exact record ever announce this"), so it is
98
- # raised structurally, the same way AlreadyExists/NotFound are, rather
99
- # than being expressible as an ordinary `given`. Raised by
100
- # `CommandRules::Admissibility#enforce_correction_target`.
58
+ # A `corrects` command whose target event this record never emitted.
59
+ # Raised by `CommandRules::Admissibility#enforce_correction_target`.
101
60
  class NothingToCorrect < StandardError; end
102
61
 
103
- # A runtime fault, not a domain refusal — deliberately absent from
104
- # `DOMAIN_REFUSALS` below and from `vocabulary.bluebook`'s own
105
- # `DomainRefusal` list. Raised when an optimistic-concurrency CAS write
106
- # (`AppendOnly#save`'s `expected_version:`) finds the stored version has
107
- # moved since this instance was read — someone else's write committed
108
- # in between. `CommandInterpreter#call`/`EntityInterpreter#call` catch
109
- # this themselves and retry the whole dispatch from a fresh hydrate, so
110
- # `enforce_givens` re-evaluates against the now-current state; a caller
111
- # only ever sees this escape when every retry is exhausted under
112
- # sustained contention — an operational condition (many concurrent
113
- # writers hammering one aggregate), not a business rule a domain author
114
- # declared. See docs/decisions/ (concurrency-control ADR).
62
+ # A CAS write (`expected_version:`) found the stored version moved since the read.
63
+ # A runtime fault, not a domain refusal: the interpreters retry, so it escapes only under
64
+ # sustained contention.
115
65
  class StaleWrite < StandardError; end
116
66
 
117
- # A Lambda-routed domain's own refusal (rust/host, `Runtime::
118
- # RemoteDispatcher`), carrying Rust's own refusal text verbatim —
119
- # not yet mapped back to the specific matching class above
120
- # (GivenNotMet vs. EnsuresNotMet vs. ...), a real, known,
121
- # documented gap: the WASM projector's own event/refusal-wording
122
- # parity work (ADR 0021) makes the text match Ruby's, but nothing
123
- # yet parses that text back into a typed Ruby exception the way a
124
- # local dispatch already raises one directly. Callers that only
125
- # need "the domain said no" (not which specific rule) are
126
- # unaffected; callers pattern-matching a specific refusal class
127
- # against a Lambda-routed domain are the ones this gap would bite.
67
+ # A Lambda-routed domain's refusal (`Runtime::RemoteDispatcher`), with Rust's text verbatim.
68
+ # It is not mapped back to a specific class such as GivenNotMet.
128
69
  class RemoteRefusal < StandardError; end
129
70
 
130
- # The domain saying no — the errors a reaction may legitimately meet and
131
- # record as an undelivered outcome. A policy whose target refuses is a fact
132
- # about the domain ; the originating command still stands.
133
- #
134
- # Everything else is a defect : a NoMethodError in an interpreter, a
135
- # NameError from a missing constant, a TypeError from a bad assumption. A
136
- # blanket `rescue StandardError` would fold both into one line —
137
- # `delivered: false, reason: "..."` — making a crash in the runtime
138
- # indistinguishable from a rule doing its job, reading as normal
139
- # operation in the log.
71
+ # The refusals that are the domain saying no, which a reaction records as undelivered.
72
+ # Anything else is a runtime defect and must propagate rather than read as a refusal.
140
73
  #
141
- # UnknownVerb is one of these, and deliberately : a cross-domain policy
142
- # (`across "Notifications"`) fires in deployments where that domain is not
143
- # loaded, and recording the undelivered reaction rather than raising is the
144
- # design — spec/policy_spec states it in so many words, "records a reaction
145
- # it cannot deliver rather than swallowing it".
146
- # InvariantViolation belongs here and was missing. A value object refusing
147
- # its own rule is the domain saying no as plainly as a given is — but the
148
- # class is declared over in value.rb and never made the list, so the policy
149
- # and saga interpreters, which rescue exactly these, would let it propagate
150
- # as though the runtime had broken. A reaction whose target violates an
151
- # invariant is declined, not crashed. Found by spec/domain_refusal_spec on
152
- # its first run : every corpus refusal must be a class named here, and 23
153
- # of banking's were InvariantViolation.
154
- # The names come from the language, the classes from this module.
155
- # `DomainRefusal` declares which refusals are the domain's own —
156
- # a rule the caller broke — as against a runtime fault. Resolving
157
- # each name here means a refusal declared but never defined fails
158
- # at load with a NameError, rather than being quietly absent from
159
- # a list nothing re-checks.
74
+ # UnknownVerb is included on purpose: a cross-domain policy fires where its target domain is
75
+ # not loaded. InvariantViolation is included too, so a value object's refusal is declined.
76
+ # Names come from the language; resolving them here fails at load if one is undefined.
160
77
  DOMAIN_REFUSALS = Hecks::Vocabulary.fetch("DomainRefusal").map { |name| const_get(name) }.freeze
161
78
  end
162
79
  end
@@ -2,32 +2,10 @@ require "time"
2
2
 
3
3
  module Hecks
4
4
  module Runtime
5
- # `correlation` is not on the wire — `to_h` below deliberately omits it,
6
- # the same as `bin/run`'s own event projection does. It is runtime
7
- # bookkeeping stamped by `Dispatcher#dispatch` when a saga leg's own
8
- # dispatch causes this event (see `SagaInterpreter#deliver_saga_dispatch`
9
- # and `#saga_correlation`) : a Hash of `correlation_head` -> correlation
10
- # value, so an event caused by one saga cannot be misread by an unrelated
11
- # one correlating on a different field. Absent for any event no saga
12
- # dispatch caused, which is most of them.
5
+ # An emitted domain event. `correlation` (saga head -> value) is runtime bookkeeping
6
+ # and deliberately absent from `to_h`.
13
7
  Event = Struct.new(:name, :aggregate, :id, :payload, :occurred_at, :correlation, keyword_init: true) do
14
- # Freezes the event deep, so nothing about it can change after it happens.
15
- #
16
- # An emitted event is a record of something that happened, and a
17
- # mutable audit trail is not one. The payload — the domain fact the
18
- # event carries — is frozen through on emission: freezing the Hash
19
- # alone would leave every value in it editable in place, which is
20
- # the shape all four previous freezing bugs had.
21
- #
22
- # The whole event, not just its payload. Correlation is set at
23
- # construction rather than merged in here by `Dispatcher#dispatch`
24
- # after the event already exists, because it is part of the
25
- # transaction and known from `dispatch`'s own argument before
26
- # anything is emitted — that is what keeps an event immutable once
27
- # it exists.
28
- #
29
- # The log stays appendable: new events are still recorded. It is
30
- # each event that stops changing once it exists.
8
+ # Freezes the event deep, payload and correlation included.
31
9
  #
32
10
  # @return [void]
33
11
  def emit!