hecks 6.0.0 → 7.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 (754) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +19 -12
  3. data/lib/hecks/adapters/driven/claude_code.rb +2 -2
  4. data/lib/hecks/adapters/driven/folder.rb +10 -1
  5. data/lib/hecks/adapters/driven/folder_overlay.rb +15 -0
  6. data/lib/hecks/adapters/driven/heki.rb +1 -1
  7. data/lib/hecks/adapters/driven/in_process_key_vault.rb +1 -1
  8. data/lib/hecks/adapters/driven/memory/outbox_rows.rb +2 -2
  9. data/lib/hecks/adapters/driven/postgres/name_guard.rb +25 -0
  10. data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -3
  11. data/lib/hecks/adapters/driven/postgres/repository.rb +1 -1
  12. data/lib/hecks/adapters/driven/postgres/shared_connection.rb +1 -1
  13. data/lib/hecks/adapters/driven/postgres.rb +3 -0
  14. data/lib/hecks/adapters/driven/postgres_era/boot.rb +28 -16
  15. data/lib/hecks/adapters/driven/postgres_era/class_methods.rb +27 -7
  16. data/lib/hecks/adapters/driven/postgres_era/dialect.rb +10 -5
  17. data/lib/hecks/adapters/driven/postgres_era/field_cache_provisioner.rb +39 -0
  18. data/lib/hecks/adapters/driven/postgres_era/journal.rb +52 -13
  19. data/lib/hecks/adapters/driven/postgres_era/lineage/chain_sql.rb +29 -49
  20. data/lib/hecks/adapters/driven/postgres_era/lineage/direct_sql.rb +73 -0
  21. data/lib/hecks/adapters/driven/postgres_era/lineage/direct_verified.json +10 -0
  22. data/lib/hecks/adapters/driven/postgres_era/lineage/direct_verified.rb +65 -0
  23. data/lib/hecks/adapters/driven/postgres_era/lineage/domain_rename.rb +77 -25
  24. data/lib/hecks/adapters/driven/postgres_era/lineage/domain_rename_state.rb +108 -0
  25. data/lib/hecks/adapters/driven/postgres_era/lineage/era_integrity.rb +11 -6
  26. data/lib/hecks/adapters/driven/postgres_era/lineage/era_store.rb +63 -5
  27. data/lib/hecks/adapters/driven/postgres_era/lineage/layered_sql.rb +64 -0
  28. data/lib/hecks/adapters/driven/postgres_era/lineage/ledger_reset.rb +150 -0
  29. data/lib/hecks/adapters/driven/postgres_era/lineage/mint_provisioning.rb +85 -0
  30. data/lib/hecks/adapters/driven/postgres_era/lineage/mint_transaction.rb +11 -7
  31. data/lib/hecks/adapters/driven/postgres_era/lineage/provisioning.rb +11 -5
  32. data/lib/hecks/adapters/driven/postgres_era/lineage/split_sql.rb +76 -0
  33. data/lib/hecks/adapters/driven/postgres_era/lineage/sql_templates.rb +9 -0
  34. data/lib/hecks/adapters/driven/postgres_era/lineage.rb +10 -2
  35. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/context.rb +23 -3
  36. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/coverage_check.rb +3 -1
  37. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/disposable_ledger.rb +119 -0
  38. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolution.rb +219 -0
  39. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolver.rb +68 -71
  40. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/held_era.rb +68 -0
  41. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/ledger_change.rb +63 -0
  42. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/merge_coordinator.rb +1 -1
  43. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/mint_decision.rb +163 -0
  44. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/mint_request.rb +24 -0
  45. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/minter.rb +59 -21
  46. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/refusals.rb +24 -11
  47. data/lib/hecks/adapters/driven/postgres_era/lineage_manager.rb +40 -6
  48. data/lib/hecks/adapters/driven/postgres_era/shared_tables.rb +32 -0
  49. data/lib/hecks/adapters/driven/postgres_era.adapter +12 -0
  50. data/lib/hecks/adapters/driven/postgres_era.rb +25 -10
  51. data/lib/hecks/adapters/driven/prism.rb +0 -1
  52. data/lib/hecks/adapters/driven/sql_query_builder.rb +1 -0
  53. data/lib/hecks/adapters/driven/sqlite/dispatch_claims.rb +1 -1
  54. data/lib/hecks/adapters/driven/sqlite/name_guard.rb +25 -0
  55. data/lib/hecks/adapters/driven/sqlite/outbox.rb +2 -2
  56. data/lib/hecks/adapters/driven/sqlite/repository.rb +1 -1
  57. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +20 -0
  58. data/lib/hecks/adapters/driven/sqlite.rb +9 -1
  59. data/lib/hecks/adapters/driven/tenant_provisioner.rb +1 -1
  60. data/lib/hecks/adapters/driven/worktree_overlay.rb +117 -0
  61. data/lib/hecks/adapters/driving/cli/shorthand.rb +5 -1
  62. data/lib/hecks/adapters/driving/cli.rb +1 -1
  63. data/lib/hecks/adapters/driving/cli_runner/answers.rb +77 -22
  64. data/lib/hecks/adapters/driving/cli_runner/bang_rule.rb +35 -0
  65. data/lib/hecks/adapters/driving/cli_runner/completion_words.rb +36 -0
  66. data/lib/hecks/adapters/driving/cli_runner/json_words.rb +55 -0
  67. data/lib/hecks/adapters/driving/cli_runner/name_index.rb +63 -0
  68. data/lib/hecks/adapters/driving/cli_runner/read_context.rb +32 -0
  69. data/lib/hecks/adapters/driving/cli_runner/renamed_names.rb +49 -0
  70. data/lib/hecks/adapters/driving/cli_runner/resolution.rb +43 -17
  71. data/lib/hecks/adapters/driving/cli_runner/resume_words.rb +63 -0
  72. data/lib/hecks/adapters/driving/cli_runner/run_reference.rb +66 -0
  73. data/lib/hecks/adapters/driving/cli_runner/run_replay.rb +118 -0
  74. data/lib/hecks/adapters/driving/cli_runner/search_words.rb +35 -0
  75. data/lib/hecks/adapters/driving/cli_runner/settling.rb +6 -5
  76. data/lib/hecks/adapters/driving/cli_runner/streaming.rb +11 -10
  77. data/lib/hecks/adapters/driving/cli_runner/suggestions.rb +1 -1
  78. data/lib/hecks/adapters/driving/cli_runner/tour_words.rb +77 -0
  79. data/lib/hecks/adapters/driving/cli_runner/verb_names.rb +36 -4
  80. data/lib/hecks/adapters/driving/cli_runner/verbosity.rb +75 -0
  81. data/lib/hecks/adapters/driving/cli_runner.rb +106 -7
  82. data/lib/hecks/adapters/driving/context_line.rb +85 -0
  83. data/lib/hecks/adapters/driving/exit_status.rb +31 -0
  84. data/lib/hecks/adapters/driving/launcher_options.rb +7 -5
  85. data/lib/hecks/adapters/driving/mcp/progress_sink.rb +45 -0
  86. data/lib/hecks/adapters/driving/mcp/tool_calls.rb +7 -5
  87. data/lib/hecks/adapters/driving/mcp.rb +25 -5
  88. data/lib/hecks/adapters/driving/mcp_scope/argument_policy.rb +40 -7
  89. data/lib/hecks/adapters/driving/mcp_scope.rb +8 -7
  90. data/lib/hecks/adapters/driving/ruby/aggregate_module/hooks.rb +154 -0
  91. data/lib/hecks/adapters/driving/ruby/aggregate_module.rb +64 -93
  92. data/lib/hecks/adapters/driving/usage_log.rb +146 -0
  93. data/lib/hecks/adapters/driving/write_guard.rb +55 -0
  94. data/lib/hecks/adapters/driving.rb +0 -1
  95. data/lib/hecks/behaviors/dsl.rb +5 -1
  96. data/lib/hecks/behaviors/expectations/boot.rb +0 -1
  97. data/lib/hecks/bluebook/acknowledgements.rb +1 -1
  98. data/lib/hecks/bluebook/aggregate.rb +21 -18
  99. data/lib/hecks/bluebook/assembly/contracts/sagas.rb +2 -0
  100. data/lib/hecks/bluebook/assembly/contracts/structure.rb +18 -13
  101. data/lib/hecks/bluebook/behaviour/aggregate.rb +27 -3
  102. data/lib/hecks/bluebook/command.rb +16 -5
  103. data/lib/hecks/bluebook/declaration.rb +32 -4
  104. data/lib/hecks/bluebook/domain_port.rb +7 -3
  105. data/lib/hecks/bluebook/dsl/aggregate_builder/relationships.rb +0 -2
  106. data/lib/hecks/bluebook/dsl/aggregate_builder/renaming.rb +25 -0
  107. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +3 -0
  108. data/lib/hecks/bluebook/dsl/attribute_collector.rb +0 -1
  109. data/lib/hecks/bluebook/dsl/audience_word.rb +40 -0
  110. data/lib/hecks/bluebook/dsl/bluebook_builder/metadata.rb +56 -0
  111. data/lib/hecks/bluebook/dsl/bluebook_builder/modules.rb +80 -0
  112. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/correlation_keys.rb +51 -0
  113. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +1 -0
  114. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +17 -34
  115. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +8 -0
  116. data/lib/hecks/bluebook/dsl/command_builder.rb +13 -3
  117. data/lib/hecks/bluebook/dsl/entity_builder.rb +0 -2
  118. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +6 -4
  119. data/lib/hecks/bluebook/dsl/kinds.rb +53 -0
  120. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +9 -2
  121. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +25 -15
  122. data/lib/hecks/bluebook/dsl/translation_builder.rb +16 -1
  123. data/lib/hecks/bluebook/dsl/word_gate.rb +1 -1
  124. data/lib/hecks/bluebook/dsl.rb +1 -0
  125. data/lib/hecks/bluebook/meta_validator/judge/identity.rb +9 -4
  126. data/lib/hecks/bluebook/meta_validator/plan/category.rb +10 -2
  127. data/lib/hecks/bluebook/meta_validator/plan/verbs.rb +9 -0
  128. data/lib/hecks/bluebook/meta_validator/plan.rb +2 -1
  129. data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +3 -1
  130. data/lib/hecks/bluebook/meta_validator/reconstruction/reading.rb +7 -0
  131. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +7 -2
  132. data/lib/hecks/bluebook/meta_validator/shapes.rb +3 -0
  133. data/lib/hecks/bluebook/meta_validator/syntax_boot/disk_cache.rb +1 -1
  134. data/lib/hecks/bluebook/model_check/aggregate_checks.rb +27 -0
  135. data/lib/hecks/bluebook/model_check/ask_checks.rb +25 -0
  136. data/lib/hecks/bluebook/model_check/reaction_chains.rb +114 -0
  137. data/lib/hecks/bluebook/model_check/reaction_cycles.rb +53 -0
  138. data/lib/hecks/bluebook/model_check/reaction_depth_checks.rb +58 -0
  139. data/lib/hecks/bluebook/model_check/reaction_walk.rb +62 -0
  140. data/lib/hecks/bluebook/model_check.rb +5 -27
  141. data/lib/hecks/bluebook/process_manager.rb +20 -3
  142. data/lib/hecks/bluebook/translation.rb +5 -3
  143. data/lib/hecks/bluebook/translation_plan.rb +9 -2
  144. data/lib/hecks/ci_pipeline/adapters/ci_cache.adapter +7 -0
  145. data/lib/hecks/ci_pipeline/adapters/ci_cache.rb +39 -0
  146. data/lib/hecks/ci_pipeline/adapters/ci_runner.adapter +7 -0
  147. data/lib/hecks/ci_pipeline/adapters/ci_runner.rb +55 -0
  148. data/lib/hecks/ci_pipeline/ci_pipeline.behaviors +322 -0
  149. data/lib/hecks/ci_pipeline/ci_pipeline.bluebook +938 -0
  150. data/lib/hecks/ci_pipeline/ci_pipeline.hecksagon +12 -0
  151. data/lib/hecks/ci_pipeline/ci_pipeline.ports.hecksagon +16 -0
  152. data/lib/hecks/ci_speed/adapters/ci_reader.adapter +7 -0
  153. data/lib/hecks/ci_speed/adapters/ci_reader.rb +141 -0
  154. data/lib/hecks/ci_speed/adapters/local_runner/answer.rb +41 -0
  155. data/lib/hecks/ci_speed/adapters/local_runner/catalog.rb +89 -0
  156. data/lib/hecks/ci_speed/adapters/local_runner/checkouts.rb +89 -0
  157. data/lib/hecks/ci_speed/adapters/local_runner/launcher.rb +69 -0
  158. data/lib/hecks/ci_speed/adapters/local_runner/load_average.rb +38 -0
  159. data/lib/hecks/ci_speed/adapters/local_runner/refs.rb +39 -0
  160. data/lib/hecks/ci_speed/adapters/local_runner/refused.rb +11 -0
  161. data/lib/hecks/ci_speed/adapters/local_runner/verdict.rb +71 -0
  162. data/lib/hecks/ci_speed/adapters/local_runner.adapter +7 -0
  163. data/lib/hecks/ci_speed/adapters/local_runner.rb +168 -0
  164. data/lib/hecks/ci_speed/adapters/replayed_runner.rb +39 -0
  165. data/lib/hecks/ci_speed/ci_speed.behaviors +341 -0
  166. data/lib/hecks/ci_speed/ci_speed.bluebook +1073 -0
  167. data/lib/hecks/ci_speed/ci_speed.hecksagon +11 -0
  168. data/lib/hecks/ci_speed/ci_speed.ports.hecksagon +21 -0
  169. data/lib/hecks/ci_workflows/ci_workflows.behaviors +13 -0
  170. data/lib/hecks/ci_workflows/ci_workflows.bluebook +173 -0
  171. data/lib/hecks/ci_workflows/ci_workflows.hecksagon +15 -0
  172. data/lib/hecks/coder/coder.bluebook +385 -0
  173. data/lib/hecks/coder/coder.hecksagon +12 -0
  174. data/lib/hecks/command_names/check.rb +39 -0
  175. data/lib/hecks/command_names/extractor.rb +67 -0
  176. data/lib/hecks/command_names/index.rb +40 -0
  177. data/lib/hecks/command_names/resolution.rb +81 -0
  178. data/lib/hecks/command_names/scan.rb +54 -0
  179. data/lib/hecks/command_names/sources.rb +73 -0
  180. data/lib/hecks/command_names.rb +26 -0
  181. data/lib/hecks/composer/jobs.rb +1 -1
  182. data/lib/hecks/composer/toolbox.rb +8 -1
  183. data/lib/hecks/corpus/generated_key.rb +205 -0
  184. data/lib/hecks/corpus/listing.rb +34 -0
  185. data/lib/hecks/corpus/rust.rb +27 -11
  186. data/lib/hecks/corpus/sources.rb +2 -1
  187. data/lib/hecks/corpus.rb +37 -42
  188. data/lib/hecks/deprecation.rb +23 -0
  189. data/lib/hecks/doc/reference/readme.rb +1 -1
  190. data/lib/hecks/doc/reference/rendering.rb +2 -2
  191. data/lib/hecks/doc/reference.rb +1 -1
  192. data/lib/hecks/embryonaut_bluebook/manifest.rb +1 -1
  193. data/lib/hecks/fixer/fixer.bluebook +240 -0
  194. data/lib/hecks/fixer/fixer.hecksagon +17 -0
  195. data/lib/hecks/framework_bluebooks.rb +32 -7
  196. data/lib/hecks/fuzzing/concurrent_dispatch/world_copy.rb +1 -0
  197. data/lib/hecks/fuzzing/isolated_boot/postgres_scratch.rb +11 -12
  198. data/lib/hecks/fuzzing/isolated_boot/worlds.rb +23 -5
  199. data/lib/hecks/fuzzing/isolated_boot.rb +1 -1
  200. data/lib/hecks/fuzzing/mutation/checks.rb +3 -3
  201. data/lib/hecks/grammar/translation.bluebook +1 -1
  202. data/lib/hecks/grammar/translation_rules.json +64 -0
  203. data/lib/hecks/hecks/adapter_words.json +7 -0
  204. data/lib/hecks/hecks/adapters/area_overlap.rb +156 -0
  205. data/lib/hecks/hecks/adapters/claude_agents.rb +8 -3
  206. data/lib/hecks/hecks/adapters/codebase/batch_runs.rb +60 -0
  207. data/lib/hecks/hecks/adapters/codebase/changed_specs.rb +52 -0
  208. data/lib/hecks/hecks/adapters/codebase/codemods.rb +3 -2
  209. data/lib/hecks/hecks/adapters/codebase/conformance.rb +14 -1
  210. data/lib/hecks/hecks/adapters/codebase/corpus_queries.rb +53 -0
  211. data/lib/hecks/hecks/adapters/codebase/generated_keys.rb +31 -0
  212. data/lib/hecks/hecks/adapters/codebase/impacted_specs.rb +110 -0
  213. data/lib/hecks/hecks/adapters/codebase/language.rb +2 -2
  214. data/lib/hecks/hecks/adapters/codebase/launcher_text.rb +39 -0
  215. data/lib/hecks/hecks/adapters/codebase/minitest_runs.rb +52 -0
  216. data/lib/hecks/hecks/adapters/codebase/regeneration.rb +51 -8
  217. data/lib/hecks/hecks/adapters/codebase/run_options.rb +35 -0
  218. data/lib/hecks/hecks/adapters/codebase/scripting.rb +39 -0
  219. data/lib/hecks/hecks/adapters/codebase/search.rb +1 -1
  220. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +79 -51
  221. data/lib/hecks/hecks/adapters/codebase/spec_files/report.rb +71 -0
  222. data/lib/hecks/hecks/adapters/codebase/spec_files/shared_run.rb +73 -0
  223. data/lib/hecks/hecks/adapters/codebase/spec_files.rb +95 -0
  224. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +53 -4
  225. data/lib/hecks/hecks/adapters/codebase/test_scope.rb +105 -0
  226. data/lib/hecks/hecks/adapters/codebase/test_suite.rb +48 -34
  227. data/lib/hecks/hecks/adapters/console_capture.rb +1 -1
  228. data/lib/hecks/hecks/adapters/cost_explorer.rb +9 -1
  229. data/lib/hecks/hecks/adapters/dispatching/brief_text.rb +51 -0
  230. data/lib/hecks/hecks/adapters/dispatching/launcher.rb +97 -0
  231. data/lib/hecks/hecks/adapters/dispatching/plan.rb +82 -0
  232. data/lib/hecks/hecks/adapters/dispatching/rows.rb +66 -0
  233. data/lib/hecks/hecks/adapters/dispatching/settings.rb +81 -0
  234. data/lib/hecks/hecks/adapters/dispatching/settler.rb +40 -0
  235. data/lib/hecks/hecks/adapters/dispatching.adapter +7 -0
  236. data/lib/hecks/hecks/adapters/dispatching.rb +93 -0
  237. data/lib/hecks/hecks/adapters/doctor_reading/report.rb +27 -0
  238. data/lib/hecks/hecks/adapters/doctor_reading.adapter +7 -0
  239. data/lib/hecks/hecks/adapters/doctor_reading.rb +161 -0
  240. data/lib/hecks/hecks/adapters/git_checkout.rb +1 -1
  241. data/lib/hecks/hecks/adapters/git_commit.adapter +7 -0
  242. data/lib/hecks/hecks/adapters/git_commit.rb +61 -0
  243. data/lib/hecks/hecks/adapters/git_landing/finisher.rb +82 -0
  244. data/lib/hecks/hecks/adapters/git_landing/foreign_hold.rb +111 -0
  245. data/lib/hecks/hecks/adapters/git_landing/line.rb +171 -0
  246. data/lib/hecks/hecks/adapters/git_landing/lineup.rb +98 -0
  247. data/lib/hecks/hecks/adapters/git_landing/merger.rb +1 -1
  248. data/lib/hecks/hecks/adapters/git_landing/numbering.rb +54 -0
  249. data/lib/hecks/hecks/adapters/git_landing/rivals.rb +59 -0
  250. data/lib/hecks/hecks/adapters/git_landing/ticket.rb +156 -0
  251. data/lib/hecks/hecks/adapters/git_landing/tidy.rb +147 -0
  252. data/lib/hecks/hecks/adapters/git_landing/train.rb +104 -0
  253. data/lib/hecks/hecks/adapters/git_landing/verdict.rb +64 -0
  254. data/lib/hecks/hecks/adapters/git_landing/waiting.rb +120 -0
  255. data/lib/hecks/hecks/adapters/git_landing.rb +106 -20
  256. data/lib/hecks/hecks/adapters/git_main_pull.rb +99 -0
  257. data/lib/hecks/hecks/adapters/git_rehearsal/bench.rb +82 -0
  258. data/lib/hecks/hecks/adapters/git_rehearsal/due.rb +84 -0
  259. data/lib/hecks/hecks/adapters/git_rehearsal/impacted/skips.rb +47 -0
  260. data/lib/hecks/hecks/adapters/git_rehearsal/impacted/spec_run.rb +75 -0
  261. data/lib/hecks/hecks/adapters/git_rehearsal/impacted.rb +181 -0
  262. data/lib/hecks/hecks/adapters/git_rehearsal/line.rb +76 -0
  263. data/lib/hecks/hecks/adapters/git_rehearsal/reading.rb +24 -0
  264. data/lib/hecks/hecks/adapters/git_rehearsal/record.rb +146 -0
  265. data/lib/hecks/hecks/adapters/git_rehearsal/spec_map/corpus.rb +25 -0
  266. data/lib/hecks/hecks/adapters/git_rehearsal/spec_map/needles.rb +61 -0
  267. data/lib/hecks/hecks/adapters/git_rehearsal/spec_map.rb +105 -0
  268. data/lib/hecks/hecks/adapters/git_rehearsal/stages.rb +118 -0
  269. data/lib/hecks/hecks/adapters/git_rehearsal.adapter +7 -0
  270. data/lib/hecks/hecks/adapters/git_rehearsal.rb +141 -0
  271. data/lib/hecks/hecks/adapters/git_train/bench.rb +15 -15
  272. data/lib/hecks/hecks/adapters/git_train/branch_guard.rb +62 -0
  273. data/lib/hecks/hecks/adapters/git_train/carriage.rb +27 -28
  274. data/lib/hecks/hecks/adapters/git_train/launcher_shape.rb +75 -0
  275. data/lib/hecks/hecks/adapters/git_train/mint_step.rb +47 -0
  276. data/lib/hecks/hecks/adapters/git_train/settlement.rb +167 -0
  277. data/lib/hecks/hecks/adapters/git_train.rb +73 -15
  278. data/lib/hecks/hecks/adapters/git_worktree_add.adapter +7 -0
  279. data/lib/hecks/hecks/adapters/git_worktree_add.rb +68 -0
  280. data/lib/hecks/hecks/adapters/github_pull_requests.adapter +7 -0
  281. data/lib/hecks/hecks/adapters/github_pull_requests.rb +109 -0
  282. data/lib/hecks/hecks/adapters/host_http.rb +6 -6
  283. data/lib/hecks/hecks/adapters/in_process_boot.rb +10 -8
  284. data/lib/hecks/hecks/adapters/in_process_operations.rb +11 -17
  285. data/lib/hecks/hecks/adapters/in_process_undo.rb +17 -0
  286. data/lib/hecks/hecks/adapters/journal_store/changes.rb +13 -4
  287. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +28 -15
  288. data/lib/hecks/hecks/adapters/journal_store/examination.rb +17 -1
  289. data/lib/hecks/hecks/adapters/journal_store/held_domain/renaming.rb +45 -0
  290. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +31 -5
  291. data/lib/hecks/hecks/adapters/journal_store/held_mint.rb +128 -0
  292. data/lib/hecks/hecks/adapters/journal_store/readings/attestation.rb +1 -1
  293. data/lib/hecks/hecks/adapters/journal_store/readings/boot_status.rb +58 -0
  294. data/lib/hecks/hecks/adapters/journal_store/readings/composition.rb +39 -0
  295. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/outcomes.rb +76 -0
  296. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/postgres_reader.rb +44 -0
  297. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/reader.rb +64 -0
  298. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/report.rb +102 -0
  299. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/sqlite_reader.rb +43 -0
  300. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/stores.rb +80 -0
  301. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/subscribers.rb +72 -0
  302. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/summary.rb +39 -0
  303. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace.rb +39 -0
  304. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/command_line.rb +57 -0
  305. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/edge_guards.rb +107 -0
  306. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/inspection.rb +94 -0
  307. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/plan.rb +66 -0
  308. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/report.rb +72 -0
  309. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/store.rb +34 -0
  310. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/watermark_guards.rb +86 -0
  311. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/world.rb +66 -0
  312. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan.rb +36 -0
  313. data/lib/hecks/hecks/adapters/journal_store/readings/projection_audit.rb +64 -0
  314. data/lib/hecks/hecks/adapters/journal_store/readings/scaffolding.rb +3 -3
  315. data/lib/hecks/hecks/adapters/journal_store/readings/sqlite_status/database_reading.rb +113 -0
  316. data/lib/hecks/hecks/adapters/journal_store/readings/sqlite_status/read_only.rb +33 -0
  317. data/lib/hecks/hecks/adapters/journal_store/readings/sqlite_status.rb +32 -0
  318. data/lib/hecks/hecks/adapters/journal_store/readings.rb +13 -1
  319. data/lib/hecks/hecks/adapters/journal_store/reconcile_report.rb +60 -0
  320. data/lib/hecks/hecks/adapters/journal_store/reconciliation.rb +121 -0
  321. data/lib/hecks/hecks/adapters/journal_store/translation_write/shape_edge.rb +59 -0
  322. data/lib/hecks/hecks/adapters/journal_store/translation_write.rb +123 -0
  323. data/lib/hecks/hecks/adapters/journal_store.rb +16 -0
  324. data/lib/hecks/hecks/adapters/landed_work.adapter +7 -0
  325. data/lib/hecks/hecks/adapters/landed_work.rb +52 -0
  326. data/lib/hecks/hecks/adapters/local_files.rb +6 -6
  327. data/lib/hecks/hecks/adapters/process_pool.rb +3 -2
  328. data/lib/hecks/hecks/adapters/push_size.rb +57 -0
  329. data/lib/hecks/hecks/adapters/qa_quiescing.adapter +7 -0
  330. data/lib/hecks/hecks/adapters/qa_quiescing.rb +57 -0
  331. data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +30 -3
  332. data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +63 -3
  333. data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +29 -6
  334. data/lib/hecks/hecks/adapters/rehearsal/subject.rb +11 -5
  335. data/lib/hecks/hecks/adapters/rust_toolchain.rb +10 -1
  336. data/lib/hecks/hecks/adapters/rust_workspace.rb +1 -1
  337. data/lib/hecks/hecks/adapters/settings_reading/disposable_ledger.rb +32 -0
  338. data/lib/hecks/hecks/adapters/settings_reading/push_nudge.rb +26 -0
  339. data/lib/hecks/hecks/adapters/settings_reading/stores.rb +76 -0
  340. data/lib/hecks/hecks/adapters/settings_reading/test_scope.rb +28 -0
  341. data/lib/hecks/hecks/adapters/settings_reading.rb +28 -2
  342. data/lib/hecks/hecks/adapters/started_work.rb +42 -0
  343. data/lib/hecks/hecks/adapters/terminal.rb +12 -10
  344. data/lib/hecks/hecks/adapters/where_reading.adapter +7 -0
  345. data/lib/hecks/hecks/adapters/where_reading.rb +64 -0
  346. data/lib/hecks/hecks/adapters/work_areas.rb +57 -0
  347. data/lib/hecks/hecks/adapters/work_limits.rb +57 -0
  348. data/lib/hecks/hecks/build/build.bluebook +576 -0
  349. data/lib/hecks/hecks/check/check.bluebook +966 -0
  350. data/lib/hecks/hecks/codebase.behaviors +61 -5
  351. data/lib/hecks/hecks/composer.behaviors +1 -1
  352. data/lib/hecks/hecks/context_map.hecksagon +1 -1
  353. data/lib/hecks/hecks/custodian.behaviors +33 -7
  354. data/lib/hecks/hecks/delegate/delegate.bluebook +355 -0
  355. data/lib/hecks/hecks/deliver/deliver.bluebook +945 -0
  356. data/lib/hecks/hecks/deploy.behaviors +1 -1
  357. data/lib/hecks/hecks/evolve/evolve.bluebook +788 -0
  358. data/lib/hecks/hecks/find/find.bluebook +81 -0
  359. data/lib/hecks/hecks/hecks.behaviors +1 -1
  360. data/lib/hecks/hecks/hecks.bluebook +0 -133
  361. data/lib/hecks/hecks/hecks.contextmap +2 -0
  362. data/lib/hecks/hecks/hecks.hecksagon +185 -29
  363. data/lib/hecks/hecks/hecks.world +35 -9
  364. data/lib/hecks/hecks/implicit_moves.json +24 -0
  365. data/lib/hecks/hecks/migrate/migrate.bluebook +1066 -0
  366. data/lib/hecks/hecks/operate/operate.bluebook +695 -0
  367. data/lib/hecks/hecks/quiesce/quiesce.bluebook +117 -0
  368. data/lib/hecks/hecks/rehearse/rehearse.bluebook +133 -0
  369. data/lib/hecks/hecks/release/release.bluebook +916 -0
  370. data/lib/hecks/hecks/serve/serve.bluebook +134 -0
  371. data/lib/hecks/hecks/shapes.json +1 -15
  372. data/lib/hecks/hecks/site.behaviors +1 -1
  373. data/lib/hecks/hecks/start/start.bluebook +194 -0
  374. data/lib/hecks/hecks/test/test.bluebook +638 -0
  375. data/lib/hecks/hecks/tickets.world +14 -0
  376. data/lib/hecks/language/bluebook/aggregate.bluebook +22 -0
  377. data/lib/hecks/language/bluebook/bluebook.bluebook +34 -0
  378. data/lib/hecks/language/bluebook/command.bluebook +35 -0
  379. data/lib/hecks/language/bluebook/process_manager.bluebook +14 -1
  380. data/lib/hecks/language/bluebook/vocabulary.bluebook +174 -54
  381. data/lib/hecks/language/hecksagon/domain_port.bluebook +1 -0
  382. data/lib/hecks/language/hecksagon/port_operation.bluebook +14 -0
  383. data/lib/hecks/language/kinds/run.kind +120 -0
  384. data/lib/hecks/language/oidc.json +10 -0
  385. data/lib/hecks/language/translation/translation_aggregate.bluebook +24 -0
  386. data/lib/hecks/module_folders.rb +31 -0
  387. data/lib/hecks/ports/key_vault.rb +1 -1
  388. data/lib/hecks/ports/persistence/append_only.rb +26 -8
  389. data/lib/hecks/ports/persistence/binding_policy.rb +3 -1
  390. data/lib/hecks/ports/persistence/codec_boundary.rb +1 -1
  391. data/lib/hecks/ports/persistence/mint_door.rb +74 -0
  392. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +6 -5
  393. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +5 -1
  394. data/lib/hecks/ports/persistence/plugins/era/era_status.rb +48 -0
  395. data/lib/hecks/ports/persistence/plugins/era/projected_bluebook.rb +127 -0
  396. data/lib/hecks/ports/persistence/plugins/era/translation/additive_shape.rb +107 -0
  397. data/lib/hecks/ports/persistence/plugins/era/translation/compose.rb +155 -0
  398. data/lib/hecks/ports/persistence/plugins/era/translation/compose_render.rb +79 -0
  399. data/lib/hecks/ports/persistence/plugins/era/translation/edge_files.rb +49 -0
  400. data/lib/hecks/ports/persistence/plugins/era/translation/edge_route.rb +61 -0
  401. data/lib/hecks/ports/persistence/plugins/era/translation/implicit_edge.rb +67 -0
  402. data/lib/hecks/ports/persistence/plugins/era/translation/reconcile.rb +130 -0
  403. data/lib/hecks/ports/persistence/plugins/era/translation/reconcile_files.rb +35 -0
  404. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +13 -5
  405. data/lib/hecks/ports/persistence/plugins/era/translation.rb +5 -0
  406. data/lib/hecks/ports/persistence/plugins/era.rb +1 -0
  407. data/lib/hecks/ports/persistence/repository_factory.rb +11 -3
  408. data/lib/hecks/ports/persistence/stored_name_guard.rb +36 -0
  409. data/lib/hecks/ports/persistence.rb +2 -0
  410. data/lib/hecks/projections/ci_pipeline/table/checks.rb +137 -0
  411. data/lib/hecks/projections/ci_pipeline/table/lookup.rb +59 -0
  412. data/lib/hecks/projections/ci_pipeline/table/refusals.rb +58 -0
  413. data/lib/hecks/projections/ci_pipeline/table/rows.rb +119 -0
  414. data/lib/hecks/projections/ci_pipeline/table/tree.rb +30 -0
  415. data/lib/hecks/projections/ci_pipeline/table/typing.rb +92 -0
  416. data/lib/hecks/projections/ci_pipeline/table.rb +112 -0
  417. data/lib/hecks/projections/ci_pipeline/workflows.rb +162 -0
  418. data/lib/hecks/projections/ci_pipeline/yaml_text.rb +104 -0
  419. data/lib/hecks/projections/deploy/box/hosting.rb +1 -1
  420. data/lib/hecks/projections/deploy/box/roll_recipe.rb +1 -1
  421. data/lib/hecks/projections/deploy/box/roll_scripts.rb +1 -1
  422. data/lib/hecks/projections/deploy/box.rb +1 -1
  423. data/lib/hecks/projections/deploy/templates/fargate/Makefile.tmpl +1 -1
  424. data/lib/hecks/projections/deploy/templates/lambda/Makefile.tmpl +3 -3
  425. data/lib/hecks/projections/undo.rb +46 -0
  426. data/lib/hecks/projections.rb +2 -0
  427. data/lib/hecks/projector/cli_projector/claims.rb +11 -0
  428. data/lib/hecks/projector/cli_projector/command_help.rb +6 -1
  429. data/lib/hecks/projector/cli_projector/command_specs.rb +11 -1
  430. data/lib/hecks/projector/cli_projector/completion.rb +87 -0
  431. data/lib/hecks/projector/cli_projector/everyday.rb +40 -0
  432. data/lib/hecks/projector/cli_projector/json_listing.rb +77 -0
  433. data/lib/hecks/projector/cli_projector/listing.rb +1 -1
  434. data/lib/hecks/projector/cli_projector/modules.rb +39 -0
  435. data/lib/hecks/projector/cli_projector/query_specs.rb +1 -0
  436. data/lib/hecks/projector/cli_projector/renames.rb +58 -0
  437. data/lib/hecks/projector/cli_projector/search.rb +74 -0
  438. data/lib/hecks/projector/cli_projector/usage.rb +23 -6
  439. data/lib/hecks/projector/cli_projector.rb +24 -1
  440. data/lib/hecks/quality_control/adapters/ci_head.adapter +8 -0
  441. data/lib/hecks/quality_control/adapters/image_roll.adapter +9 -0
  442. data/lib/hecks/quality_control/adapters/image_roll.rb +158 -0
  443. data/lib/hecks/quality_control/adapters/main_maintenance.adapter +8 -0
  444. data/lib/hecks/quality_control/adapters/main_maintenance.rb +275 -0
  445. data/lib/hecks/quality_control/adapters/pump_tools.adapter +7 -0
  446. data/lib/hecks/quality_control/adapters/pump_tools.rb +18 -0
  447. data/lib/hecks/quality_control/adapters/push_due_reader.adapter +8 -0
  448. data/lib/hecks/quality_control/adapters/push_due_reader.rb +99 -0
  449. data/lib/hecks/quality_control/adapters/qa_auto_mint.rb +183 -0
  450. data/lib/hecks/quality_control/adapters/qa_era_mint.rb +94 -0
  451. data/lib/hecks/quality_control/adapters/qa_quiesce_marker.rb +126 -0
  452. data/lib/hecks/quality_control/adapters/run_keys.rb +36 -0
  453. data/lib/hecks/quality_control/adapters/run_reader.adapter +7 -0
  454. data/lib/hecks/quality_control/adapters/run_reader.rb +188 -0
  455. data/lib/hecks/quality_control/cli/child.rb +1 -0
  456. data/lib/hecks/quality_control/cli/qa_discover_external_domains/scanning.rb +1 -1
  457. data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +3 -3
  458. data/lib/hecks/quality_control/cli/qa_event_pump/attached.rb +67 -0
  459. data/lib/hecks/quality_control/cli/qa_event_pump/consumer.rb +103 -0
  460. data/lib/hecks/quality_control/cli/qa_event_pump/cursors.rb +60 -0
  461. data/lib/hecks/quality_control/cli/qa_event_pump/reactions.rb +46 -0
  462. data/lib/hecks/quality_control/cli/qa_event_pump/reader.rb +30 -0
  463. data/lib/hecks/quality_control/cli/qa_event_pump.rb +76 -0
  464. data/lib/hecks/quality_control/cli/qa_fix_main_bug/publishing.rb +79 -0
  465. data/lib/hecks/quality_control/cli/qa_fix_main_bug.rb +167 -0
  466. data/lib/hecks/quality_control/cli/qa_generated_domains/evaluation.rb +1 -1
  467. data/lib/hecks/quality_control/cli/qa_generated_domains/promotion.rb +3 -3
  468. data/lib/hecks/quality_control/cli/qa_main_gate/gate_run.rb +52 -0
  469. data/lib/hecks/quality_control/cli/qa_main_gate/logging.rb +70 -0
  470. data/lib/hecks/quality_control/cli/qa_main_gate/shell.rb +47 -0
  471. data/lib/hecks/quality_control/cli/qa_main_gate/sweeping.rb +59 -0
  472. data/lib/hecks/quality_control/cli/qa_main_gate/worktree.rb +62 -0
  473. data/lib/hecks/quality_control/cli/qa_main_gate.rb +135 -0
  474. data/lib/hecks/quality_control/cli/qa_postgres_role.rb +1 -1
  475. data/lib/hecks/quality_control/cli/qa_pr_check/checking.rb +2 -3
  476. data/lib/hecks/quality_control/cli/qa_push_nudge.rb +48 -0
  477. data/lib/hecks/quality_control/cli/qa_seed_angles/seed.rb +1 -1
  478. data/lib/hecks/quality_control/cli/qa_sweep/seat.rb +1 -1
  479. data/lib/hecks/quality_control/cli/qa_tick/event_pump_step.rb +34 -0
  480. data/lib/hecks/quality_control/cli/qa_tick/output.rb +16 -1
  481. data/lib/hecks/quality_control/cli/qa_tick/push_nudge_step.rb +28 -0
  482. data/lib/hecks/quality_control/cli/qa_tick/quiesce_guard.rb +51 -0
  483. data/lib/hecks/quality_control/cli/qa_tick.rb +36 -8
  484. data/lib/hecks/quality_control/quality_control.behaviors +65 -0
  485. data/lib/hecks/quality_control/quality_control.bluebook +1131 -11
  486. data/lib/hecks/quality_control/quality_control.hecksagon +11 -0
  487. data/lib/hecks/quality_control/quality_control.ports.hecksagon +138 -0
  488. data/lib/hecks/query_ir/touchpoints.rb +5 -7
  489. data/lib/hecks/refused.rb +21 -0
  490. data/lib/hecks/release/approval.rb +6 -3
  491. data/lib/hecks/release/conditions.rb +46 -0
  492. data/lib/hecks/release/runner/gem_publisher.rb +4 -4
  493. data/lib/hecks/release/version_commit.rb +48 -0
  494. data/lib/hecks/runtime/command_interpreter/hydration.rb +5 -4
  495. data/lib/hecks/runtime/command_interpreter/persisting.rb +11 -3
  496. data/lib/hecks/runtime/command_interpreter.rb +2 -2
  497. data/lib/hecks/runtime/command_rules/admissibility.rb +0 -2
  498. data/lib/hecks/runtime/command_rules/emission.rb +0 -1
  499. data/lib/hecks/runtime/dependency_planning/expression_reads.rb +0 -1
  500. data/lib/hecks/runtime/dispatcher/planning.rb +24 -0
  501. data/lib/hecks/runtime/dispatcher/routing.rb +6 -0
  502. data/lib/hecks/runtime/dispatcher/value_routing.rb +54 -0
  503. data/lib/hecks/runtime/dispatcher.rb +7 -1
  504. data/lib/hecks/runtime/dry_run_plan.rb +60 -0
  505. data/lib/hecks/runtime/entity_element/location.rb +0 -1
  506. data/lib/hecks/runtime/entity_element/mutations.rb +0 -1
  507. data/lib/hecks/runtime/entity_interpreter/locating.rb +5 -0
  508. data/lib/hecks/runtime/entity_interpreter.rb +0 -1
  509. data/lib/hecks/runtime/errors.rb +26 -0
  510. data/lib/hecks/runtime/instance.rb +0 -1
  511. data/lib/hecks/runtime/invocation_builder.rb +0 -1
  512. data/lib/hecks/runtime/outbox/consumer_runner.rb +9 -1
  513. data/lib/hecks/runtime/outbox/relay.rb +25 -4
  514. data/lib/hecks/runtime/outbox/runnable.rb +3 -1
  515. data/lib/hecks/runtime/outbox.rb +6 -2
  516. data/lib/hecks/runtime/policy_interpreter/fan_out.rb +18 -2
  517. data/lib/hecks/runtime/policy_interpreter.rb +17 -9
  518. data/lib/hecks/runtime/port_operation_interpreter.rb +21 -7
  519. data/lib/hecks/runtime/query_interpreter/arguments.rb +6 -5
  520. data/lib/hecks/runtime/reaction_invocation.rb +0 -1
  521. data/lib/hecks/runtime/refusal_wording.rb +12 -1
  522. data/lib/hecks/runtime/registry/context_maps.rb +1 -5
  523. data/lib/hecks/runtime/registry/declarations.rb +34 -4
  524. data/lib/hecks/runtime/registry/hecksagon_rules.rb +15 -1
  525. data/lib/hecks/runtime/registry/runtime_state.rb +10 -0
  526. data/lib/hecks/runtime/registry/world_defaults.rb +24 -2
  527. data/lib/hecks/runtime/registry/world_names.rb +99 -0
  528. data/lib/hecks/runtime/registry.rb +33 -27
  529. data/lib/hecks/runtime/saga_interpreter/compensation.rb +10 -0
  530. data/lib/hecks/runtime/saga_interpreter/correlation.rb +29 -3
  531. data/lib/hecks/runtime/saga_interpreter/delivery.rb +0 -1
  532. data/lib/hecks/runtime/saga_interpreter/lifecycle.rb +1 -1
  533. data/lib/hecks/runtime/saga_interpreter.rb +46 -2
  534. data/lib/hecks/runtime/value/coercion.rb +36 -8
  535. data/lib/hecks/rust_build/conformance.rb +16 -5
  536. data/lib/hecks/rust_build/parser.rb +25 -0
  537. data/lib/hecks/rust_build/project_rust/codegen_run.rb +45 -12
  538. data/lib/hecks/rust_build/project_rust/declared.rb +80 -0
  539. data/lib/hecks/rust_build/project_rust/features_header.rb +22 -0
  540. data/lib/hecks/rust_build/project_rust/manifest.rb +96 -0
  541. data/lib/hecks/rust_build/project_rust/meta.rb +36 -0
  542. data/lib/hecks/rust_build/project_rust.rb +28 -90
  543. data/lib/hecks/rust_build/write_if_changed.rb +19 -4
  544. data/lib/hecks/rust_build.rb +2 -1
  545. data/lib/hecks/rust_format.rb +32 -2
  546. data/lib/hecks/secrets.rb +111 -0
  547. data/lib/hecks/shape_ledger/edge_hygiene.rb +170 -0
  548. data/lib/hecks/shape_ledger/scope.rb +51 -0
  549. data/lib/hecks/shape_ledger/status.rb +89 -0
  550. data/lib/hecks/shape_ledger.rb +78 -33
  551. data/lib/hecks/site/bluebook/site.bluebook +1 -0
  552. data/lib/hecks/storehouse/audit.rb +34 -4
  553. data/lib/hecks/storehouse/callers.rb +8 -0
  554. data/lib/hecks/storehouse/dispatching.rb +14 -3
  555. data/lib/hecks/storehouse/identity.rb +41 -0
  556. data/lib/hecks/storehouse/querying.rb +7 -7
  557. data/lib/hecks/storehouse.rb +28 -10
  558. data/lib/hecks/tickets/bluebook/adapters/work_areas.adapter +7 -0
  559. data/lib/hecks/tickets/bluebook/adapters/work_limits.adapter +7 -0
  560. data/lib/hecks/tickets/bluebook/tickets.behaviors +70 -0
  561. data/lib/hecks/tickets/bluebook/tickets.bluebook +323 -28
  562. data/lib/hecks/tickets/bluebook/tickets.hecksagon +7 -0
  563. data/lib/hecks/tickets/bluebook/tickets.ports.hecksagon +17 -0
  564. data/lib/hecks/{cli → tools}/behaviors.rb +1 -1
  565. data/lib/hecks/{cli → tools}/canonicalise.rb +1 -1
  566. data/lib/hecks/{cli → tools}/check_engine_agreement.rb +1 -1
  567. data/lib/hecks/{cli → tools}/check_era.rb +6 -6
  568. data/lib/hecks/tools/ci_gates.rb +8 -2
  569. data/lib/hecks/tools/ci_workflows.rb +98 -0
  570. data/lib/hecks/{cli → tools}/console.rb +1 -1
  571. data/lib/hecks/{cli → tools}/deploy_template_diff.rb +1 -1
  572. data/lib/hecks/{cli → tools}/doc_coverage.rb +2 -2
  573. data/lib/hecks/{cli → tools}/document.rb +1 -1
  574. data/lib/hecks/{cli → tools}/domain_stub.rb +1 -1
  575. data/lib/hecks/{cli → tools}/domain_writer.rb +1 -1
  576. data/lib/hecks/tools/downstream_model_check.rb +122 -0
  577. data/lib/hecks/tools/evolve_run.rb +2 -2
  578. data/lib/hecks/{cli → tools}/expected_era.rb +1 -1
  579. data/lib/hecks/{cli → tools}/expression_projection.rb +1 -1
  580. data/lib/hecks/{cli → tools}/follow.rb +1 -1
  581. data/lib/hecks/tools/fuzz_sweep/options.rb +40 -5
  582. data/lib/hecks/tools/fuzz_sweep/pool.rb +12 -1
  583. data/lib/hecks/tools/fuzz_sweep/shards.rb +155 -0
  584. data/lib/hecks/tools/fuzz_sweep.rb +11 -5
  585. data/lib/hecks/tools/gate.rb +38 -29
  586. data/lib/hecks/tools/gate_memo/local_files.rb +33 -0
  587. data/lib/hecks/tools/gate_memo/rehearsal.rb +54 -0
  588. data/lib/hecks/tools/gate_memo/ruby_files.rb +152 -0
  589. data/lib/hecks/tools/gate_memo/session.rb +114 -0
  590. data/lib/hecks/tools/gate_memo/standalone.rb +67 -0
  591. data/lib/hecks/tools/gate_memo.rb +196 -0
  592. data/lib/hecks/tools/gate_report.rb +56 -0
  593. data/lib/hecks/{cli → tools}/history.rb +1 -1
  594. data/lib/hecks/{cli → tools}/interview_agent.rb +1 -1
  595. data/lib/hecks/{cli → tools}/interview_aggregate.rb +1 -1
  596. data/lib/hecks/{cli → tools}/interview_draft.rb +1 -1
  597. data/lib/hecks/{cli → tools}/interview_record.rb +1 -1
  598. data/lib/hecks/{cli → tools}/interview_run.rb +2 -2
  599. data/lib/hecks/{cli → tools}/interview_session/agent_state.rb +1 -1
  600. data/lib/hecks/{cli → tools}/interview_session/catalog.rb +1 -1
  601. data/lib/hecks/{cli → tools}/interview_session/manual_findings.rb +1 -1
  602. data/lib/hecks/{cli → tools}/interview_session/proposals.rb +1 -1
  603. data/lib/hecks/{cli → tools}/interview_session.rb +2 -2
  604. data/lib/hecks/{cli → tools}/interview_shape/lifecycle.rb +1 -1
  605. data/lib/hecks/{cli → tools}/interview_shape.rb +1 -1
  606. data/lib/hecks/{cli → tools}/ir.rb +1 -1
  607. data/lib/hecks/tools/lanes/files.rb +1 -1
  608. data/lib/hecks/tools/lanes/watch_workflow.rb +6 -8
  609. data/lib/hecks/tools/lanes/workflow.rb +1 -1
  610. data/lib/hecks/tools/lanes.rb +1 -1
  611. data/lib/hecks/{cli → tools}/mcp.rb +1 -1
  612. data/lib/hecks/{cli → tools}/model_check/examination.rb +1 -1
  613. data/lib/hecks/{cli → tools}/model_check/sources.rb +1 -1
  614. data/lib/hecks/{cli → tools}/model_check.rb +1 -1
  615. data/lib/hecks/tools/move_disables/reasons.rb +35 -0
  616. data/lib/hecks/tools/move_disables.rb +211 -0
  617. data/lib/hecks/tools/move_former_name.rb +105 -0
  618. data/lib/hecks/{cli → tools}/pattern_cases.rb +1 -1
  619. data/lib/hecks/{cli → tools}/persistence_notice.rb +1 -1
  620. data/lib/hecks/{cli → tools}/present.rb +1 -1
  621. data/lib/hecks/{cli → tools}/project_cli/launcher_source.rb +32 -22
  622. data/lib/hecks/{cli → tools}/project_cli/templates.rb +22 -15
  623. data/lib/hecks/{cli → tools}/project_cli.rb +11 -7
  624. data/lib/hecks/{cli → tools}/project_diagrams.rb +3 -3
  625. data/lib/hecks/{cli → tools}/project_glossary.rb +2 -2
  626. data/lib/hecks/{cli → tools}/reference.rb +2 -2
  627. data/lib/hecks/{cli → tools}/refresh_projections.rb +1 -1
  628. data/lib/hecks/{cli → tools}/refresh_rspec_runtime_baseline.rb +1 -1
  629. data/lib/hecks/tools/regeneration_run/pool.rb +148 -0
  630. data/lib/hecks/tools/regeneration_run/scratch.rb +76 -0
  631. data/lib/hecks/tools/regeneration_run.rb +125 -103
  632. data/lib/hecks/{cli → tools}/release.rb +1 -1
  633. data/lib/hecks/{cli → tools}/release_gem.rb +1 -1
  634. data/lib/hecks/{cli → tools}/rspec_io_parallel_files.rb +1 -1
  635. data/lib/hecks/{cli → tools}/rspec_shard_files.rb +1 -1
  636. data/lib/hecks/{cli → tools}/run.rb +9 -2
  637. data/lib/hecks/{cli → tools}/run_expectations.rb +1 -1
  638. data/lib/hecks/{cli → tools}/seed_semantics_corpus.rb +4 -4
  639. data/lib/hecks/{cli → tools}/serve_query_ir_mcp.rb +1 -1
  640. data/lib/hecks/{cli → tools}/shape.rb +3 -2
  641. data/lib/hecks/{cli → tools}/smoke_http/checks.rb +1 -1
  642. data/lib/hecks/{cli → tools}/smoke_http/settings.rb +1 -1
  643. data/lib/hecks/{cli → tools}/smoke_http/transport.rb +1 -1
  644. data/lib/hecks/{cli → tools}/smoke_http.rb +1 -1
  645. data/lib/hecks/{cli → tools}/smoke_test.rb +1 -1
  646. data/lib/hecks/{cli → tools}/spec_example.rb +1 -1
  647. data/lib/hecks/tools/stage_progress.rb +54 -0
  648. data/lib/hecks/{cli → tools}/statements.rb +1 -1
  649. data/lib/hecks/{cli → tools}/stores.rb +1 -1
  650. data/lib/hecks/{cli → tools}/stress_concurrency_specs/reporting.rb +1 -1
  651. data/lib/hecks/{cli → tools}/stress_concurrency_specs/usage.rb +4 -4
  652. data/lib/hecks/{cli → tools}/stress_concurrency_specs.rb +3 -3
  653. data/lib/hecks/tools/tenant_provisioning.rb +23 -0
  654. data/lib/hecks/tools/tools_doc.rb +10 -8
  655. data/lib/hecks/tools/translation_audit/edges.rb +21 -16
  656. data/lib/hecks/tools/translation_audit/verdicts.rb +1 -1
  657. data/lib/hecks/tools/translation_audit.rb +1 -1
  658. data/lib/hecks/tools/translation_scaffold.rb +1 -1
  659. data/lib/hecks/tools.rb +4 -1
  660. data/lib/hecks/version.rb +1 -1
  661. data/lib/hecks/vocabulary.rb +61 -31
  662. data/lib/hecks/workflow_pagination/judge.rb +48 -0
  663. data/lib/hecks/workflow_pagination/statement.rb +50 -0
  664. data/lib/hecks/workflow_pagination.rb +58 -0
  665. data/lib/hecks.rb +2 -0
  666. data/lib/rubocop/cop/hecks/bare_event_and_query_names.rb +58 -0
  667. data/lib/rubocop/cop/hecks/correlates_by_aggregate.rb +39 -0
  668. data/lib/rubocop/cop/hecks/creating_command_sets.rb +75 -0
  669. data/lib/rubocop/cop/hecks/invariant_expression_language.rb +47 -0
  670. data/lib/rubocop/cop/hecks/lifecycle_needs_attribute.rb +58 -0
  671. data/lib/rubocop/cop/hecks/no_id_string_attribute.rb +49 -0
  672. data/lib/rubocop/cop/hecks/one_terminal_mark_per_lifecycle.rb +47 -0
  673. data/lib/rubocop/cop/hecks/value_object_shorthand.rb +56 -0
  674. data/prebuilt/13c04bdc5970295b310f0a980d397ba722232c8da99cc1a0cdb383249921e871.marshal +0 -0
  675. data/prebuilt/e3857b77f47d9ecc1787b2e1f5136364f3cb3444ef4aea5479f3b98167affea2.marshal +0 -0
  676. data/qa/settings.yml +23 -0
  677. data/rust/.gitignore +0 -6
  678. data/rust/Cargo.toml +2 -1
  679. data/rust/build/Cargo.toml +1 -1
  680. data/rust/build/src/binding_pass.rs +57 -4
  681. data/rust/build/src/pipeline.rs +6 -4
  682. data/rust/build/src/resolve.rs +1 -0
  683. data/rust/codegen/Cargo.toml +1 -1
  684. data/rust/codegen/src/domain_generator.rs +3 -0
  685. data/rust/codegen/src/json_codec.rs +182 -23
  686. data/rust/codegen/src/one_of_references.rs +1 -0
  687. data/rust/codegen/src/queries.rs +20 -2
  688. data/rust/codegen/src/registry.rs +21 -5
  689. data/rust/expr/Cargo.toml +1 -1
  690. data/rust/host/Cargo.toml +1 -1
  691. data/rust/host/HECKS_RELEASE +1 -1
  692. data/rust/host/core/Cargo.toml +1 -1
  693. data/rust/host/src/bin/mint_harness.rs +1 -0
  694. data/rust/host/src/boot.rs +1 -0
  695. data/rust/host/src/store/mint.rs +40 -6
  696. data/rust/lsp/Cargo.toml +1 -1
  697. data/rust/parser/Cargo.toml +1 -1
  698. data/rust/parser/src/build/correlation_keys.rs +125 -0
  699. data/rust/parser/src/build/mod.rs +1 -0
  700. data/rust/parser/src/emit.rs +55 -3
  701. data/rust/parser/src/ir.rs +33 -1
  702. data/rust/parser/src/keywords.rs +289 -1
  703. data/rust/parser/src/main.rs +2 -0
  704. data/rust/parser/src/parse/aggregate.rs +10 -1
  705. data/rust/parser/src/parse/audience.rs +65 -0
  706. data/rust/parser/src/parse/command.rs +14 -0
  707. data/rust/parser/src/parse/declaration.rs +97 -0
  708. data/rust/parser/src/parse/domain_port.rs +6 -0
  709. data/rust/parser/src/parse/mod.rs +1 -0
  710. data/rust/parser/src/parse/process_manager.rs +17 -10
  711. data/rust/parser/src/parse/world.rs +12 -8
  712. data/rust/parser/src/render_ruby.rs +9 -0
  713. data/rust/parser/src/sentence/format.rs +3 -0
  714. data/rust/parser/src/sentence/process.rs +6 -2
  715. data/rust/src/exemplar/json.rs +17 -0
  716. data/rust/src/kernel/cli.rs +27 -3
  717. data/rust/src/kernel/dispatch.rs +4 -2
  718. data/rust/src/kernel/json.rs +62 -0
  719. data/rust/src/kernel/orchestrate.rs +28 -3
  720. data/rust/src/kernel/orchestrate_guard_tests.rs +12 -12
  721. data/rust/web/Cargo.toml +1 -1
  722. metadata +389 -96
  723. data/lib/hecks/cli/command_table.rb +0 -72
  724. data/lib/hecks/cli/launcher_words.rb +0 -168
  725. data/lib/hecks/cli.rb +0 -133
  726. data/lib/hecks/hecks/agents.bluebook +0 -246
  727. data/lib/hecks/hecks/codebase.bluebook +0 -3209
  728. data/lib/hecks/hecks/custodian.bluebook +0 -1300
  729. data/lib/hecks/hecks/ledger.bluebook +0 -190
  730. data/lib/hecks/hecks/rehearsal.bluebook +0 -437
  731. data/lib/hecks/hecks/tooling.bluebook +0 -1234
  732. data/lib/hecks/hecks/translations/2-148748.bluebook +0 -2
  733. data/lib/hecks/hecks/translations/2-15a2e4.bluebook +0 -2
  734. data/lib/hecks/hecks/translations/2-1b447c.bluebook +0 -5
  735. data/lib/hecks/hecks/translations/2-240474.bluebook +0 -2
  736. data/lib/hecks/hecks/translations/2-44446d.bluebook +0 -2
  737. data/lib/hecks/hecks/translations/2-46ca26.bluebook +0 -2
  738. data/lib/hecks/hecks/translations/2-473eab.bluebook +0 -2
  739. data/lib/hecks/hecks/translations/2-75cc28.bluebook +0 -2
  740. data/lib/hecks/hecks/translations/2-781c07.bluebook +0 -2
  741. data/lib/hecks/hecks/translations/2-84c18b.bluebook +0 -2
  742. data/lib/hecks/hecks/translations/2-aa5fff.bluebook +0 -2
  743. data/lib/hecks/hecks/translations/2-bfdb48.bluebook +0 -2
  744. data/lib/hecks/hecks/translations/2-cd96d8.bluebook +0 -10
  745. data/lib/hecks/hecks/translations/2-d43f71.bluebook +0 -2
  746. data/lib/hecks/hecks/translations/2-eea577.bluebook +0 -2
  747. data/lib/hecks/hecks/translations/2-f53248.bluebook +0 -2
  748. data/lib/hecks/hecks/translations/2-fbb677.bluebook +0 -2
  749. data/lib/hecks/hecks/translations/2-ffdf12.bluebook +0 -6
  750. data/lib/hecks/quality_control/adapters/clearance_recorder.rb +0 -36
  751. data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +0 -56
  752. data/prebuilt/31cf81e12f16236ad26249be590cfea3799c9db67432e6a4ef54b801c355b6ae.marshal +0 -0
  753. data/prebuilt/68ecb2bd3abb1a221007db4f2b0375834c13aaccac8f2b99778e8517f11aa113.marshal +0 -0
  754. data/prebuilt/verdicts-0328c2403383837d780ad5ed81d1da351c56436b894cf9015b5d56b8f1f1bf10.json +0 -1
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hecks
4
+ module Runtime
5
+ # What an in-memory dispatch would have written and announced, collected while the dispatch
6
+ # runs. The command interpreter reports each save and each emitted event here when it runs
7
+ # in dry mode, so every command gets a plan from the same seam with no per-command code.
8
+ module DryRunPlan
9
+ KEY = :hecks_dry_run_plan
10
+
11
+ module_function
12
+
13
+ # Runs the block and returns the lines it would have produced.
14
+ #
15
+ # @yield the in-memory dispatch
16
+ # @return [Array<String>] one `would …` line per write or event, in order
17
+ def collect
18
+ previous = Thread.current[KEY]
19
+ Thread.current[KEY] = []
20
+ yield
21
+ Thread.current[KEY]
22
+ ensure
23
+ Thread.current[KEY] = previous
24
+ end
25
+
26
+ # Records one write the dispatch would make.
27
+ #
28
+ # @param aggregate [Bluebook::Aggregate] the aggregate the record belongs to
29
+ # @param instance [Runtime::Instance] the record the dispatch would write
30
+ # @return [void]
31
+ def write(aggregate, instance)
32
+ record("would write #{aggregate.hecks_name} #{instance.id}")
33
+ end
34
+
35
+ # Records one event the dispatch would announce.
36
+ #
37
+ # @param name [String] the event's name
38
+ # @return [void]
39
+ def emit(name)
40
+ record("would emit #{name}")
41
+ end
42
+
43
+ # Records each event a command announces.
44
+ #
45
+ # @param command [Bluebook::Command] the command the dispatch runs
46
+ # @return [void]
47
+ def emits(command)
48
+ command.emits.each { |name| emit(name) }
49
+ end
50
+
51
+ # Appends a line when a plan is being collected; otherwise does nothing.
52
+ #
53
+ # @param line [String]
54
+ # @return [void]
55
+ def record(line)
56
+ Thread.current[KEY]&.push(line)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -26,7 +26,6 @@ module Hecks
26
26
  # Walks `chain` one hop at a time and returns the located element (or `instance`
