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,6 +4,7 @@ require "hecks"
4
4
  # --adapter=PostgresEra needs the era persistence plugin (ADR 0033).
5
5
  require "hecks/ports/persistence/plugins/era"
6
6
  require "optparse"
7
+ require "hecks/hecks/adapters/journal_store"
7
8
  require_relative "../tools"
8
9
 
9
10
  module Hecks
@@ -85,6 +86,7 @@ module Hecks
85
86
  refuse_if_refused(dispatcher, slug)
86
87
 
87
88
  puts "wrote #{File.join(domain_directory, "environments", "#{slug}.world")}"
89
+ hold_first_eras(domain_directory, slug)
88
90
  dispatcher
89
91
  end
90
92
 
@@ -139,6 +141,27 @@ module Hecks
139
141
  puts "#{options[:domain]} is tenant_capable? for #{slug.inspect} — registered under realm #{options[:realm].inspect}"
140
142
  end
141
143
 
144
+ # Holds era 1 of each era-keeping bluebook in the tenant's schema before the boot reads it:
145
+ # a boot only reads (ADR 0168), and `hold_first` is the one writer. A bluebook whose lineage
146
+ # already holds an era is left untouched, so a re-provision mints nothing and an existing
147
+ # schema's eras and rows are never read as new.
148
+ def hold_first_eras(domain_directory, slug)
149
+ held = Hecks::Adapters::JournalStore::HeldDomain.open(domain_directory, mode: :bare, environment: slug)
150
+ held.bluebook_names.each do |name|
151
+ domain = Hecks::Adapters::JournalStore::HeldDomain.new(held.registry, held.directory, name)
152
+ hold_first_era(domain) if domain.capable?
153
+ end
154
+ end
155
+
156
+ def hold_first_era(domain)
157
+ text = Hecks::Runtime::EraCheck.source_text_for(domain.bluebook, domain.directory, registry: domain.registry)
158
+ domain.writing do |lineage|
159
+ next if lineage.eras.any?
160
+
161
+ lineage.hold_first_era!(text, projection: domain.shape, aggregates: domain.aggregates, role: domain.app_role)
162
+ end
163
+ end
164
+
142
165
  # @raise [SystemExit] when a bluebook of the registry is not tenant capable
143
166
  def refuse_unless_tenant_capable(registry)
144
167
  registry.bluebooks.each_key do |name|
@@ -164,7 +164,7 @@ module Hecks
164
164
 
165
165
  stale = SECTIONS.reject { |section| section_text(text, section) == section_text(fresh, section) }
166
166
  warn "tools_doc: #{DOCUMENT} differs from the RetiredScript rows in: #{stale.join(", ")} " \
167
- "(run hecks regeneration_run.project_tools_doc --confirm)"
167
+ "(run hecks regeneration_run.project_tools_doc! --confirm)"
168
168
  1
169
169
  end
170
170
 
@@ -183,13 +183,14 @@ module Hecks
183
183
 
184
184
  # @param row [Hash{String => String}] a `RetiredScript` row
185
185
  # @return [Array(Hash, Array<String>)] the projected command or query, and the words that
186
- # name it on the command line
186
+ # name it on the command line, a command's with the bang the launcher requires
187
187
  # @raise [SystemExit] when the row names no command or query
188
188
  def spec_for(row)
189
189
  declaration = %w[Custodian Codebase].include?(row["section"]) ? "Hecks" : row["section"]
190
190
  name = "#{Naming.snake(row["aggregate"])}.#{row["verb"]}"
191
- spec = find_spec(projection(declaration), name) or abort "tools_doc: #{declaration} has no command or query #{name}"
192
- [spec, words(declaration, name, row)]
191
+ cli = projection(declaration)
192
+ spec = find_spec(cli, name) or abort "tools_doc: #{declaration} has no command or query #{name}"
193
+ [spec, words(declaration, name, row, bang: cli[:names][:command].key?(name))]
193
194
  end
194
195
 
195
196
  private
@@ -207,13 +208,14 @@ module Hecks
207
208
  end
208
209
  end
209
210
 
210
- # `hecks ir`, `hecks console`, `hecks quality_control sweep.run`, `hecks host.check_era`.
211
+ # `hecks ir`, `hecks console!`, `hecks quality_control sweep.run`, `hecks host.check_era!`.
211
212
  # The launcher takes a name that is only a query as a query, so no `query` word is needed.
212
- def words(declaration, name, row)
213
+ def words(declaration, name, row, bang:)
213
214
  route = route_for(Adapters::Driving::LauncherOptions.settings(@runtime, declaration) || {}, declaration, name, row)
214
- return [route] if route
215
+ marked = ->(word) { bang ? "#{word}!" : word }
216
+ return [marked.call(route)] if route
215
217
 
216
- [*(Naming.snake(declaration) unless declaration == "Hecks"), name]
218
+ [*(Naming.snake(declaration) unless declaration == "Hecks"), marked.call(name)]
217
219
  end
218
220
 
219
221
  # @return [String, nil] the one word the launcher routes the name by, when it has one
@@ -11,16 +11,17 @@ module Hecks
11
11
  # The era the edge leads to and the chain of translations ending in it, or nil when the
12
12
  # journal stands at era 1 with nothing to audit.
13
13
  #
14
+ # @param directory [String, nil] the domain's bluebook directory, holding its implicit moves
14
15
  # @return [Array, nil] the era ordinal and the chain
15
- def edge_chain(registry, bluebook, lineage)
16
+ def edge_chain(registry, bluebook, lineage, directory = nil)
16
17
  eras = lineage.eras
17
18
  current_shape = Hecks::Runtime::StorageShape.project(bluebook)
18
- held_shape = Hecks::Runtime::StorageShape.project(lineage_manager.shadow(eras.last[:held_text]))
19
+ held_shape = lineage_manager.held_shape(eras.last)
19
20
 
20
21
  if held_shape == current_shape
21
22
  standing_chain(registry, bluebook, eras)
22
23
  else
23
- pending_chain(registry, bluebook, lineage, eras)
24
+ pending_chain(registry, bluebook, lineage, eras, directory)
24
25
  end
25
26
  end
26
27
 
@@ -38,32 +39,36 @@ module Hecks
38
39
  puts "#{bluebook.name} stands at era 1 — no edge to audit."
39
40
  return nil
40
41
  end
41
- [era, lineage_manager.edge_chain(registry, bluebook, eras, latest[:label])]
42
+ [era, lineage_manager.edge_chain(registry, bluebook, eras, latest[:label], target: latest)]
42
43
  end
43
44
 
44
45
  # The chain when the bluebook has moved past the held journal: audit the pending edge
45
46
  # before any mint.
46
- def pending_chain(registry, bluebook, lineage, eras)
47
+ def pending_chain(registry, bluebook, lineage, eras, directory)
47
48
  lineage_manager.ensure_named!(lineage, eras.last)
48
49
  latest = lineage.eras.last
49
- pending = pending_translation(registry, bluebook, latest)
50
+ pending = pending_translation(registry, bluebook, latest, lineage, directory)
50
51
  chain = begin
51
- lineage_manager.edge_chain(registry, bluebook, eras, latest[:label])
52
+ lineage_manager.edge_chain(registry, bluebook, eras, latest[:label], target: latest)
52
53
  rescue StandardError
53
54
  []
54
55
  end
55
56
  [latest[:ordinal] + 1, (chain || []) + [{ translation: pending }]]
56
57
  end
57
58
 
