hecks 3.9.1 → 3.11.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 (504) hide show
  1. checksums.yaml +4 -4
  2. data/examples/pizzas/bluebook/pizzas.bluebook +29 -0
  3. data/examples/pizzas/bluebook/pizzas.hecksagon +7 -0
  4. data/exe/hecks +4 -4
  5. data/lib/hecks/adapters/driven/d1.rb +2 -10
  6. data/lib/hecks/adapters/driven/heki.adapter +1 -1
  7. data/lib/hecks/adapters/driven/heki.rb +2 -12
  8. data/lib/hecks/adapters/driven/lambda.adapter +1 -1
  9. data/lib/hecks/adapters/driven/lambda.rb +3 -18
  10. data/lib/hecks/adapters/driven/postgres.rb +4 -11
  11. data/lib/hecks/adapters/driven/sqlite.adapter +1 -1
  12. data/lib/hecks/adapters/driven/sqlite.rb +2 -10
  13. data/lib/hecks/adapters/driving/admission.rb +46 -0
  14. data/lib/hecks/adapters/driving/cli/nesting.rb +36 -0
  15. data/lib/hecks/adapters/driving/cli/shorthand.rb +88 -0
  16. data/lib/hecks/adapters/driving/cli.rb +127 -0
  17. data/lib/hecks/adapters/driving/cli_runner/answers.rb +160 -0
  18. data/lib/hecks/adapters/driving/cli_runner/resolution.rb +155 -0
  19. data/lib/hecks/adapters/driving/cli_runner/settling.rb +120 -0
  20. data/lib/hecks/adapters/driving/cli_runner/streaming.rb +93 -0
  21. data/lib/hecks/adapters/driving/cli_runner/suggestions.rb +47 -0
  22. data/lib/hecks/adapters/driving/cli_runner.rb +69 -0
  23. data/lib/hecks/adapters/driving/command_request.rb +121 -0
  24. data/lib/hecks/adapters/driving/handle.rb +214 -0
  25. data/lib/hecks/adapters/driving/json.rb +136 -0
  26. data/lib/hecks/adapters/driving/launcher_options.rb +267 -0
  27. data/lib/hecks/adapters/driving/mcp/properties.rb +49 -0
  28. data/lib/hecks/adapters/driving/mcp/tool_calls.rb +116 -0
  29. data/lib/hecks/adapters/driving/mcp/tool_definitions/auditing.rb +53 -0
  30. data/lib/hecks/adapters/driving/mcp/tool_definitions/calling.rb +71 -0
  31. data/lib/hecks/adapters/driving/mcp/tool_definitions/reading.rb +99 -0
  32. data/lib/hecks/adapters/driving/mcp/tool_definitions.rb +18 -0
  33. data/lib/hecks/adapters/driving/mcp.rb +159 -0
  34. data/lib/hecks/adapters/driving/mcp_guide_cache.rb +78 -0
  35. data/lib/hecks/adapters/driving/mcp_scope/argument_policy.rb +97 -0
  36. data/lib/hecks/adapters/driving/mcp_scope/env_problems.rb +69 -0
  37. data/lib/hecks/adapters/driving/mcp_scope/presenter.rb +83 -0
  38. data/lib/hecks/adapters/driving/mcp_scope.rb +213 -0
  39. data/lib/hecks/adapters/driving/ruby/aggregate_module.rb +171 -0
  40. data/lib/hecks/adapters/driving/ruby/chapter.rb +91 -0
  41. data/lib/hecks/adapters/driving/ruby.rb +83 -0
  42. data/lib/hecks/adapters/driving/usage_cache.rb +144 -0
  43. data/lib/hecks/{doors.rb → adapters/driving.rb} +10 -6
  44. data/lib/hecks/behaviors/expectations/boot.rb +1 -1
  45. data/lib/hecks/bench/ruby_runner.rb +1 -1
  46. data/lib/hecks/bluebook/ask_resolution.rb +130 -0
  47. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +8 -2
  48. data/lib/hecks/bluebook/assembly/contracts/rules.rb +4 -2
  49. data/lib/hecks/bluebook/assembly/contracts/structure.rb +3 -1
  50. data/lib/hecks/bluebook/assembly/marks.rb +1 -0
  51. data/lib/hecks/bluebook/attribute.rb +1 -1
  52. data/lib/hecks/bluebook/behaviour/command.rb +13 -8
  53. data/lib/hecks/bluebook/behaviour/policy.rb +30 -0
  54. data/lib/hecks/bluebook/capabilities/attribute_values.rb +72 -0
  55. data/lib/hecks/bluebook/capabilities.rb +91 -9
  56. data/lib/hecks/bluebook/domain_port.rb +16 -4
  57. data/lib/hecks/bluebook/dsl/adapter_builder.rb +18 -6
  58. data/lib/hecks/bluebook/dsl/binding_proxy.rb +13 -0
  59. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/computed_sources.rb +98 -0
  60. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/fan_out_rows.rb +42 -0
  61. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/projected_fields.rb +14 -2
  62. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/provisions.rb +69 -3
  63. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/with_projections.rb +17 -10
  64. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +5 -0
  65. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -0
  66. data/lib/hecks/bluebook/dsl/command_builder/mutations.rb +8 -1
  67. data/lib/hecks/bluebook/dsl/command_builder/operands.rb +121 -0
  68. data/lib/hecks/bluebook/dsl/command_builder.rb +2 -0
  69. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +10 -1
  70. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +45 -2
  71. data/lib/hecks/bluebook/dsl/policy_builder.rb +47 -10
  72. data/lib/hecks/bluebook/dsl/rule_reference.rb +7 -4
  73. data/lib/hecks/bluebook/dsl/world_builder.rb +1 -1
  74. data/lib/hecks/bluebook/expression/ast_json/emitters.rb +6 -0
  75. data/lib/hecks/bluebook/expression/ast_json.rb +9 -6
  76. data/lib/hecks/bluebook/expression/ast_reader.rb +14 -9
  77. data/lib/hecks/bluebook/expression/projection.json +36 -0
  78. data/lib/hecks/bluebook/expression/resolver/operations.rb +31 -0
  79. data/lib/hecks/bluebook/expression/resolver/parsing.rb +38 -5
  80. data/lib/hecks/bluebook/expression/resolver/scanning.rb +22 -5
  81. data/lib/hecks/bluebook/expression/resolver/values.rb +10 -0
  82. data/lib/hecks/bluebook/expression/resolver.rb +20 -1
  83. data/lib/hecks/bluebook/hecksagon.rb +23 -3
  84. data/lib/hecks/bluebook/lifecycle.rb +22 -3
  85. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +13 -1
  86. data/lib/hecks/bluebook/meta_validator/modes.rb +4 -1
  87. data/lib/hecks/bluebook/meta_validator/readings.rb +18 -1
  88. data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +2 -1
  89. data/lib/hecks/bluebook/meta_validator/shapes.rb +5 -0
  90. data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +1 -1
  91. data/lib/hecks/bluebook/meta_validator.rb +12 -12
  92. data/lib/hecks/bluebook/model_check/ask_checks.rb +71 -0
  93. data/lib/hecks/bluebook/model_check/policy_checks.rb +2 -1
  94. data/lib/hecks/bluebook/model_check/reference_checks.rb +70 -0
  95. data/lib/hecks/bluebook/model_check.rb +8 -2
  96. data/lib/hecks/bluebook/policy.rb +4 -2
  97. data/lib/hecks/bluebook/smoke_test.rb +1 -1
  98. data/lib/hecks/bluebook/synthesizer.rb +2 -0
  99. data/lib/hecks/bluebook.rb +1 -0
  100. data/lib/hecks/cli/command_table.rb +1 -1
  101. data/lib/hecks/cli/console.rb +2 -1
  102. data/lib/hecks/cli/document.rb +1 -1
  103. data/lib/hecks/cli/launcher_words.rb +4 -4
  104. data/lib/hecks/cli/mcp.rb +4 -4
  105. data/lib/hecks/cli/project_cli/launcher_source.rb +2 -2
  106. data/lib/hecks/cli/project_cli/templates.rb +5 -5
  107. data/lib/hecks/cli/project_cli.rb +9 -6
  108. data/lib/hecks/cli/run.rb +2 -2
  109. data/lib/hecks/cli/smoke_http/checks.rb +4 -1
  110. data/lib/hecks/cli/smoke_http/transport.rb +3 -3
  111. data/lib/hecks/cli/smoke_http.rb +3 -0
  112. data/lib/hecks/codemod.rb +5 -2
  113. data/lib/hecks/corpus/routes.rb +7 -0
  114. data/lib/hecks/corpus/rust.rb +3 -2
  115. data/lib/hecks/deploy/bluebook/deploy.bluebook +124 -2
  116. data/lib/hecks/deploy/bluebook/deploy.hecksagon +8 -0
  117. data/lib/hecks/deploy/oidc.json +16 -3
  118. data/lib/hecks/doc/reference/rendering.rb +6 -3
  119. data/lib/hecks/forms/app/commands.rb +8 -7
  120. data/lib/hecks/forms/app/queries.rb +2 -1
  121. data/lib/hecks/forms/app.rb +1 -1
  122. data/lib/hecks/forms/record_renderer.rb +1 -1
  123. data/lib/hecks/framework/bluebook/privacy.bluebook +11 -0
  124. data/lib/hecks/fuzzing/concurrent_dispatch.rb +4 -1
  125. data/lib/hecks/fuzzing/failure_triage.rb +2 -1
  126. data/lib/hecks/fuzzing/mutation/run.rb +11 -4
  127. data/lib/hecks/fuzzing/properties/catalog.rb +6 -4
  128. data/lib/hecks/fuzzing/properties/guaranteed_by_construction.rb +18 -11
  129. data/lib/hecks/fuzzing/properties/guards.rb +1 -1
  130. data/lib/hecks/fuzzing/self_consistency/saga_redelivery.rb +1 -1
  131. data/lib/hecks/fuzzing/self_consistency.rb +6 -2
  132. data/lib/hecks/fuzzing/shrinker.rb +3 -1
  133. data/lib/hecks/fuzzing/value_generator.rb +19 -5
  134. data/lib/hecks/gate/stages.yml +4 -10
  135. data/lib/hecks/grammar/evolve.rb +1 -1
  136. data/lib/hecks/grammar/expression_operators.json +372 -0
  137. data/lib/hecks/grammar/operators.rb +3 -1
  138. data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +10 -10
  139. data/lib/hecks/hecks/adapters/codebase/inspection/rubycritic.rb +35 -0
  140. data/lib/hecks/hecks/adapters/codebase/inspection.rb +104 -0
  141. data/lib/hecks/hecks/adapters/codebase/publishing.rb +2 -1
  142. data/lib/hecks/hecks/adapters/codebase/release_facts.rb +12 -2
  143. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +2 -1
  144. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +1 -1
  145. data/lib/hecks/hecks/adapters/cost_explorer.rb +8 -5
  146. data/lib/hecks/hecks/adapters/deploy_toolchain/clearing.rb +51 -0
  147. data/lib/hecks/hecks/adapters/deploy_toolchain/statuses.rb +2 -1
  148. data/lib/hecks/hecks/adapters/deploy_toolchain.rb +2 -0
  149. data/lib/hecks/hecks/adapters/finding_github.rb +13 -6
  150. data/lib/hecks/hecks/adapters/first_admin.rb +2 -2
  151. data/lib/hecks/hecks/adapters/github_rulesets.rb +6 -3
  152. data/lib/hecks/hecks/adapters/in_process_boot.rb +1 -1
  153. data/lib/hecks/hecks/adapters/journal_store/compaction.rb +1 -1
  154. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +10 -20
  155. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +28 -5
  156. data/lib/hecks/hecks/adapters/local_files.rb +2 -2
  157. data/lib/hecks/hecks/adapters/rehearsal/audit_report.rb +107 -0
  158. data/lib/hecks/hecks/adapters/rehearsal/census.rb +71 -0
  159. data/lib/hecks/hecks/adapters/rehearsal/declaration.rb +133 -0
  160. data/lib/hecks/hecks/adapters/rehearsal/environment.rb +83 -0
  161. data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +142 -0
  162. data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +96 -0
  163. data/lib/hecks/hecks/adapters/rehearsal/postgres_census.rb +100 -0
  164. data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +69 -0
  165. data/lib/hecks/hecks/adapters/rehearsal/postgres_store.rb +129 -0
  166. data/lib/hecks/hecks/adapters/rehearsal/rows.rb +41 -0
  167. data/lib/hecks/hecks/adapters/rehearsal/rust_audit.rb +83 -0
  168. data/lib/hecks/hecks/adapters/rehearsal/subject.rb +104 -0
  169. data/lib/hecks/hecks/adapters/rehearsal.rb +54 -0
  170. data/lib/hecks/hecks/adapters/rehearsal_store.adapter +7 -0
  171. data/lib/hecks/hecks/adapters/rehearsal_store.rb +81 -0
  172. data/lib/hecks/hecks/adapters/site_toolchain/role_prober.rb +78 -0
  173. data/lib/hecks/hecks/adapters/site_toolchain.rb +29 -4
  174. data/lib/hecks/hecks/adapters/terminal.rb +13 -11
  175. data/lib/hecks/hecks/adapters/world_clearing.rb +65 -0
  176. data/lib/hecks/hecks/codebase.behaviors +13 -1
  177. data/lib/hecks/hecks/codebase.bluebook +239 -5
  178. data/lib/hecks/hecks/custodian.behaviors +24 -6
  179. data/lib/hecks/hecks/custodian.bluebook +6 -1227
  180. data/lib/hecks/hecks/deploy.behaviors +1 -1
  181. data/lib/hecks/hecks/deploy.world +1 -3
  182. data/lib/hecks/hecks/hecks.behaviors +1 -1
  183. data/lib/hecks/hecks/hecks.hecksagon +61 -18
  184. data/lib/hecks/hecks/hecks.world +11 -10
  185. data/lib/hecks/hecks/rehearsal.bluebook +477 -0
  186. data/lib/hecks/hecks/site.behaviors +1 -1
  187. data/lib/hecks/hecks/site.world +0 -1
  188. data/lib/hecks/hecks/tooling.bluebook +1238 -0
  189. data/lib/hecks/indifferent_key.rb +20 -0
  190. data/lib/hecks/language/adapter.bluebook +13 -3
  191. data/lib/hecks/language/bluebook/aggregate.bluebook +23 -0
  192. data/lib/hecks/language/bluebook/bluebook.bluebook +15 -0
  193. data/lib/hecks/language/bluebook/entity.bluebook +18 -0
  194. data/lib/hecks/language/bluebook/policy.bluebook +9 -1
  195. data/lib/hecks/language/bluebook/query.bluebook +1 -1
  196. data/lib/hecks/language/bluebook/vocabulary.bluebook +11 -4
  197. data/lib/hecks/language/hecksagon/domain_port.bluebook +1 -1
  198. data/lib/hecks/language/hecksagon/hecksagon.bluebook +22 -0
  199. data/lib/hecks/language/oidc.json +10 -0
  200. data/lib/hecks/language/port.bluebook +4 -4
  201. data/lib/hecks/literal.rb +12 -3
  202. data/lib/hecks/ports/key_vault.rb +7 -2
  203. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +21 -10
  204. data/lib/hecks/ports/persistence/plugins/era/postgres_era/boot.rb +4 -2
  205. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +2 -1
  206. data/lib/hecks/ports/persistence/repository_factory.rb +6 -3
  207. data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +29 -0
  208. data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +1 -1
  209. data/lib/hecks/projections/deploy/fargate/settings/tuning.rb +15 -0
  210. data/lib/hecks/projections/deploy/fargate/settings.rb +3 -1
  211. data/lib/hecks/projections/deploy/fargate/stack/readers.rb +1 -0
  212. data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
  213. data/lib/hecks/projections/deploy/shared.rb +5 -2
  214. data/lib/hecks/projections/deploy/templates/fargate/Makefile.tmpl +7 -4
  215. data/lib/hecks/projections/model/deviations.rb +2 -2
  216. data/lib/hecks/projections/model.rb +2 -2
  217. data/lib/hecks/projections/oidc.rb +13 -1
  218. data/lib/hecks/projections/shape.rb +5 -2
  219. data/lib/hecks/projections/site/cms_editor/attributes.rb +95 -0
  220. data/lib/hecks/projections/site/cms_editor/blocks.rb +157 -0
  221. data/lib/hecks/projections/site/cms_editor/checks.rb +77 -0
  222. data/lib/hecks/projections/site/cms_editor/clearing.rb +70 -0
  223. data/lib/hecks/projections/site/cms_editor/color.rb +124 -0
  224. data/lib/hecks/projections/site/cms_editor/composition.rb +42 -0
  225. data/lib/hecks/projections/site/cms_editor/destructive.rb +61 -0
  226. data/lib/hecks/projections/site/cms_editor/drafts.rb +102 -0
  227. data/lib/hecks/projections/site/cms_editor/hints.rb +74 -0
  228. data/lib/hecks/projections/site/cms_editor/icons.rb +86 -0
  229. data/lib/hecks/projections/site/cms_editor/key_kinds.rb +31 -0
  230. data/lib/hecks/projections/site/cms_editor/limits.rb +72 -0
  231. data/lib/hecks/projections/site/cms_editor/media.rb +85 -0
  232. data/lib/hecks/projections/site/cms_editor/moment.rb +34 -0
  233. data/lib/hecks/projections/site/cms_editor/palette.rb +115 -0
  234. data/lib/hecks/projections/site/cms_editor/pickers.rb +85 -0
  235. data/lib/hecks/projections/site/cms_editor/pretty.rb +40 -0
  236. data/lib/hecks/projections/site/cms_editor/preview.rb +91 -0
  237. data/lib/hecks/projections/site/cms_editor/relations.rb +92 -0
  238. data/lib/hecks/projections/site/cms_editor/scale_checks.rb +66 -0
  239. data/lib/hecks/projections/site/cms_editor/scheduling.rb +150 -0
  240. data/lib/hecks/projections/site/cms_editor/schema.rb +161 -0
  241. data/lib/hecks/projections/site/cms_editor/setting.rb +130 -0
  242. data/lib/hecks/projections/site/cms_editor/targets.rb +86 -0
  243. data/lib/hecks/projections/site/cms_editor/templates/package.json.tmpl +36 -0
  244. data/lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl +370 -0
  245. data/lib/hecks/projections/site/cms_editor/templates/src/assets.ts.tmpl +98 -0
  246. data/lib/hecks/projections/site/cms_editor/templates/src/auth/membership.ts.tmpl +87 -0
  247. data/lib/hecks/projections/site/cms_editor/templates/src/auth/session.ts.tmpl +36 -0
  248. data/lib/hecks/projections/site/cms_editor/templates/src/auth/sso.ts.tmpl +20 -0
  249. data/lib/hecks/projections/site/cms_editor/templates/src/browser/app.css.tmpl +412 -0
  250. data/lib/hecks/projections/site/cms_editor/templates/src/browser/autosave.js.tmpl +144 -0
  251. data/lib/hecks/projections/site/cms_editor/templates/src/browser/blocks.js.tmpl +500 -0
  252. data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_doc.js.tmpl +175 -0
  253. data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_editor.js.tmpl +418 -0
  254. data/lib/hecks/projections/site/cms_editor/templates/src/browser/epoch.js.tmpl +61 -0
  255. data/lib/hecks/projections/site/cms_editor/templates/src/browser/forms.js.tmpl +210 -0
  256. data/lib/hecks/projections/site/cms_editor/templates/src/browser/lists.js.tmpl +40 -0
  257. data/lib/hecks/projections/site/cms_editor/templates/src/browser/main.js.tmpl +26 -0
  258. data/lib/hecks/projections/site/cms_editor/templates/src/browser/media_picker.js.tmpl +232 -0
  259. data/lib/hecks/projections/site/cms_editor/templates/src/browser/moments.js.tmpl +73 -0
  260. data/lib/hecks/projections/site/cms_editor/templates/src/browser/pickers.js.tmpl +152 -0
  261. data/lib/hecks/projections/site/cms_editor/templates/src/browser/preview.js.tmpl +98 -0
  262. data/lib/hecks/projections/site/cms_editor/templates/src/browser/shell.js.tmpl +140 -0
  263. data/lib/hecks/projections/site/cms_editor/templates/src/browser/toast.js.tmpl +66 -0
  264. data/lib/hecks/projections/site/cms_editor/templates/src/choices.ts.tmpl +99 -0
  265. data/lib/hecks/projections/site/cms_editor/templates/src/commands.ts.tmpl +133 -0
  266. data/lib/hecks/projections/site/cms_editor/templates/src/config.ts.tmpl +29 -0
  267. data/lib/hecks/projections/site/cms_editor/templates/src/flash.ts.tmpl +52 -0
  268. data/lib/hecks/projections/site/cms_editor/templates/src/host.ts.tmpl +43 -0
  269. data/lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl +177 -0
  270. data/lib/hecks/projections/site/cms_editor/templates/src/media/multipart.ts.tmpl +53 -0
  271. data/lib/hecks/projections/site/cms_editor/templates/src/media/sniff.ts.tmpl +94 -0
  272. data/lib/hecks/projections/site/cms_editor/templates/src/media/storage.ts.tmpl +50 -0
  273. data/lib/hecks/projections/site/cms_editor/templates/src/names.ts.tmpl +36 -0
  274. data/lib/hecks/projections/site/cms_editor/templates/src/schema.ts.tmpl +214 -0
  275. data/lib/hecks/projections/site/cms_editor/templates/src/server.ts.tmpl +65 -0
  276. data/lib/hecks/projections/site/cms_editor/templates/src/ui/availability.ts.tmpl +15 -0
  277. data/lib/hecks/projections/site/cms_editor/templates/src/ui/block_list.js.tmpl +213 -0
  278. data/lib/hecks/projections/site/cms_editor/templates/src/ui/blocks.ts.tmpl +275 -0
  279. data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_model.js.tmpl +123 -0
  280. data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_parse.js.tmpl +320 -0
  281. data/lib/hecks/projections/site/cms_editor/templates/src/ui/detail.ts.tmpl +88 -0
  282. data/lib/hecks/projections/site/cms_editor/templates/src/ui/dialogs.ts.tmpl +43 -0
  283. data/lib/hecks/projections/site/cms_editor/templates/src/ui/fields.ts.tmpl +275 -0
  284. data/lib/hecks/projections/site/cms_editor/templates/src/ui/html.ts.tmpl +61 -0
  285. data/lib/hecks/projections/site/cms_editor/templates/src/ui/icons.ts.tmpl +15 -0
  286. data/lib/hecks/projections/site/cms_editor/templates/src/ui/input.ts.tmpl +92 -0
  287. data/lib/hecks/projections/site/cms_editor/templates/src/ui/links.ts.tmpl +100 -0
  288. data/lib/hecks/projections/site/cms_editor/templates/src/ui/moments.ts.tmpl +44 -0
  289. data/lib/hecks/projections/site/cms_editor/templates/src/ui/outline.ts.tmpl +63 -0
  290. data/lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl +213 -0
  291. data/lib/hecks/projections/site/cms_editor/templates/src/ui/paging.ts.tmpl +82 -0
  292. data/lib/hecks/projections/site/cms_editor/templates/src/ui/pickers.ts.tmpl +110 -0
  293. data/lib/hecks/projections/site/cms_editor/templates/src/ui/preview.ts.tmpl +87 -0
  294. data/lib/hecks/projections/site/cms_editor/templates/src/ui/related.ts.tmpl +97 -0
  295. data/lib/hecks/projections/site/cms_editor/templates/src/ui/schedule.ts.tmpl +160 -0
  296. data/lib/hecks/projections/site/cms_editor/templates/src/ui/shell.ts.tmpl +211 -0
  297. data/lib/hecks/projections/site/cms_editor/templates/src/ui/table.ts.tmpl +151 -0
  298. data/lib/hecks/projections/site/cms_editor/templates/src/ui/theme.js.tmpl +16 -0
  299. data/lib/hecks/projections/site/cms_editor/templates/src/ui/values.ts.tmpl +69 -0
  300. data/lib/hecks/projections/site/cms_editor/templates/src/ui/words.ts.tmpl +97 -0
  301. data/lib/hecks/projections/site/cms_editor/templates/src/ui/world.ts.tmpl +35 -0
  302. data/lib/hecks/projections/site/cms_editor/templates/tsconfig.json.tmpl +17 -0
  303. data/lib/hecks/projections/site/cms_editor/theme.rb +29 -0
  304. data/lib/hecks/projections/site/cms_editor/theme_checks.rb +57 -0
  305. data/lib/hecks/projections/site/cms_editor.rb +133 -0
  306. data/lib/hecks/projections/site/role_probe.rb +74 -0
  307. data/lib/hecks/projector/cli_audience.rb +2 -1
  308. data/lib/hecks/projector/cli_projector/listing.rb +1 -1
  309. data/lib/hecks/projector/cli_projector/option_specs.rb +1 -1
  310. data/lib/hecks/projector/docs_projector/closing.rb +1 -1
  311. data/lib/hecks/projector/docs_projector.rb +1 -1
  312. data/lib/hecks/projector/exporter/bindings.rb +40 -10
  313. data/lib/hecks/projector/exporter/capability_values.rb +55 -0
  314. data/lib/hecks/projector/narrate_projector/reactions.rb +1 -1
  315. data/lib/hecks/projector/target.rb +11 -0
  316. data/lib/hecks/projector.rb +32 -5
  317. data/lib/hecks/quality_control/adapters/github_checks.rb +12 -8
  318. data/lib/hecks/quality_control/adapters/github_issues.rb +8 -4
  319. data/lib/hecks/quality_control/cli/qa_open_pr.rb +2 -2
  320. data/lib/hecks/quality_control/cli/qa_sweep/checks/shrinking.rb +1 -1
  321. data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +1 -1
  322. data/lib/hecks/quality_control/cli/qa_sweep.rb +1 -1
  323. data/lib/hecks/quality_control/quality_control.bluebook +6 -2
  324. data/lib/hecks/release/approval.rb +64 -0
  325. data/lib/hecks/router/{door.rb → aggregate_reader.rb} +5 -4
  326. data/lib/hecks/router/namespace_installer.rb +16 -16
  327. data/lib/hecks/router.rb +1 -1
  328. data/lib/hecks/runtime/best_effort.rb +22 -0
  329. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +12 -2
  330. data/lib/hecks/runtime/command_interpreter.rb +3 -2
  331. data/lib/hecks/runtime/command_rules/emission.rb +1 -1
  332. data/lib/hecks/runtime/dispatcher.rb +4 -4
  333. data/lib/hecks/runtime/entity_element/location.rb +1 -1
  334. data/lib/hecks/runtime/event.rb +5 -0
  335. data/lib/hecks/runtime/identity.rb +7 -6
  336. data/lib/hecks/runtime/interpreting.rb +2 -1
  337. data/lib/hecks/runtime/invocation_builder.rb +1 -1
  338. data/lib/hecks/runtime/loader/boot_steps.rb +8 -5
  339. data/lib/hecks/runtime/loader.rb +10 -10
  340. data/lib/hecks/runtime/policy_interpreter/arguments.rb +7 -4
  341. data/lib/hecks/runtime/policy_interpreter/fan_out.rb +3 -3
  342. data/lib/hecks/runtime/policy_interpreter.rb +6 -6
  343. data/lib/hecks/runtime/port_operation_interpreter.rb +1 -1
  344. data/lib/hecks/runtime/reaction_invocation.rb +1 -1
  345. data/lib/hecks/runtime/rebuild_sweep.rb +11 -1
  346. data/lib/hecks/runtime/registry/ask_verification.rb +35 -0
  347. data/lib/hecks/runtime/registry/hecksagon_rules.rb +10 -0
  348. data/lib/hecks/runtime/registry/merging.rb +1 -1
  349. data/lib/hecks/runtime/registry/providers.rb +16 -0
  350. data/lib/hecks/runtime/registry/read_repository.rb +6 -4
  351. data/lib/hecks/runtime/registry/verification.rb +4 -1
  352. data/lib/hecks/runtime/registry/world_defaults.rb +29 -0
  353. data/lib/hecks/runtime/registry.rb +1 -1
  354. data/lib/hecks/runtime/saga_interpreter/compensation.rb +1 -1
  355. data/lib/hecks/runtime/saga_interpreter/delivery.rb +4 -4
  356. data/lib/hecks/runtime/saga_interpreter/transitions.rb +1 -1
  357. data/lib/hecks/runtime/saga_interpreter.rb +3 -3
  358. data/lib/hecks/runtime/tenant_check.rb +5 -4
  359. data/lib/hecks/runtime/value/coercion.rb +2 -2
  360. data/lib/hecks/runtime/value/validation.rb +16 -4
  361. data/lib/hecks/runtime.rb +9 -9
  362. data/lib/hecks/rust_build/project_rust/target_ir.rb +1 -1
  363. data/lib/hecks/rust_build/wasm.rb +1 -1
  364. data/lib/hecks/rust_build/wasm_browser.rb +1 -1
  365. data/lib/hecks/rust_build.rb +11 -0
  366. data/lib/hecks/served_options.rb +53 -0
  367. data/lib/hecks/site/bluebook/site.bluebook +29 -1
  368. data/lib/hecks/site/bluebook/site.ports.hecksagon +6 -0
  369. data/lib/hecks/storehouse/audit.rb +1 -1
  370. data/lib/hecks/storehouse/dispatching.rb +8 -6
  371. data/lib/hecks/storehouse/introspection.rb +2 -2
  372. data/lib/hecks/storehouse/querying.rb +6 -4
  373. data/lib/hecks/storehouse.rb +4 -4
  374. data/lib/hecks/tools/comment_style/source_file.rb +4 -1
  375. data/lib/hecks/tools/deploy_recipe_lint/fixtures.rb +4 -1
  376. data/lib/hecks/tools/lanes/rows.rb +6 -0
  377. data/lib/hecks/tools/oidc_manifests.rb +4 -5
  378. data/lib/hecks/tools/regeneration_run.rb +11 -4
  379. data/lib/hecks/tools/site_routes/cli.rb +1 -1
  380. data/lib/hecks/tools/site_routes/editor_files.rb +45 -0
  381. data/lib/hecks/tools/site_routes.rb +14 -7
  382. data/lib/hecks/tools/tenant_provisioning.rb +2 -2
  383. data/lib/hecks/tools/tools_doc.rb +4 -4
  384. data/lib/hecks/version.rb +1 -1
  385. data/lib/hecks/vocabulary.rb +4 -4
  386. data/lib/hecks.rb +15 -15
  387. data/lib/rubocop/cop/hecks/env_dump.rb +69 -0
  388. data/lib/rubocop/cop/hecks/monotonic_duration.rb +53 -0
  389. data/lib/rubocop/cop/hecks/no_wall_clock_in_runtime.rb +34 -0
  390. data/lib/rubocop/cop/hecks/raw_shell_interpolation.rb +79 -0
  391. data/lib/rubocop/cop/hecks/sleep_in_spec.rb +34 -0
  392. data/lib/rubocop/cop/hecks/swallowed_rescue.rb +37 -0
  393. data/lib/rubocop/cop/hecks/symbol_string_key_mix.rb +50 -0
  394. data/lib/rubocop/cop/hecks/untyped_raise.rb +37 -0
  395. data/prebuilt/05c358d38d661a3774f813d49c66f5b68939af94432d66257a56f49ee2598994.marshal +0 -0
  396. data/prebuilt/26c40c61f09b09b11651c64668eda3ceb180f83cf2a3802d3033d2fd99ac841b.marshal +0 -0
  397. data/prebuilt/verdicts-230ac18c25abfd3d92ede032bee2661a4c2cd2773ab0cf0e2ae52546ba2f7af9.json +1 -0
  398. data/rust/.gitignore +6 -0
  399. data/rust/Cargo.toml +9 -1
  400. data/rust/build/src/binding_pass.rs +103 -0
  401. data/rust/build/src/cargo_sync.rs +6 -0
  402. data/rust/build/src/lineage_pass.rs +3 -3
  403. data/rust/build/src/main.rs +17 -5
  404. data/rust/build/src/pipeline.rs +48 -5
  405. data/rust/build/src/seams_pass.rs +123 -0
  406. data/rust/build/src/translation_pass.rs +167 -0
  407. data/rust/codegen/src/asks.rs +103 -0
  408. data/rust/codegen/src/bridging.rs +1 -1
  409. data/rust/codegen/src/commands.rs +13 -8
  410. data/rust/codegen/src/constraints.rs +25 -0
  411. data/rust/codegen/src/domain_generator.rs +11 -9
  412. data/rust/codegen/src/expr_emitter.rs +13 -0
  413. data/rust/codegen/src/json_codec.rs +54 -15
  414. data/rust/codegen/src/main.rs +2 -1
  415. data/rust/codegen/src/mutations.rs +174 -4
  416. data/rust/codegen/src/naming.rs +30 -0
  417. data/rust/codegen/src/queries.rs +11 -2
  418. data/rust/codegen/src/reactions.rs +1 -1
  419. data/rust/codegen/src/types.rs +166 -8
  420. data/rust/host/HECKS_RELEASE +1 -1
  421. data/rust/host/src/api.rs +4 -4
  422. data/rust/host/src/bin/validate_harness.rs +43 -0
  423. data/rust/host/src/boundary_fuzz/expr_json.rs +2 -2
  424. data/rust/host/src/boundary_fuzz/ir.rs +1 -0
  425. data/rust/host/src/boundary_fuzz/server.rs +1 -1
  426. data/rust/host/src/checkout.rs +35 -19
  427. data/rust/host/src/commerce_ir.rs +408 -2
  428. data/rust/host/src/expr_json.rs +118 -0
  429. data/rust/host/src/mint.rs +1 -1
  430. data/rust/host/src/payments/tests.rs +27 -1
  431. data/rust/host/src/payments.rs +12 -4
  432. data/rust/host/src/query_step.rs +22 -4
  433. data/rust/host/src/reference_validate.rs +653 -108
  434. data/rust/host/src/resend.rs +2 -0
  435. data/rust/host/src/server.rs +19 -6
  436. data/rust/host/src/ui_schema.rs +132 -5
  437. data/rust/host/src/web/newsletter.rs +7 -8
  438. data/rust/host/src/web/newsletter_send.rs +38 -13
  439. data/rust/host/src/web/registrations.rs +229 -26
  440. data/rust/host/src/web.rs +3 -3
  441. data/rust/parser/src/emit.rs +38 -6
  442. data/rust/parser/src/expr/ast_json.rs +7 -1
  443. data/rust/parser/src/expr/resolver.rs +171 -6
  444. data/rust/parser/src/ir.rs +7 -0
  445. data/rust/parser/src/keywords.rs +24 -0
  446. data/rust/parser/src/main.rs +3 -0
  447. data/rust/parser/src/parse/aggregate.rs +2 -1
  448. data/rust/parser/src/parse/chapter.rs +2 -2
  449. data/rust/parser/src/parse/command.rs +2 -0
  450. data/rust/parser/src/parse/hecksagon.rs +5 -2
  451. data/rust/parser/src/parse/lifecycle.rs +81 -0
  452. data/rust/parser/src/parse/mod.rs +15 -1
  453. data/rust/parser/src/parse/policy.rs +13 -2
  454. data/rust/parser/src/parse/value_object.rs +13 -8
  455. data/rust/parser/src/ruby_value.rs +1 -1
  456. data/rust/src/exemplar/commands.rs +4 -4
  457. data/rust/src/exemplar/constraints.rs +1 -1
  458. data/rust/src/exemplar/json.rs +43 -1
  459. data/rust/src/kernel/cli.rs +7 -5
  460. data/rust/src/kernel/dispatch.rs +2 -2
  461. data/rust/src/kernel/dispatch_guard_tests.rs +1 -1
  462. data/rust/src/kernel/expr.rs +73 -4
  463. data/rust/src/kernel/expression_operators/arithmetic.rs +130 -5
  464. data/rust/src/kernel/expression_operators/presence.rs +41 -3
  465. data/rust/src/kernel/expression_operators/text.rs +26 -2
  466. data/rust/src/kernel/json.rs +15 -0
  467. data/rust/src/kernel/mod.rs +1 -1
  468. data/rust/src/kernel/orchestrate.rs +54 -5
  469. data/rust/src/kernel/orchestrate_guard_tests.rs +67 -0
  470. data/rust/src/kernel/pattern.rs +60 -0
  471. data/rust/src/kernel/reference_lookup.rs +90 -7
  472. metadata +174 -36
  473. data/lib/hecks/doors/cli_door/nesting.rb +0 -34
  474. data/lib/hecks/doors/cli_door/shorthand.rb +0 -85
  475. data/lib/hecks/doors/cli_door.rb +0 -124
  476. data/lib/hecks/doors/cli_runner/answers.rb +0 -138
  477. data/lib/hecks/doors/cli_runner/resolution.rb +0 -146
  478. data/lib/hecks/doors/cli_runner/settling.rb +0 -115
  479. data/lib/hecks/doors/cli_runner/streaming.rb +0 -90
  480. data/lib/hecks/doors/cli_runner/suggestions.rb +0 -43
  481. data/lib/hecks/doors/cli_runner.rb +0 -66
  482. data/lib/hecks/doors/command_request.rb +0 -119
  483. data/lib/hecks/doors/handle.rb +0 -208
  484. data/lib/hecks/doors/json_door.rb +0 -132
  485. data/lib/hecks/doors/launcher_options.rb +0 -247
  486. data/lib/hecks/doors/mcp_door/properties.rb +0 -47
  487. data/lib/hecks/doors/mcp_door/tool_calls.rb +0 -113
  488. data/lib/hecks/doors/mcp_door/tool_definitions/auditing.rb +0 -51
  489. data/lib/hecks/doors/mcp_door/tool_definitions/calling.rb +0 -69
  490. data/lib/hecks/doors/mcp_door/tool_definitions/reading.rb +0 -97
  491. data/lib/hecks/doors/mcp_door/tool_definitions.rb +0 -15
  492. data/lib/hecks/doors/mcp_door.rb +0 -156
  493. data/lib/hecks/doors/mcp_door_scope/argument_policy.rb +0 -92
  494. data/lib/hecks/doors/mcp_door_scope/env_problems.rb +0 -55
  495. data/lib/hecks/doors/mcp_door_scope/presenter.rb +0 -78
  496. data/lib/hecks/doors/mcp_door_scope.rb +0 -201
  497. data/lib/hecks/doors/mcp_guide_cache.rb +0 -75
  498. data/lib/hecks/doors/ruby_door/aggregate_door.rb +0 -162
  499. data/lib/hecks/doors/ruby_door/chapter.rb +0 -89
  500. data/lib/hecks/doors/ruby_door.rb +0 -80
  501. data/lib/hecks/doors/usage_cache.rb +0 -139
  502. data/prebuilt/0ee7f83cba59ce7d1c45c65ba166b071779f70143449f584f33ff7989f64eccb.marshal +0 -0
  503. data/prebuilt/6e4a6bcf0aa880e2e6b056e1846b70e5a768090b9dc998bbadeaf5d6bcfd3db8.marshal +0 -0
  504. data/prebuilt/verdicts-91aaf93ce8981bd9a754948f075d95650dc2ec6435015376f5c60992b36a24b1.json +0 -1
