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
@@ -4,7 +4,6 @@ module Hecks
4
4
  class Plan
5
5
  # One append command: the verb, and the value-object-field -> argument map.
6
6
  # `:map` shadows Enumerable#map on purpose; spec/plan_spec.rb asserts on it.
7
- # rubocop:disable-next Lint/StructNewOverride
8
7
  Append = Struct.new(:verb, :map, keyword_init: true)
9
8
 
10
9
  # One setting command. `targets` is target -> argument ; Lifecycle sets two
@@ -12,7 +11,7 @@ module Hecks
12
11
  Setter = Struct.new(:verb, :targets, keyword_init: true)
13
12
 
14
13
  Category = Struct.new(:name, :declare, :parent, :parent_key, :fields,
15
- :appends, :alternates, :setters, :sealers, :references,
14
+ :appends, :alternates, :setters, :sealers, :references, :lists,
16
15
  :identity_paths, :entity_owned,
17
16
  keyword_init: true) do
18
17
  # Every verb this category declares, in declaration order; a verb missing
@@ -35,6 +34,15 @@ module Hecks
35
34
  Array(references[verb.to_s]).include?(argument.to_s)
36
35
  end
37
36
 
37
+ # Whether `argument` on `verb` is a list, so each of its items is one value.
38
+ #
39
+ # @param verb [String] the command name declaring `argument`
40
+ # @param argument [String] the argument name to check
41
+ # @return [Boolean] whether `argument` on `verb` is declared as a list
42
+ def list?(verb, argument)
43
+ Array(lists&.dig(verb.to_s)).include?(argument.to_s)
44
+ end
45
+
38
46
  # Whether this category has no parent — the root of the containment tree.
39
47
  def root? = parent.nil?
40
48
  end
@@ -15,6 +15,15 @@ module Hecks
15
15
  end
16
16
  end
17
17
 
18
+ # Which arguments of which verbs are lists, read straight off the IR, so a list
19
+ # argument's items are each wrapped as a value rather than the list as one.
20
+ def lists_in(commands)
21
+ commands.each_with_object({}) do |command, found|
22
+ named = command.attributes.select(&:list?).map { |attribute| attribute.name.to_s }
23
+ found[command.hecks_name] = named unless named.empty?
24
+ end
25
+ end
26
+
18
27
  # Every reference argument is dropped, not just the parent link:
19
28
  # a reference is not a field.
20
29
  def declared_fields(declare)
@@ -126,7 +126,8 @@ module Hecks
126
126
  sealers: sealers_in(rest),
127
127
  # Every command, not `rest` — the creating command carries the parent
128
128
  # link, which is the most common reference of all.
129
- references: references_in(aggregate.commands)
129
+ references: references_in(aggregate.commands),
130
+ lists: lists_in(aggregate.commands)
130
131
  }
131
132
  end
132
133
 
@@ -26,7 +26,9 @@ module Hecks
26
26
  description: text(row[:description]),
27
27
  identified_by: identity_paths(row),
28
28
  attributes: Array(row[:attributes]).map { |field| attribute(field, id) }
29
- }.merge(aggregate_rules(row)).merge(lifecycle: lifecycle(row), provenance: provenance(row))
29
+ }.merge(aggregate_rules(row)).merge(lifecycle: lifecycle(row), provenance: provenance(row),
30
+ formerly_known_as: row[:formerly_known_as],
31
+ created_by: row[:created_by])
30
32
  end
31
33
 
32
34
  # The rules and projected fields an aggregate row holds.
@@ -65,10 +65,17 @@ module Hecks
65
65
  end
66
66
  end
67
67
 
68
+ def memberships(row)
69
+ Array(row[:modules]).map do |part|
70
+ { name: text(part[:name]).to_s, vision: text(part[:vision]).to_s, aggregate: text(part[:aggregate]).to_s }
71
+ end
72
+ end
73
+
68
74
  # Every cell of the meta-domain is a single-field value object, so a row
69
75
  # arrives holding Values rather than Strings.
70
76
  def text(cell)
71
77
  return nil if cell.nil?
78
+ return cell.map { |held| text(held) } if cell.is_a?(Array)
72
79
  return cell.to_h.values.first if cell.respond_to?(:to_h) && !cell.is_a?(String)
73
80
 
74
81
  cell
@@ -66,11 +66,16 @@ module Hecks
66
66
  classification: text(@declaration[:classification]),