27
27
  # itself when `chain` is empty). `route`, when given, offers each hop's identity
28
28
  # before falling back to `args`.
29
- # rubocop:disable-next Metrics/ParameterLists -- the positional entry point EntityInterpreter and delegation call
30
29
  def locate_chain(root_aggregate, chain, instance, args, command_name, route = nil)
31
30
  container = instance
32
31
  owner = root_aggregate
@@ -37,7 +37,6 @@ module Hecks
37
37
  # Applies one declared mutation to an entity element, in place. `pre` is the
38
38
  # element as it stood before this command: every read goes through it, every
39
39
  # write lands on `element`.
40
- # rubocop:disable-next Metrics/ParameterLists -- the positional signature callers (and specs) wrap
41
40
  def apply_to_element(rules, aggregate, entity, element, mutation, args, pre = element)
42
41
  handler = OP_HANDLERS.fetch(mutation.op) do
43
42
  # Backstop: an unhandled op must refuse, not silently apply nothing.
@@ -19,7 +19,12 @@ module Hecks
19
19
  ctx.instance = step(:hydrate_parent) { parent_record(ctx) }
20
20
  end
21
21
 
22
+ # A validation records `hydrate_parent`'s refusal and goes on within the stage, so the
23
+ # parent may be missing here: then there is nothing to locate in, and the one refusal
24
+ # already recorded is the answer a dispatch raises.
22
25
  def step_locate_element(ctx)