@@ -46,8 +46,8 @@ module Hecks
46
46
  end
47
47
 
48
48
  def apply_set(instance, aggregate, mutation, args, pre)
49
- from_state = mutation.source.is_a?(StateRef)
50
- value = from_state ? pre[mutation.source.name] : @rules.resolve_source(mutation.source, args)
49
+ from_state = mutation.source.is_a?(StateRef) || mutation.source.is_a?(Computed)
50
+ value = set_source_value(mutation.source, args, pre)
51
51
  # A plain `sets` of a list takes the whole list; only `append:` and `remove:` take
52
52
  # one element.
53
53
  list_attribute = aggregate.attribute(mutation.target)
@@ -55,6 +55,16 @@ module Hecks
55
55
  instance[mutation.target] = Value.for(aggregate, mutation.target, value)
56
56
  end
57
57
 
58
+ # A `state(:field)` reads the pre-dispatch record; an expression is evaluated over the
59
+ # command's arguments, then that record; anything else resolves as an argument or literal.
60
+ def set_source_value(source, args, pre)
61
+ case source
62
+ when StateRef then pre[source.name]
63
+ when Computed then Bluebook::Expression::Resolver.resolve(source.text, pre, args)
64
+ else @rules.resolve_source(source, args)
65
+ end
66
+ end
67
+
58
68
  def apply_append(instance, aggregate, mutation, args, pre)