67
67
  formerly_known_as: text(@declaration[:formerly_known_as]),
68
68
  namespace: text(@declaration[:namespace]),
69
- attaches_to: attached_contexts(@declaration),
70
- provides: provisions(@declaration)
69
+ **row_fields(@declaration)
71
70
  }
72
71
  end
73
72
 
73
+ # The row-valued fields of the bluebook: its attachments, provisions and module memberships.
74
+ def row_fields(declaration)
75
+ { attaches_to: attached_contexts(declaration), provides: provisions(declaration),
76
+ modules: memberships(declaration) }
77
+ end
78
+
74
79
  def policy(row) = declaration("Policy", row)
75
80
 
76
81
  # A process manager's handlers live inline on its own dispatched state,
@@ -60,6 +60,9 @@ module Hecks
60
60
  # `idempotent` is held as text like `expect_undelivered`, and emitted as a boolean.
61
61
  def idempotent?(row) = text(row[:idempotent]).to_s == "true"
62
62
 
63
+ # `mints_era` is held as text like `idempotent`, and emitted as a boolean.
64
+ def mints_era?(row) = text(row[:mints_era]).to_s == "true"
65
+
63
66
  # Kept as raw text, not decoded: this feeds `Assembly::Marks#where_clause`,
64
67
  # which decodes it via `read` — decoding here first would strip a kwarg
65
68
  # reference's colon, indistinguishable after from a same-named literal.
@@ -47,7 +47,7 @@ module Hecks
47
47
  # @param touch [Boolean] whether to mark it as used (a shipped file is read-only)
48
48
  # @return [Hash, nil] the table
49
49
  def load_table(path, touch: false)
50
- table = Marshal.load(File.binread(path)) # rubocop:disable Security/MarshalLoad -- own cache or the gem's own file, never external input
50
+ table = Marshal.load(File.binread(path))
51
51
  FileUtils.touch(path) if touch
52
52
  table
53
53
  end
@@ -23,6 +23,33 @@ module Hecks
23
23
  bluebook.aggregates.filter_map { |aggregate| large_aggregate_finding(aggregate, limit) }
24
24
  end
25
25
 
26
+ # An aggregate with no commands has nothing that changes it and no command surface for a
27
+ # diagram to draw from. Reads are queries; a change needs a command.
28
+ #
29
+ # @param bluebook [Bluebook::Declaration] the assembled bluebook to check
30
+ # @return [Array<Finding>] one :no_command_surface error per aggregate with no commands
31
+ def no_command_surface_findings(bluebook)
32
+ unacknowledged_commandless(bluebook).map do |aggregate|
33
+ Finding.new(kind: :no_command_surface, severity: :error, subject: aggregate.hecks_name,
34
+ message: "declares no commands, so nothing changes it and no command surface can " \
35
+ "be drawn — give it a command")
36
+ end
37
+ end
38
+
39
+ # @return [Array<Bluebook::Aggregate>] the aggregates with no commands that do not acknowledge it
40
+ def unacknowledged_commandless(bluebook)
41
+ commandless = bluebook.aggregates.select { |aggregate| aggregate.commands.empty? }
42
+ commandless.reject { |aggregate| Acknowledgements.held?(aggregate, :no_command_surface) }
43
+ end
44
+
45
+ # Every finding about an aggregate's size and its command surface.
46
+ #
47
+ # @param bluebook [Bluebook::Declaration] the assembled bluebook to check
48
+ # @return [Array<Finding>] the size and command-surface findings, in that order
49
+ def aggregate_findings(bluebook)
50
+ [*large_aggregate_findings(bluebook), *no_command_surface_findings(bluebook)]
51
+ end
52
+
26
53
  # @return [Finding, nil] the warning for an aggregate heavier than `limit`
27
54
  def large_aggregate_finding(aggregate, limit)
28
55
  weight = aggregate_weight(aggregate)
@@ -36,6 +36,31 @@ module Hecks
36
36
  end
37
37
  end
38
38
 