26
+ return unless ctx.instance
27
+
23
28
  ctx.element = step(:locate_element) do
24
29
  EntityElement.locate_chain(ctx.aggregate, ctx.chain, ctx.instance, ctx.args, ctx.command_name, ctx.route)
25
30
  end
@@ -48,7 +48,6 @@ module Hecks
48
48
  # `element`/`view` are the entity piece itself, pre- and
49
49
  # post-mutation. `:chain` intentionally shadows Enumerable#chain —
50
50
  # every read is the struct field, never enumerable-combining.
51
- # rubocop:disable-next Lint/StructNewOverride
52
51
  Context = Struct.new(:domain, :aggregate, :entity, :entity_name, :command, :command_name,
53
52
  :args, :repository, :instance, :chain, :element, :view, :transition,
54
53
  :old_element, :result, :route, :plan, :persistence_outcome, :dry_run, :outbox_rows,
@@ -88,5 +88,31 @@ module Hecks
88
88
  # Names come from the language; resolving them here fails at load if one is undefined.
89
89
  # Each is a `Hecks::Refused`, and nothing else is, so rescuing either catches the same set.
90
90
  DOMAIN_REFUSALS = Hecks::Vocabulary.fetch("DomainRefusal").map { |name| const_get(name) }.freeze
91
+
92
+ # The errors that mean the code is wrong, not that the outside world said no: a name that
93
+ # does not resolve (`NameError`, and `NoMethodError` under it), a value of the wrong class
94
+ # (`TypeError`), a write to a frozen value (`FrozenError`), and code that would not load
95
+ # (`ScriptError`: `LoadError`, `NotImplementedError`, `SyntaxError`). An ask that meets one
96
+ # raises it instead of announcing its `refuses` event, so the defect is seen where it happens.
97
+ #
98
+ # `ArgumentError` is left out on purpose: adapters raise its subclasses to refuse input they
99
+ # were handed (`TenantProvisioner::Refused`, `Composer::Workspace::OutsideWorkspace`), and
100
+ # parsing outside data raises it (`Integer("x")`, `Date::Error`), so it is the world saying no
101
+ # as often as it is a wrong call.
102
+ PROGRAMMING_ERRORS = [NameError, TypeError, FrozenError, ScriptError].freeze
103
+
104
+ # @param error [Exception] the error an adapter raised
105
+ # @return [Boolean] whether `error` is a defect in the code rather than a refusal
106
+ def self.programming_error?(error) = PROGRAMMING_ERRORS.any? { |kind| error.is_a?(kind) }
107
+
108
+ # The refusal text of a failure an ask records: its class and message. An error raised with no
109
+ # message still names its class, so a refusal never arrives empty.
110
+ #
111
+ # @param error [Exception] the error an adapter raised
112
+ # @return [String] `"Class: message"`, never blank
113
+ def self.failure_reason(error)
114
+ message = error.message.to_s.strip
115
+ "#{error.class}: #{message.empty? ? "raised with no message" : message}"
116
+ end
91
117
  end
92
118
  end
@@ -19,7 +19,6 @@ module Hecks
19
19
  # `hydrate_with:` replaces the default hydration with a callable that takes the given
20
20
  # state and answers the hydrated one (defaults filled), for an adapter that can reuse
21
21
  # work across saves.
22
- # rubocop:disable-next Metrics/ParameterLists -- the public keyword constructor every caller spells out
23
22
  def initialize(aggregate:, id:, state: nil, args: nil, hydrate: true, hydrate_with: nil)
24
23
  @aggregate = aggregate
25
24
  @id = id
@@ -21,7 +21,6 @@ module Hecks
21
21
  # :entity, :port). Each checks its own parts in a fixed order, because
22
22
  # a malformed call's refusal depends on that order; `declaring` is
23
23
  # called exactly once, at that shape's point in the order below.
24
- # rubocop:disable-next Metrics/ParameterLists -- the public keyword entry point every dispatch calls
25
24
  def from_call(verb, to:, with:, flat:, receiver: :aggregate, entity_depth: 0, aggregate: nil, &declaring)
26
25
  call = Call.new(verb, to, with, flat, entity_depth, aggregate, declaring)
27
26
  case receiver
@@ -15,7 +15,7 @@ module Hecks
15
15
  kind, fqn = row.consumer.split(":", 2)
16
16
  home, name = fqn.split("::", 2)
17
17
  case kind
18
- when "policy" then run_policy(row, event, fqn, home, name)
18
+ when "policy" then refusal_reason(run_policy(row, event, fqn, home, name))
19
19
  when "saga" then run_saga(row, event, fqn, home, name)
20
20
  else
21
21
  raise WiringError, "outbox row #{row.delivery_id} has an unknown consumer kind #{kind.inspect}"
@@ -28,11 +28,19 @@ module Hecks
28
28
  @policies.react(event, row.domain, only: [policy, home], event_uid: row.event_uid)
29
29
  end
30
30
 
31
+ # The reason the domain refused a policy's reaction, nil when none was refused. A defect
32
+ # is not a refusal: it is warned where it happens and the row settles as before.
33
+ def refusal_reason(records)
34
+ refused = Array(records).find { |record| record[:delivered] == false && !record[:defect] }
35
+ refused && (refused[:reason].to_s.empty? ? "refused (no reason given)" : refused[:reason].to_s)
36
+ end
37
+
31
38
  def run_saga(row, event, fqn, home, name)
32
39
  process_manager = @registry.bluebook(home)&.process_managers&.find { |candidate| candidate.name == name } ||
33
40
  raise(WiringError,
34
41
  "outbox row #{row.delivery_id} names process_manager #{fqn}, which no bluebook declares")
35
42
  @sagas.advance(event, row.domain, only: process_manager)
43
+ nil
36
44
  end
37
45
  end
38
46
  end
@@ -31,6 +31,26 @@ module Hecks
31
31
 
32
32
  def attached? = !@policies.nil?
33
33
 
34
+ # Runs one policy's reaction to `event`, as a row's delivery runs it: its outcome is
35
+ # recorded on the registry's reaction log, a refusal included, and nothing is raised.
36
+ #
37
+ # @param event [Runtime::Event] the event the policy reacts to
38
+ # @param policy [Bluebook::Policy] the policy to run
39
+ # @param home [String] the bluebook the policy is declared in
40
+ # @param domain [String] the domain the event came from
41
+ # @param event_uid [String] the identity the reaction log records for the event
42
+ # @return [void]
43
+ def react_policy(event, policy:, home:, domain:, event_uid:)
44
+ @policies.react(event, domain, only: [policy, home], event_uid: event_uid)
45
+ end
46
+
47
+ # Answers the policies `event` triggers in `domain`, as `[policy, home]` pairs.
48
+ #
49
+ # @param event [Runtime::Event] the event to react to
50
+ # @param domain [String] the domain the event came from
51
+ # @return [Array(Bluebook::Policy, String)]
52
+ def policies_for(event, domain) = @policies.policies_for(event, domain)
53
+
34
54
  # Forgets every delivery the relay recorded, as a fresh boot starts with none.
35
55
  #
36
56
  # @return [void]
@@ -82,11 +102,12 @@ module Hecks
82
102
  private
83
103
 
84
104
  def settle_delivery(row, repository)
85
- run_consumer(row)
86
- repository.outbox_settle(row.id, status: "delivered")
87
- row.status = "delivered"
105
+ reason = run_consumer(row)
106
+ row.status = reason ? "refused" : "delivered"
107
+ repository.outbox_settle(row.id, status: row.status, error: reason)
108
+ row.error = reason
88
109
  true
89
- rescue StandardError => e
110
+ rescue StandardError, ScriptError => e
90
111
  settle_failed(row, repository, e)
91
112
  false
92
113
  end
@@ -48,7 +48,9 @@ module Hecks
48
48
  def ask_target(row)
49
49
  kind, fqn = row.consumer.split(":", 2)
50
50
  home, name = fqn.split("::", 2)
51
- policy = kind == "policy" && @registry.bluebook(home)&.policies&.find { |candidate| candidate.name == name }
51
+ return nil unless kind == "policy"
52
+
53
+ policy = @registry.bluebook(home)&.policies&.find { |candidate| candidate.name == name }
52
54
  return nil unless policy&.asks?
53
55
 
54
56
  aggregate_and_port, operation = policy.trigger_command.split(".", 2)
@@ -10,8 +10,11 @@ module Hecks
10
10
  # A durable outbox (ADR 0053): one row per (event, consumer), written in
11
11
  # the same transaction as the aggregate save so a reaction is never lost.
12
12
  module Outbox
13
- # pending -> claimed -> delivered | failed
14
- STATUSES = %w[pending claimed delivered failed].freeze
13
+ # pending -> claimed -> delivered | failed | refused. A reaction the domain refused (its
14
+ # trigger was declined, its `with:` read a key the event lacked, the cascade was too deep)
15
+ # is settled `refused` with the reason in `error`: it ran and said no, which is neither
16
+ # delivery nor a defect, and a trace reads it back.
17
+ STATUSES = %w[pending claimed delivered failed refused].freeze
15
18
 
16
19
  # How long a row stays claimed before it counts as stalled: a claim that old was left by a
17
20
  # process that is gone, where a younger one is a reaction running in another process. Ten
@@ -26,6 +29,7 @@ module Hecks
26
29
  def claimed? = status == "claimed"
27
30
  def delivered? = status == "delivered"
28
31
  def failed? = status == "failed"
32
+ def refused? = status == "refused"
29
33
 
30
34
  # A claimed row is stalled when its age is unknown or past `STALLED_AFTER`; a younger one is
31
35
  # a reaction still running.
@@ -7,6 +7,9 @@ module Hecks
7
7
  # A `for_each` policy: asks a query which rows the event concerns, and fires the trigger
8
8
  # once per row through the {RowSweep} a bulk run shares. Mixed into {PolicyInterpreter}.
9
9
  module FanOut
10
+ # The bare scalar types a `for_each` query may declare as an argument.
11
+ SCALAR_ARGUMENT_TYPES = %w[String Integer Float].freeze
12
+
10
13
  private
11
14
 
12
15
  # Runs the `for_each` query against the event payload and fires the trigger once
@@ -45,9 +48,22 @@ module Hecks
45
48
  def for_each_query_args(query, event)
46
49
  args = event.payload.transform_keys(&:to_sym)
47
50
  construct = query && emitting_construct(event)
48
- return args unless construct
51
+ lent_attributes(query, construct, args).each { |attribute| args[attribute.name] = event.id } if construct
52
+ unwrap_scalar_arguments(query, args)
53
+ end
54
+
55
+ # A bare-scalar query argument takes the one value its single-field value object carries:
56
+ # the payload hands over the object, but the query declares the scalar, and a query's
57
+ # argument is shape-checked against its declared type.
58
+ def unwrap_scalar_arguments(query, args)
59
+ return args unless query
49
60
 
50
- lent_attributes(query, construct, args).each { |attribute| args[attribute.name] = event.id }
61
+ query.attributes.each do |attribute|
62
+ value = args[attribute.name]
63
+ next unless value.is_a?(Hash) && value.size == 1 && SCALAR_ARGUMENT_TYPES.include?(attribute.type.to_s)
64
+
65
+ args[attribute.name] = value.values.first
66
+ end
51
67
  args
52
68
  end
53
69
 
@@ -36,23 +36,27 @@ module Hecks
36
36
  # @param only [Array(Bluebook::Policy, String), nil] one `[policy, home_domain]`
37
37
  # pair to run exactly (the outbox relay's consumer), instead of scanning every
38
38
  # loaded bluebook for candidates
39
- # @param event_uid [String, nil] the outbox uid every consumer of this event shares, when the
40
- # event was rebuilt from an outbox row; otherwise the event object itself is the identity
41
- # @return [void]
39
+ # @param event_uid [String, nil] the outbox uid every consumer of this event shares; the
40
+ # reaction identity only when the event has no id
41
+ # @return [Array<Hash>] the reactions recorded, one per delivery attempted
42
42
  def react(event, domain, only: nil, event_uid: nil)
43
43
  selected = only ? [only] : policies_for(event, domain)
44
- selected.each do |policy, home_domain|
44
+ selected.flat_map do |policy, home_domain|
45
45
  result = deliver(policy, event, home_domain)
46
- next if result.nil?
47
-
48
- # A for_each policy answers an array; Array(...) would explode a record Hash.
49
- identity = event_uid || event.object_id
50
- (result.is_a?(Array) ? result : [result]).each { |record| @registry.log_reaction(record, event: identity) }
46
+ # A for_each policy answers an array; Array(...) would explode a record Hash. The identity
47
+ # is the event's own id: a later run recognises the reaction, whichever path ran it.
48
+ records = result.is_a?(Array) ? result : [result].compact
49
+ records.each { |record| @registry.log_reaction(record, event: reaction_identity(event, event_uid)) }
51
50
  end
52
51
  end
53
52
 
54
53
  private
55
54
 
55
+ # The identity a reaction is logged under: the event's own id, so a later run can recognise
56
+ # the reaction whichever path delivered the event; the outbox uid or the object when the event
57
+ # has no id.
58
+ def reaction_identity(event, event_uid) = event.id || event_uid || event.object_id
59
+
56
60
  # Scans every loaded bluebook, since a policy commonly lives in a different
57
61
  # domain than the event it reacts to. Returns [policy, home_domain] pairs: the
58
62
  # home domain is the fallback for a bare trigger or for_each route. Order is the
@@ -69,6 +73,10 @@ module Hecks
69
73
  end
70
74
  end
71
75
 
76
+ # Answers the policies `event` triggers in `domain`, as `[policy, home_domain]` pairs, in
77
+ # the order a delivery tries them. The event pump reads this, then runs one of them at a time.
78
+ public :policies_for
79
+
72
80
  # Evaluated against the event payload alone (a policy has no aggregate state).
73
81
  # Not rescued here: an EvaluationError must reach `deliver`'s defect rescue, not
74
82
  # read as a policy that declined to fire.
@@ -86,9 +86,11 @@ module Hecks
86
86
  ctx.result = step(:emit) { ctx.operation.outbound? ? ask(ctx) : emit(ctx) }
87
87
  end
88
88
 
89
- # The domain calling out. Any failure, however wide (timeout, bad credential, missing
90
- # adapter), becomes the `refuses` event rather than a raise, so a policy can react to it.
91
- # The adapter is found by port name across the adapters this boot loaded.
89
+ # The domain calling out. A failure of the outside world (timeout, bad credential, missing
90
+ # adapter, the adapter's own refusal) becomes the `refuses` event rather than a raise, so a
91
+ # policy can react to it. A defect in the code (`Runtime::PROGRAMMING_ERRORS`) is raised:
92
+ # read as a refusal, it hides its cause behind a domain event. The adapter is found by port
93
+ # name across the adapters this boot loaded.
92
94
  #
93
95
  # Unlike an inbound operation, an ask is handed the record's held state: the adapter
94
96
  # needs data that lives on the record, and an event payload carries only arguments.
@@ -96,10 +98,21 @@ module Hecks
96
98
  def ask(ctx)
97
99
  operation = ctx.operation
98
100
  announce(ctx, operation.answers, ctx.args.merge(spread(adapter_answer(ctx))))
101
+ rescue Interrupt
102
+ refuse_ask(ctx, operation, interrupted(ctx))
99
103
  rescue StandardError => e
100
- announce(ctx, operation.refuses, ctx.args.merge(refusal: { value: "#{e.class}: #{e.message}" }))
104
+ raise if Runtime.programming_error?(e)
105
+
106
+ refuse_ask(ctx, operation, Runtime.failure_reason(e))
101
107
  end
102
108
 
109
+ # Announces an ask's refusal with the text it failed with.
110
+ def refuse_ask(ctx, operation, text) = announce(ctx, operation.refuses, ctx.args.merge(refusal: { value: text }))
111
+
112
+ # The refusal an interrupted ask records: the operation it was in and that it was not
113
+ # finished, so the run ends faulted with the stage it reached, not open with no record.
114
+ def interrupted(ctx) = "interrupted during #{ctx.operation_hecks_name}: the run stopped before it finished"
115
+
103
116
  def adapter_answer(ctx)
104
117
  payload = held_state(ctx).merge(materialise(ctx.args))
105
118
  adapter = adapter_for(ctx)
@@ -117,11 +130,12 @@ module Hecks
117
130
  end
118
131
 
119
132
  # The record, if there is one. A missing record is not an error here: the ask still
120
- # goes with only its arguments, since `resolve_references` already checked existence.
133
+ # goes with only its arguments, since `resolve_references` already checked existence. A
134
+ # defect in reading the state is raised, as an adapter's is.
121
135
  def held_state(ctx)
122
136
  ctx.instance ? Value.materialize(ctx.state) : {}
123
- rescue StandardError
124
- {}
137
+ rescue StandardError => e
138
+ Runtime.programming_error?(e) ? raise : {}
125
139
  end
126
140
 
127
141
  # The port this operation belongs to, found through the aggregate rather than
@@ -9,10 +9,11 @@ module Hecks
9
9
  module Arguments
10
10
  private
11
11
 
12
- # Coerces with `boundary: false`: a query's declared argument types are not a
13
- # runtime shape check. The exception is a nil for a required value-object-typed
14
- # argument, which must refuse as a command argument does; passing it through
15
- # would run an unfiltered query (a Ruby/Rust divergence).
12
+ # Coerces a query's arguments exactly as a command's are: a bare scalar of the wrong
13
+ # type refuses with TypeMismatch before any store is read, and so does a nil for a
14
+ # required value-object-typed argument, which would otherwise run an unfiltered query
15
+ # (a Ruby/Rust divergence). The Postgres query builder checks the same shapes
16
+ # (`Value.check_query_arguments!`), so both engines refuse the same way.
16
17
  #
17
18
  # It does not use `Value::Coercion#nil_argument`, which builds a null value object
18
19
  # from field defaults and only refuses when a field has none. `null_vo_argument!`
@@ -29,7 +30,7 @@ module Hecks
29
30
  def coerce_argument(aggregate, attribute, value)
30
31
  return null_vo_argument!(aggregate, attribute) if checked_vo?(aggregate, attribute, value)
31
32
 
32
- Value.for_attribute(aggregate, attribute, value, boundary: false)
33
+ Value.for_attribute(aggregate, attribute, value)
33
34
  end
34
35
 
35
36
  def checked_vo?(aggregate, attribute, value)
@@ -93,7 +93,6 @@ module Hecks
93
93
  # @raise [Runtime::UnknownVerb] if `verb` does not resolve (only when `explicit`)
94
94
  # @raise [Runtime::TypeMismatch] if no receiver identity resolves for an explicit target
95
95
  # @raise [Runtime::UnknownArgument] if an explicit projection has an undeclared fact
96
- # rubocop:disable-next Metrics/ParameterLists -- the keyword entry point both interpreters call
97
96
  def build(registry:, verb:, projected:, explicit:, passthrough: [], source_receiver: nil)
98
97
  args = projected.transform_keys(&:to_sym)
99
98
  return forwarded(registry, verb, args, source_receiver) unless explicit
@@ -55,6 +55,15 @@ module Hecks
55
55
  render_with(template(refusal, site), specs, arguments)
56
56
  end
57
57
 
58
+ # Appends the command that creates an aggregate's records, when the bluebook declares one.
59
+ # The message is returned unchanged for an aggregate that declares no creator.
60
+ def with_creator_hint(message, aggregate)
61
+ creator = aggregate.created_by
62
+ return message if creator.nil? || creator.to_s.empty?
63
+
64
+ "#{message}: run #{creator} first"
65
+ end
66
+
58
67
  def refuse_wrong_arguments!(refusal, site, declared, offered)
59
68
  missing = declared - offered
60
69
  extra = offered - declared
@@ -84,8 +93,10 @@ module Hecks
84
93
  items.empty? ? spec.fetch("when_empty") : items.join(spec.fetch("separator"))
85
94
  end
86
95
 
96
+ # The block form inserts each value as written: a replacement string would have `gsub` read
97
+ # its `\\`, `\0` and `\&` as escapes, so a quoted value's own backslash would collapse.
87
98
  def substitute(template, values)
88
- values.reduce(template) { |text, (key, value)| text.gsub("{#{key}}", value.to_s) }
99
+ values.reduce(template) { |text, (key, value)| text.gsub("{#{key}}") { value.to_s } }
89
100
  end
90
101
 
91
102
  def template(refusal, site)
@@ -5,16 +5,12 @@ module Hecks
5
5
  module ContextMaps
6
6
  # Boot-time-only, single-threaded: it runs from Hecks.collect while a `.contextmap` file is
7
7
  # being Kernel.loaded, before the registry reaches a live, multi-threaded caller.
8
- # rubocop:disable Hecks/ThreadSharedIvarMutation
9
8
  # Registers a declared context map under its system's name, a later one of the same name
10
9
  # replacing the earlier (a map is one declaration, not a layered overlay).
11
10
  #
12
11
  # @param item [Bluebook::ContextMap] the declared map
13
12
  # @return [Bluebook::ContextMap] the map
14
- def add_context_map(item)
15
- @declared.context_maps[item.name] = item
16
- end
17
- # rubocop:enable Hecks/ThreadSharedIvarMutation
13
+ def add_context_map(item) = @declared.store(:context_maps, item.name, item)
18
14
 
19
15
  # Finds a system's declared context map by name.
20
16
  #
@@ -3,16 +3,46 @@ module Hecks
3
3
  class Registry
4
4
  # What a boot gathers while the `.bluebook`, `.hecksagon`, `.world` and `.contextmap` files
5
5
  # load: the bluebooks and their builders, the wiring, ports, adapters, worlds, translations,
6
- # context maps, the eras the boot gate resolved, and the privacy markings still to be
7
- # dispatched.
6
+ # context maps, the eras the boot gate resolved, the domains whose booted shape no era holds
7
+ # yet, the domains whose unheld shape one recorded move leads to, and the privacy markings
8
+ # still to be dispatched.
8
9
  Declarations = Struct.new(:bluebooks, :bluebook_sources, :hecksagons, :bounded_bluebooks, :ports,
9
10
  :adapters, :worlds, :translations, :bluebook_builders,
10
11
  :pending_privacy_markings, :resolved_eras, :superseded_eras,
11
- :context_maps) do
12
+ :context_maps, :unminted_eras, :behind_eras) do
12
13
  # @return [Declarations] every collection empty