59
69
  instance[mutation.target] = appended(pre, aggregate, mutation, args)
60
70
  end
@@ -65,7 +65,7 @@ module Hecks
65
65
  # @return [Array] the settled instance, events, plan, persistence outcome, and outbox rows
66
66
  # @raise [StandardError] a domain refusal (Runtime::DOMAIN_REFUSALS) when a rule refuses
67
67
  # @raise [Runtime::StaleWrite, Runtime::WiringError] every retry loses, or resolve fails
68
- # rubocop:disable-next Metrics/ParameterLists -- the public dispatch signature every door calls
68
+ # rubocop:disable-next Metrics/ParameterLists -- the public dispatch signature every entry point calls
69
69
  def call(domain, aggregate, command, invocation, correlation = nil, dry_run: false)
70
70
  args = invocation.to_args
71
71
  settings = { invocation: invocation, route: invocation.target, correlation: correlation, dry_run: dry_run }
@@ -181,7 +181,8 @@ module Hecks
181
181
 
182
182
  # `ctx.pending_delegation` is only ever set by `step_delegate_to_entity`, and only when this
183
183
  # command carries a `:delegate` mutation. The same dispatch, so the same correlation —
184
- # without threading `ctx.correlation` through, a saga-driven door's events would lose their
184
+ # without threading `ctx.correlation` through, a saga-driven entry point's events would lose
185
+ # their
185
186
  # stamp here.