58
- # @return [Object] the translation leading from `latest` to the bluebook
59
- # @raise [SystemExit] when none is declared
60
- def pending_translation(registry, bluebook, latest)
61
- to_label = Hecks::Runtime::StorageShape.mint_hash(bluebook)[0, Hecks::Runtime::StorageShape::LABEL_LENGTH]
62
- pending = registry.translations.find do |t|
63
- t.domain == bluebook.name && t.from == latest[:label] && t.to == to_label
64
- end
65
- pending or abort "no translation edge leads #{latest[:label]} to #{to_label} — " \
66
- "run hecks scaffold_translation first"
59
+ # The edge the shared decision leads `latest` by, as a mint takes it.
60
+ #
61
+ # @return [Object] the edge leading from `latest` to the bluebook
62
+ # @raise [SystemExit] when the decision names no edge
63
+ def pending_translation(registry, bluebook, latest, lineage, directory)
64
+ verdict = lineage_manager::MintDecision.decide_latest(
65
+ latest, bluebook: bluebook, translations: registry.translations, directory: directory,
66
+ watermark: lineage.last_ordinal
67
+ )
68
+ return verdict.edge if verdict.verdict == "would_mint"
69
+
70
+ abort "no translation edge leads #{latest[:label]} to the current shape (the decision is " \
71
+ "#{verdict.verdict}) — run hecks scaffold_translation first"
67
72
  end
68
73
  end
69
74
  end
@@ -50,7 +50,7 @@ module Hecks
50
50
  end
51
51
 
52
52
  def records_before(lineage, aggregate, era, chain)
53
- return lineage.translated_latest(aggregate, era, chain[0..-2]) if chain.size > 1
53
+ return lineage.received_latest(aggregate, era, chain) if chain.size > 1
54
54
 
55
55
  lineage.ancestor_latest(aggregate, era, chain)
56
56
  end
@@ -56,7 +56,7 @@ module Hecks
56
56
  def audit(session)
57
57
  return hold_first_era(session) if session.no_era?
58
58
 
59
- audit_edge(session, edge_chain(session.registry, session.bluebook, session.lineage))
59
+ audit_edge(session, edge_chain(session.registry, session.bluebook, session.lineage, session.directory))
60
60
  end
61
61
 
62
62
  # @param found [Array, nil] the era ordinal and the chain of translations ending in it, or nil
@@ -115,7 +115,7 @@ module Hecks
115
115
  # @return [Array] the journal's latest era and the bluebook it held
116
116
  def held_era(lineage)
117
117
  latest = lineage.eras.last
118
- [latest, lineage_manager.shadow(latest[:held_text])]
118
+ [latest, lineage_manager.held_bluebook(latest)]
119
119
  end
120
120
 
121
121
  # A journal with no era yet holds the bluebook as its first, so there is nothing to scaffold.
data/lib/hecks/tools.rb CHANGED
@@ -20,9 +20,11 @@ module Hecks
20
20
  "standardize_comments_rust" => ["tools/rust_comment_style", "RustCommentStyle"],
21
21
  "regen_codegen_domains" => ["tools/regeneration_run", "RegenerationRun"],
22
22
  "gate" => ["tools/gate", "Gate"],
23
+ "move_disables" => ["tools/move_disables", "MoveDisables"],
23
24
  "argument_gate_matrix" => ["tools/argument_gate_matrix", "ArgumentGateMatrix"],
24
25
  "project_ci_gates" => ["tools/ci_gates", "CiGates"],
25
26
  "decide_ci_gate" => ["tools/ci_gate_decision", "CiGateDecision"],
27
+ "project_ci_pipeline" => ["tools/ci_workflows", "CiWorkflows"],
26
28
  "project_lanes" => ["tools/lanes", "Lanes"],
27
29
  "project_tools_doc" => ["tools/tools_doc", "ToolsDoc"],
28
30
  "project_deploy" => ["tools/deploy_recipe", "DeployRecipe"],
@@ -44,7 +46,8 @@ module Hecks
44
46
  "evolve" => ["tools/evolve_run", "EvolveRun"],
45
47
  "query_ir" => ["tools/query_ir_run", "QueryIrRun"],
46
48
  "codemod_hoist_local_givens" => ["tools/hoist_local_givens", "HoistLocalGivens"],
47
- "codemod_implicit_append_fields" => ["tools/drop_implicit_append_fields", "DropImplicitAppendFields"]
49
+ "codemod_implicit_append_fields" => ["tools/drop_implicit_append_fields", "DropImplicitAppendFields"],
50
+ "codemod_move_former_name" => ["tools/move_former_name", "MoveFormerName"]
48
51
  }.freeze
49
52
 
50
53
  module_function
data/lib/hecks/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Hecks
2
2
  # Read directly by the gemspec, so this file must never require the
3
3
  # rest of the gem (its dependencies aren't resolved yet at that point).
4
- VERSION = "6.0.0".freeze # rust/host/HECKS_RELEASE names the same release
4
+ VERSION = "7.0.0".freeze # rust/host/HECKS_RELEASE names the same release
5
5
  end
@@ -115,39 +115,51 @@ module Hecks
115
115
  {"name"=>"textarea", "pattern"=>"\\b(text|body|note|notes|description|message|comment)\\b", "resolves_to"=>"kind"}.freeze
116
116
  ].freeze,