39
+ # Flags a query the hecksagon binds to a port's adapter. Only the Ruby runtime asks an
40
+ # adapter for an answer; a Rust host would find nothing behind the query.
41
+ #
42
+ # @param bluebook [Bluebook::Declaration] the assembled bluebook, its hecksagon's ports
43
+ # attached
44
+ # @param rust_target [Boolean] whether this domain has a real Rust target; a domain without
45
+ # one is not checked, since nothing but the Ruby runtime serves it
46
+ # @return [Array<Finding>] one :external_query error per bound query, none off a Rust target
47
+ def external_query_findings(bluebook, rust_target: false)
48
+ return [] unless rust_target
49
+
50
+ bluebook.aggregates.flat_map do |aggregate|
51
+ aggregate.ports.flat_map do |port|
52
+ port.answered_queries.map { |answer| external_query_finding(aggregate, port, answer) }
53
+ end
54
+ end
55
+ end
56
+
57
+ def external_query_finding(aggregate, port, answer)
58
+ Finding.new(kind: :external_query, severity: :error,
59
+ subject: "#{aggregate.hecks_name}.#{answer.name}",
60
+ message: "the #{port.name} port's adapter answers this query, and only the Ruby " \
61
+ "runtime asks an adapter — the Rust host cannot serve it")
62
+ end
63
+
39
64
  private
40
65
 
41
66
  def port_trigger_finding(bluebook, policy)