186
187
  def emit_events(ctx)
187
188
  command, args = ctx.pending_delegation || [ctx.command, ctx.args]
@@ -20,7 +20,7 @@ module Hecks
20
20
  stamp = { aggregate: "#{domain}::#{aggregate.hecks_name}", id: instance.id,
21
21
  payload: args, correlation: correlation }
22
22
  command.emits.map do |event_name|
23
- record_emitted(Event.new(name: event_name, occurred_at: Time.now.utc.iso8601, **stamp), repository)
23
+ record_emitted(Event.new(name: event_name, occurred_at: Event.stamp, **stamp), repository)
24
24
  end
25
25
  end
26
26
 
@@ -37,8 +37,8 @@ module Hecks
37
37
  @entities = EntityInterpreter.new(registry, rules: rules)
38
38
  @queries = QueryInterpreter.new(registry)
39
39
  @read_models = ReadModelInterpreter.new(registry)
40
- @policies = PolicyInterpreter.new(registry, door: self)
41
- @sagas = SagaInterpreter.new(registry, door: self)
40
+ @policies = PolicyInterpreter.new(registry, dispatcher: self)
41
+ @sagas = SagaInterpreter.new(registry, dispatcher: self)
42
42
  # One relay per registry: interpreters enqueue through it inside the save transaction.