117
117
  "GateCheck" => [
118
- {"name"=>"rspec", "id"=>"rspec", "title"=>"rspec (parallel)", "argv"=>"", "script"=>"# Workers are grouped by this machine's own last timings, kept under the git directory\n# (shared by every worktree, never committed). CI's committed baseline leaves out the io\n# specs this run includes, so it only seeds the first run; each run then rewrites the log.\nlog=\"$(git rev-parse --git-common-dir)/hecks_rspec_runtime.log\"\n[ -f \"$log\" ] || cp .github/rspec_runtime_baseline.log \"$log\"\nbundle exec parallel_rspec spec -n {workers} --group-by runtime --runtime-log \"$log\" --allowed-missing 100 \\\n -o \"--format progress --format ParallelTests::RSpec::RuntimeLogger --out $log\"\n", "blocked"=>"the suite is red."}.freeze,
118
+ {"name"=>"rspec", "id"=>"rspec", "title"=>"rspec (parallel)", "runs_in"=>"ci", "argv"=>"", "script"=>"# Workers are grouped by this machine's own last timings, kept under the git directory\n# (shared by every worktree, never committed). CI's committed baseline leaves out the io\n# specs this run includes, so it only seeds the first run; each run then rewrites the log.\nlog=\"$(git rev-parse --git-common-dir)/hecks_rspec_runtime.log\"\n[ -f \"$log\" ] || cp .github/rspec_runtime_baseline.log \"$log\"\nbundle exec parallel_rspec spec -n {workers} --group-by runtime --runtime-log \"$log\" --allowed-missing 100 \\\n -o \"--format progress --format ParallelTests::RSpec::RuntimeLogger --out $log\"\n", "blocked"=>"the suite is red."}.freeze,
119
119
  {"name"=>"fuzzing", "id"=>"fuzzing", "title"=>"spec/fuzzing, which the parallel run above excludes", "argv"=>"bundle exec rspec spec/fuzzing --tag fuzzing", "script"=>"", "blocked"=>"spec/fuzzing is red."}.freeze,
120
120
  {"name"=>"query_agreement", "id"=>"query_agreement", "title"=>"adapter agreement, one declared query and every engine giving the same answer", "argv"=>"bundle exec rspec spec/adapters/query_agreement_spec.rb --tag io", "script"=>"", "blocked"=>"the engines disagree about a declared query; one of them is wrong, and a self-consistent adapter spec cannot tell which."}.freeze,
121
- {"name"=>"engine_agreement", "id"=>"engine_agreement", "title"=>"engine agreement, every declared comparator on both engines", "argv"=>"bundle exec exe/hecks conformance_run.check_engine_agreement --wait", "script"=>"", "blocked"=>"a comparator is missing a shared case or a cross-engine spec."}.freeze,
122
- {"name"=>"shape_ledger", "id"=>"shape_ledger", "title"=>"shape ledger, every bluebook's storage shape held by the ledger or reached by a translation edge", "argv"=>"bundle exec exe/hecks conformance_run.check_shape_ledger --wait", "script"=>"", "blocked"=>"a bluebook's storage shape moved with no translation edge from the shape the ledger holds; the failure prints the edge to commit. A change that only adds is settled in one step with `hecks conformance_run.check_shape_ledger --confirm --additive --wait`, which writes the empty edge and moves the ledger; a change that renames or reshapes data needs rules first."}.freeze,
123
- {"name"=>"model_check", "id"=>"model_check", "title"=>"model check, unreachable states, dead transitions and orphaned handlers", "argv"=>"bundle exec exe/hecks model_check --wait", "script"=>"", "blocked"=>"the model checker found something."}.freeze,
124
- {"name"=>"doc_coverage", "id"=>"doc_coverage", "title"=>"docs coverage, words with no running example", "argv"=>"bundle exec exe/hecks conformance_run.measure_doc_coverage --wait", "script"=>"", "blocked"=>"the language ships something undocumented; write the missing sections and examples."}.freeze,
121
+ {"name"=>"engine_agreement", "id"=>"engine_agreement", "title"=>"engine agreement, every declared comparator on both engines", "argv"=>"bundle exec exe/hecks conformance_run.check_engine_agreement! --wait", "script"=>"", "blocked"=>"a comparator is missing a shared case or a cross-engine spec."}.freeze,
122
+ {"name"=>"shape_ledger", "id"=>"shape_ledger", "title"=>"shape ledger, every bluebook's storage shape held by the ledger or reached by a translation edge", "argv"=>"bundle exec exe/hecks conformance_run.check_shape_ledger! --wait", "script"=>"", "blocked"=>"a bluebook's storage shape moved with no translation edge from the shape the ledger holds; the failure prints the edge to commit. A change that only adds is settled in one step with `hecks conformance_run.check_shape_ledger! --confirm --additive --wait`, which writes the empty edge and moves the ledger; a change that renames or reshapes data needs rules first."}.freeze,
123
+ {"name"=>"model_check", "id"=>"model_check", "title"=>"model check, unreachable states, dead transitions and orphaned handlers", "argv"=>"bundle exec exe/hecks ModelCheckRun.model_check! --wait", "script"=>"", "blocked"=>"the model checker found something."}.freeze,
124
+ {"name"=>"doc_coverage", "id"=>"doc_coverage", "title"=>"docs coverage, words with no running example", "argv"=>"bundle exec exe/hecks conformance_run.measure_doc_coverage! --wait", "script"=>"", "blocked"=>"the language ships something undocumented; write the missing sections and examples."}.freeze,
125
125
  {"name"=>"rubocop", "id"=>"rubocop", "title"=>"rubocop, the static style and correctness gate", "argv"=>"bundle exec rubocop -c .rubocop.yml", "script"=>"", "blocked"=>"rubocop found an offense."}.freeze,
126
- {"name"=>"codegen_drift", "id"=>"codegen_drift", "title"=>"codegen drift, rust/src/generated/ must match a fresh regeneration", "argv"=>"bundle exec exe/hecks regeneration_run.regenerate_corpus --check --wait", "script"=>"", "blocked"=>"regenerating hits a diff. Only pizzas, mod.rs and Cargo.toml are committed, so run `hecks regenerate_corpus --confirm` (it also materializes the rest on a fresh checkout) and commit what it changed."}.freeze,
127
- {"name"=>"comment_style", "id"=>"comment_style", "title"=>"comment style, every comment under lib/hecks and spec against docs/COMMENT_STYLE_GUIDE.md", "argv"=>"bundle exec exe/hecks style_run.check_comments paths=lib/hecks spec --wait", "script"=>"", "blocked"=>"a comment breaks the style guide, such as a line past 100 characters; `hecks fix_comments` rewrites the mechanical ones, and the rest are shortened by hand. CI runs this same check."}.freeze,
128
- {"name"=>"comment_blocks", "id"=>"comment_blocks", "title"=>"comment blocks, no run of comment lines past ADR 0075's cap", "argv"=>"bundle exec exe/hecks style_run.check_comments paths=lib,spec,examples only=long_block --wait", "script"=>"", "blocked"=>"a comment block ran past the cap; shorten it."}.freeze,
126
+ {"name"=>"codegen_drift", "id"=>"codegen_drift", "title"=>"codegen drift, rust/src/generated/ must match a fresh regeneration", "argv"=>"bundle exec exe/hecks regeneration_run.regenerate_corpus! --check --wait", "script"=>"", "blocked"=>"regenerating hits a diff. The whole generated tree is committed, so run `hecks regeneration_run.regenerate_corpus! --confirm` and commit what it changed."}.freeze,
127
+ {"name"=>"comment_style", "id"=>"comment_style", "title"=>"comment style, every comment under lib/hecks and spec against docs/COMMENT_STYLE_GUIDE.md", "argv"=>"bundle exec exe/hecks style_run.check_comments! paths=lib/hecks spec --wait", "script"=>"", "blocked"=>"a comment breaks the style guide, such as a line past 100 characters; `hecks StyleRun.fix_comments!` rewrites the mechanical ones, and the rest are shortened by hand. CI runs this same check."}.freeze,
128
+ {"name"=>"comment_blocks", "id"=>"comment_blocks", "title"=>"comment blocks, no run of comment lines past ADR 0075's cap", "argv"=>"bundle exec exe/hecks style_run.check_comments! paths=lib,spec,examples only=long_block --wait", "script"=>"", "blocked"=>"a comment block ran past the cap; shorten it."}.freeze,
129
+ {"name"=>"command_names", "id"=>"command_names", "title"=>"command names, every launcher name a workflow, hook, gate row, spec or guide invokes still resolves", "argv"=>"bundle exec exe/hecks conformance_run.check_command_names! --wait", "script"=>"", "blocked"=>"a file invokes a launcher name the launcher no longer accepts (a renamed command, or a write without its !), so what runs it runs nothing. The failure names each file:line and the nearest valid name. Mark an invocation that is shown and not run with `dead-name-check: skip` on its line or the one before, a fence with `skip`, `historical` or `illustrative` after its language, or a whole page with `dead-name-check: skip-file` in its first lines."}.freeze,
130
+ {"name"=>"workflow_pagination", "id"=>"workflow_pagination", "title"=>"workflow pagination, no step counts or waits for GitHub list items from the first page alone", "argv"=>"bundle exec exe/hecks conformance_run.check_workflow_pagination! --wait", "script"=>"", "blocked"=>"a workflow step counts or waits for the items of a list call (artifacts, runs, jobs, issues, releases, pulls, commits) and reads only the first 30. Add --paginate and count the lines it prints, or filter the path with ?name=."}.freeze,
131
+ {"name"=>"secret_output", "id"=>"secret_output", "title"=>"secret output, no value a world hands an adapter as a secret reaches what a launcher prints", "argv"=>"bundle exec rspec spec/secret_output_spec.rb", "script"=>"", "blocked"=>"a declared secret, or a database URL's password, reached a refusal, a note or a result. Hold it through `Hecks::Secrets` where the world hands it over, and print through a guarded stream."}.freeze,
132
+ {"name"=>"adapter_words", "id"=>"adapter_words", "title"=>"adapter words, no domain name equal to a technology word the adapters are named for", "argv"=>"bundle exec rspec spec/adapter_words_spec.rb", "script"=>"", "blocked"=>"a domain name (a module, aggregate, command or query) equals a technology word listed in lib/hecks/hecks/adapter_words.json. The failure names each one; rename the domain name, not the adapter."}.freeze,
129
133
  {"name"=>"rust_fmt", "id"=>"rust_fmt", "title"=>"rustfmt, every Rust crate laid out as `cargo fmt` would", "argv"=>"", "script"=>"# The main crate's generated modules are not committed, so cargo fmt would stop at a\n# missing file on a fresh checkout; its hand-written entry points are named instead.\nrustfmt --check --edition 2021 rust/src/main.rs rust/src/kernel/mod.rs rust/tests/*.rs\nfor crate in parser codegen lsp host web build; do\n cargo fmt --check --manifest-path \"rust/$crate/Cargo.toml\"\ndone\n", "blocked"=>"a Rust file is not laid out as rustfmt has it; run `cargo fmt` in its crate (rust/src/exemplar is exempt, it is text templates). Generated Rust is laid out by its generators, so fix the generator, not the output."}.freeze,
130
- {"name"=>"rust_io", "id"=>"rust_io", "title"=>"rust io specs, conformance, coercion, has_many, semantics corpus and feature exclusivity", "argv"=>"", "script"=>"# Building the banking crate makes banking the default feature and rewrites the module\n# list, both tracked. They are put back on the way out, and the check will not start over\n# a person's uncommitted edits to them.\nrewritten=\"rust/Cargo.toml rust/src/generated/mod.rs\"\nif [ -n \"$(git status --porcelain -- $rewritten)\" ]; then\n echo \"uncommitted changes in $rewritten; commit or discard them first\" >&2\n exit 1\nfi\ntrap 'git checkout -q -- $rewritten' EXIT\nenv -u CARGO_TARGET_DIR bundle exec exe/hecks regeneration_run.regenerate_corpus --confirm --wait\nbundle exec exe/hecks build.project_rust domain=examples/banking --wait\nbundle exec rspec --tag io --profile 8 spec/rust_conformance_spec.rb spec/rust_conformance_fuzz_spec.rb spec/rust_numeric_coercion_spec.rb spec/rust_generated/has_many_spec.rb spec/semantics_corpus_spec.rb\nbundle exec rspec --tag io --profile 8 spec/rust_generated/domain_feature_exclusivity_spec.rb\n", "blocked"=>"a Rust io spec failed, or skipped; the crate it built is under rust/target."}.freeze,
131
- {"name"=>"ci_codegen_drift", "id"=>"codegen_drift", "title"=>"codegen drift, the committed generated Rust must match the regeneration this job holds", "argv"=>"git diff --exit-code --stat -- rust/src/generated rust/Cargo.toml", "script"=>"", "blocked"=>"regenerating hits a diff. Only pizzas, mod.rs and Cargo.toml are committed, so run `hecks regenerate_corpus --confirm` (it also materializes the rest on a fresh checkout) and commit what it changed."}.freeze,
132
- {"name"=>"rust_clippy", "id"=>"rust_clippy", "title"=>"clippy, every Rust crate with its warnings as errors", "argv"=>"", "script"=>"for crate in . parser codegen lsp host web build; do\n cargo clippy --all-targets --manifest-path \"rust/$crate/Cargo.toml\" -- -D warnings\ndone\n", "blocked"=>"clippy found a warning in a Rust crate, under the strict `[lints.clippy]` table of its Cargo.toml. The main crate needs rust/src/generated, so run `hecks regenerate_corpus --confirm` first on a fresh checkout. Fix the code, or allow a lint at the one site with a line saying why; a warning in generated Rust is fixed in its generator."}.freeze,
133
- {"name"=>"lint_deploy_recipes", "id"=>"lint_deploy_recipes", "title"=>"generated deploy recipes, a command with no checked exit status or no echo", "argv"=>"bundle exec exe/hecks deploy makefile_check.lint --wait", "script"=>"", "blocked"=>"a generated deploy Makefile has an unchecked command, or real AWS or database work with no echo telling the person running it what is about to happen."}.freeze,
134
- {"name"=>"fuzz", "id"=>"fuzz", "title"=>"fuzz, every example domain on the Memory adapter", "argv"=>"bundle exec exe/hecks fuzz_run.fuzz --wait", "script"=>"", "blocked"=>"a property, an interpreter crash or a determinism check failed on a replayed sequence; the seed is in the output."}.freeze,
135
- {"name"=>"fuzz_sqlite", "id"=>"fuzz_sqlite", "title"=>"fuzz on a real on-disk SQLite database", "argv"=>"bundle exec exe/hecks fuzz_run.fuzz adapter=sqlite seeds=6 --wait", "script"=>"", "blocked"=>"the SQLite adapter broke a property the Memory adapter held; seeds are 1..N, so the run repeats."}.freeze,
136
- {"name"=>"fuzz_postgres", "id"=>"fuzz_postgres", "title"=>"fuzz on real Postgres, up to four workers (each in its own scratch schema)", "argv"=>"bundle exec exe/hecks fuzz_run.fuzz adapter=postgres seeds=3 steps=20 --wait", "script"=>"", "blocked"=>"the Postgres adapter broke a property the Memory adapter held; it needs PGHOST, PGUSER and PGPASSWORD."}.freeze,
137
- {"name"=>"vocabulary_drift", "id"=>"vocabulary_drift", "title"=>"vocabulary, the reserved-name tables regenerated must match the committed ones", "argv"=>"", "script"=>"bundle exec exe/hecks language_run.project_vocabulary --confirm --wait\nbundle exec exe/hecks language_run.project_reserved_names --confirm --wait\ngit diff --exit-code -- lib/hecks/vocabulary.rb rust/codegen/src/reserved_names.rs rust/build/src/reserved_names.rs\n", "blocked"=>"a generated vocabulary file is stale; the check rewrote it, so commit the result."}.freeze,
138
- {"name"=>"ci_gates", "id"=>"ci_gates", "title"=>"ci gates, the CiGate rows must match the marked regions of the workflows", "argv"=>"bundle exec exe/hecks regeneration_run.project_ci_gates --wait", "script"=>"", "blocked"=>"a CiGate row changed with no projection, or a region was edited by hand; run `hecks regeneration_run.project_ci_gates --confirm`."}.freeze,
139
- {"name"=>"tools_doc", "id"=>"tools_doc", "title"=>"tools doc, docs/tools.md must match the RetiredScript rows", "argv"=>"bundle exec exe/hecks regeneration_run.project_tools_doc --wait", "script"=>"", "blocked"=>"a command's arguments changed with no regenerated doc; run `hecks regeneration_run.project_tools_doc --confirm`."}.freeze,
134
+ {"name"=>"rust_io", "id"=>"rust_io", "title"=>"rust io specs, conformance, coercion, has_many, semantics corpus, corpus regeneration and feature exclusivity", "argv"=>"", "script"=>"# Building the banking crate makes banking the default feature and rewrites the module\n# list, both tracked. They are put back on the way out, and the check will not start over\n# a person's uncommitted edits to them.\nrewritten=\"rust/Cargo.toml rust/src/generated/mod.rs\"\nif [ -n \"$(git status --porcelain -- $rewritten)\" ]; then\n echo \"uncommitted changes in $rewritten; commit or discard them first\" >&2\n exit 1\nfi\ntrap 'git checkout -q -- $rewritten' EXIT\nenv -u CARGO_TARGET_DIR bundle exec exe/hecks regeneration_run.regenerate_corpus! --confirm --wait\nbundle exec exe/hecks build.project_rust! domain=examples/banking --wait\nbundle exec rspec --tag io --profile 8 spec/rust_conformance_spec.rb spec/rust_conformance_fuzz_spec.rb spec/rust_numeric_coercion_spec.rb spec/rust_generated/has_many_spec.rb spec/semantics_corpus_spec.rb\nbundle exec rspec --tag io --profile 8 spec/rust_generated/domain_feature_exclusivity_spec.rb\nbundle exec rspec --tag io --profile 8 spec/rust_build_regeneration_order_spec.rb spec/rust_build_regeneration_subset_spec.rb\n", "blocked"=>"a Rust io spec failed, or skipped; the crate it built is under rust/target."}.freeze,
135
+ {"name"=>"ci_codegen_drift", "id"=>"codegen_drift", "title"=>"codegen drift, the committed generated Rust must match the regeneration this job holds", "argv"=>"git diff --exit-code --stat -- rust/src/generated rust/Cargo.toml", "script"=>"", "blocked"=>"regenerating hits a diff. The whole generated tree is committed, so run `hecks regeneration_run.regenerate_corpus! --confirm` and commit what it changed."}.freeze,
136
+ {"name"=>"generated_tree", "id"=>"generated_tree", "title"=>"whole-tree specs, the examples tagged generated_all against every domain's generated Rust", "argv"=>"bundle exec rspec --tag generated_all", "script"=>"", "blocked"=>"a spec that reads the whole generated tree failed; run `hecks regeneration_run.regenerate_corpus! --confirm` to materialize every domain, then `bundle exec rspec --tag generated_all`."}.freeze,
137
+ {"name"=>"rust_clippy", "id"=>"rust_clippy", "title"=>"clippy, every Rust crate with its warnings as errors", "argv"=>"", "script"=>"for crate in . parser codegen lsp host web build; do\n cargo clippy --all-targets --manifest-path \"rust/$crate/Cargo.toml\" -- -D warnings\ndone\n", "blocked"=>"clippy found a warning in a Rust crate, under the strict `[lints.clippy]` table of its Cargo.toml. The main crate needs rust/src/generated, so run `hecks regeneration_run.regenerate_corpus! --confirm` first on a fresh checkout. Fix the code, or allow a lint at the one site with a line saying why; a warning in generated Rust is fixed in its generator."}.freeze,
138
+ {"name"=>"lint_deploy_recipes", "id"=>"lint_deploy_recipes", "title"=>"generated deploy recipes, a command with no checked exit status or no echo", "argv"=>"bundle exec exe/hecks deploy MakefileCheck.lint! --wait", "script"=>"", "blocked"=>"a generated deploy Makefile has an unchecked command, or real AWS or database work with no echo telling the person running it what is about to happen."}.freeze,
139
+ {"name"=>"fuzz_1_of_3", "id"=>"fuzz_1_of_3", "title"=>"fuzz, shard 1 of 3 of the example domains on the Memory adapter", "argv"=>"bundle exec exe/hecks fuzz_run.fuzz! shard=1/3 --wait", "script"=>"", "blocked"=>"a property, an interpreter crash or a determinism check failed on a replayed sequence; the seed is in the output."}.freeze,
140
+ {"name"=>"fuzz_2_of_3", "id"=>"fuzz_2_of_3", "title"=>"fuzz, shard 2 of 3 of the example domains on the Memory adapter", "argv"=>"bundle exec exe/hecks fuzz_run.fuzz! shard=2/3 --wait", "script"=>"", "blocked"=>"a property, an interpreter crash or a determinism check failed on a replayed sequence; the seed is in the output."}.freeze,
141
+ {"name"=>"fuzz_3_of_3", "id"=>"fuzz_3_of_3", "title"=>"fuzz, shard 3 of 3 of the example domains on the Memory adapter", "argv"=>"bundle exec exe/hecks fuzz_run.fuzz! shard=3/3 --wait", "script"=>"", "blocked"=>"a property, an interpreter crash or a determinism check failed on a replayed sequence; the seed is in the output."}.freeze,
142
+ {"name"=>"fuzz_sqlite_1_of_3", "id"=>"fuzz_sqlite_1_of_3", "title"=>"fuzz, shard 1 of 3 on a real on-disk SQLite database", "argv"=>"bundle exec exe/hecks fuzz_run.fuzz! adapter=sqlite seeds=6 shard=1/3 --wait", "script"=>"", "blocked"=>"the SQLite adapter broke a property the Memory adapter held; seeds are 1..N, so the run repeats."}.freeze,
143
+ {"name"=>"fuzz_sqlite_2_of_3", "id"=>"fuzz_sqlite_2_of_3", "title"=>"fuzz, shard 2 of 3 on a real on-disk SQLite database", "argv"=>"bundle exec exe/hecks fuzz_run.fuzz! adapter=sqlite seeds=6 shard=2/3 --wait", "script"=>"", "blocked"=>"the SQLite adapter broke a property the Memory adapter held; seeds are 1..N, so the run repeats."}.freeze,
144
+ {"name"=>"fuzz_sqlite_3_of_3", "id"=>"fuzz_sqlite_3_of_3", "title"=>"fuzz, shard 3 of 3 on a real on-disk SQLite database", "argv"=>"bundle exec exe/hecks fuzz_run.fuzz! adapter=sqlite seeds=6 shard=3/3 --wait", "script"=>"", "blocked"=>"the SQLite adapter broke a property the Memory adapter held; seeds are 1..N, so the run repeats."}.freeze,
145
+ {"name"=>"fuzz_shards", "id"=>"fuzz_shards", "title"=>"fuzz shards, the three shards together hold every domain of the sweep once", "argv"=>"bundle exec exe/hecks fuzz_run.fuzz! list_shards=3 --wait", "script"=>"", "blocked"=>"the split of the fuzz sweep into three shards drops or repeats a domain, or cannot be listed; a shard would then sweep less than the sweep it stands for. Read the refusal, and fix lib/hecks/tools/fuzz_sweep/shards.rb or the cost table spec/fuzzing/fuzz_runtime_baseline.log."}.freeze,
146
+ {"name"=>"fuzz_postgres_1_of_2", "id"=>"fuzz_postgres_1_of_2", "title"=>"fuzz, shard 1 of 2 on real Postgres (each run in its own scratch schema)", "argv"=>"bundle exec exe/hecks fuzz_run.fuzz! adapter=postgres seeds=3 steps=20 shard=1/2 --wait", "script"=>"", "blocked"=>"the Postgres adapter broke a property the Memory adapter held; it needs PGHOST, PGUSER and PGPASSWORD."}.freeze,
147
+ {"name"=>"fuzz_postgres_2_of_2", "id"=>"fuzz_postgres_2_of_2", "title"=>"fuzz, shard 2 of 2 on real Postgres (each run in its own scratch schema)", "argv"=>"bundle exec exe/hecks fuzz_run.fuzz! adapter=postgres seeds=3 steps=20 shard=2/2 --wait", "script"=>"", "blocked"=>"the Postgres adapter broke a property the Memory adapter held; it needs PGHOST, PGUSER and PGPASSWORD."}.freeze,
148
+ {"name"=>"vocabulary_drift", "id"=>"vocabulary_drift", "title"=>"vocabulary, the reserved-name tables regenerated must match the committed ones", "argv"=>"", "script"=>"bundle exec exe/hecks language_run.project_vocabulary! --confirm --wait\nbundle exec exe/hecks language_run.project_reserved_names! --confirm --wait\ngit diff --exit-code -- lib/hecks/vocabulary.rb rust/codegen/src/reserved_names.rs rust/build/src/reserved_names.rs\n", "blocked"=>"a generated vocabulary file is stale; the check rewrote it, so commit the result."}.freeze,
149
+ {"name"=>"ci_gates", "id"=>"ci_gates", "title"=>"ci gates, the CiGate rows must match the marked regions of the workflows", "argv"=>"bundle exec exe/hecks regeneration_run.project_ci_gates! --wait", "script"=>"", "blocked"=>"a CiGate row changed with no projection, or a region was edited by hand; run `hecks regeneration_run.project_ci_gates! --confirm`."}.freeze,
150
+ {"name"=>"ci_pipeline", "id"=>"ci_pipeline", "title"=>"ci pipeline, the workflow rows must match the files they project", "argv"=>"bundle exec exe/hecks regeneration_run.project_ci_pipeline! --wait", "script"=>"", "blocked"=>"a workflow row changed with no projection, or a projected workflow was edited by hand; run `hecks regeneration_run.project_ci_pipeline! --confirm`."}.freeze,
151
+ {"name"=>"tools_doc", "id"=>"tools_doc", "title"=>"tools doc, docs/tools.md must match the RetiredScript rows", "argv"=>"bundle exec exe/hecks regeneration_run.project_tools_doc! --wait", "script"=>"", "blocked"=>"a command's arguments changed with no regenerated doc; run `hecks regeneration_run.project_tools_doc! --confirm`."}.freeze,
140
152
  {"name"=>"rust_coverage", "id"=>"rust_coverage", "title"=>"rust coverage, every generated module", "argv"=>"bundle exec exe/hecks query corpus_run.corpus_rust_coverage --wait", "script"=>"", "blocked"=>"a construct a domain declares has no generated Rust, or an entry on RUST_COVERAGE_PENDING is now fixed and must be deleted."}.freeze,
141
153
  {"name"=>"rust_coverage_codegen", "id"=>"rust_coverage_codegen", "title"=>"rust coverage against hecks-codegen's own manifest, pizzas governance identity banking meta", "argv"=>"", "script"=>"for module in pizzas governance identity banking meta; do\n bundle exec exe/hecks query build.rust_coverage module_name=$module codegen=rust --wait\ndone\n", "blocked"=>"hecks-codegen generated nothing for a construct a domain declares."}.freeze,
142
- {"name"=>"kernel_coverage", "id"=>"kernel_coverage", "title"=>"rust kernel coverage, every capability variant has a kernel file", "argv"=>"bundle exec exe/hecks kernel_run.measure_kernel_coverage --wait", "script"=>"", "blocked"=>"a capability's enum variant has no rust/src/kernel file behind it."}.freeze,
143
- {"name"=>"rust_vocabulary_drift", "id"=>"rust_vocabulary_drift", "title"=>"rust vocabulary, the kernel vocab tables regenerated must match the committed ones", "argv"=>"", "script"=>"bundle exec exe/hecks language_run.project_rust_vocabulary --confirm --wait\ngit diff --exit-code -- rust/src/kernel/vocab/\nuntracked=\"$(git status --porcelain --untracked-files=all -- rust/src/kernel/vocab/)\"\nif [ -n \"$untracked\" ]; then\n echo \"rust/src/kernel/vocab has uncommitted generated files:\" >&2\n echo \"$untracked\" >&2\n exit 1\nfi\n", "blocked"=>"the generated kernel vocab tables are stale or untracked; the check rewrote them, so commit the result."}.freeze
154
+ {"name"=>"kernel_coverage", "id"=>"kernel_coverage", "title"=>"rust kernel coverage, every capability variant has a kernel file", "argv"=>"bundle exec exe/hecks kernel_run.measure_kernel_coverage! --wait", "script"=>"", "blocked"=>"a capability's enum variant has no rust/src/kernel file behind it."}.freeze,
155
+ {"name"=>"rust_vocabulary_drift", "id"=>"rust_vocabulary_drift", "title"=>"rust vocabulary, the kernel vocab tables regenerated must match the committed ones", "argv"=>"", "script"=>"bundle exec exe/hecks language_run.project_rust_vocabulary! --confirm --wait\ngit diff --exit-code -- rust/src/kernel/vocab/\nuntracked=\"$(git status --porcelain --untracked-files=all -- rust/src/kernel/vocab/)\"\nif [ -n \"$untracked\" ]; then\n echo \"rust/src/kernel/vocab has uncommitted generated files:\" >&2\n echo \"$untracked\" >&2\n exit 1\nfi\n", "blocked"=>"the generated kernel vocab tables are stale or untracked; the check rewrote them, so commit the result."}.freeze
144
156
  ].freeze,