@@ -0,0 +1,114 @@
1
+ require_relative "../ask_resolution"
2
+ require_relative "reaction_cycles"
3
+ require_relative "reaction_walk"
4
+
5
+ module Hecks
6
+ module Bluebook
7
+ module ModelCheck
8
+ # The reaction graph of one bluebook: which verb emits which event, which policy reacts to
9
+ # it, and which verb that policy dispatches in turn, an `ask` resolved through the
10
+ # hecksagon to its port operation. `from` walks it to the longest chain a verb's events start.
11
+ #
12
+ # A policy already on the path is not followed again: a loop is cut where it closes, so a
13
+ # chain counts each policy once; `cycles` reports the loops themselves. A cross-domain
14
+ # (`across`) policy ends a chain, since the other domain's policies are not in this
15
+ # bluebook. A `where` is not evaluated, so a chain is the deepest one the declarations
16
+ # allow, not one a run is certain to take.
17
+ class ReactionChains
18
+ # One reaction step: the policy that fires and the verb it dispatches.
19
+ Step = Struct.new(:policy, :verb) do
20
+ # @return [String] the policy's name
21
+ def policy_name = policy.name
22
+ end
23
+
24
+ # @param bluebook [Bluebook::Declaration] the assembled bluebook, its hecksagon attached
25
+ def initialize(bluebook)
26
+ @bluebook = bluebook
27
+ @emitted = emitted_by_verb
28
+ @policies = bluebook.policies.reject(&:target_domain)
29
+ @dispatch = @policies.to_h { |policy| [policy, dispatched_by(policy)] }
30
+ @successors = @policies.to_h { |policy| [policy, @dispatch[policy] ? reacting_to(@dispatch[policy]) : []] }
31
+ end
32
+
33
+ # @return [Array<Array<String>>] each verb that emits an event, as split_verb parses it
34
+ def verbs = @emitted.keys
35
+
36
+ # @return [Set<Array>] the verbs some policy dispatches, which a longer chain already covers
37
+ def reaction_targets = @dispatch.values.compact.to_set
38
+
39
+ # @param verb [Array<String>] a verb, as `Naming.split_verb` parses it
40
+ # @return [Array<Step>] the longest chain of reactions the verb's events start, in order
41
+ def from(verb) = walk.longest(reacting_to(verb))
42
+
43
+ # @return [Boolean] whether the last `from` stopped searching, so its chain is a lower bound
44
+ def capped? = walk.capped?
45
+
46
+ # @return [Array<Array>] each loop in the graph, as the policies that reach one another
47
+ def cycles = @cycles ||= ReactionCycles.new(@policies, @successors).groups
48
+
49
+ # @param policy [Object] a policy of this bluebook
50
+ # @return [Step] the policy with the verb it dispatches
51
+ def step(policy) = Step.new(policy, @dispatch[policy])
52
+
53
+ # @param policy [Object] a policy of this bluebook
54
+ # @return [Array] the policies the verb it dispatches starts
55
+ def successors(policy) = @successors.fetch(policy)
56
+
57
+ private
58
+
59
+ def walk = @walk ||= ReactionWalk.new(self, cycles.flatten)
60
+
61
+ # Policies that react to an event the verb emits.
62
+ def reacting_to(verb)
63
+ events = @emitted.fetch(verb, [])
64
+ @policies.select { |policy| events.any? { |aggregate, event| hears?(policy, aggregate, event) } }
65
+ end
66
+
67
+ def hears?(policy, aggregate, event)
68
+ return false unless policy.event_name == event
69
+
70
+ qualifier = policy.event_qualifier
71
+ qualifier.nil? || Naming.demodulise(qualifier) == aggregate
72
+ end
73
+
74
+ def dispatched_by(policy)
75
+ verb = policy.asks? ? asked_verb(policy) : "#{@bluebook.name}::#{policy.trigger_command}"
76
+ Naming.split_verb(verb) if verb
77
+ end
78
+
79
+ # The port operation an `ask` resolves to, spelled as a trigger names it, or nil.
80
+ def asked_verb(policy)
81
+ outcome = AskResolution.call(@bluebook, policy)
82
+ "#{@bluebook.name}::#{outcome.verb}" if outcome.resolved?
83
+ end
84
+
85
+ # Each verb the bluebook declares to the `[aggregate, event]` pairs it announces.
86
+ def emitted_by_verb
87
+ @bluebook.aggregates.each_with_object({}) do |aggregate, held|
88
+ commands_of(aggregate).each { |verb, events| held[verb] = events.map { |event| [aggregate.hecks_name, event] } }
89
+ end
90
+ end
91
+
92
+ def commands_of(aggregate)
93
+ prefix = "#{@bluebook.name}::#{aggregate.hecks_name}"
94
+ [*aggregate.commands.map { |command| ["#{prefix}.#{command.hecks_name}", command.emits] },
95
+ *aggregate.entities.flat_map { |entity| entity_commands(prefix, entity) },
96
+ *aggregate.ports.flat_map { |port| operations(prefix, port) }]
97
+ .to_h { |verb, events| [Naming.split_verb(verb), bare_names(events)] }
98
+ end
99
+
100
+ def bare_names(events) = Array(events).map { |event| event.to_s.split("::").last }
101
+
102
+ def entity_commands(prefix, entity)
103
+ entity.commands.map { |command| ["#{prefix}.#{entity.hecks_name}.#{command.hecks_name}", command.emits] }
104
+ end
105
+
106
+ def operations(prefix, port)
107
+ port.operations.map do |operation|
108
+ ["#{prefix}.#{port.name}.#{operation.hecks_name}", [*operation.emits, operation.answers, operation.refuses].compact]
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,53 @@
1
+ module Hecks
2
+ module Bluebook
3
+ module ModelCheck
4
+ # The loops of a reaction graph: groups of policies that can each reach the others through
5
+ # the commands they dispatch (the strongly connected components with a cycle in them, found
6
+ # with Tarjan's algorithm), whether or not any command outside the group starts them.
7
+ class ReactionCycles
8
+ # @param policies [Array] the graph's nodes, in declaration order
9
+ # @param successors [Hash{Object => Array}] the policies each policy's dispatch can start
10
+ def initialize(policies, successors)
11
+ @policies = policies
12
+ @successors = successors
13
+ end
14
+
15
+ # @return [Array<Array>] each loop's policies, in declaration order
16
+ def groups
17
+ @index = {}
18
+ @low = {}
19
+ @stack = []
20
+ @found = []
21
+ @policies.each { |policy| connect(policy) unless @index.key?(policy) }
22
+ @found.select { |group| loop?(group) }.map { |group| group.sort_by { |policy| @policies.index(policy) } }
23
+ end
24
+
25
+ private
26
+
27
+ def loop?(group) = group.size > 1 || @successors.fetch(group.first).include?(group.first)
28
+
29
+ def connect(node)
30
+ @index[node] = @low[node] = @index.size
31
+ @stack.push(node)
32
+ @successors.fetch(node).each { |next_node| visit(node, next_node) }
33
+ @found << pop_group(node) if @low[node] == @index[node]
34
+ end
35
+
36
+ def visit(node, next_node)
37
+ if @index.key?(next_node)
38
+ @low[node] = [@low[node], @index[next_node]].min if @stack.include?(next_node)
39
+ else
40
+ connect(next_node)
41
+ @low[node] = [@low[node], @low[next_node]].min
42
+ end
43
+ end
44
+
45
+ def pop_group(root)
46
+ group = []
47
+ group << @stack.pop until group.last.equal?(root)
48
+ group
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,58 @@
1
+ require_relative "reaction_chains"
2
+
3
+ module Hecks
4
+ module Bluebook
5
+ module ModelCheck
6
+ # The checks over reaction chains. A command whose events start a chain of policies longer
7
+ # than the dispatcher's reaction limit has the reactions past it refused without anyone
8
+ # being told; a chain of exactly the limit runs whole, in both runtimes. A loop of
9
+ # policies, which no limit on the chain's length can describe, is reported as a loop.
10
+ module ReactionDepthChecks
11
+ # @param bluebook [Bluebook::Declaration] the assembled bluebook, its hecksagon attached
12
+ # @param limit [Integer] the reaction depth limit; the dispatcher's own when not given
13
+ # @return [Array<Finding>] a warning for each entry command whose longest chain exceeds
14
+ # `limit`, for each loop of policies, and for each chain search that gave up
15
+ def reaction_depth_findings(bluebook, limit: Hecks::Runtime::Dispatcher::MAX_REACTION_DEPTH)
16
+ chains = ReactionChains.new(bluebook)
17
+ [*(chains.verbs - chains.reaction_targets.to_a).flat_map { |verb| chain_findings(chains, verb, limit) },
18
+ *chains.cycles.map { |policies| loop_finding(policies, limit) }]
19
+ end
20
+
21
+ # @return [Array<Finding>] the deep-chain warning for the verb, and the search warning if
22
+ # the walk gave up
23
+ def chain_findings(chains, verb, limit)
24
+ chain = chains.from(verb)
25
+ [(deep_chain_finding(verb, chain, limit) if chain.size > limit),
26
+ (capped_search_finding(verb, chain) if chains.capped?)].compact
27
+ end
28
+
29
+ # @return [Finding] the warning naming every policy of a loop
30
+ def loop_finding(policies, limit)
31
+ names = policies.map(&:name)
32
+ Finding.new(kind: :unbounded_reaction_loop, severity: :warning, subject: names.join(", "),
33
+ message: "policies #{names.join(", ")} reach one another, so a command that starts " \
34
+ "them reacts until the reaction depth limit of #{limit}, and the " \
35
+ "#{limit + 1}th reaction is refused without anyone being told")
36
+ end
37
+
38
+ # @return [Finding] the warning that the chain found for the verb is a lower bound
39
+ def capped_search_finding(verb, chain)
40
+ Finding.new(kind: :reaction_chain_search_capped, severity: :warning, subject: verb_text(verb),
41
+ message: "the search for the longest chain stopped after " \
42
+ "#{ReactionWalk::WORK_LIMIT} steps; the chain of #{chain.size} reactions is a lower bound")
43
+ end
44
+
45
+ # @return [Finding] the warning naming the entry verb and each policy and verb of its chain
46
+ def deep_chain_finding(verb, chain, limit)
47
+ path = chain.map { |step| "#{step.policy_name} -> #{verb_text(step.verb)}" }.join(" -> ")
48
+ Finding.new(kind: :deep_reaction_chain, severity: :warning, subject: verb_text(verb),
49
+ message: "starts a chain of #{chain.size} reactions, past the reaction depth " \
50
+ "limit of #{limit}: the #{limit + 1}th and any after it are refused: " \
51
+ "#{verb_text(verb)} -> #{path}")
52
+ end
53
+
54
+ def verb_text(verb) = "#{verb[0]}::#{verb[1]}.#{verb[2]}"
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,62 @@
1
+ module Hecks
2
+ module Bluebook
3
+ module ModelCheck
4
+ # The longest chain of reactions a policy starts, counting each policy once per chain. A
5
+ # policy that reaches no loop has one longest chain whatever path led to it, so those are
6
+ # remembered; the rest are searched path by path, and the search stops after `WORK_LIMIT`
7
+ # steps per chain, which `capped?` reports.
8
+ class ReactionWalk
9
+ # Policies visited by one search before it gives up and answers the best chain so far.
10
+ WORK_LIMIT = 10_000
11
+
12
+ # @param graph [ReactionChains] answers `step(policy)` and `successors(policy)`
13
+ # @param looping [Array] the policies that lie on a loop
14
+ def initialize(graph, looping)
15
+ @graph = graph
16
+ @looping = looping.to_set
17
+ @settled = {}
18
+ @reaches = {}
19
+ @work = 0
20
+ end
21
+
22
+ # @param starts [Array] the policies the first event reaches
23
+ # @return [Array<ReactionChains::Step>] the longest chain, in order
24
+ def longest(starts)
25
+ @work = 0
26
+ @capped = false
27
+ starts.map { |policy| search(policy, []) }.max_by(&:size) || []
28
+ end
29
+
30
+ # @return [Boolean] whether the last `longest` gave up, so its chain is a lower bound
31
+ def capped? = @capped
32
+
33
+ private
34
+
35
+ def search(policy, path)
36
+ return settled(policy) unless reaches_loop?(policy)
37
+ return give_up if (@work += 1) > WORK_LIMIT
38
+
39
+ open = @graph.successors(policy) - path - [policy]
40
+ [@graph.step(policy)] + (open.map { |next_policy| search(next_policy, [*path, policy]) }.max_by(&:size) || [])
41
+ end
42
+
43
+ def give_up
44
+ @capped = true
45
+ []
46
+ end
47
+
48
+ def settled(policy)
49
+ @settled[policy] ||= [@graph.step(policy)] +
50
+ (@graph.successors(policy).map { |next_policy| settled(next_policy) }.max_by(&:size) || [])
51
+ end
52
+
53
+ def reaches_loop?(policy)
54
+ @reaches.fetch(policy) do
55
+ onward = @graph.successors(policy)
56
+ @reaches[policy] = @looping.include?(policy) || onward.any? { |next_policy| reaches_loop?(next_policy) }
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -7,6 +7,7 @@ require_relative "model_check/policy_checks"
7
7
  require_relative "model_check/context_checks"