43
43
  @registry.outbox.attach(policies: @policies, sagas: @sagas)
44
44
  end
@@ -141,7 +141,7 @@ module Hecks
141
141
 
142
142
  # Runs one port operation named by its parts, then the reactions its events owe.
143
143
  #
144
- # The door for an adapter outside the bluebook; no wire spelling packs a port verb.
144
+ # The dispatcher for an adapter outside the bluebook; no wire spelling packs a port verb.
145
145
  #
146
146
  # @param to [String, Hash, nil] the receiver; when nil it is read from the facts
147
147
  # @param with [Hash, nil] the operation's facts, keyed by argument name
@@ -150,7 +150,7 @@ module Hecks
150
150
  # @raise [Runtime::UnknownVerb] if the domain, aggregate, port or operation is undeclared
151
151
  # @raise [Runtime::TypeMismatch] if no receiving identity is found, or `to:`/`with:` is bad
152
152
  # @raise [Runtime::NotFound] if the receiving record does not exist
153
- # rubocop:disable-next Metrics/ParameterLists -- the public door's parts, one argument per verb segment
153
+ # rubocop:disable-next Metrics/ParameterLists -- the public dispatcher's parts, one argument per verb segment
154
154
  def dispatch_port(domain, aggregate_name, port_name, operation_name, to: nil, with: nil, flat: {})
155
155
  verb = "#{domain}::#{aggregate_name}.#{port_name}.#{operation_name}"
156
156
  aggregate = resolve_aggregate(domain, aggregate_name, verb)
@@ -17,7 +17,7 @@ module Hecks
17
17
  # Walks `chain` one hop at a time and returns the located element (or `instance`
18
18
  # itself when `chain` is empty). `route`, when given, offers each hop's identity
19
19
  # before falling back to `args`.
20
- # rubocop:disable-next Metrics/ParameterLists -- the positional door EntityInterpreter and delegation call
20
+ # rubocop:disable-next Metrics/ParameterLists -- the positional entry point EntityInterpreter and delegation call
21
21
  def locate_chain(root_aggregate, chain, instance, args, command_name, route = nil)
22
22
  container = instance
23
23
  owner = root_aggregate
@@ -5,6 +5,11 @@ module Hecks
5
5
  # An emitted domain event. `correlation` (saga head -> value) is runtime bookkeeping
6
6
  # and deliberately absent from `to_h`.
7
7
  Event = Struct.new(:name, :aggregate, :id, :payload, :occurred_at, :correlation, keyword_init: true) do