13
14
  def self.empty
14
- new({}, {}, {}, {}, {}, {}, {}, [], {}, [], {}, {}, {})
15
+ new({}, {}, {}, {}, {}, {}, {}, [], {}, [], {}, {}, {}, {}, {})
15
16
  end
17
+
18
+ # Stores a value under a key in a keyed collection, and answers the value.
19
+ #
20
+ # @param collection [Symbol] the member holding the keyed collection
21
+ # @param key [Object] the key
22
+ # @param value [Object] the value to store
23
+ # @return [Object] `value`
24
+ def store(collection, key, value) = self[collection][key] = value
25
+
26
+ # Removes a key from a keyed collection.
27
+ #
28
+ # @param collection [Symbol] the member holding the keyed collection
29
+ # @param key [Object] the key to remove
30
+ # @return [Object, nil] the value removed, or nil when the key was absent
31
+ def remove(collection, key) = self[collection].delete(key)
32
+
33
+ # Appends a value to a list collection.
34
+ #
35
+ # @param collection [Symbol] the member holding the list
36
+ # @param value [Object] the value to append
37
+ # @return [Array] the list, `value` last
38
+ def append(collection, value) = self[collection] << value
39
+
40
+ # Records that a `.bluebook` file contributed to a bluebook name.
41
+ #
42
+ # @param name [String] the bluebook name
43
+ # @param path [String] the file that declared it
44
+ # @return [Array<String>] every path recorded for that name, `path` last
45
+ def record_source(name, path) = (bluebook_sources[name] ||= []) << path
16
46
  end