8
8
  require_relative "model_check/context_map_checks"
9
9
  require_relative "model_check/ask_checks"
10
+ require_relative "model_check/reaction_depth_checks"
10
11
  require_relative "model_check/reference_checks"
11
12
  require_relative "model_check/orphan_checks"
12
13
  require_relative "model_check/one_of_checks"
@@ -41,6 +42,7 @@ module Hecks
41
42
  extend PolicyChecks
42
43
  extend ContextChecks
43
44
  extend AskChecks
45
+ extend ReactionDepthChecks
44
46
  extend ReferenceChecks
45
47
  extend OrphanChecks
46
48
  extend OneOfChecks
@@ -78,10 +80,11 @@ module Hecks
78
80
  [
79
81
  *bluebook.aggregates.flat_map { |aggregate| aggregate_lifecycle_findings(aggregate) },
80
82
  *reference_findings(bluebook),
81
- *large_aggregate_findings(bluebook),
83
+ *aggregate_findings(bluebook),
82
84
  *bluebook.process_managers.flat_map { |process_manager| saga_findings(bluebook, process_manager) },
83
85
  *reaction_findings(bluebook, options),
84
- *unused_ask_findings(bluebook)
86
+ *unused_ask_findings(bluebook),
87
+ *reaction_depth_findings(bluebook)
85
88
  ]