8
+ # The one place the runtime reads the wall clock, so every event is stamped the same way.
9
+ #
10
+ # @return [String] the current UTC time as ISO 8601
11
+ def self.stamp = Time.now.utc.iso8601
12
+
8
13
  # Freezes the event deep, payload and correlation included.
9
14
  #
10
15
  # @return [void]
@@ -1,4 +1,5 @@
1
1
  require_relative "../naming"
2
+ require_relative "best_effort"
2
3
  require_relative "value"
3
4
 
4
5
  module Hecks
@@ -82,12 +83,12 @@ module Hecks
82
83
  # Resolves a best-effort identity for `construct` to use as a lock key; never raises.
83
84
  # Returns nil when nothing resolves, and the caller then locks by aggregate type alone.
84
85
  def best_effort(construct, args, route = nil, reference_key: nil)
85
- route&.aggregate ||
86
- of(construct, args) ||
87
- from(construct, args, :id) ||
88
- (reference_key && from(construct, args, reference_key))
89
- rescue StandardError
90
- nil
86
+ BestEffort.call(nil) do
87
+ route&.aggregate ||
88
+ of(construct, args) ||
89
+ from(construct, args, :id) ||
90
+ (reference_key && from(construct, args, reference_key))
91
+ end
91
92
  end
92
93
  end
93
94
  end
@@ -32,7 +32,8 @@ module Hecks
32
32
 
33
33
  # Gives each argument the caller left out the default its attribute declares
34
34
  # (`attribute :runs, Count, default: 30`), so a declared default holds on every way in and
35
- # not only where a door spells it out. An argument the caller passed is kept, whatever it is.
35
+ # not only where an entry point spells it out. An argument the caller passed is kept, whatever
36
+ # it is.
36
37
  #
37
38
  # @param command [Class] the command being dispatched
38
39
  # @param args [Hash{Symbol => Object}] the arguments the caller passed
@@ -18,7 +18,7 @@ module Hecks
18
18
  # :entity, :port). Each checks its own parts in a fixed order, because
19
19
  # a malformed call's refusal depends on that order; `declaring` is
20
20
  # called exactly once, at that shape's point in the order below.
21
- # rubocop:disable-next Metrics/ParameterLists -- the public keyword door every dispatch calls
21
+ # rubocop:disable-next Metrics/ParameterLists -- the public keyword entry point every dispatch calls
22
22
  def from_call(verb, to:, with:, flat:, receiver: :aggregate, entity_depth: 0, aggregate: nil, &declaring)
23
23
  call = Call.new(verb, to, with, flat, entity_depth, aggregate, declaring)
24
24
  case receiver
@@ -15,20 +15,23 @@ module Hecks
15
15
  # the domain never attached Privacy at all.
16
16
  def seed_privacy_markings!(dispatcher, registry)
17
17
  return if registry.pending_privacy_markings.empty?
18
- return unless registry.bluebook("Privacy")
19
18
 
20
- already_marked = already_marked_by_domain(dispatcher, registry)
19
+ provider = registry.provider_of(Bluebook::Capabilities::PRIVACY)
20
+ return unless provider
21
+
22
+ already_marked = already_marked_by_domain(dispatcher, registry, provider)
21
23
  registry.pending_privacy_markings.each do |marking|
22
24
  next if already_marked[marking[:domain]].include?(marking[:attribute_path])
23
25
 
24
- dispatcher.dispatch_flat("Privacy::Marking.Mark", marking)
26
+ dispatcher.dispatch_flat(provider.provided_verb(Bluebook::Capabilities::PRIVACY, :mark_sensitive), marking)
25
27
  end
26
28
  end
27
29
 
28
30
  # Each domain with a pending marking, with the attribute paths Privacy already marks for it.
29
- def already_marked_by_domain(dispatcher, registry)
31
+ def already_marked_by_domain(dispatcher, registry, provider)
32
+ verb = provider.provided_verb(Bluebook::Capabilities::PRIVACY, :markings_for)
30
33
  registry.pending_privacy_markings.map { |marking| marking[:domain] }.uniq.to_h do |domain|
31
- [domain, dispatcher.query("Privacy::Marking.ForDomain", domain: domain).map { |row| row[:attribute_path][:value] }]
34
+ [domain, dispatcher.query(verb, domain: domain).map { |row| row[:attribute_path][:value] }]
32
35
  end
33
36
  end
34
37
 
@@ -1,4 +1,4 @@
1
- require_relative "../doors/ruby_door"
1
+ require_relative "../adapters/driving/ruby"
2
2
  require_relative "../ports/loading"
3
3
  require_relative "../ports/persistence"
4
4
  require_relative "dispatcher"
@@ -21,7 +21,7 @@ module Hecks
21
21
 
22
22
  # Boots `path`: loads its bluebook directory into a fresh Registry, runs
23
23
  # every registered boot gate, and returns the bound dispatcher. Pass
24
- # `install_doors: false` to skip the `Widget::Item.Add(...)` global
24
+ # `install_driving: false` to skip the `Widget::Item.Add(...)` global
25
25
  # facade sugar (only a caller dispatching by FQN string needs to).
26
26
  #
27
27
  # @param path [String] a domain directory to boot
@@ -31,25 +31,25 @@ module Hecks
31
31
  # @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted dispatcher
32
32
  # @raise [Errno::ENOENT] if `path` names no domain directory
33
33
  # @raise [Runtime::WiringError] if a boot gate finds a wiring problem
34
- def self.boot(path, shared: nil, install_doors: true, environment: FROM_ENV)
34
+ def self.boot(path, shared: nil, install_driving: true, environment: FROM_ENV)
35
35
  described = describe(path, shared: shared, environment: environment)
36
- boot_described(described, install_doors: install_doors)
36
+ boot_described(described, install_driving: install_driving)
37
37
  end
38
38
 
39
39
  # Finishes a boot from declarations `describe` already loaded: runs every boot gate and binds
40
40
  # the dispatcher, without reading the domain's files again.
41
41
  #
42
42
  # @param described [Described] what `describe` answered for the domain to boot
43
- # @param install_doors [Boolean] install the `Widget::Item.Add(...)` global facade sugar
43
+ # @param install_driving [Boolean] install the `Widget::Item.Add(...)` global facade sugar
44
44
  # @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted dispatcher
45
45
  # @raise [Runtime::WiringError] if a boot gate finds a wiring problem
46
- def self.boot_described(described, install_doors: true)
46
+ def self.boot_described(described, install_driving: true)
47
47
  registry = described.registry
48
48
  run_boot_gates!(registry, described.directory)
49
49
  dispatcher = dispatcher_for(registry)
50
50
  redrive_outbox!(dispatcher)
51
51
  seed_privacy_markings!(dispatcher, registry)
52
- install_doors ? bind_runtime(dispatcher) : dispatcher
52
+ install_driving ? bind_runtime(dispatcher) : dispatcher
53
53
  end
54
54
 
55
55
  # Loads `path`'s declarations into a fresh Registry and stops: no boot gate runs, no
@@ -118,7 +118,7 @@ module Hecks
118
118
  # defaults to `HECKS_ENVIRONMENT`, and an explicit nil loads none
119
119
  # @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted dispatcher
120
120
  # @raise [Runtime::WiringError] if a boot gate finds a wiring problem
121
- def self.boot_files(paths, shared: nil, install_doors: true, environment: FROM_ENV)
121
+ def self.boot_files(paths, shared: nil, install_driving: true, environment: FROM_ENV)
122
122
  loading = Ports::Loading.bootstrap
123
123
  files = Array(paths).map { |path| File.expand_path(path) }
124
124
  directory = File.dirname(files.first)
@@ -126,7 +126,7 @@ module Hecks
126
126
 
127
127
  run_boot_gates!(registry, directory)
128
128
  dispatcher = dispatcher_for(registry)
129
- install_doors ? bind_runtime(dispatcher) : dispatcher
129
+ install_driving ? bind_runtime(dispatcher) : dispatcher
130
130
  end
131
131
 
132
132
  # Loads exactly `files` into a fresh Registry rooted beside their directory, answering it.
@@ -160,7 +160,7 @@ module Hecks
160
160
  # `dispatcher`. The binding lives in the facade's own modules, not a
161
161
  # class-level global, so two boots in one process don't share one name.
162
162
  def self.bind_runtime(dispatcher)
163
- Doors::RubyDoor.install(dispatcher)
163
+ Adapters::Driving::Ruby.install(dispatcher)
164
164
  dispatcher
165
165
  end
166
166
  end
@@ -4,7 +4,7 @@ module Hecks
4
4
  module Runtime
5
5
  class PolicyInterpreter
6
6
  # What a policy's trigger is given: the event payload or its `with:` projection, the
7
- # emitting record's identity, and the invocation the door re-enters with. Mixed into
7
+ # emitting record's identity, and the invocation the entry point re-enters with. Mixed into
8
8
  # {PolicyInterpreter}.
9
9
  module Arguments
10
10
  private
@@ -12,12 +12,15 @@ module Hecks
12
12
  # What the trigger is given: the whole event payload verbatim when no `with:` is
13
13
  # declared, otherwise the projection (a Symbol names a payload field, anything else
14
14
  # is a literal). `extra` is a fan-out's row key, merged into the source before the