17
47
  end
18
48
  end
@@ -44,18 +44,32 @@ module Hecks
44
44
  def refuse_unwired_attachments!(hecksagon)
45
45
  hecksagon.attachments.each do |attachment|
46
46
  next if hecksagon(attachment.declaration_name)
47
+ next if contextmap_declares?(hecksagon, attachment)
47
48
 
48
49
  raise WiringError, unwired_attachment_message(hecksagon, attachment)
49
50
  end
50
51
  end
51
52
 
53
+ # A gem bluebook that the system's `.contextmap` names as a context needs no sibling
54
+ # hecksagon: its wiring is the attach itself. A vendored package still needs one, since
55
+ # its persistence and `translates` ACL can only be written there.
56
+ #
57
+ # @return [Boolean] true if the system's context map names the attached gem bluebook
58
+ def contextmap_declares?(hecksagon, attachment)
59
+ return false if attachment.vendor?
60
+
61
+ map = context_map(hecksagon.domain)
62
+ !map.nil? && map.context_names.include?(attachment.declaration_name.to_s)
63
+ end
64
+
52
65
  def unwired_attachment_message(hecksagon, attachment)
53
66
  declaration_name = attachment.declaration_name
54
67
  what = attachment.vendor? ? "vendored bluebook #{attachment.name.inspect}" : declaration_name.inspect