145
157
  "GateStage" => [
146
- {"name"=>"pre_push", "env"=>"HECKS_ENVIRONMENT=memory HECKS_PROCESS_SPECS=1", "checks"=>"rspec,fuzzing,query_agreement,engine_agreement,shape_ledger,model_check,doc_coverage,rubocop,codegen_drift,comment_style,comment_blocks,rust_fmt"}.freeze,
147
- {"name"=>"quick", "env"=>"HECKS_ENVIRONMENT=memory", "checks"=>"shape_ledger,rubocop,comment_style,comment_blocks"}.freeze,
148
- {"name"=>"unguarded_push", "env"=>"HECKS_ENVIRONMENT=memory", "checks"=>"shape_ledger,rubocop,comment_style,comment_blocks,fuzzing"}.freeze,
158
+ {"name"=>"pre_push", "env"=>"HECKS_ENVIRONMENT=memory HECKS_PROCESS_SPECS=1", "checks"=>"fuzzing,query_agreement,engine_agreement,shape_ledger,model_check,doc_coverage,rubocop,codegen_drift,comment_style,comment_blocks,rust_fmt"}.freeze,
159
+ {"name"=>"ci_suite", "env"=>"HECKS_ENVIRONMENT=memory HECKS_PROCESS_SPECS=1", "checks"=>"rspec"}.freeze,
160
+ {"name"=>"quick", "env"=>"HECKS_ENVIRONMENT=memory", "checks"=>"shape_ledger,rubocop,comment_style,comment_blocks,secret_output,adapter_words"}.freeze,
149
161
  {"name"=>"rust_io", "env"=>"CI=true HECKS_ENVIRONMENT=memory", "checks"=>"rust_io"}.freeze,
150
- {"name"=>"ci", "env"=>"", "checks"=>"model_check,shape_ledger,engine_agreement,doc_coverage,rubocop,comment_style,comment_blocks,ci_codegen_drift,rust_fmt,rust_clippy,lint_deploy_recipes,fuzz,fuzz_sqlite,fuzz_postgres,vocabulary_drift,ci_gates,tools_doc,rust_coverage,rust_coverage_codegen,kernel_coverage,rust_vocabulary_drift"}.freeze
162
+ {"name"=>"ci", "env"=>"", "checks"=>"model_check,shape_ledger,engine_agreement,doc_coverage,rubocop,comment_style,comment_blocks,ci_codegen_drift,generated_tree,rust_fmt,rust_clippy,lint_deploy_recipes,command_names,workflow_pagination,fuzz_1_of_3,fuzz_2_of_3,fuzz_3_of_3,fuzz_sqlite_1_of_3,fuzz_sqlite_2_of_3,fuzz_sqlite_3_of_3,fuzz_postgres_1_of_2,fuzz_postgres_2_of_2,fuzz_shards,vocabulary_drift,ci_gates,ci_pipeline,tools_doc,rust_coverage,rust_coverage_codegen,kernel_coverage,rust_vocabulary_drift"}.freeze
151
163
  ].freeze,