86
89
  end
87
90
 
@@ -112,31 +115,6 @@ module Hecks
112
115
  aggregate.entities.flat_map { |entity| lifecycle_findings(aggregate, entity) }
113
116
  end
114
117
 
115
- # Flags a query the hecksagon binds to a port's adapter. Only the Ruby runtime asks an
116
- # adapter for an answer; a Rust host would find nothing behind the query.
117
- #
118
- # @param bluebook [Bluebook::Declaration] the assembled bluebook, its hecksagon's ports
119
- # attached
120
- # @param rust_target [Boolean] whether this domain has a real Rust target; a domain without
121
- # one is not checked, since nothing but the Ruby runtime serves it
122
- # @return [Array<Finding>] one :external_query error per bound query, none off a Rust target
123
- def external_query_findings(bluebook, rust_target: false)
124
- return [] unless rust_target
125
-
126
- bluebook.aggregates.flat_map do |aggregate|
127
- aggregate.ports.flat_map do |port|
128
- port.answered_queries.map { |answer| external_query_finding(aggregate, port, answer) }
129
- end
130
- end
131
- end
132
-
133
- def external_query_finding(aggregate, port, answer)
134
- Finding.new(kind: :external_query, severity: :error,
135
- subject: "#{aggregate.hecks_name}.#{answer.name}",
136
- message: "the #{port.name} port's adapter answers this query, and only the Ruby " \
137
- "runtime asks an adapter — the Rust host cannot serve it")
138
- end
139
-
140
118
  # Flags an aggregate or domain name that collides with a Rust keyword or reserved
141
119
  # Cargo key — both become bare module identifiers with no `r#` escape hatch.