55
68
  "#{hecksagon.domain} attaches #{what} " \
56
69
  "(bounded context #{declaration_name}) but never declared " \
57
70
  "Hecks.hecksagon #{declaration_name.inspect} — put that sibling " \
58
- "(and any `translates` ACL) in context_map.hecksagon; " \
71
+ "(and any `translates` ACL) in context_map.hecksagon, or name the context in " \
72
+ "#{hecksagon.domain}'s `.contextmap` (gem bluebooks only); " \
59
73
  "same-name blocks merge, order-independent."
60
74
  end
61
75
 
@@ -22,6 +22,16 @@ module Hecks
22
22
  def clear
23
23
  to_a.each(&:clear)
24
24
  end
25
+
26
+ # Logs one reaction's outcome, and the event instance it answered when known.
27
+ #
28
+ # @param record [Hash{Symbol => Object}] the reaction's outcome
29
+ # @param event [String, Integer, nil] the event instance, or nil when not known
30
+ # @return [void]
31
+ def log_reaction(record, event)
32
+ reaction_log << record
33
+ reaction_events[record] = event if event
34
+ end
25
35
  end
26
36
  end
27
37
  end
@@ -8,9 +8,31 @@ module Hecks
8
8
  AGGREGATE_PLACEHOLDER = /\{(name|storage_name)\}/