152
164
  "IncludeHaystack" => [
153
165
  {"type"=>"Array", "strategy"=>"membership"}.freeze,
@@ -195,12 +207,12 @@ module Hecks
195
207
  ].freeze,
196
208
  "QaDial" => [
197
209
  {"name"=>"cadence_seconds", "type"=>"Integer", "meaning"=>"Minimum gap in seconds between one tick's report and the next dispatch; 0 is immediately. Read by the `/loop hecks_qa` caller, not by any script."}.freeze,
198
- {"name"=>"pr_cap_per_day", "type"=>"Integer", "meaning"=>"Most PRs (Patch plus Improvement) `hecks quality_control patch.open` opens per calendar day; 0 is uncapped."}.freeze,
210
+ {"name"=>"pr_cap_per_day", "type"=>"Integer", "meaning"=>"Most PRs (Patch plus Improvement) `hecks quality_control Patch.open!` opens per calendar day; 0 is uncapped."}.freeze,
199
211
  {"name"=>"widening_tiers", "type"=>"Array", "meaning"=>"Fuzz depth by `Target.clean_streak`, in three discrete tiers, read by `SweepDepth.for_streak`. The last row (`upto: Float::INFINITY`) is the ceiling."}.freeze,
200
212
  {"name"=>"sweep_max_parallel", "type"=>"Integer", "meaning"=>"How many `hecks quality_control query sweep.run <target>` children `--all` keeps running at once."}.freeze,
201
213
  {"name"=>"liveness_fallback_seconds", "type"=>"Integer", "meaning"=>"How long the `/loop hecks_qa` caller waits for a tick's report before assuming it stalled."}.freeze,
202
- {"name"=>"draft_only", "type"=>"Boolean", "meaning"=>"Whether `hecks quality_control patch.open` opens its PR as a draft; false opens it ready for review."}.freeze,
203
- {"name"=>"auto_merge", "type"=>"Boolean", "meaning"=>"Whether `hecks quality_control patch.open` queues the PR for auto-merge once it is open."}.freeze,
214
+ {"name"=>"draft_only", "type"=>"Boolean", "meaning"=>"Whether `hecks quality_control Patch.open!` opens its PR as a draft; false opens it ready for review."}.freeze,
215
+ {"name"=>"auto_merge", "type"=>"Boolean", "meaning"=>"Whether `hecks quality_control Patch.open!` queues the PR for auto-merge once it is open."}.freeze,
204
216
  {"name"=>"adversarial_fraction", "type"=>"Numeric", "meaning"=>"Fraction (0.0..1.0) of generated command steps mutated adversarially; 0 turns the layer off. Higher finds refusal-ordering splits sooner but reaches deep state less often."}.freeze,
205
217
  {"name"=>"guided_generation", "type"=>"Boolean", "meaning"=>"Coverage-guided generation across one sweep's seeds (`Hecks::Fuzzing::CoverageCampaign`)."}.freeze,
206
218
  {"name"=>"corpus_splice_probability", "type"=>"Numeric", "meaning"=>"Fraction (0.0..1.0) of seeds that start from a prefix of an earlier seed's new coverage. Off by default: measured, it trades breadth for depth (banking reached 1.41x the deep-state tuples, chess lost 0.12x of all tuples), while favoring rare verbs alone never lost."}.freeze,
@@ -222,7 +234,13 @@ module Hecks
222
234
  {"name"=>"generated_domain_seeds", "type"=>"Integer", "meaning"=>"Generated sequences run per generated domain."}.freeze,
223
235
  {"name"=>"mutation_files", "type"=>"Array", "meaning"=>"Rust files `hecks quality_control target.mutate --from-dials` mutates, and so the files one `hecks quality_control sweep.tick` mutation-tests after the generated domains; empty skips the step."}.freeze,
224
236
  {"name"=>"mutation_equivalent", "type"=>"Array", "meaning"=>"Mutants that behave the same as the original code, by the name `cargo mutants --list` gives them without the file and line; never run, so they cannot be reported as survivors."}.freeze,
225
- {"name"=>"structural_refusal_boundary", "type"=>"Array", "meaning"=>"Construct families a skipped query verb may belong to. A skip inside the list is logged Held, one outside it Surprised. Shrink-only: spec/fuzzing/rust_gap_manifest_spec.rb fails when a family here is declared by no committed manifest."}.freeze
237
+ {"name"=>"structural_refusal_boundary", "type"=>"Array", "meaning"=>"Construct families a skipped query verb may belong to. A skip inside the list is logged Held, one outside it Surprised. Shrink-only: spec/fuzzing/rust_gap_manifest_spec.rb fails when a family here is declared by no committed manifest."}.freeze,
238
+ {"name"=>"red_main_check", "type"=>"Boolean", "meaning"=>"Whether each `hecks quality_control sweep.tick` runs the quick gate on local main as its last finding step, logging each red check as a bug and fixing the self-contained ones; false skips the step."}.freeze,
239
+ {"name"=>"event_pump", "type"=>"Boolean", "meaning"=>"Whether each `hecks quality_control sweep.tick` runs the event pump as its last step: each attached domain's policies react to the events past their cursors, and every refusal is named. false skips the step; `hecks quality_control event_pump.pump!` runs it regardless."}.freeze,
240
+ {"name"=>"push_nudge", "type"=>"Boolean", "meaning"=>"Whether each `hecks quality_control sweep.tick` checks once whether a push of local main is due and files, revises or finishes the one `push-due` Work row; false skips the check. The thresholds are the QualityControl world's `push_nudge` setting."}.freeze,
241
+ {"name"=>"quiesced", "type"=>"Boolean", "meaning"=>"Whether each `hecks quality_control sweep.tick` runs no step at all: every step prints `quiesced: skipped <step>` and the tick exits 0, so a mint window sees a quiet ledger. The setting is read once at the start of a tick; `hecks qa_quiesce.hold!` writes a marker file every step checks as well, which a tick already running notices before its next step."}.freeze,
242
+ {"name"=>"main_maintenance", "type"=>"Boolean", "meaning"=>"Whether each `hecks quality_control sweep.tick` runs the main-maintenance chain after the main-check step: the quick gate on main, the reconcile plan, and the push through the train when origin is behind. false skips the chain."}.freeze,
243
+ {"name"=>"maintenance_confirm", "type"=>"Boolean", "meaning"=>"Whether the main-maintenance chain's reconcile writes after its plan (`Era.Reconcile` with confirm); false leaves the reconcile a dry run that writes nothing."}.freeze
226
244
  ].freeze,