142
120
  #
@@ -54,25 +54,42 @@ module Hecks
54
54
  correlates_by: -> { correlates_by&.to_s },
55
55
  starts_on: :starts_on,
56
56
  ends_on: :ends_on,
57
+ endings: :endings,
58
+ resumes: :resumes,
57
59
  states: :states,
58
60
  handlers: many(:handlers)
59
61
  )
60
62
 
61
- attr_reader :name, :correlates_by, :starts_on, :ends_on, :states, :handlers
63
+ attr_reader :name, :correlates_by, :starts_on, :ends_on, :endings, :resumes, :states, :handlers
62
64
 
63
65
  # Every optional keyword and what it holds when the declaration omits it.
64
66
  FIELD_DEFAULTS = {
65
- correlates_by: nil, starts_on: nil, ends_on: nil, states: [], handlers: []
67
+ correlates_by: nil, starts_on: nil, ends_on: nil, endings: [], resumes: [],
68
+ states: [], handlers: []
66
69
  }.freeze
67
70
 
68
71
  # @param correlates_by [Symbol, nil] the payload field that correlates a triggering
69
72
  # event to an instance
70
73
  # @param starts_on [String, nil] the event that starts a new instance
71
- # @param ends_on [String, nil] the event that ends an instance
74
+ # @param ends_on [String, nil] the first event that ends an instance
75
+ # @param endings [Array<String>] every event that ends an instance, in declaration order;
76
+ # empty when the declaration names only `ends_on`
72
77
  def initialize(name:, **given)
73
78
  KeywordFields.assign(self, KeywordFields.fill(given, FIELD_DEFAULTS))
74
79
  @name = name.to_s
75
80
  end
81
+
82
+ # Every event that ends an instance. A process manager that declares one `ends_on` has
83
+ # that event alone; one that declares several ends on any of them.
84
+ #
85
+ # @return [Array<String>] the ending events, never empty when `ends_on` is set
86
+ def ending_events = endings.empty? ? [ends_on].compact : endings
87
+
88
+ # Replaces a bare aggregate name with the dotted path the bluebook resolved it to.
89
+ #
90
+ # @param key [String] the `"<Aggregate>.<identity>"` path
91
+ # @return [String] the path now held
92
+ def correlate_by!(key) = @correlates_by = key
76
93
  end
77
94
  end
78
95
  end
@@ -9,7 +9,6 @@ module Hecks
9
9
  # One field whose value changed, bridged by an exhaustive lookup table.
10
10
  # Paths follow `TranslationMove`; `values` maps each old-era value to its new-era one.
11
11
  # `:values` shadows Struct#values on purpose; no caller reads the built-in.
12
- # rubocop:disable-next Lint/StructNewOverride
13
12
  TranslationConvert = Struct.new(:from, :to, :values)
14
13
 
15
14
  # A value object's or entity's type name changed with its members unchanged.
@@ -27,6 +26,9 @@ module Hecks
27
26
  # derive has a value; a record where it has none keeps its id.
28
27
  TranslationRekey = Struct.new(:to)
29
28
 
29
+ # ADR 0166: one aggregate's rows fan out into another, keyed by a field both share.
30
+ TranslationSplit = Struct.new(:into, :keyed_by, :fields)
31
+
30
32
  # A newly added, required attribute with no source in old data.
31
33
  # `default` is what an existing record reads until a command writes a real value;
32
34
  # applied in-process by `Lineage#translate` on every adapter.
@@ -35,12 +37,12 @@ module Hecks
35
37
  # One aggregate's part of a translation between eras.
36
38
  # `drops` makes data loss a declared decision.
37
39
  class TranslationAggregate
38
- attr_reader :name, :was, :renames, :moves, :converts, :drops, :retypes, :derives, :rekeys, :backfills
40
+ attr_reader :name, :was, :renames, :moves, :converts, :drops, :retypes, :derives, :rekeys, :backfills, :splits
39
41
 
40
42
  # Every optional field and what it holds when the declaration omits it.
41
43
  FIELD_DEFAULTS = {
42
44
  was: nil, renames: {}, moves: [], converts: [], drops: [], retypes: [],
43
- derives: [], rekeys: [], backfills: []
45
+ derives: [], rekeys: [], backfills: [], splits: []
44
46
  }.freeze
45
47
 
46
48
  # @param name [String, Symbol] the aggregate's name in the destination era