9
9
 
10
10
  # The default database only reaches a persistence bind whose adapter declares a
11
- # `database` field; a `database` the bluebook's own settings name always wins.
11
+ # `database` field; a `database` the bluebook's own settings name always wins. Every
12
+ # value the adapter declares as a secret is held by `Secrets` on the way, so no text the
13
+ # launcher prints can carry it.
12
14
  def binding_settings(domain, verb, adapter)
13
15
  declared = world(domain)&.for_binding(verb, adapter) || {}
16
+ settings = with_world_mint_names(domain, verb, adapter, with_default_database(domain, verb, adapter, declared))
17
+ Secrets.register_settings(@declared.adapters[adapter.to_s], settings)
18
+ settings
19
+ end
20
+
21
+ # The commands a world names at its top level (`minting commands: [...]`) join the names a
22
+ # persistence block gives, for an adapter that declares `mints_era`: a domain whose binding
23
+ # lives in uncommitted local files still has a committed place to say them.
24
+ def with_world_mint_names(domain, verb, adapter, settings)
25
+ return settings unless mint_names_apply?(verb, adapter)
26
+
27
+ named = Array(world(domain)&.for_verb("minting")&.fetch(:commands, nil)).map(&:to_s)
28
+ named.empty? ? settings : settings.merge(mints_era: (Ports::Persistence::MintDoor.names(settings) + named).uniq)
29
+ end
30
+
31
+ def mint_names_apply?(verb, adapter)
32
+ verb.to_s == Ports::Persistence::VERB && @declared.adapters[adapter.to_s]&.declares?(:mints_era)
33
+ end
34
+
35
+ def with_default_database(domain, verb, adapter, declared)
14
36
  database = default_database_for(domain)
15
37
  return declared unless database && default_database_applies?(verb, adapter)
16
38
 
@@ -28,7 +50,7 @@ module Hecks
28
50
 
29
51
  verify_default_adapter_named!(declared.domain, name)
30
52
  end
31
- self
53
+ apply_world_names!
32
54
  end
33
55
 
34
56
  # The defaults an adapter's `.adapter` declares for its fields, with each `{name}` or