15
- # projection so a `with:` can name the row it acts on.
16
- def trigger_args(policy, event, extra = {})
15
+ # projection so a `with:` can name the row it acts on. `row` is the fan-out row itself:
16
+ # its fields are offered to a projection only, below the emitter identity and the
17
+ # payload, and never reach an unprojected payload.
18
+ def trigger_args(policy, event, extra = {}, row = {})
17
19
  payload = event.payload.transform_keys(&:to_sym).merge(extra)
18
20
  return payload unless ReactionInvocation.projection_declared?(policy)
19
21
 
20
- projected_args(policy, event, emitter_identity(event).merge(payload))
22
+ source = row.transform_keys(&:to_sym).merge(emitter_identity(event)).merge(payload)
23
+ projected_args(policy, event, source)
21
24
  end
22
25
 
23
26
  def projected_args(policy, event, payload)
@@ -20,7 +20,7 @@ module Hecks
20
20
 
21
21
  rows, reference_key = for_each_rows(policy, event, domain, target)
22
22
  Array(rows).map do |row|
23
- args = trigger_args(policy, event, reference_key => row[:id])
23
+ args = trigger_args(policy, event, { reference_key => row[:id] }, row)
24
24
  deliver_for_each_row(target, record.merge(for_row: row[:id]), args, policy, event)
25
25
  end
26
26
  rescue *DOMAIN_REFUSALS => e
@@ -74,10 +74,10 @@ module Hecks
74
74
  end
75
75
 
76
76
  def deliver_for_each_row(target, row_record, args, policy, event)
77
- return depth_refusal(row_record) if @door.reaction_depth_reached?
77
+ return depth_refusal(row_record) if @dispatcher.reaction_depth_reached?
78
78
 
79
79
  # The row key is already merged by `trigger_args`, so a projection can name it.
80
- @door.reenter(target, **reaction_invocation(target, args, policy, event))
80
+ @dispatcher.reenter(target, **reaction_invocation(target, args, policy, event))
81
81
  row_record.merge(delivered: true)
82
82
  rescue *DOMAIN_REFUSALS => e
83
83
  row_record.merge(delivered: false, reason: e.message)
@@ -20,11 +20,11 @@ module Hecks
20
20
 
21
21
  # @param registry [Runtime::Registry] the booted registry whose loaded
22
22
  # bluebooks are scanned for candidate policies
23
- # @param door [Runtime::Dispatcher] the dispatcher reactions re-enter through,
23
+ # @param dispatcher [Runtime::Dispatcher] the dispatcher reactions re-enter through,
24
24
  # and whose reaction-depth guard is checked before each delivery
25
- def initialize(registry, door:)
25
+ def initialize(registry, dispatcher:)
26
26
  @registry = registry
27
- @door = door
27
+ @dispatcher = dispatcher
28
28
  end
29
29
 
30
30
  # Fires every declared policy `event` triggers, recording each outcome on
@@ -96,15 +96,15 @@ module Hecks
96
96
  # may go.
97
97
  def fire(policy, event, target, record)
98
98
  return nil unless where_holds?(policy, event)
99
- return depth_refusal(record) if @door.reaction_depth_reached?
99
+ return depth_refusal(record) if @dispatcher.reaction_depth_reached?
100
100
 
101
101
  args = trigger_args(policy, event)
102
- @door.reenter(target, **reaction_invocation(target, args, policy, event))
102
+ @dispatcher.reenter(target, **reaction_invocation(target, args, policy, event))
103
103
  record.merge(delivered: true)
104
104
  end
105
105
 
106
106
  def depth_refusal(record)
107
- record.merge(delivered: false, reason: "reaction depth #{@door.max_reaction_depth} reached")
107
+ record.merge(delivered: false, reason: "reaction depth #{@dispatcher.max_reaction_depth} reached")
108
108
  end
109
109
 
110
110
  # A defect, not a refusal: recorded with `defect: true` and warned, never
@@ -157,7 +157,7 @@ module Hecks
157
157
  aggregate: "#{ctx.domain}::#{ctx.aggregate.hecks_name}",
158
158
  id: ctx.route.aggregate,
159
159
  payload: payload,
160
- occurred_at: Time.now.utc.iso8601
160
+ occurred_at: Event.stamp
161
161
  )
162
162
  end
163
163
  end
@@ -90,7 +90,7 @@ module Hecks
90
90
  # @raise [Runtime::UnknownVerb] if `verb` does not resolve (only when `explicit`)
91
91
  # @raise [Runtime::TypeMismatch] if no receiver identity resolves for an explicit target
92
92
  # @raise [Runtime::UnknownArgument] if an explicit projection has an undeclared fact
93
- # rubocop:disable-next Metrics/ParameterLists -- the keyword door both interpreters call
93
+ # rubocop:disable-next Metrics/ParameterLists -- the keyword entry point both interpreters call
94
94
  def build(registry:, verb:, projected:, explicit:, passthrough: [], source_receiver: nil)
95
95
  args = projected.transform_keys(&:to_sym)
96
96
  return forwarded(registry, verb, args, source_receiver) unless explicit
@@ -49,7 +49,17 @@ module Hecks
49
49
  return nil if id.nil?
50
50
 
51
51
  remote = registry.repository(domain, target).find(id.to_s)
52
- remote&.[](field.remote_field)
52
+ unwrap_single_field(target, field, remote&.[](field.remote_field))
53
+ end
54
+
55
+ # A remote field typed by a single-field value object is copied as its one scalar, so the
56
+ # projecting aggregate holds `123`, never `{ value: 123 }`. Any other value is copied as is.
57
+ def unwrap_single_field(target, field, value)
58
+ attribute = target.attribute(field.remote_field)
59
+ sole = attribute && target.value_object(attribute.type)&.sole_attribute
60
+ return value unless sole && !value.nil?
61
+
62
+ value.is_a?(Hash) ? value.fetch(sole.name) { value[sole.name.to_s] } : value[sole.name]
53
63
  end
54
64
  end
55
65
  end
@@ -0,0 +1,35 @@
1
+ require_relative "../../bluebook/ask_resolution"
2
+
3
+ module Hecks
4
+ module Runtime
5
+ class Registry
6
+ # The boot gate for `ask`: every policy's ask must resolve to one declared port operation,
7
+ # so a name the hecksagon never declared stops the boot instead of firing at nothing.
8
+ # Mixed into {Verification}.
9
+ module AskVerification
10
+ private
11
+
12
+ # A port operation a chapter provides, and an ask a policy makes, each name a port
13
+ # operation the hecksagon declared.
14
+ def refuse_unresolved_ports!
15
+ refuse_unresolved_port_operations!
16
+ refuse_unresolved_asks!
17
+ end
18
+
19
+ # Binds each ask to the operation it resolves to, refusing the first that resolves to none.
20
+ #
21
+ # @raise [WiringError] naming the policy, the ask and what the hecksagon would need
22
+ def refuse_unresolved_asks!
23
+ @declared.bluebooks.each_value do |chapter|
24
+ chapter.policies.select(&:asks?).each do |policy|
25
+ outcome = Bluebook::AskResolution.call(chapter, policy)
26
+ raise WiringError, outcome.detail unless outcome.resolved?
27
+
28
+ policy.resolve_ask!(outcome.verb)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -27,6 +27,16 @@ module Hecks
27
27
  "without that it is silent decoration, the exact defect this refusal exists to catch"
28
28
  end
29
29
 
30
+ # `driven_by` names a driving adapter; a name none answers to would silently admit nothing.
31
+ def refuse_unknown_driving!(hecksagon)
32
+ unknown = hecksagon.driving - Bluebook::Hecksagon::DRIVING_ADAPTERS
33
+ return if unknown.empty?
34
+
35
+ raise WiringError,
36
+ "#{hecksagon.domain} is driven_by #{unknown.map(&:inspect).join(", ")}, which no driving " \
37
+ "adapter answers to — the adapters are #{Bluebook::Hecksagon::DRIVING_ADAPTERS.join(", ")}"
38
+ end
39
+
30
40
  # `attaches` loads a bounded context; the consumer must declare the sibling hecksagon
31
41
  # that is its ACL (Governance/Identity/Privacy already do). A vendored package only
32
42
  # loads its `.bluebook` files, so persistence, Governance and the `translates` ACL live
@@ -17,7 +17,7 @@ module Hecks
17
17
  def merge_hecksagons(base, overlay)
18
18
  # Order-independent: list facts uniq, so loading context_map before or after the
19
19
  # domain file yields the same merged hecksagon.
20
- lists = %i[subscriptions attachments translates].to_h do |facet|
20
+ lists = %i[subscriptions attachments translates driving].to_h do |facet|
21
21
  [facet, (base.public_send(facet) + overlay.public_send(facet)).uniq]
22
22
  end