227
245
  "QueryComparator" => [
228
246
  {"name"=>"eq"}.freeze,
@@ -451,6 +469,14 @@ module Hecks
451
469
  {"refusal"=>"AttributeAbsent", "site"=>"absent_read", "template"=>"{aggregate} {field} is absent on this record — declared, not optional, and added since it was written. Backfill it in a translation (backfill :{field}, default: ...), or declare it optional: true"}.freeze,
452
470
  {"refusal"=>"ProjectionAbsent", "site"=>"absent_read", "template"=>"{aggregate} {field} is not yet projected on this record — declared via projects :{field}, but no rebuild sweep has populated it. Run the sweep, or read {reference}.{remote_field} directly if this rule cannot wait"}.freeze
453
471
  ].freeze,
472
+ "RehearsalScope" => [
473
+ {"name"=>"quick", "stages"=>"quick"}.freeze,
474
+ {"name"=>"deep", "stages"=>"quick,impacted"}.freeze
475
+ ].freeze,
476
+ "RehearsalStage" => [
477
+ {"name"=>"quick", "kind"=>"gate", "argument"=>"quick"}.freeze,
478
+ {"name"=>"impacted", "kind"=>"impacted", "argument"=>""}.freeze
479
+ ].freeze,
454
480
  "ReleaseFile" => [
455
481
  {"path"=>"lib/hecks/version.rb", "lines"=>"^\\s*VERSION = \"[0-9]+\\.[0-9]+\\.[0-9]+\"\\.freeze$"}.freeze,
456
482
  {"path"=>"CHANGELOG.md", "lines"=>""}.freeze,
@@ -500,7 +526,7 @@ module Hecks
500
526
  {"script"=>"heki_compact", "section"=>"Custodian", "aggregate"=>"Era", "verb"=>"compact_heki"}.freeze,
501
527
  {"script"=>"vendor_bluebook", "section"=>"Custodian", "aggregate"=>"Package", "verb"=>"vendor", "note"=>"waits: a refusal exits 1 with its reason on stderr"}.freeze,
502
528
  {"script"=>"project_cli", "section"=>"Custodian", "aggregate"=>"Launch", "verb"=>"project_cli"}.freeze,
503
- {"script"=>"hecks_mcp_door", "section"=>"Custodian", "aggregate"=>"Launch", "verb"=>"serve_mcp"}.freeze,
529
+ {"script"=>"hecks_mcp_door", "section"=>"Custodian", "aggregate"=>"Server", "verb"=>"serve_mcp"}.freeze,
504
530
  {"script"=>"project_rust", "section"=>"Custodian", "aggregate"=>"Build", "verb"=>"project_rust"}.freeze,
505
531
  {"script"=>"project_wasm", "section"=>"Custodian", "aggregate"=>"Build", "verb"=>"build_wasm"}.freeze,
506
532
  {"script"=>"project_host", "section"=>"Custodian", "aggregate"=>"Build", "verb"=>"build_host"}.freeze,
@@ -559,6 +585,7 @@ module Hecks
559
585
  {"script"=>"canonicalise", "section"=>"Codebase", "aggregate"=>"StyleRun", "verb"=>"canonicalise"}.freeze,
560
586
  {"script"=>"codemod_hoist_local_givens", "section"=>"Codebase", "aggregate"=>"CodemodRun", "verb"=>"hoist_local_givens"}.freeze,
561
587
  {"script"=>"codemod_implicit_append_fields", "section"=>"Codebase", "aggregate"=>"CodemodRun", "verb"=>"drop_implicit_append_fields"}.freeze,
588
+ {"script"=>"codemod_move_former_name", "section"=>"Codebase", "aggregate"=>"CodemodRun", "verb"=>"move_former_name"}.freeze,
562
589
  {"script"=>"rspec_shard_files", "section"=>"Codebase", "aggregate"=>"TestSuiteRun", "verb"=>"shard_specs"}.freeze,
563
590
  {"script"=>"rspec_io_parallel_files", "section"=>"Codebase", "aggregate"=>"TestSuiteRun", "verb"=>"list_io_parallel_specs"}.freeze,
564
591
  {"script"=>"rspec_io_parallel_files", "section"=>"Codebase", "aggregate"=>"TestSuiteRun", "verb"=>"write_io_parallel_spec_list"}.freeze,
@@ -574,12 +601,13 @@ module Hecks
574
601
  {"script"=>"query_ir", "section"=>"Codebase", "aggregate"=>"CorpusRun", "verb"=>"ir_constructs"}.freeze,
575
602
  {"script"=>"query_ir", "section"=>"Codebase", "aggregate"=>"CorpusRun", "verb"=>"ir_duplicates"}.freeze,
576
603
  {"script"=>"query_ir", "section"=>"Codebase", "aggregate"=>"CorpusRun", "verb"=>"ir_impact"}.freeze,
577
- {"script"=>"hecks_query_ir_mcp", "section"=>"Codebase", "aggregate"=>"CorpusRun", "verb"=>"serve_query_ir_mcp"}.freeze,
578
- {"script"=>"present", "section"=>"Codebase", "aggregate"=>"CorpusRun", "verb"=>"present"}.freeze,
604
+ {"script"=>"hecks_query_ir_mcp", "section"=>"Codebase", "aggregate"=>"Server", "verb"=>"serve_query_ir_mcp"}.freeze,
605
+ {"script"=>"present", "section"=>"Codebase", "aggregate"=>"Server", "verb"=>"present"}.freeze,
579
606
  {"script"=>"release", "section"=>"Codebase", "aggregate"=>"PublishingRun", "verb"=>"publish", "note"=>"without --confirm, the old --dry-run"}.freeze,
580
607
  {"script"=>"release_gem", "section"=>"Codebase", "aggregate"=>"PublishingRun", "verb"=>"publish_gem"}.freeze,
581
608
  {"script"=>"(new)", "section"=>"Codebase", "aggregate"=>"GateRun", "verb"=>"gate"}.freeze,
582
609
  {"script"=>"qa_tick", "section"=>"QualityControl", "aggregate"=>"Sweep", "verb"=>"tick"}.freeze,
610
+ {"script"=>"qa_event_pump", "section"=>"QualityControl", "aggregate"=>"EventPump", "verb"=>"pump"}.freeze,
583
611
  {"script"=>"qa_sweep", "section"=>"QualityControl", "aggregate"=>"Sweep", "verb"=>"run", "passes"=>"--all --seeds N --steps N --adversarial F --role-draw F --dry-run F --self-consistency BOOL --modes a,b --persistence-parity --no-parity"}.freeze,
584
612
  {"script"=>"qa_sweep", "section"=>"QualityControl", "aggregate"=>"Target", "verb"=>"release"}.freeze,
585
613
  {"script"=>"qa_pr_check", "section"=>"QualityControl", "aggregate"=>"Clearance", "verb"=>"check_pull_requests"}.freeze,
@@ -595,6 +623,8 @@ module Hecks
595
623
  {"script"=>"qa_discover_external_domains", "section"=>"QualityControl", "aggregate"=>"Target", "verb"=>"discover_external_domains", "passes"=>"--projects-dir ~/Projects --max-depth 3 --known-path PATH …"}.freeze,
596
624
  {"script"=>"qa_postgres_migrate", "section"=>"QualityControl", "aggregate"=>"Sweep", "verb"=>"migrate_ledger_from_heki", "passes"=>"[aggregate …] --force", "note"=>"a dry run without --force"}.freeze,
597
625
  {"script"=>"qa_postgres_role", "section"=>"QualityControl", "aggregate"=>"Sweep", "verb"=>"create_ledger_role"}.freeze,
626
+ {"script"=>"qa_main_gate", "section"=>"QualityControl", "aggregate"=>"MainCheck", "verb"=>"check_main"}.freeze,
627
+ {"script"=>"qa_fix_main_bug", "section"=>"QualityControl", "aggregate"=>"Bug", "verb"=>"fix_and_land", "passes"=>"--bug BUG#n"}.freeze,
598
628
  {"script"=>"qa_concurrency_racer", "section"=>"QualityControl", "aggregate"=>"Sweep", "verb"=>"race", "note"=>"not user-facing; ProcessPool starts it"}.freeze
599
629
  ].freeze,