23
23
  Bluebook::Hecksagon.new(domain: base.domain, binds: base.binds + overlay.binds,
@@ -101,6 +101,16 @@ module Hecks
101
101
  vendored_provider_for(domain, Bluebook::Capabilities::PAYMENT_CONNECTION)
102
102
  end
103
103
 
104
+ # The chapter that owns the checkout boundary for `domain` — resolved by what it
105
+ # declares (`provides "checkout"`). Nil when none does.
106
+ #
107
+ # @param domain [String, Symbol] the domain whose checkout chapter is being resolved
108
+ # @return [Bluebook::Chapter, nil] the chapter that owns `domain`'s checkout windows,
109
+ # or nil if none does
110
+ def checkout_provider_for(domain)
111
+ vendored_provider_for(domain, Bluebook::Capabilities::CHECKOUT)
112
+ end
113
+
104
114
  # The chapter that takes payments for `domain`: the domain's own chapter, a
105
115
  # framework member, or a vendored embryonaut bluebook it attaches, that
106
116
  # declares `provides "payments"`.
@@ -112,6 +122,12 @@ module Hecks
112
122
  vendored_provider_for(domain, Bluebook::Capabilities::PAYMENTS)
113
123
  end
114
124
 
125
+ # The first loaded chapter that declares `capability`, whichever domain asks.
126
+ #
127
+ # @param capability [String] a `Bluebook::Capabilities` name
128
+ # @return [Bluebook::Chapter, nil] the providing chapter, or nil if none loaded does
129
+ def provider_of(capability) = bluebooks.values.find { |chapter| chapter.provides?(capability) }
130
+
115
131
  # The chapter that provides `capability` for `domain`: the domain's own chapter,
116
132
  # a framework member its hecksagon attaches, or a vendored embryonaut bluebook
117
133
  # it attaches, that declares it.
@@ -1,3 +1,5 @@
1
+ require_relative "../best_effort"
2
+
1
3
  module Hecks
2
4
  module Runtime
3
5
  class Registry
@@ -37,10 +39,10 @@ module Hecks
37
39
  # `authoritative`, in the same order; false on any mismatch, or if comparing
38
40
  # them raises
39
41
  def projection_current?(projection, authoritative)
40
- entries_match?(projection.entries, authoritative.entries) &&
41
- sorted_rows(projection) == sorted_rows(authoritative)
42
- rescue StandardError
43
- false
42
+ BestEffort.call(false) do
43
+ entries_match?(projection.entries, authoritative.entries) &&
44
+ sorted_rows(projection) == sorted_rows(authoritative)
45
+ end
44
46
  end
45
47
 
46
48
  private
@@ -1,5 +1,6 @@
1
1
  require_relative "../../bluebook/hecksagon"
2
2
  require_relative "hecksagon_rules"
3
+ require_relative "ask_verification"
3
4
  require_relative "query_verification"
4
5
  require_relative "chapter_verification"
5
6
  require_relative "durability_warnings"
@@ -11,6 +12,7 @@ module Hecks
11
12
  # port's verb, and every world default is usable. `verify!` runs it all at boot.
12
13
  module Verification
13
14
  include HecksagonRules
15
+ include AskVerification
14
16
  include QueryVerification
15
17
  include ChapterVerification
16
18
  include DurabilityWarnings
@@ -24,7 +26,7 @@ module Hecks
24
26
  refuse_cross_package_bluebook_merge!
25
27
  refuse_reserved_chapter_names!
26
28
  refuse_membership_without_identity!
27
- refuse_unresolved_port_operations!
29
+ refuse_unresolved_ports!
28
30
  refuse_unanswerable_queries!
29
31
 
30
32
  @declared.hecksagons.each_value { |hecksagon| verify_hecksagon!(hecksagon) }
@@ -126,6 +128,7 @@ module Hecks
126
128
  # warnings for its chapter.
127
129
  def verify_hecksagon!(hecksagon)
128
130
  refuse_ungoverned_roles!(hecksagon)
131
+ refuse_unknown_driving!(hecksagon)
129
132
  refuse_unwired_attachments!(hecksagon)
130
133
  refuse_bounded_without_acl!(hecksagon)
131
134
  hecksagon.binds.each { |bind| verify_bind!(hecksagon, bind) }
@@ -28,8 +28,37 @@ module Hecks
28
28
  self
29
29
  end
30
30
 
31
+ # The defaults an adapter's `.adapter` declares for its fields, with each `{name}` or
32
+ # `{storage_name}` in a string filled from `aggregate`. A world's own setting always wins.
33
+ #
34
+ # @param adapter [String, Symbol] the adapter's name
35
+ # @param aggregate [Bluebook::Aggregate] the aggregate the adapter is built for
36
+ # @return [Hash{Symbol => Object}] the defaults, empty when the adapter declares none
37
+ def adapter_defaults(adapter, aggregate)
38
+ declared = @declared.adapters[adapter.to_s]&.declared_defaults || {}
39
+ declared.transform_values { |value| fill_placeholders(value, aggregate) }
40
+ end
41
+
42
+ # `settings` laid over the adapter's declared defaults. A field a world gives as `:default`
43
+ # asks for the declared default, so it is left out and the default shows through.
44
+ #
45
+ # @param adapter [String, Symbol] the adapter's name
46
+ # @param aggregate [Bluebook::Aggregate] the aggregate the adapter is built for
47
+ # @param settings [Hash{Symbol => Object}] the settings the world gave
48
+ # @return [Hash{Symbol => Object}] the defaults, overridden by the settings given
49
+ def with_adapter_defaults(adapter, aggregate, settings)
50
+ adapter_defaults(adapter, aggregate).merge(settings.reject { |_, value| value == :default })
51
+ end
52
+
31
53
  private
32
54
 
55
+ # A string default with its placeholders filled from the aggregate; any other value as is.
56
+ def fill_placeholders(value, aggregate)
57
+ return value unless value.is_a?(String)
58
+
59
+ value.gsub(/\{(name|storage_name)\}/) { aggregate.public_send(Regexp.last_match(1)) }
60
+ end
61
+
33
62
  # The chapter's own world answers first; the project's world fills the gap.
34
63
  def world_default(domain, field)
35
64
  world(domain)&.public_send(field) || project_world&.public_send(field)
@@ -45,7 +45,7 @@ module Hecks
45
45
  # against; nil for a registry with no such root
46
46
  def initialize(root: nil)
47
47
  @root = root
48
- # Recorded at hecksagon-build time (AggregateDoor#mark_sensitive), Loader.boot's
48
+ # Recorded at hecksagon-build time (AggregateModule#mark_sensitive), Loader.boot's
49
49
  # post-dispatch step turns each pending privacy marking into a real Privacy::Marking.Mark,
50
50
  # idempotently. `resolved_eras` and `superseded_eras` are eager, not lazy, so no two
51
51
  # dispatching threads race to create them; all writes still happen at boot,
@@ -7,7 +7,7 @@ module Hecks
7
7
  module Compensation
8
8
  private
9
9
 
10
- # Recorded before dispatching, not after `@door.reenter` returns —
10
+ # Recorded before dispatching, not after `@dispatcher.reenter` returns —
11
11
  # reenter can recursively re-enter this interpreter and refuse
12
12
  # before ever returning here, and recording only on success would
13
13
  # be too late for that nested refusal to see this leg's own
@@ -24,7 +24,7 @@ module Hecks
24
24
  record = { process_manager: process_manager.name, instance: correlation, dispatch: spec.command_name }
25
25
 
26
26
  log_dispatch_inputs(leg, spec, args) unless spec.with_spec.to_a.empty?
27
- return refuse_at_depth_ceiling(leg, record) if @door.reaction_depth_reached?
27
+ return refuse_at_depth_ceiling(leg, record) if @dispatcher.reaction_depth_reached?
28
28
 
29
29
  attempt_dispatch(leg, spec, args, record)
30
30
  end
@@ -46,7 +46,7 @@ module Hecks
46
46
  # it unwinds like a refusal rather than stranding the instance.
47
47
  def refuse_at_depth_ceiling(leg, record)
48
48
  @registry.saga_log << record.merge(delivered: false,
49
- reason: "reaction depth #{@door.max_reaction_depth} reached")
49
+ reason: "reaction depth #{@dispatcher.max_reaction_depth} reached")
50
50
  unwind(leg)
51
51
  end
52
52
 
@@ -95,14 +95,14 @@ module Hecks
95
95
  nil
96
96
  end
97
97
 
98
- # Dispatches `command_name` through the door, stamped with this saga's correlation.
98
+ # Dispatches `command_name` through the dispatcher, stamped with this saga's correlation.
99
99
  def reenter_command(leg, command_name, projected, explicit:, source_receiver:)
100
100
  head = leg.process_manager.correlation_head
101
101
  verb = qualified(command_name, leg.domain)
102
102
  invocation = ReactionInvocation.build(registry: @registry, verb: verb, projected: projected,
103
103
  explicit: explicit, passthrough: [head],
104
104
  source_receiver: source_receiver)
105
- @door.reenter(verb, saga_correlation: { head.to_s => leg.correlation }, **invocation)
105
+ @dispatcher.reenter(verb, saga_correlation: { head.to_s => leg.correlation }, **invocation)
106
106
  end
107
107
 
108
108
  # Unlike a refusal, a crash isn't a domain decision, so it
@@ -21,7 +21,7 @@ module Hecks
21
21
 
22
22
  # The mutex covers only the check-mutate-checkpoint step, never the
23
23
  # dispatch cascade that follows — `deliver_saga_dispatch`'s
24
- # `@door.reenter` can recursively re-enter this interpreter on the
24
+ # `@dispatcher.reenter` can recursively re-enter this interpreter on the
25
25
  # same thread, and `Mutex` is not reentrant.
26
26
  def remembered_leg_taken?(leg)
27
27
  leg.instance = @registry.saga_instances[leg.process_manager.name][leg.correlation]