600
630
  "RustReservedWord" => [
@@ -0,0 +1,48 @@
1
+ module Hecks
2
+ module WorkflowPagination
3
+ # Whether a GitHub API call can take its answer from one page and still be right.
4
+ #
5
+ # A list endpoint answers 30 items a page. A call that counts or waits for items, and reads that
6
+ # one page, is right until the list grows past it and then fails without a word.
7
+ module Judge
8
+ # The last path segment of an endpoint that answers an array, or an object holding one.
9
+ LISTS = %w[artifacts runs jobs issues releases pulls commits comments tags branches labels workflows
10
+ check-runs check-suites reviews assets].freeze
11
+
12
+ # Query terms that narrow a list to the item asked for.
13
+ FILTERS = /(?:\A|&)(?:name|head_sha|sha)=/
14
+
15
+ # A call that counts what it reads, or looks one item up by a test.
16
+ COUNTING = /\|\s*length\b|'length'|"length"|wc -l|grep -c|\bcount\b/
17
+
18
+ # A call that waits for an item to show among those it reads.
19
+ WAITING = /select\(|grep -q|startswith|contains\(/
20
+
21
+ # The words that open a loop which polls.
22
+ LOOP = /\b(?:until|while|seq)\b/
23
+
24
+ # A comparison to a fixed number, which bounds how many items the call can need.
25
+ BOUNDED = /(?:=|==|-eq|-ge|-gt|-lt|-le)\s*"?\d+"?/
26
+
27
+ module_function
28
+
29
+ # @param call [Statement] one API call
30
+ # @return [String, nil] what is wrong with it, or nil when one page is enough
31
+ def fault(call)
32
+ return unless LISTS.include?(call.route.split("/").last) && reads_items?(call)
33
+ return if call.text.include?("--paginate") || call.query.match?(FILTERS)
34
+ return if call.query.include?("per_page=100") && call.after.match?(BOUNDED)
35
+
36
+ "counts or waits for the items of #{call.route} from its first page (30 items); " \
37
+ "add --paginate and count the lines it prints, or filter the path with ?name="
38
+ end
39
+
40
+ # @return [Boolean] whether the call counts the items or waits for one among them
41
+ def reads_items?(call)
42
+ return true if call.text.match?(COUNTING)
43
+
44
+ call.text.match?(WAITING) && call.before.match?(LOOP)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,50 @@
1
+ module Hecks
2
+ module WorkflowPagination
3
+ # One GitHub API call written in a workflow: the line it starts on and its text, with the lines
4
+ # a trailing backslash joins, and the lines around it that say what it is used for.
5
+ class Statement
6
+ # What the call is for, read from the lines around it.
7
+ Setting = Struct.new(:before, :after)
8
+
9
+ # How far around a call the lines that say what it is for reach.
10
+ REACH = 6
11
+
12
+ # A GitHub API path: the part after the host, up to the quote or space that ends it.
13
+ PATH = %r{(?:api\.github\.com/)?\b((?:repos|orgs|user|search|enterprises)/[^\s"'\\)]+)}
14
+
15
+ attr_reader :line, :text
16
+
17
+ # @param lines [Array<String>] the file's lines
18
+ # @param index [Integer] where the call starts
19
+ def initialize(lines, index)
20
+ @line = index + 1
21
+ @lines = lines
22
+ @text = joined(index)
23
+ @index = index
24
+ end
25
+
26
+ # @return [String, nil] the path the call reads, with its query
27
+ def path = @text[PATH, 1]
28
+
29
+ # @return [String] the path without its query
30
+ def route = path.to_s.partition("?").first
31
+
32
+ # @return [String] the query of the path
33
+ def query = path.to_s.partition("?").last
34
+
35
+ # @return [String] the lines after the call, where its answer is compared
36
+ def after = @lines[(@index + 1)..(@index + REACH)].to_a.join
37
+
38
+ # @return [String] the lines before the call, where a loop opens
39
+ def before = @lines[[@index - REACH, 0].max...@index].join
40
+
41
+ private
42
+
43
+ def joined(index)
44
+ text = @lines[index].dup
45
+ text << @lines[index += 1] while text.rstrip.end_with?("\\") && @lines[index + 1]
46
+ text
47
+ end
48
+ end
49
+ end
50
+ end