hecks 6.0.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (754) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +19 -12
  3. data/lib/hecks/adapters/driven/claude_code.rb +2 -2
  4. data/lib/hecks/adapters/driven/folder.rb +10 -1
  5. data/lib/hecks/adapters/driven/folder_overlay.rb +15 -0
  6. data/lib/hecks/adapters/driven/heki.rb +1 -1
  7. data/lib/hecks/adapters/driven/in_process_key_vault.rb +1 -1
  8. data/lib/hecks/adapters/driven/memory/outbox_rows.rb +2 -2
  9. data/lib/hecks/adapters/driven/postgres/name_guard.rb +25 -0
  10. data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -3
  11. data/lib/hecks/adapters/driven/postgres/repository.rb +1 -1
  12. data/lib/hecks/adapters/driven/postgres/shared_connection.rb +1 -1
  13. data/lib/hecks/adapters/driven/postgres.rb +3 -0
  14. data/lib/hecks/adapters/driven/postgres_era/boot.rb +28 -16
  15. data/lib/hecks/adapters/driven/postgres_era/class_methods.rb +27 -7
  16. data/lib/hecks/adapters/driven/postgres_era/dialect.rb +10 -5
  17. data/lib/hecks/adapters/driven/postgres_era/field_cache_provisioner.rb +39 -0
  18. data/lib/hecks/adapters/driven/postgres_era/journal.rb +52 -13
  19. data/lib/hecks/adapters/driven/postgres_era/lineage/chain_sql.rb +29 -49
  20. data/lib/hecks/adapters/driven/postgres_era/lineage/direct_sql.rb +73 -0
  21. data/lib/hecks/adapters/driven/postgres_era/lineage/direct_verified.json +10 -0
  22. data/lib/hecks/adapters/driven/postgres_era/lineage/direct_verified.rb +65 -0
  23. data/lib/hecks/adapters/driven/postgres_era/lineage/domain_rename.rb +77 -25
  24. data/lib/hecks/adapters/driven/postgres_era/lineage/domain_rename_state.rb +108 -0
  25. data/lib/hecks/adapters/driven/postgres_era/lineage/era_integrity.rb +11 -6
  26. data/lib/hecks/adapters/driven/postgres_era/lineage/era_store.rb +63 -5
  27. data/lib/hecks/adapters/driven/postgres_era/lineage/layered_sql.rb +64 -0
  28. data/lib/hecks/adapters/driven/postgres_era/lineage/ledger_reset.rb +150 -0
  29. data/lib/hecks/adapters/driven/postgres_era/lineage/mint_provisioning.rb +85 -0
  30. data/lib/hecks/adapters/driven/postgres_era/lineage/mint_transaction.rb +11 -7
  31. data/lib/hecks/adapters/driven/postgres_era/lineage/provisioning.rb +11 -5
  32. data/lib/hecks/adapters/driven/postgres_era/lineage/split_sql.rb +76 -0
  33. data/lib/hecks/adapters/driven/postgres_era/lineage/sql_templates.rb +9 -0
  34. data/lib/hecks/adapters/driven/postgres_era/lineage.rb +10 -2
  35. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/context.rb +23 -3
  36. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/coverage_check.rb +3 -1
  37. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/disposable_ledger.rb +119 -0
  38. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolution.rb +219 -0
  39. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolver.rb +68 -71
  40. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/held_era.rb +68 -0
  41. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/ledger_change.rb +63 -0
  42. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/merge_coordinator.rb +1 -1
  43. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/mint_decision.rb +163 -0
  44. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/mint_request.rb +24 -0
  45. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/minter.rb +59 -21
  46. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/refusals.rb +24 -11
  47. data/lib/hecks/adapters/driven/postgres_era/lineage_manager.rb +40 -6
  48. data/lib/hecks/adapters/driven/postgres_era/shared_tables.rb +32 -0
  49. data/lib/hecks/adapters/driven/postgres_era.adapter +12 -0
  50. data/lib/hecks/adapters/driven/postgres_era.rb +25 -10
  51. data/lib/hecks/adapters/driven/prism.rb +0 -1
  52. data/lib/hecks/adapters/driven/sql_query_builder.rb +1 -0
  53. data/lib/hecks/adapters/driven/sqlite/dispatch_claims.rb +1 -1
  54. data/lib/hecks/adapters/driven/sqlite/name_guard.rb +25 -0
  55. data/lib/hecks/adapters/driven/sqlite/outbox.rb +2 -2
  56. data/lib/hecks/adapters/driven/sqlite/repository.rb +1 -1
  57. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +20 -0
  58. data/lib/hecks/adapters/driven/sqlite.rb +9 -1
  59. data/lib/hecks/adapters/driven/tenant_provisioner.rb +1 -1
  60. data/lib/hecks/adapters/driven/worktree_overlay.rb +117 -0
  61. data/lib/hecks/adapters/driving/cli/shorthand.rb +5 -1
  62. data/lib/hecks/adapters/driving/cli.rb +1 -1
  63. data/lib/hecks/adapters/driving/cli_runner/answers.rb +77 -22
  64. data/lib/hecks/adapters/driving/cli_runner/bang_rule.rb +35 -0
  65. data/lib/hecks/adapters/driving/cli_runner/completion_words.rb +36 -0
  66. data/lib/hecks/adapters/driving/cli_runner/json_words.rb +55 -0
  67. data/lib/hecks/adapters/driving/cli_runner/name_index.rb +63 -0
  68. data/lib/hecks/adapters/driving/cli_runner/read_context.rb +32 -0
  69. data/lib/hecks/adapters/driving/cli_runner/renamed_names.rb +49 -0
  70. data/lib/hecks/adapters/driving/cli_runner/resolution.rb +43 -17
  71. data/lib/hecks/adapters/driving/cli_runner/resume_words.rb +63 -0
  72. data/lib/hecks/adapters/driving/cli_runner/run_reference.rb +66 -0
  73. data/lib/hecks/adapters/driving/cli_runner/run_replay.rb +118 -0
  74. data/lib/hecks/adapters/driving/cli_runner/search_words.rb +35 -0
  75. data/lib/hecks/adapters/driving/cli_runner/settling.rb +6 -5
  76. data/lib/hecks/adapters/driving/cli_runner/streaming.rb +11 -10
  77. data/lib/hecks/adapters/driving/cli_runner/suggestions.rb +1 -1
  78. data/lib/hecks/adapters/driving/cli_runner/tour_words.rb +77 -0
  79. data/lib/hecks/adapters/driving/cli_runner/verb_names.rb +36 -4
  80. data/lib/hecks/adapters/driving/cli_runner/verbosity.rb +75 -0
  81. data/lib/hecks/adapters/driving/cli_runner.rb +106 -7
  82. data/lib/hecks/adapters/driving/context_line.rb +85 -0
  83. data/lib/hecks/adapters/driving/exit_status.rb +31 -0
  84. data/lib/hecks/adapters/driving/launcher_options.rb +7 -5
  85. data/lib/hecks/adapters/driving/mcp/progress_sink.rb +45 -0
  86. data/lib/hecks/adapters/driving/mcp/tool_calls.rb +7 -5
  87. data/lib/hecks/adapters/driving/mcp.rb +25 -5
  88. data/lib/hecks/adapters/driving/mcp_scope/argument_policy.rb +40 -7
  89. data/lib/hecks/adapters/driving/mcp_scope.rb +8 -7
  90. data/lib/hecks/adapters/driving/ruby/aggregate_module/hooks.rb +154 -0
  91. data/lib/hecks/adapters/driving/ruby/aggregate_module.rb +64 -93
  92. data/lib/hecks/adapters/driving/usage_log.rb +146 -0
  93. data/lib/hecks/adapters/driving/write_guard.rb +55 -0
  94. data/lib/hecks/adapters/driving.rb +0 -1
  95. data/lib/hecks/behaviors/dsl.rb +5 -1
  96. data/lib/hecks/behaviors/expectations/boot.rb +0 -1
  97. data/lib/hecks/bluebook/acknowledgements.rb +1 -1
  98. data/lib/hecks/bluebook/aggregate.rb +21 -18
  99. data/lib/hecks/bluebook/assembly/contracts/sagas.rb +2 -0
  100. data/lib/hecks/bluebook/assembly/contracts/structure.rb +18 -13
  101. data/lib/hecks/bluebook/behaviour/aggregate.rb +27 -3
  102. data/lib/hecks/bluebook/command.rb +16 -5
  103. data/lib/hecks/bluebook/declaration.rb +32 -4
  104. data/lib/hecks/bluebook/domain_port.rb +7 -3
  105. data/lib/hecks/bluebook/dsl/aggregate_builder/relationships.rb +0 -2
  106. data/lib/hecks/bluebook/dsl/aggregate_builder/renaming.rb +25 -0
  107. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +3 -0
  108. data/lib/hecks/bluebook/dsl/attribute_collector.rb +0 -1
  109. data/lib/hecks/bluebook/dsl/audience_word.rb +40 -0
  110. data/lib/hecks/bluebook/dsl/bluebook_builder/metadata.rb +56 -0
  111. data/lib/hecks/bluebook/dsl/bluebook_builder/modules.rb +80 -0
  112. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/correlation_keys.rb +51 -0
  113. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +1 -0
  114. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +17 -34
  115. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +8 -0
  116. data/lib/hecks/bluebook/dsl/command_builder.rb +13 -3
  117. data/lib/hecks/bluebook/dsl/entity_builder.rb +0 -2
  118. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +6 -4
  119. data/lib/hecks/bluebook/dsl/kinds.rb +53 -0
  120. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +9 -2
  121. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +25 -15
  122. data/lib/hecks/bluebook/dsl/translation_builder.rb +16 -1
  123. data/lib/hecks/bluebook/dsl/word_gate.rb +1 -1
  124. data/lib/hecks/bluebook/dsl.rb +1 -0
  125. data/lib/hecks/bluebook/meta_validator/judge/identity.rb +9 -4
  126. data/lib/hecks/bluebook/meta_validator/plan/category.rb +10 -2
  127. data/lib/hecks/bluebook/meta_validator/plan/verbs.rb +9 -0
  128. data/lib/hecks/bluebook/meta_validator/plan.rb +2 -1
  129. data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +3 -1
  130. data/lib/hecks/bluebook/meta_validator/reconstruction/reading.rb +7 -0
  131. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +7 -2
  132. data/lib/hecks/bluebook/meta_validator/shapes.rb +3 -0
  133. data/lib/hecks/bluebook/meta_validator/syntax_boot/disk_cache.rb +1 -1
  134. data/lib/hecks/bluebook/model_check/aggregate_checks.rb +27 -0
  135. data/lib/hecks/bluebook/model_check/ask_checks.rb +25 -0
  136. data/lib/hecks/bluebook/model_check/reaction_chains.rb +114 -0
  137. data/lib/hecks/bluebook/model_check/reaction_cycles.rb +53 -0
  138. data/lib/hecks/bluebook/model_check/reaction_depth_checks.rb +58 -0
  139. data/lib/hecks/bluebook/model_check/reaction_walk.rb +62 -0
  140. data/lib/hecks/bluebook/model_check.rb +5 -27
  141. data/lib/hecks/bluebook/process_manager.rb +20 -3
  142. data/lib/hecks/bluebook/translation.rb +5 -3
  143. data/lib/hecks/bluebook/translation_plan.rb +9 -2
  144. data/lib/hecks/ci_pipeline/adapters/ci_cache.adapter +7 -0
  145. data/lib/hecks/ci_pipeline/adapters/ci_cache.rb +39 -0
  146. data/lib/hecks/ci_pipeline/adapters/ci_runner.adapter +7 -0
  147. data/lib/hecks/ci_pipeline/adapters/ci_runner.rb +55 -0
  148. data/lib/hecks/ci_pipeline/ci_pipeline.behaviors +322 -0
  149. data/lib/hecks/ci_pipeline/ci_pipeline.bluebook +938 -0
  150. data/lib/hecks/ci_pipeline/ci_pipeline.hecksagon +12 -0
  151. data/lib/hecks/ci_pipeline/ci_pipeline.ports.hecksagon +16 -0
  152. data/lib/hecks/ci_speed/adapters/ci_reader.adapter +7 -0
  153. data/lib/hecks/ci_speed/adapters/ci_reader.rb +141 -0
  154. data/lib/hecks/ci_speed/adapters/local_runner/answer.rb +41 -0
  155. data/lib/hecks/ci_speed/adapters/local_runner/catalog.rb +89 -0
  156. data/lib/hecks/ci_speed/adapters/local_runner/checkouts.rb +89 -0
  157. data/lib/hecks/ci_speed/adapters/local_runner/launcher.rb +69 -0
  158. data/lib/hecks/ci_speed/adapters/local_runner/load_average.rb +38 -0
  159. data/lib/hecks/ci_speed/adapters/local_runner/refs.rb +39 -0
  160. data/lib/hecks/ci_speed/adapters/local_runner/refused.rb +11 -0
  161. data/lib/hecks/ci_speed/adapters/local_runner/verdict.rb +71 -0
  162. data/lib/hecks/ci_speed/adapters/local_runner.adapter +7 -0
  163. data/lib/hecks/ci_speed/adapters/local_runner.rb +168 -0
  164. data/lib/hecks/ci_speed/adapters/replayed_runner.rb +39 -0
  165. data/lib/hecks/ci_speed/ci_speed.behaviors +341 -0
  166. data/lib/hecks/ci_speed/ci_speed.bluebook +1073 -0
  167. data/lib/hecks/ci_speed/ci_speed.hecksagon +11 -0
  168. data/lib/hecks/ci_speed/ci_speed.ports.hecksagon +21 -0
  169. data/lib/hecks/ci_workflows/ci_workflows.behaviors +13 -0
  170. data/lib/hecks/ci_workflows/ci_workflows.bluebook +173 -0
  171. data/lib/hecks/ci_workflows/ci_workflows.hecksagon +15 -0
  172. data/lib/hecks/coder/coder.bluebook +385 -0
  173. data/lib/hecks/coder/coder.hecksagon +12 -0
  174. data/lib/hecks/command_names/check.rb +39 -0
  175. data/lib/hecks/command_names/extractor.rb +67 -0
  176. data/lib/hecks/command_names/index.rb +40 -0
  177. data/lib/hecks/command_names/resolution.rb +81 -0
  178. data/lib/hecks/command_names/scan.rb +54 -0
  179. data/lib/hecks/command_names/sources.rb +73 -0
  180. data/lib/hecks/command_names.rb +26 -0
  181. data/lib/hecks/composer/jobs.rb +1 -1
  182. data/lib/hecks/composer/toolbox.rb +8 -1
  183. data/lib/hecks/corpus/generated_key.rb +205 -0
  184. data/lib/hecks/corpus/listing.rb +34 -0
  185. data/lib/hecks/corpus/rust.rb +27 -11
  186. data/lib/hecks/corpus/sources.rb +2 -1
  187. data/lib/hecks/corpus.rb +37 -42
  188. data/lib/hecks/deprecation.rb +23 -0
  189. data/lib/hecks/doc/reference/readme.rb +1 -1
  190. data/lib/hecks/doc/reference/rendering.rb +2 -2
  191. data/lib/hecks/doc/reference.rb +1 -1
  192. data/lib/hecks/embryonaut_bluebook/manifest.rb +1 -1
  193. data/lib/hecks/fixer/fixer.bluebook +240 -0
  194. data/lib/hecks/fixer/fixer.hecksagon +17 -0
  195. data/lib/hecks/framework_bluebooks.rb +32 -7
  196. data/lib/hecks/fuzzing/concurrent_dispatch/world_copy.rb +1 -0
  197. data/lib/hecks/fuzzing/isolated_boot/postgres_scratch.rb +11 -12
  198. data/lib/hecks/fuzzing/isolated_boot/worlds.rb +23 -5
  199. data/lib/hecks/fuzzing/isolated_boot.rb +1 -1
  200. data/lib/hecks/fuzzing/mutation/checks.rb +3 -3
  201. data/lib/hecks/grammar/translation.bluebook +1 -1
  202. data/lib/hecks/grammar/translation_rules.json +64 -0
  203. data/lib/hecks/hecks/adapter_words.json +7 -0
  204. data/lib/hecks/hecks/adapters/area_overlap.rb +156 -0
  205. data/lib/hecks/hecks/adapters/claude_agents.rb +8 -3
  206. data/lib/hecks/hecks/adapters/codebase/batch_runs.rb +60 -0
  207. data/lib/hecks/hecks/adapters/codebase/changed_specs.rb +52 -0
  208. data/lib/hecks/hecks/adapters/codebase/codemods.rb +3 -2
  209. data/lib/hecks/hecks/adapters/codebase/conformance.rb +14 -1
  210. data/lib/hecks/hecks/adapters/codebase/corpus_queries.rb +53 -0
  211. data/lib/hecks/hecks/adapters/codebase/generated_keys.rb +31 -0
  212. data/lib/hecks/hecks/adapters/codebase/impacted_specs.rb +110 -0
  213. data/lib/hecks/hecks/adapters/codebase/language.rb +2 -2
  214. data/lib/hecks/hecks/adapters/codebase/launcher_text.rb +39 -0
  215. data/lib/hecks/hecks/adapters/codebase/minitest_runs.rb +52 -0
  216. data/lib/hecks/hecks/adapters/codebase/regeneration.rb +51 -8
  217. data/lib/hecks/hecks/adapters/codebase/run_options.rb +35 -0
  218. data/lib/hecks/hecks/adapters/codebase/scripting.rb +39 -0
  219. data/lib/hecks/hecks/adapters/codebase/search.rb +1 -1
  220. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +79 -51
  221. data/lib/hecks/hecks/adapters/codebase/spec_files/report.rb +71 -0
  222. data/lib/hecks/hecks/adapters/codebase/spec_files/shared_run.rb +73 -0
  223. data/lib/hecks/hecks/adapters/codebase/spec_files.rb +95 -0
  224. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +53 -4
  225. data/lib/hecks/hecks/adapters/codebase/test_scope.rb +105 -0
  226. data/lib/hecks/hecks/adapters/codebase/test_suite.rb +48 -34
  227. data/lib/hecks/hecks/adapters/console_capture.rb +1 -1
  228. data/lib/hecks/hecks/adapters/cost_explorer.rb +9 -1
  229. data/lib/hecks/hecks/adapters/dispatching/brief_text.rb +51 -0
  230. data/lib/hecks/hecks/adapters/dispatching/launcher.rb +97 -0
  231. data/lib/hecks/hecks/adapters/dispatching/plan.rb +82 -0
  232. data/lib/hecks/hecks/adapters/dispatching/rows.rb +66 -0
  233. data/lib/hecks/hecks/adapters/dispatching/settings.rb +81 -0
  234. data/lib/hecks/hecks/adapters/dispatching/settler.rb +40 -0
  235. data/lib/hecks/hecks/adapters/dispatching.adapter +7 -0
  236. data/lib/hecks/hecks/adapters/dispatching.rb +93 -0
  237. data/lib/hecks/hecks/adapters/doctor_reading/report.rb +27 -0
  238. data/lib/hecks/hecks/adapters/doctor_reading.adapter +7 -0
  239. data/lib/hecks/hecks/adapters/doctor_reading.rb +161 -0
  240. data/lib/hecks/hecks/adapters/git_checkout.rb +1 -1
  241. data/lib/hecks/hecks/adapters/git_commit.adapter +7 -0
  242. data/lib/hecks/hecks/adapters/git_commit.rb +61 -0
  243. data/lib/hecks/hecks/adapters/git_landing/finisher.rb +82 -0
  244. data/lib/hecks/hecks/adapters/git_landing/foreign_hold.rb +111 -0
  245. data/lib/hecks/hecks/adapters/git_landing/line.rb +171 -0
  246. data/lib/hecks/hecks/adapters/git_landing/lineup.rb +98 -0
  247. data/lib/hecks/hecks/adapters/git_landing/merger.rb +1 -1
  248. data/lib/hecks/hecks/adapters/git_landing/numbering.rb +54 -0
  249. data/lib/hecks/hecks/adapters/git_landing/rivals.rb +59 -0
  250. data/lib/hecks/hecks/adapters/git_landing/ticket.rb +156 -0
  251. data/lib/hecks/hecks/adapters/git_landing/tidy.rb +147 -0
  252. data/lib/hecks/hecks/adapters/git_landing/train.rb +104 -0
  253. data/lib/hecks/hecks/adapters/git_landing/verdict.rb +64 -0
  254. data/lib/hecks/hecks/adapters/git_landing/waiting.rb +120 -0
  255. data/lib/hecks/hecks/adapters/git_landing.rb +106 -20
  256. data/lib/hecks/hecks/adapters/git_main_pull.rb +99 -0
  257. data/lib/hecks/hecks/adapters/git_rehearsal/bench.rb +82 -0
  258. data/lib/hecks/hecks/adapters/git_rehearsal/due.rb +84 -0
  259. data/lib/hecks/hecks/adapters/git_rehearsal/impacted/skips.rb +47 -0
  260. data/lib/hecks/hecks/adapters/git_rehearsal/impacted/spec_run.rb +75 -0
  261. data/lib/hecks/hecks/adapters/git_rehearsal/impacted.rb +181 -0
  262. data/lib/hecks/hecks/adapters/git_rehearsal/line.rb +76 -0
  263. data/lib/hecks/hecks/adapters/git_rehearsal/reading.rb +24 -0
  264. data/lib/hecks/hecks/adapters/git_rehearsal/record.rb +146 -0
  265. data/lib/hecks/hecks/adapters/git_rehearsal/spec_map/corpus.rb +25 -0
  266. data/lib/hecks/hecks/adapters/git_rehearsal/spec_map/needles.rb +61 -0
  267. data/lib/hecks/hecks/adapters/git_rehearsal/spec_map.rb +105 -0
  268. data/lib/hecks/hecks/adapters/git_rehearsal/stages.rb +118 -0
  269. data/lib/hecks/hecks/adapters/git_rehearsal.adapter +7 -0
  270. data/lib/hecks/hecks/adapters/git_rehearsal.rb +141 -0
  271. data/lib/hecks/hecks/adapters/git_train/bench.rb +15 -15
  272. data/lib/hecks/hecks/adapters/git_train/branch_guard.rb +62 -0
  273. data/lib/hecks/hecks/adapters/git_train/carriage.rb +27 -28
  274. data/lib/hecks/hecks/adapters/git_train/launcher_shape.rb +75 -0
  275. data/lib/hecks/hecks/adapters/git_train/mint_step.rb +47 -0
  276. data/lib/hecks/hecks/adapters/git_train/settlement.rb +167 -0
  277. data/lib/hecks/hecks/adapters/git_train.rb +73 -15
  278. data/lib/hecks/hecks/adapters/git_worktree_add.adapter +7 -0
  279. data/lib/hecks/hecks/adapters/git_worktree_add.rb +68 -0
  280. data/lib/hecks/hecks/adapters/github_pull_requests.adapter +7 -0
  281. data/lib/hecks/hecks/adapters/github_pull_requests.rb +109 -0
  282. data/lib/hecks/hecks/adapters/host_http.rb +6 -6
  283. data/lib/hecks/hecks/adapters/in_process_boot.rb +10 -8
  284. data/lib/hecks/hecks/adapters/in_process_operations.rb +11 -17
  285. data/lib/hecks/hecks/adapters/in_process_undo.rb +17 -0
  286. data/lib/hecks/hecks/adapters/journal_store/changes.rb +13 -4
  287. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +28 -15
  288. data/lib/hecks/hecks/adapters/journal_store/examination.rb +17 -1
  289. data/lib/hecks/hecks/adapters/journal_store/held_domain/renaming.rb +45 -0
  290. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +31 -5
  291. data/lib/hecks/hecks/adapters/journal_store/held_mint.rb +128 -0
  292. data/lib/hecks/hecks/adapters/journal_store/readings/attestation.rb +1 -1
  293. data/lib/hecks/hecks/adapters/journal_store/readings/boot_status.rb +58 -0
  294. data/lib/hecks/hecks/adapters/journal_store/readings/composition.rb +39 -0
  295. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/outcomes.rb +76 -0
  296. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/postgres_reader.rb +44 -0
  297. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/reader.rb +64 -0
  298. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/report.rb +102 -0
  299. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/sqlite_reader.rb +43 -0
  300. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/stores.rb +80 -0
  301. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/subscribers.rb +72 -0
  302. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/summary.rb +39 -0
  303. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace.rb +39 -0
  304. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/command_line.rb +57 -0
  305. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/edge_guards.rb +107 -0
  306. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/inspection.rb +94 -0
  307. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/plan.rb +66 -0
  308. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/report.rb +72 -0
  309. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/store.rb +34 -0
  310. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/watermark_guards.rb +86 -0
  311. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/world.rb +66 -0
  312. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan.rb +36 -0
  313. data/lib/hecks/hecks/adapters/journal_store/readings/projection_audit.rb +64 -0
  314. data/lib/hecks/hecks/adapters/journal_store/readings/scaffolding.rb +3 -3
  315. data/lib/hecks/hecks/adapters/journal_store/readings/sqlite_status/database_reading.rb +113 -0
  316. data/lib/hecks/hecks/adapters/journal_store/readings/sqlite_status/read_only.rb +33 -0
  317. data/lib/hecks/hecks/adapters/journal_store/readings/sqlite_status.rb +32 -0
  318. data/lib/hecks/hecks/adapters/journal_store/readings.rb +13 -1
  319. data/lib/hecks/hecks/adapters/journal_store/reconcile_report.rb +60 -0
  320. data/lib/hecks/hecks/adapters/journal_store/reconciliation.rb +121 -0
  321. data/lib/hecks/hecks/adapters/journal_store/translation_write/shape_edge.rb +59 -0
  322. data/lib/hecks/hecks/adapters/journal_store/translation_write.rb +123 -0
  323. data/lib/hecks/hecks/adapters/journal_store.rb +16 -0
  324. data/lib/hecks/hecks/adapters/landed_work.adapter +7 -0
  325. data/lib/hecks/hecks/adapters/landed_work.rb +52 -0
  326. data/lib/hecks/hecks/adapters/local_files.rb +6 -6
  327. data/lib/hecks/hecks/adapters/process_pool.rb +3 -2
  328. data/lib/hecks/hecks/adapters/push_size.rb +57 -0
  329. data/lib/hecks/hecks/adapters/qa_quiescing.adapter +7 -0
  330. data/lib/hecks/hecks/adapters/qa_quiescing.rb +57 -0
  331. data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +30 -3
  332. data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +63 -3
  333. data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +29 -6
  334. data/lib/hecks/hecks/adapters/rehearsal/subject.rb +11 -5
  335. data/lib/hecks/hecks/adapters/rust_toolchain.rb +10 -1
  336. data/lib/hecks/hecks/adapters/rust_workspace.rb +1 -1
  337. data/lib/hecks/hecks/adapters/settings_reading/disposable_ledger.rb +32 -0
  338. data/lib/hecks/hecks/adapters/settings_reading/push_nudge.rb +26 -0
  339. data/lib/hecks/hecks/adapters/settings_reading/stores.rb +76 -0
  340. data/lib/hecks/hecks/adapters/settings_reading/test_scope.rb +28 -0
  341. data/lib/hecks/hecks/adapters/settings_reading.rb +28 -2
  342. data/lib/hecks/hecks/adapters/started_work.rb +42 -0
  343. data/lib/hecks/hecks/adapters/terminal.rb +12 -10
  344. data/lib/hecks/hecks/adapters/where_reading.adapter +7 -0
  345. data/lib/hecks/hecks/adapters/where_reading.rb +64 -0
  346. data/lib/hecks/hecks/adapters/work_areas.rb +57 -0
  347. data/lib/hecks/hecks/adapters/work_limits.rb +57 -0
  348. data/lib/hecks/hecks/build/build.bluebook +576 -0
  349. data/lib/hecks/hecks/check/check.bluebook +966 -0
  350. data/lib/hecks/hecks/codebase.behaviors +61 -5
  351. data/lib/hecks/hecks/composer.behaviors +1 -1
  352. data/lib/hecks/hecks/context_map.hecksagon +1 -1
  353. data/lib/hecks/hecks/custodian.behaviors +33 -7
  354. data/lib/hecks/hecks/delegate/delegate.bluebook +355 -0
  355. data/lib/hecks/hecks/deliver/deliver.bluebook +945 -0
  356. data/lib/hecks/hecks/deploy.behaviors +1 -1
  357. data/lib/hecks/hecks/evolve/evolve.bluebook +788 -0
  358. data/lib/hecks/hecks/find/find.bluebook +81 -0
  359. data/lib/hecks/hecks/hecks.behaviors +1 -1
  360. data/lib/hecks/hecks/hecks.bluebook +0 -133
  361. data/lib/hecks/hecks/hecks.contextmap +2 -0
  362. data/lib/hecks/hecks/hecks.hecksagon +185 -29
  363. data/lib/hecks/hecks/hecks.world +35 -9
  364. data/lib/hecks/hecks/implicit_moves.json +24 -0
  365. data/lib/hecks/hecks/migrate/migrate.bluebook +1066 -0
  366. data/lib/hecks/hecks/operate/operate.bluebook +695 -0
  367. data/lib/hecks/hecks/quiesce/quiesce.bluebook +117 -0
  368. data/lib/hecks/hecks/rehearse/rehearse.bluebook +133 -0
  369. data/lib/hecks/hecks/release/release.bluebook +916 -0
  370. data/lib/hecks/hecks/serve/serve.bluebook +134 -0
  371. data/lib/hecks/hecks/shapes.json +1 -15
  372. data/lib/hecks/hecks/site.behaviors +1 -1
  373. data/lib/hecks/hecks/start/start.bluebook +194 -0
  374. data/lib/hecks/hecks/test/test.bluebook +638 -0
  375. data/lib/hecks/hecks/tickets.world +14 -0
  376. data/lib/hecks/language/bluebook/aggregate.bluebook +22 -0
  377. data/lib/hecks/language/bluebook/bluebook.bluebook +34 -0
  378. data/lib/hecks/language/bluebook/command.bluebook +35 -0
  379. data/lib/hecks/language/bluebook/process_manager.bluebook +14 -1
  380. data/lib/hecks/language/bluebook/vocabulary.bluebook +174 -54
  381. data/lib/hecks/language/hecksagon/domain_port.bluebook +1 -0
  382. data/lib/hecks/language/hecksagon/port_operation.bluebook +14 -0
  383. data/lib/hecks/language/kinds/run.kind +120 -0
  384. data/lib/hecks/language/oidc.json +10 -0
  385. data/lib/hecks/language/translation/translation_aggregate.bluebook +24 -0
  386. data/lib/hecks/module_folders.rb +31 -0
  387. data/lib/hecks/ports/key_vault.rb +1 -1
  388. data/lib/hecks/ports/persistence/append_only.rb +26 -8
  389. data/lib/hecks/ports/persistence/binding_policy.rb +3 -1
  390. data/lib/hecks/ports/persistence/codec_boundary.rb +1 -1
  391. data/lib/hecks/ports/persistence/mint_door.rb +74 -0
  392. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +6 -5
  393. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +5 -1
  394. data/lib/hecks/ports/persistence/plugins/era/era_status.rb +48 -0
  395. data/lib/hecks/ports/persistence/plugins/era/projected_bluebook.rb +127 -0
  396. data/lib/hecks/ports/persistence/plugins/era/translation/additive_shape.rb +107 -0
  397. data/lib/hecks/ports/persistence/plugins/era/translation/compose.rb +155 -0
  398. data/lib/hecks/ports/persistence/plugins/era/translation/compose_render.rb +79 -0
  399. data/lib/hecks/ports/persistence/plugins/era/translation/edge_files.rb +49 -0
  400. data/lib/hecks/ports/persistence/plugins/era/translation/edge_route.rb +61 -0
  401. data/lib/hecks/ports/persistence/plugins/era/translation/implicit_edge.rb +67 -0
  402. data/lib/hecks/ports/persistence/plugins/era/translation/reconcile.rb +130 -0
  403. data/lib/hecks/ports/persistence/plugins/era/translation/reconcile_files.rb +35 -0
  404. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +13 -5
  405. data/lib/hecks/ports/persistence/plugins/era/translation.rb +5 -0
  406. data/lib/hecks/ports/persistence/plugins/era.rb +1 -0
  407. data/lib/hecks/ports/persistence/repository_factory.rb +11 -3
  408. data/lib/hecks/ports/persistence/stored_name_guard.rb +36 -0
  409. data/lib/hecks/ports/persistence.rb +2 -0
  410. data/lib/hecks/projections/ci_pipeline/table/checks.rb +137 -0
  411. data/lib/hecks/projections/ci_pipeline/table/lookup.rb +59 -0
  412. data/lib/hecks/projections/ci_pipeline/table/refusals.rb +58 -0
  413. data/lib/hecks/projections/ci_pipeline/table/rows.rb +119 -0
  414. data/lib/hecks/projections/ci_pipeline/table/tree.rb +30 -0
  415. data/lib/hecks/projections/ci_pipeline/table/typing.rb +92 -0
  416. data/lib/hecks/projections/ci_pipeline/table.rb +112 -0
  417. data/lib/hecks/projections/ci_pipeline/workflows.rb +162 -0
  418. data/lib/hecks/projections/ci_pipeline/yaml_text.rb +104 -0
  419. data/lib/hecks/projections/deploy/box/hosting.rb +1 -1
  420. data/lib/hecks/projections/deploy/box/roll_recipe.rb +1 -1
  421. data/lib/hecks/projections/deploy/box/roll_scripts.rb +1 -1
  422. data/lib/hecks/projections/deploy/box.rb +1 -1
  423. data/lib/hecks/projections/deploy/templates/fargate/Makefile.tmpl +1 -1
  424. data/lib/hecks/projections/deploy/templates/lambda/Makefile.tmpl +3 -3
  425. data/lib/hecks/projections/undo.rb +46 -0
  426. data/lib/hecks/projections.rb +2 -0
  427. data/lib/hecks/projector/cli_projector/claims.rb +11 -0
  428. data/lib/hecks/projector/cli_projector/command_help.rb +6 -1
  429. data/lib/hecks/projector/cli_projector/command_specs.rb +11 -1
  430. data/lib/hecks/projector/cli_projector/completion.rb +87 -0
  431. data/lib/hecks/projector/cli_projector/everyday.rb +40 -0
  432. data/lib/hecks/projector/cli_projector/json_listing.rb +77 -0
  433. data/lib/hecks/projector/cli_projector/listing.rb +1 -1
  434. data/lib/hecks/projector/cli_projector/modules.rb +39 -0
  435. data/lib/hecks/projector/cli_projector/query_specs.rb +1 -0
  436. data/lib/hecks/projector/cli_projector/renames.rb +58 -0
  437. data/lib/hecks/projector/cli_projector/search.rb +74 -0
  438. data/lib/hecks/projector/cli_projector/usage.rb +23 -6
  439. data/lib/hecks/projector/cli_projector.rb +24 -1
  440. data/lib/hecks/quality_control/adapters/ci_head.adapter +8 -0
  441. data/lib/hecks/quality_control/adapters/image_roll.adapter +9 -0
  442. data/lib/hecks/quality_control/adapters/image_roll.rb +158 -0
  443. data/lib/hecks/quality_control/adapters/main_maintenance.adapter +8 -0
  444. data/lib/hecks/quality_control/adapters/main_maintenance.rb +275 -0
  445. data/lib/hecks/quality_control/adapters/pump_tools.adapter +7 -0
  446. data/lib/hecks/quality_control/adapters/pump_tools.rb +18 -0
  447. data/lib/hecks/quality_control/adapters/push_due_reader.adapter +8 -0
  448. data/lib/hecks/quality_control/adapters/push_due_reader.rb +99 -0
  449. data/lib/hecks/quality_control/adapters/qa_auto_mint.rb +183 -0
  450. data/lib/hecks/quality_control/adapters/qa_era_mint.rb +94 -0
  451. data/lib/hecks/quality_control/adapters/qa_quiesce_marker.rb +126 -0
  452. data/lib/hecks/quality_control/adapters/run_keys.rb +36 -0
  453. data/lib/hecks/quality_control/adapters/run_reader.adapter +7 -0
  454. data/lib/hecks/quality_control/adapters/run_reader.rb +188 -0
  455. data/lib/hecks/quality_control/cli/child.rb +1 -0
  456. data/lib/hecks/quality_control/cli/qa_discover_external_domains/scanning.rb +1 -1
  457. data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +3 -3
  458. data/lib/hecks/quality_control/cli/qa_event_pump/attached.rb +67 -0
  459. data/lib/hecks/quality_control/cli/qa_event_pump/consumer.rb +103 -0
  460. data/lib/hecks/quality_control/cli/qa_event_pump/cursors.rb +60 -0
  461. data/lib/hecks/quality_control/cli/qa_event_pump/reactions.rb +46 -0
  462. data/lib/hecks/quality_control/cli/qa_event_pump/reader.rb +30 -0
  463. data/lib/hecks/quality_control/cli/qa_event_pump.rb +76 -0
  464. data/lib/hecks/quality_control/cli/qa_fix_main_bug/publishing.rb +79 -0
  465. data/lib/hecks/quality_control/cli/qa_fix_main_bug.rb +167 -0
  466. data/lib/hecks/quality_control/cli/qa_generated_domains/evaluation.rb +1 -1
  467. data/lib/hecks/quality_control/cli/qa_generated_domains/promotion.rb +3 -3
  468. data/lib/hecks/quality_control/cli/qa_main_gate/gate_run.rb +52 -0
  469. data/lib/hecks/quality_control/cli/qa_main_gate/logging.rb +70 -0
  470. data/lib/hecks/quality_control/cli/qa_main_gate/shell.rb +47 -0
  471. data/lib/hecks/quality_control/cli/qa_main_gate/sweeping.rb +59 -0
  472. data/lib/hecks/quality_control/cli/qa_main_gate/worktree.rb +62 -0
  473. data/lib/hecks/quality_control/cli/qa_main_gate.rb +135 -0
  474. data/lib/hecks/quality_control/cli/qa_postgres_role.rb +1 -1
  475. data/lib/hecks/quality_control/cli/qa_pr_check/checking.rb +2 -3
  476. data/lib/hecks/quality_control/cli/qa_push_nudge.rb +48 -0
  477. data/lib/hecks/quality_control/cli/qa_seed_angles/seed.rb +1 -1
  478. data/lib/hecks/quality_control/cli/qa_sweep/seat.rb +1 -1
  479. data/lib/hecks/quality_control/cli/qa_tick/event_pump_step.rb +34 -0
  480. data/lib/hecks/quality_control/cli/qa_tick/output.rb +16 -1
  481. data/lib/hecks/quality_control/cli/qa_tick/push_nudge_step.rb +28 -0
  482. data/lib/hecks/quality_control/cli/qa_tick/quiesce_guard.rb +51 -0
  483. data/lib/hecks/quality_control/cli/qa_tick.rb +36 -8
  484. data/lib/hecks/quality_control/quality_control.behaviors +65 -0
  485. data/lib/hecks/quality_control/quality_control.bluebook +1131 -11
  486. data/lib/hecks/quality_control/quality_control.hecksagon +11 -0
  487. data/lib/hecks/quality_control/quality_control.ports.hecksagon +138 -0
  488. data/lib/hecks/query_ir/touchpoints.rb +5 -7
  489. data/lib/hecks/refused.rb +21 -0
  490. data/lib/hecks/release/approval.rb +6 -3
  491. data/lib/hecks/release/conditions.rb +46 -0
  492. data/lib/hecks/release/runner/gem_publisher.rb +4 -4
  493. data/lib/hecks/release/version_commit.rb +48 -0
  494. data/lib/hecks/runtime/command_interpreter/hydration.rb +5 -4
  495. data/lib/hecks/runtime/command_interpreter/persisting.rb +11 -3
  496. data/lib/hecks/runtime/command_interpreter.rb +2 -2
  497. data/lib/hecks/runtime/command_rules/admissibility.rb +0 -2
  498. data/lib/hecks/runtime/command_rules/emission.rb +0 -1
  499. data/lib/hecks/runtime/dependency_planning/expression_reads.rb +0 -1
  500. data/lib/hecks/runtime/dispatcher/planning.rb +24 -0
  501. data/lib/hecks/runtime/dispatcher/routing.rb +6 -0
  502. data/lib/hecks/runtime/dispatcher/value_routing.rb +54 -0
  503. data/lib/hecks/runtime/dispatcher.rb +7 -1
  504. data/lib/hecks/runtime/dry_run_plan.rb +60 -0
  505. data/lib/hecks/runtime/entity_element/location.rb +0 -1
  506. data/lib/hecks/runtime/entity_element/mutations.rb +0 -1
  507. data/lib/hecks/runtime/entity_interpreter/locating.rb +5 -0
  508. data/lib/hecks/runtime/entity_interpreter.rb +0 -1
  509. data/lib/hecks/runtime/errors.rb +26 -0
  510. data/lib/hecks/runtime/instance.rb +0 -1
  511. data/lib/hecks/runtime/invocation_builder.rb +0 -1
  512. data/lib/hecks/runtime/outbox/consumer_runner.rb +9 -1
  513. data/lib/hecks/runtime/outbox/relay.rb +25 -4
  514. data/lib/hecks/runtime/outbox/runnable.rb +3 -1
  515. data/lib/hecks/runtime/outbox.rb +6 -2
  516. data/lib/hecks/runtime/policy_interpreter/fan_out.rb +18 -2
  517. data/lib/hecks/runtime/policy_interpreter.rb +17 -9
  518. data/lib/hecks/runtime/port_operation_interpreter.rb +21 -7
  519. data/lib/hecks/runtime/query_interpreter/arguments.rb +6 -5
  520. data/lib/hecks/runtime/reaction_invocation.rb +0 -1
  521. data/lib/hecks/runtime/refusal_wording.rb +12 -1
  522. data/lib/hecks/runtime/registry/context_maps.rb +1 -5
  523. data/lib/hecks/runtime/registry/declarations.rb +34 -4
  524. data/lib/hecks/runtime/registry/hecksagon_rules.rb +15 -1
  525. data/lib/hecks/runtime/registry/runtime_state.rb +10 -0
  526. data/lib/hecks/runtime/registry/world_defaults.rb +24 -2
  527. data/lib/hecks/runtime/registry/world_names.rb +99 -0
  528. data/lib/hecks/runtime/registry.rb +33 -27
  529. data/lib/hecks/runtime/saga_interpreter/compensation.rb +10 -0
  530. data/lib/hecks/runtime/saga_interpreter/correlation.rb +29 -3
  531. data/lib/hecks/runtime/saga_interpreter/delivery.rb +0 -1
  532. data/lib/hecks/runtime/saga_interpreter/lifecycle.rb +1 -1
  533. data/lib/hecks/runtime/saga_interpreter.rb +46 -2
  534. data/lib/hecks/runtime/value/coercion.rb +36 -8
  535. data/lib/hecks/rust_build/conformance.rb +16 -5
  536. data/lib/hecks/rust_build/parser.rb +25 -0
  537. data/lib/hecks/rust_build/project_rust/codegen_run.rb +45 -12
  538. data/lib/hecks/rust_build/project_rust/declared.rb +80 -0
  539. data/lib/hecks/rust_build/project_rust/features_header.rb +22 -0
  540. data/lib/hecks/rust_build/project_rust/manifest.rb +96 -0
  541. data/lib/hecks/rust_build/project_rust/meta.rb +36 -0
  542. data/lib/hecks/rust_build/project_rust.rb +28 -90
  543. data/lib/hecks/rust_build/write_if_changed.rb +19 -4
  544. data/lib/hecks/rust_build.rb +2 -1
  545. data/lib/hecks/rust_format.rb +32 -2
  546. data/lib/hecks/secrets.rb +111 -0
  547. data/lib/hecks/shape_ledger/edge_hygiene.rb +170 -0
  548. data/lib/hecks/shape_ledger/scope.rb +51 -0
  549. data/lib/hecks/shape_ledger/status.rb +89 -0
  550. data/lib/hecks/shape_ledger.rb +78 -33
  551. data/lib/hecks/site/bluebook/site.bluebook +1 -0
  552. data/lib/hecks/storehouse/audit.rb +34 -4
  553. data/lib/hecks/storehouse/callers.rb +8 -0
  554. data/lib/hecks/storehouse/dispatching.rb +14 -3
  555. data/lib/hecks/storehouse/identity.rb +41 -0
  556. data/lib/hecks/storehouse/querying.rb +7 -7
  557. data/lib/hecks/storehouse.rb +28 -10
  558. data/lib/hecks/tickets/bluebook/adapters/work_areas.adapter +7 -0
  559. data/lib/hecks/tickets/bluebook/adapters/work_limits.adapter +7 -0
  560. data/lib/hecks/tickets/bluebook/tickets.behaviors +70 -0
  561. data/lib/hecks/tickets/bluebook/tickets.bluebook +323 -28
  562. data/lib/hecks/tickets/bluebook/tickets.hecksagon +7 -0
  563. data/lib/hecks/tickets/bluebook/tickets.ports.hecksagon +17 -0
  564. data/lib/hecks/{cli → tools}/behaviors.rb +1 -1
  565. data/lib/hecks/{cli → tools}/canonicalise.rb +1 -1
  566. data/lib/hecks/{cli → tools}/check_engine_agreement.rb +1 -1
  567. data/lib/hecks/{cli → tools}/check_era.rb +6 -6
  568. data/lib/hecks/tools/ci_gates.rb +8 -2
  569. data/lib/hecks/tools/ci_workflows.rb +98 -0
  570. data/lib/hecks/{cli → tools}/console.rb +1 -1
  571. data/lib/hecks/{cli → tools}/deploy_template_diff.rb +1 -1
  572. data/lib/hecks/{cli → tools}/doc_coverage.rb +2 -2
  573. data/lib/hecks/{cli → tools}/document.rb +1 -1
  574. data/lib/hecks/{cli → tools}/domain_stub.rb +1 -1
  575. data/lib/hecks/{cli → tools}/domain_writer.rb +1 -1
  576. data/lib/hecks/tools/downstream_model_check.rb +122 -0
  577. data/lib/hecks/tools/evolve_run.rb +2 -2
  578. data/lib/hecks/{cli → tools}/expected_era.rb +1 -1
  579. data/lib/hecks/{cli → tools}/expression_projection.rb +1 -1
  580. data/lib/hecks/{cli → tools}/follow.rb +1 -1
  581. data/lib/hecks/tools/fuzz_sweep/options.rb +40 -5
  582. data/lib/hecks/tools/fuzz_sweep/pool.rb +12 -1
  583. data/lib/hecks/tools/fuzz_sweep/shards.rb +155 -0
  584. data/lib/hecks/tools/fuzz_sweep.rb +11 -5
  585. data/lib/hecks/tools/gate.rb +38 -29
  586. data/lib/hecks/tools/gate_memo/local_files.rb +33 -0
  587. data/lib/hecks/tools/gate_memo/rehearsal.rb +54 -0
  588. data/lib/hecks/tools/gate_memo/ruby_files.rb +152 -0
  589. data/lib/hecks/tools/gate_memo/session.rb +114 -0
  590. data/lib/hecks/tools/gate_memo/standalone.rb +67 -0
  591. data/lib/hecks/tools/gate_memo.rb +196 -0
  592. data/lib/hecks/tools/gate_report.rb +56 -0
  593. data/lib/hecks/{cli → tools}/history.rb +1 -1
  594. data/lib/hecks/{cli → tools}/interview_agent.rb +1 -1
  595. data/lib/hecks/{cli → tools}/interview_aggregate.rb +1 -1
  596. data/lib/hecks/{cli → tools}/interview_draft.rb +1 -1
  597. data/lib/hecks/{cli → tools}/interview_record.rb +1 -1
  598. data/lib/hecks/{cli → tools}/interview_run.rb +2 -2
  599. data/lib/hecks/{cli → tools}/interview_session/agent_state.rb +1 -1
  600. data/lib/hecks/{cli → tools}/interview_session/catalog.rb +1 -1
  601. data/lib/hecks/{cli → tools}/interview_session/manual_findings.rb +1 -1
  602. data/lib/hecks/{cli → tools}/interview_session/proposals.rb +1 -1
  603. data/lib/hecks/{cli → tools}/interview_session.rb +2 -2
  604. data/lib/hecks/{cli → tools}/interview_shape/lifecycle.rb +1 -1
  605. data/lib/hecks/{cli → tools}/interview_shape.rb +1 -1
  606. data/lib/hecks/{cli → tools}/ir.rb +1 -1
  607. data/lib/hecks/tools/lanes/files.rb +1 -1
  608. data/lib/hecks/tools/lanes/watch_workflow.rb +6 -8
  609. data/lib/hecks/tools/lanes/workflow.rb +1 -1
  610. data/lib/hecks/tools/lanes.rb +1 -1
  611. data/lib/hecks/{cli → tools}/mcp.rb +1 -1
  612. data/lib/hecks/{cli → tools}/model_check/examination.rb +1 -1
  613. data/lib/hecks/{cli → tools}/model_check/sources.rb +1 -1
  614. data/lib/hecks/{cli → tools}/model_check.rb +1 -1
  615. data/lib/hecks/tools/move_disables/reasons.rb +35 -0
  616. data/lib/hecks/tools/move_disables.rb +211 -0
  617. data/lib/hecks/tools/move_former_name.rb +105 -0
  618. data/lib/hecks/{cli → tools}/pattern_cases.rb +1 -1
  619. data/lib/hecks/{cli → tools}/persistence_notice.rb +1 -1
  620. data/lib/hecks/{cli → tools}/present.rb +1 -1
  621. data/lib/hecks/{cli → tools}/project_cli/launcher_source.rb +32 -22
  622. data/lib/hecks/{cli → tools}/project_cli/templates.rb +22 -15
  623. data/lib/hecks/{cli → tools}/project_cli.rb +11 -7
  624. data/lib/hecks/{cli → tools}/project_diagrams.rb +3 -3
  625. data/lib/hecks/{cli → tools}/project_glossary.rb +2 -2
  626. data/lib/hecks/{cli → tools}/reference.rb +2 -2
  627. data/lib/hecks/{cli → tools}/refresh_projections.rb +1 -1
  628. data/lib/hecks/{cli → tools}/refresh_rspec_runtime_baseline.rb +1 -1
  629. data/lib/hecks/tools/regeneration_run/pool.rb +148 -0
  630. data/lib/hecks/tools/regeneration_run/scratch.rb +76 -0
  631. data/lib/hecks/tools/regeneration_run.rb +125 -103
  632. data/lib/hecks/{cli → tools}/release.rb +1 -1
  633. data/lib/hecks/{cli → tools}/release_gem.rb +1 -1
  634. data/lib/hecks/{cli → tools}/rspec_io_parallel_files.rb +1 -1
  635. data/lib/hecks/{cli → tools}/rspec_shard_files.rb +1 -1
  636. data/lib/hecks/{cli → tools}/run.rb +9 -2
  637. data/lib/hecks/{cli → tools}/run_expectations.rb +1 -1
  638. data/lib/hecks/{cli → tools}/seed_semantics_corpus.rb +4 -4
  639. data/lib/hecks/{cli → tools}/serve_query_ir_mcp.rb +1 -1
  640. data/lib/hecks/{cli → tools}/shape.rb +3 -2
  641. data/lib/hecks/{cli → tools}/smoke_http/checks.rb +1 -1
  642. data/lib/hecks/{cli → tools}/smoke_http/settings.rb +1 -1
  643. data/lib/hecks/{cli → tools}/smoke_http/transport.rb +1 -1
  644. data/lib/hecks/{cli → tools}/smoke_http.rb +1 -1
  645. data/lib/hecks/{cli → tools}/smoke_test.rb +1 -1
  646. data/lib/hecks/{cli → tools}/spec_example.rb +1 -1
  647. data/lib/hecks/tools/stage_progress.rb +54 -0
  648. data/lib/hecks/{cli → tools}/statements.rb +1 -1
  649. data/lib/hecks/{cli → tools}/stores.rb +1 -1
  650. data/lib/hecks/{cli → tools}/stress_concurrency_specs/reporting.rb +1 -1
  651. data/lib/hecks/{cli → tools}/stress_concurrency_specs/usage.rb +4 -4
  652. data/lib/hecks/{cli → tools}/stress_concurrency_specs.rb +3 -3
  653. data/lib/hecks/tools/tenant_provisioning.rb +23 -0
  654. data/lib/hecks/tools/tools_doc.rb +10 -8
  655. data/lib/hecks/tools/translation_audit/edges.rb +21 -16
  656. data/lib/hecks/tools/translation_audit/verdicts.rb +1 -1
  657. data/lib/hecks/tools/translation_audit.rb +1 -1
  658. data/lib/hecks/tools/translation_scaffold.rb +1 -1
  659. data/lib/hecks/tools.rb +4 -1
  660. data/lib/hecks/version.rb +1 -1
  661. data/lib/hecks/vocabulary.rb +61 -31
  662. data/lib/hecks/workflow_pagination/judge.rb +48 -0
  663. data/lib/hecks/workflow_pagination/statement.rb +50 -0
  664. data/lib/hecks/workflow_pagination.rb +58 -0
  665. data/lib/hecks.rb +2 -0
  666. data/lib/rubocop/cop/hecks/bare_event_and_query_names.rb +58 -0
  667. data/lib/rubocop/cop/hecks/correlates_by_aggregate.rb +39 -0
  668. data/lib/rubocop/cop/hecks/creating_command_sets.rb +75 -0
  669. data/lib/rubocop/cop/hecks/invariant_expression_language.rb +47 -0
  670. data/lib/rubocop/cop/hecks/lifecycle_needs_attribute.rb +58 -0
  671. data/lib/rubocop/cop/hecks/no_id_string_attribute.rb +49 -0
  672. data/lib/rubocop/cop/hecks/one_terminal_mark_per_lifecycle.rb +47 -0
  673. data/lib/rubocop/cop/hecks/value_object_shorthand.rb +56 -0
  674. data/prebuilt/13c04bdc5970295b310f0a980d397ba722232c8da99cc1a0cdb383249921e871.marshal +0 -0
  675. data/prebuilt/e3857b77f47d9ecc1787b2e1f5136364f3cb3444ef4aea5479f3b98167affea2.marshal +0 -0
  676. data/qa/settings.yml +23 -0
  677. data/rust/.gitignore +0 -6
  678. data/rust/Cargo.toml +2 -1
  679. data/rust/build/Cargo.toml +1 -1
  680. data/rust/build/src/binding_pass.rs +57 -4
  681. data/rust/build/src/pipeline.rs +6 -4
  682. data/rust/build/src/resolve.rs +1 -0
  683. data/rust/codegen/Cargo.toml +1 -1
  684. data/rust/codegen/src/domain_generator.rs +3 -0
  685. data/rust/codegen/src/json_codec.rs +182 -23
  686. data/rust/codegen/src/one_of_references.rs +1 -0
  687. data/rust/codegen/src/queries.rs +20 -2
  688. data/rust/codegen/src/registry.rs +21 -5
  689. data/rust/expr/Cargo.toml +1 -1
  690. data/rust/host/Cargo.toml +1 -1
  691. data/rust/host/HECKS_RELEASE +1 -1
  692. data/rust/host/core/Cargo.toml +1 -1
  693. data/rust/host/src/bin/mint_harness.rs +1 -0
  694. data/rust/host/src/boot.rs +1 -0
  695. data/rust/host/src/store/mint.rs +40 -6
  696. data/rust/lsp/Cargo.toml +1 -1
  697. data/rust/parser/Cargo.toml +1 -1
  698. data/rust/parser/src/build/correlation_keys.rs +125 -0
  699. data/rust/parser/src/build/mod.rs +1 -0
  700. data/rust/parser/src/emit.rs +55 -3
  701. data/rust/parser/src/ir.rs +33 -1
  702. data/rust/parser/src/keywords.rs +289 -1
  703. data/rust/parser/src/main.rs +2 -0
  704. data/rust/parser/src/parse/aggregate.rs +10 -1
  705. data/rust/parser/src/parse/audience.rs +65 -0
  706. data/rust/parser/src/parse/command.rs +14 -0
  707. data/rust/parser/src/parse/declaration.rs +97 -0
  708. data/rust/parser/src/parse/domain_port.rs +6 -0
  709. data/rust/parser/src/parse/mod.rs +1 -0
  710. data/rust/parser/src/parse/process_manager.rs +17 -10
  711. data/rust/parser/src/parse/world.rs +12 -8
  712. data/rust/parser/src/render_ruby.rs +9 -0
  713. data/rust/parser/src/sentence/format.rs +3 -0
  714. data/rust/parser/src/sentence/process.rs +6 -2
  715. data/rust/src/exemplar/json.rs +17 -0
  716. data/rust/src/kernel/cli.rs +27 -3
  717. data/rust/src/kernel/dispatch.rs +4 -2
  718. data/rust/src/kernel/json.rs +62 -0
  719. data/rust/src/kernel/orchestrate.rs +28 -3
  720. data/rust/src/kernel/orchestrate_guard_tests.rs +12 -12
  721. data/rust/web/Cargo.toml +1 -1
  722. metadata +389 -96
  723. data/lib/hecks/cli/command_table.rb +0 -72
  724. data/lib/hecks/cli/launcher_words.rb +0 -168
  725. data/lib/hecks/cli.rb +0 -133
  726. data/lib/hecks/hecks/agents.bluebook +0 -246
  727. data/lib/hecks/hecks/codebase.bluebook +0 -3209
  728. data/lib/hecks/hecks/custodian.bluebook +0 -1300
  729. data/lib/hecks/hecks/ledger.bluebook +0 -190
  730. data/lib/hecks/hecks/rehearsal.bluebook +0 -437
  731. data/lib/hecks/hecks/tooling.bluebook +0 -1234
  732. data/lib/hecks/hecks/translations/2-148748.bluebook +0 -2
  733. data/lib/hecks/hecks/translations/2-15a2e4.bluebook +0 -2
  734. data/lib/hecks/hecks/translations/2-1b447c.bluebook +0 -5
  735. data/lib/hecks/hecks/translations/2-240474.bluebook +0 -2
  736. data/lib/hecks/hecks/translations/2-44446d.bluebook +0 -2
  737. data/lib/hecks/hecks/translations/2-46ca26.bluebook +0 -2
  738. data/lib/hecks/hecks/translations/2-473eab.bluebook +0 -2
  739. data/lib/hecks/hecks/translations/2-75cc28.bluebook +0 -2
  740. data/lib/hecks/hecks/translations/2-781c07.bluebook +0 -2
  741. data/lib/hecks/hecks/translations/2-84c18b.bluebook +0 -2
  742. data/lib/hecks/hecks/translations/2-aa5fff.bluebook +0 -2
  743. data/lib/hecks/hecks/translations/2-bfdb48.bluebook +0 -2
  744. data/lib/hecks/hecks/translations/2-cd96d8.bluebook +0 -10
  745. data/lib/hecks/hecks/translations/2-d43f71.bluebook +0 -2
  746. data/lib/hecks/hecks/translations/2-eea577.bluebook +0 -2
  747. data/lib/hecks/hecks/translations/2-f53248.bluebook +0 -2
  748. data/lib/hecks/hecks/translations/2-fbb677.bluebook +0 -2
  749. data/lib/hecks/hecks/translations/2-ffdf12.bluebook +0 -6
  750. data/lib/hecks/quality_control/adapters/clearance_recorder.rb +0 -36
  751. data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +0 -56
  752. data/prebuilt/31cf81e12f16236ad26249be590cfea3799c9db67432e6a4ef54b801c355b6ae.marshal +0 -0
  753. data/prebuilt/68ecb2bd3abb1a221007db4f2b0375834c13aaccac8f2b99778e8517f11aa113.marshal +0 -0
  754. data/prebuilt/verdicts-0328c2403383837d780ad5ed81d1da351c56436b894cf9015b5d56b8f1f1bf10.json +0 -1
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hecks
4
+ module Adapters
5
+ module Codebase
6
+ class SpecFiles
7
+ # How one file ended.
8
+ #
9
+ # @!attribute [r] file
10
+ # @return [String] the spec file, as named
11
+ # @!attribute [r] examples
12
+ # @return [Integer] how many examples ran
13
+ # @!attribute [r] failures
14
+ # @return [Integer] how many failed
15
+ # @!attribute [r] failed
16
+ # @return [Boolean] whether the file failed: a failed example, or a file that did not load
17
+ # @!attribute [r] output
18
+ # @return [String] what the runner printed for the file (empty when it shared a process)
19
+ Ending = Struct.new(:file, :examples, :failures, :failed, :output)
20
+
21
+ # The report of several files: what failing files printed, a line for each file, the
22
+ # isolation, the files that failed, and the total counts as the test runner spells them.
23
+ class Report
24
+ NOTES = {
25
+ "process" => "isolation: process (a new process for each file)",
26
+ "shared" => "isolation: shared (one process; may expose order dependence)"
27
+ }.freeze
28
+
29
+ # @param endings [Array<Ending>] how each file ended
30
+ # @param isolation [String] one of `SpecFiles::ISOLATIONS`
31
+ # @param printed [String, nil] what the one shared process printed
32
+ def initialize(endings, isolation, printed: nil)
33
+ @endings = endings
34
+ @isolation = isolation
35
+ @printed = printed
36
+ end
37
+
38
+ # @return [Boolean] whether any file failed
39
+ def failed? = @endings.any?(&:failed)
40
+
41
+ # @return [String] the report, ending with the total example and failure counts
42
+ def to_s = [@printed, *details, table, verdict, totals].compact.join("\n\n")
43
+
44
+ private
45
+
46
+ def failing = @endings.select(&:failed)
47
+
48
+ def details
49
+ failing.reject { |one| one.output.to_s.empty? }.map { |one| "--- #{one.file} ---\n#{one.output}" }
50
+ end
51
+
52
+ def table = (["files:"] + @endings.map { |one| " #{line(one)}" }).join("\n")
53
+
54
+ def line(one)
55
+ "#{one.file}: #{plural(one.examples, "example")}, #{plural(one.failures, "failure")}#{" FAILED" if one.failed}"
56
+ end
57
+
58
+ def verdict
59
+ return NOTES.fetch(@isolation) unless failed?
60
+
61
+ "#{NOTES.fetch(@isolation)}\nfailed: #{failing.map(&:file).join(" ")} (#{failing.size} of #{@endings.size} files)"
62
+ end
63
+
64
+ def totals = "#{plural(@endings.sum(&:examples), "example")}, #{plural(@endings.sum(&:failures), "failure")}"
65
+
66
+ def plural(count, word) = "#{count} #{word}#{"s" unless count == 1}"
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "tempfile"
5
+ require_relative "report"
6
+
7
+ module Hecks
8
+ module Adapters
9
+ module Codebase
10
+ class SpecFiles
11
+ # Every file in one test-runner process; the JSON formatter says which file each example
12
+ # belongs to, and the runner's own message which file did not load.
13
+ class SharedRun
14
+ LOAD_ERROR = /error occurred while loading (.+?)\.?$/
15
+
16
+ # @param tree [Tree] the checkout
17
+ # @param runner [#outcome] runs the test runner on arguments
18
+ def initialize(tree, runner)
19
+ @tree = tree
20
+ @runner = runner
21
+ end
22
+
23
+ # @param names [Array<String>] the spec files
24
+ # @param options [Array<String>] the runner's filters, such as `--example x`
25
+ # @param env [Hash{String => String}] variables the specs read
26
+ # @return [Array(Array<Ending>, String)] how each file ended, and what the process printed
27
+ def call(names, options, env)
28
+ Tempfile.create(["spec-files", ".json"]) do |json|
29
+ args = ["--format", "documentation", "--format", "json", "--out", json.path, *options, *names]
30
+ status, printed = @runner.outcome(args, env: env)
31
+ by_file = examples_by_file(json.path)
32
+ endings = names.map { |name| ending(name, by_file.fetch(key(name), [])) }
33
+ blame_load_errors(endings, status, printed)
34
+ [endings, printed]
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def examples_by_file(path)
41
+ JSON.parse(File.read(path)).fetch("examples", []).group_by { |entry| key(entry["file_path"].to_s) }
42
+ rescue JSON::ParserError, Errno::ENOENT
43
+ {}
44
+ end
45
+
46
+ # A file as the runner may spell it (relative, absolute, through a symlink), made
47
+ # comparable.
48
+ def key(path)
49
+ full = File.expand_path(path, @tree.root)
50
+ File.exist?(full) ? File.realpath(full) : full
51
+ end
52
+
53
+ def ending(name, examples)
54
+ failures = examples.count { |entry| entry["status"] == "failed" }
55
+ Ending.new(name, examples.size, failures, failures.positive?, "")
56
+ end
57
+
58
+ # A file that did not load has no examples, and the runner then runs none of the others.
59
+ # The runner names the file; when the run failed with no failed example and no name,
60
+ # every file is blamed.
61
+ def blame_load_errors(endings, status, printed)
62
+ return if status.zero? || endings.any?(&:failed)
63
+
64
+ named = loading(printed)
65
+ (named.empty? ? endings : endings.select { |one| named.include?(key(one.file)) }).each { |one| one.failed = true }
66
+ end
67
+
68
+ def loading(printed) = printed.scan(LOAD_ERROR).flatten.map { |path| key(path) }
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "tree"
4
+ require_relative "test_runner"
5
+ require_relative "spec_files/report"
6
+ require_relative "spec_files/shared_run"
7
+ require_relative "../console_capture"
8
+
9
+ module Hecks
10
+ module Adapters
11
+ module Codebase
12
+ # Several spec files run in one launcher boot, and how each ended.
13
+ #
14
+ # `process` isolation gives every file a new process of its own, so nothing one file defines,
15
+ # stubs or registers reaches the next: it saves the launcher's boot, not each file's load.
16
+ # `shared` isolation runs every file in one test-runner process, the fastest, and may expose
17
+ # an order dependence between files (constants, stubs, Memory registries are shared).
18
+ #
19
+ # The report names each file with its example and failure counts, and ends with the total
20
+ # counts as the test runner spells them. A run in which any file failed is refused with it.
21
+ class SpecFiles
22
+ # Every way the files can be isolated; the first is the default.
23
+ ISOLATIONS = %w[process shared].freeze
24
+
25
+ # The example filter that matches every example.
26
+ ALL_EXAMPLES = " "
27
+
28
+ COUNTS = /(\d+) examples?, (\d+) failures?/
29
+
30
+ # @param tree [Tree] the checkout whose specs are run
31
+ # @param runner [TestRunner] runs the test runner on arguments
32
+ def initialize(tree, runner: TestRunner.new(tree))
33
+ @tree = tree
34
+ @runner = runner
35
+ end
36
+
37
+ # @param files [String, Array<String>] spec files, relative to the checkout or absolute; a
38
+ # string is split on whitespace
39
+ # @param example [String, nil] part of an example's description; every example when nil
40
+ # @param isolation [String] one of `ISOLATIONS`
41
+ # @param env [Hash{String => String}] variables the specs read, set for these runs only
42
+ # @param tags [String, nil] RSpec tag filters as the runner spells them
43
+ # @return [String] the per-file counts and the total, when every file passed
44
+ # @raise [ConsoleCapture::Failure] naming the files that failed, or that are not there
45
+ def run(files:, example: nil, isolation: "process", env: {}, tags: nil)
46
+ names = Array(files).flat_map { |name| name.to_s.split }.uniq
47
+ check(names, isolation)
48
+ report = isolate(isolation, names, filters(example, tags), env)
49
+ raise ConsoleCapture::Failure, report.to_s if report.failed?
50
+
51
+ report.to_s
52
+ end
53
+
54
+ private
55
+
56
+ # A single space matches every example, and a named example overrides the tag exclusions
57
+ # (`:io`, `:process`, `:fuzzing`) as a one-file run does, so an absent filter is that space.
58
+ def filters(example, tags) = ["--example", example.to_s.empty? ? ALL_EXAMPLES : example, *tags.to_s.split]
59
+
60
+ def isolate(isolation, names, options, env)
61
+ isolation == "shared" ? shared(names, options, env) : fresh(names, options, env)
62
+ end
63
+
64
+ def check(names, isolation)
65
+ raise ConsoleCapture::Failure, "no spec files named" if names.empty?
66
+ unless ISOLATIONS.include?(isolation)
67
+ raise ConsoleCapture::Failure, "isolation is process or shared, not #{isolation.inspect}"
68
+ end
69
+
70
+ missing = names.reject { |name| File.file?(File.expand_path(name, @tree.root)) }
71
+ raise ConsoleCapture::Failure, "no such spec file #{missing.join(" ")}" unless missing.empty?
72
+ end
73
+
74
+ def fresh(names, options, env)
75
+ endings = names.map do |name|
76
+ status, printed = @runner.outcome([*options, name], env: env, fresh: true)
77
+ examples, failures = counts(printed)
78
+ Ending.new(name, examples, failures, !status.zero?, printed)
79
+ end
80
+ Report.new(endings, "process")
81
+ end
82
+
83
+ def shared(names, options, env)
84
+ endings, printed = SharedRun.new(@tree, @runner).call(names, options, env)
85
+ Report.new(endings, "shared", printed: printed)
86
+ end
87
+
88
+ def counts(printed)
89
+ found = printed.match(COUNTS)
90
+ found ? [found[1].to_i, found[2].to_i] : [0, 0]
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "stringio"
4
+ require "open3"
5
+ require "rbconfig"
4
6
  require_relative "tree"
5
7
  require_relative "../console_capture"
6
8
 
@@ -13,6 +15,9 @@ module Hecks
13
15
  # description for a shell. What the runner prints is captured and comes back as the answer;
14
16
  # a run that fails refuses with the same text.
15
17
  class TestRunner
18
+ # The program a fresh process runs: the test runner, on the arguments it is handed.
19
+ FRESH_RUNNER = 'require "rspec/core"; exit RSpec::Core::Runner.run(ARGV)'
20
+
16
21
  class << self
17
22
  # @return [#call, nil] takes `(args, err, out)` and answers the exit status; the test
18
23
  # runner when nil. A spec replaces it so no example has to run to test what is asked.
@@ -58,16 +63,60 @@ module Hecks
58
63
  report
59
64
  end
60
65
 
66
+ # Runs every spec in the given files or directories, from the checkout's root: a whole suite
67
+ # is one directory, a changed-file run is the specs those files map to.
68
+ #
69
+ # @param paths [Array<String>] spec files or directories, relative to the checkout or
70
+ # absolute
71
+ # @param env [Hash{String => String}] variables the specs read, set for this run only
72
+ # @param tags [String, nil] RSpec tag filters as the runner spells them
73
+ # @return [String] what the runner printed when every spec it ran passed
74
+ # @raise [ConsoleCapture::Failure] when a path is not there, or a spec failed
75
+ def run_paths(paths:, env: {}, tags: nil)
76
+ missing = paths.reject { |path| File.exist?(File.expand_path(path, @tree.root)) }
77
+ raise ConsoleCapture::Failure, "no such spec #{missing.first}" unless missing.empty?
78
+
79
+ report = with_env(env) { run_args([*tags.to_s.split, *paths]) }
80
+ raise ConsoleCapture::Failure, "the test runner printed nothing for #{paths.join(" ")}" if report.empty?
81
+
82
+ report
83
+ end
84
+
85
+ # Runs the runner on the arguments and answers how it ended, whatever the result: a
86
+ # caller that reports each of several runs reads the status, not a refusal.
87
+ #
88
+ # @param args [Array<String>] the runner's arguments
89
+ # @param env [Hash{String => String}] variables the specs read, set for this run only
90
+ # @param fresh [Boolean] whether to run it in a new process of its own (nothing a spec
91
+ # defined, stubbed or registered carries over) or in this one
92
+ # @return [Array(Integer, String)] the exit status and what the runner printed
93
+ def outcome(args, env: {}, fresh: false)
94
+ return with_env(env) { in_process(args) } unless fresh
95
+
96
+ printed, status = Open3.capture2e(env, RbConfig.ruby, "-e", FRESH_RUNNER, "--", *args, chdir: @tree.root)
97
+ [status.exitstatus || 1, printed.strip]
98
+ end
99
+
61
100
  private
62
101
 
63
102
  # What the runner printed for the example, when it passed.
64
103
  def run_example(path, example, tags = [])
104
+ run_args(["--example", example, *tags, path])
105
+ end
106
+
107
+ # What the runner printed for the arguments, when every spec it ran passed.
108
+ def run_args(args)
109
+ status, printed = in_process(args)
110
+ raise ConsoleCapture::Failure, printed unless status.zero?
111
+
112
+ printed
113
+ end
114
+
115
+ # The runner's exit status and what it printed, for the arguments, in this process.
116
+ def in_process(args)
65
117
  out = StringIO.new
66
- args = ["--example", example, *tags, path]
67
118
  status = Dir.chdir(@tree.root) { at_reaction_depth_zero { runner.call(args, out, out) } }
68
- raise ConsoleCapture::Failure, out.string.strip unless status.zero?
69
-
70
- out.string.strip
119
+ [status, out.string.strip]
71
120
  end
72
121
 
73
122
  def at_reaction_depth_zero(&) = self.class.at_reaction_depth_zero(&)
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../console_capture"
4
+
5
+ module Hecks
6
+ module Adapters
7
+ module Codebase
8
+ # How much of the spec suite this machine may run, from the world's
9
+ # `test_scope "Local", suite_runs_in: "ci", spec_files_limit: n` setting. Owner decision: the
10
+ # full suite runs only in CI (the `rspec` check is `runs_in: "ci"` in the Vocabulary rows),
11
+ # and a change is checked locally by the quick gate and the specs named for it, at most
12
+ # `spec_files_limit` files per call.
13
+ #
14
+ # CI is detected here, by the environment (`CI` or `GITHUB_ACTIONS`), never by the bluebook. A
15
+ # world that declares no `test_scope` (a client's project) is not limited.
16
+ class TestScope
17
+ # The world verb that carries the setting.
18
+ VERB = "test_scope"
19
+
20
+ # The spec files a directory holds.
21
+ SPEC_GLOB = "**/*_spec.rb"
22
+
23
+ # @param registry [Runtime::Registry, nil] the booted registry whose Hecks world is read
24
+ # @return [Hash{Symbol => Object}] the declared setting, empty when none is
25
+ def self.setting(registry) = registry&.world("Hecks")&.for_verb(VERB) || {}
26
+
27
+ # @param registry [Runtime::Registry, nil]
28
+ # @return [Integer, nil] the most spec files a local call may run, nil when none is declared
29
+ def self.limit(registry)
30
+ declared = setting(registry)[:spec_files_limit]
31
+ declared && Integer(declared)
32
+ end
33
+
34
+ # @param registry [Runtime::Registry, nil] the booted registry whose Hecks world is read
35
+ # @param env [#[]] the process environment
36
+ def initialize(registry, env: ENV)
37
+ @setting = self.class.setting(registry)
38
+ @env = env
39
+ end
40
+
41
+ # @return [Integer, nil] the limit that holds here: nil in CI or when none is declared
42
+ def limit = (Integer(@setting[:spec_files_limit]) if @setting[:spec_files_limit] && !ci?)
43
+
44
+ # @return [Boolean] whether this process runs in CI
45
+ def ci? = %w[CI GITHUB_ACTIONS].any? { |name| !["", "false"].include?(@env[name].to_s) }
46
+
47
+ # Lets a request through, or refuses one that would run more than this machine may. An
48
+ # impacted run that names no cap gets the limit as its cap.
49
+ #
50
+ # @param operation [String] the `TestSuiteRun` operation
51
+ # @param held [Hash] the record's fields, each perhaps a value object's `{ value: x }`
52
+ # @param tree [Tree] the folder whose specs would run
53
+ # @return [Hash] the fields to carry the operation out with
54
+ # @raise [ConsoleCapture::Failure] naming the limit and CI
55
+ def admit(operation, held, tree)
56
+ args = held.transform_values { |value| value.is_a?(Hash) ? value[:value] : value }
57
+ refuse!(operation, args, tree) unless ci?
58
+ return held unless operation == "run_impacted_specs" && limit && args[:cap].nil?
59
+
60
+ held.merge(cap: { value: limit })
61
+ end
62
+
63
+ private
64
+
65
+ def refuse!(operation, args, tree)
66
+ case operation
67
+ when "run_suite" then refuse_suite
68
+ when "run_spec_files" then refuse_files(files_in(args[:files], tree))
69
+ when "run_impacted_specs" then refuse_cap(args[:cap])
70
+ end
71
+ end
72
+
73
+ def refuse_suite
74
+ return unless @setting[:suite_runs_in].to_s == "ci"
75
+
76
+ fail!("the full suite runs in CI (rspec runs_in \"ci\"); run named specs, or run_impacted_specs!")
77
+ end
78
+
79
+ def refuse_files(count)
80
+ return if limit.nil? || count <= limit
81
+
82
+ fail!("run_spec_files! runs at most #{limit} spec files per call locally (spec_files_limit); #{count} named. " \
83
+ "The full suite runs in CI (rspec runs_in \"ci\"): name fewer files, or run_impacted_specs!")
84
+ end
85
+
86
+ def refuse_cap(cap)
87
+ return if limit.nil? || cap.nil? || Integer(cap) <= limit
88
+
89
+ fail!("run_impacted_specs! caps at #{limit} spec files locally (spec_files_limit); cap.value=#{cap} is more. " \
90
+ "The full suite runs in CI (rspec runs_in \"ci\")")
91
+ end
92
+
93
+ # A named directory counts as the spec files it holds.
94
+ def files_in(files, tree)
95
+ Array(files).flat_map { |name| name.to_s.split }.uniq.sum do |name|
96
+ path = File.expand_path(name, tree.root)
97
+ File.directory?(path) ? Dir.glob(File.join(path, SPEC_GLOB)).size : 1
98
+ end
99
+ end
100
+
101
+ def fail!(message) = raise(ConsoleCapture::Failure, message)
102
+ end
103
+ end
104
+ end
105
+ end
@@ -2,7 +2,11 @@
2
2
 
3
3
  require "fileutils"
4
4
  require_relative "tree"
5
+ require_relative "minitest_runs"
6
+ require_relative "run_options"
5
7
  require_relative "test_runner"
8
+ require_relative "changed_specs"
9
+ require_relative "batch_runs"
6
10
  require_relative "sqlite_fixture"
7
11
  require_relative "cargo_tests"
8
12
  require_relative "cache_clearing"
@@ -13,15 +17,23 @@ module Hecks
13
17
  # What Codebase's `TestSuiteRun` asks of the working tree: the tooling around this
14
18
  # repository's specs.
15
19
  #
16
- # The tooling owns its options, so each ask runs one of the `Hecks::CLI` commands in this
20
+ # The tooling owns its options, so each ask runs one of the `Hecks::Tools` commands in this
17
21
  # process from the checkout's root, except a single example (the `TestRunner` adapter runs it)
18
22
  # and the persistence fixtures (the `SqliteFixture` adapter). A listing is a pure read.
19
23
  # Refreshing the committed timings, regenerating the fixtures and writing the committed spec
20
24
  # list change tracked files, so unconfirmed they report what they would do and write nothing.
21
25
  module TestSuite
22
26
  # Every operation this family carries out.
23
- OPERATIONS = %w[refresh_runtime_baseline run_spec_example stress_concurrency run_cargo_tests clear_caches
24
- regenerate_legacy_fixtures seed_semantics_corpus write_io_parallel_spec_list].freeze
27
+ OPERATIONS = %w[refresh_runtime_baseline run_spec_example run_spec_files run_impacted_specs run_suite run_changed
28
+ stress_concurrency run_cargo_tests clear_caches regenerate_legacy_fixtures seed_semantics_corpus
29
+ write_io_parallel_spec_list].freeze
30
+
31
+ # The operations that run specs in a folder of their own: they need that folder to hold
32
+ # specs, not to be this checkout, so any project's suite runs through them.
33
+ FOLDER_OPERATIONS = %w[run_spec_example run_spec_files run_impacted_specs run_suite run_changed].freeze
34
+
35
+ # The spec directory a folder's whole suite lives in.
36
+ SPEC_DIRECTORY = "spec"
25
37
 
26
38
  # The tag filter the postgres job lists its specs by when none is named.
27
39
  DEFAULT_TAGS = "--tag io --tag ~fuzzing"
@@ -31,14 +43,14 @@ module Hecks
31
43
 
32
44
  module_function
33
45
 
34
- # Loads the command a `Hecks::CLI` file defines, the first time an ask needs it: several
46
+ # Loads the command a `Hecks::Tools` file defines, the first time an ask needs it: several
35
47
  # read the checkout's specs or need a development gem, which an installed gem lacks.
36
48
  #
37
- # @param file [String] the command's file under `lib/hecks/cli/`, without the extension
49
+ # @param file [String] the command's file under `lib/hecks/tools/`, without the extension
38
50
  # @return [Module] the command, named as the file is, in camel case
39
51
  def command(file)
40
- require "hecks/cli/#{file}"
41
- Hecks::CLI.const_get(file.split("_").map(&:capitalize).join)
52
+ require "hecks/tools/#{file}"
53
+ Hecks::Tools.const_get(file.split("_").map(&:capitalize).join)
42
54
  end
43
55
 
44
56
  # Carries out one operation.
@@ -52,7 +64,9 @@ module Hecks
52
64
  def call(operation, held, tree, shell: nil)
53
65
  args = plain(held)
54
66
  case operation
55
- when "run_spec_example" then spec_example(args, tree)
67
+ when *BatchRuns::OPERATIONS then BatchRuns.call(operation, args, tree)
68
+ when "run_suite" then suite(args, tree)
69
+ when "run_changed" then changed(args, tree)
56
70
  when "run_cargo_tests" then CargoTests.run(args, tree, shell)
57
71
  when "clear_caches" then CacheClearing.clear
58
72
  else tooling(operation, args, tree, shell)
@@ -73,30 +87,41 @@ module Hecks
73
87
  end
74
88
  end
75
89
 
76
- # @param args [Hash] `file`, `example`, and the arguments that set the specs' variables
77
- # @param tree [Tree] the checkout
90
+ # Runs every spec of the folder's spec directory in one process.
91
+ #
92
+ # @param args [Hash] `tags`, `strict`, `seeds` and `environment`, each perhaps absent
93
+ # @param tree [Tree] the folder whose specs run
78
94
  # @return [String] what the runner printed
79
- def spec_example(args, tree)
80
- TestRunner.new(tree).run(file: args[:file], example: args[:example], env: spec_env(args), tags: args[:tags])
95
+ def suite(args, tree)
96
+ rspec = TestRunner.new(tree).run_paths(paths: [SPEC_DIRECTORY], env: RunOptions.spec_env(args), tags: args[:tags])
97
+ minitest = MinitestRuns.files(tree)
98
+ return rspec if minitest.empty?
99
+
100
+ ([rspec] + MinitestRuns.reports(tree, minitest)).join("\n")
81
101
  end
82
102
 
83
- # The variables the specs read, set for one example only: the arguments of the run, so a
84
- # person never sets them in a shell.
103
+ # Runs the specs the files changed since a git ref map to, by name. Says so and runs nothing
104
+ # when no spec maps to a change, so an unmapped change never falls back to the whole suite.
85
105
  #
86
- # @param args [Hash] `strict`, `seeds`, `environment` and `declaration_cache`, each
87
- # perhaps absent
88
- # @return [Hash{String => String}] only those the run named
89
- def spec_env(args)
90
- { "CI" => ("true" if args[:strict] == true), "PROPERTY_SEEDS" => args[:seeds]&.to_s,
91
- "HECKS_ENVIRONMENT" => args[:environment],
92
- "HECKS_NO_DECLARATION_CACHE" => ("1" if args[:declaration_cache] == false) }.compact
106
+ # @param args [Hash] `base` (the ref, `origin/main` when absent), and the run's variables
107
+ # @param tree [Tree] the folder whose changes are read
108
+ # @return [String] what the runner printed, or that no spec maps to the changes
109
+ # @raise [ConsoleCapture::Failure] when git cannot read the changes
110
+ def changed(args, tree)
111
+ base = args[:base] || "origin/main"
112
+ files = ChangedSpecs.changed_files(tree, base)
113
+ specs = Dir.glob("#{SPEC_DIRECTORY}/**/*_spec.rb", base: tree.root).sort
114
+ mapped = ChangedSpecs.call(files, specs)
115
+ return "no spec maps to the #{files.size} changed file(s) since #{base}; nothing run" if mapped.empty?
116
+
117
+ TestRunner.new(tree).run_paths(paths: mapped, env: RunOptions.spec_env(args), tags: args[:tags])
93
118
  end
94
119
 
95
120
  # @param args [Hash] `runs`, `parallel` and `seed_start`
96
121
  # @param tree [Tree] the checkout
97
122
  # @return [String] what the stress run printed
98
123
  def stress(args, tree)
99
- answer { command("stress_concurrency_specs").call(stress_flags(args), root: tree.root) }
124
+ answer { command("stress_concurrency_specs").call(RunOptions.stress_flags(args), root: tree.root) }
100
125
  end
101
126
 
102
127
  # @param args [Hash] `confirm`
@@ -115,7 +140,7 @@ module Hecks
115
140
  # @return [String] what the seeding printed
116
141
  def seed(args, tree)
117
142
  seeding = command("seed_semantics_corpus")
118
- answer { TestRunner.at_reaction_depth_zero { seeding.call(root: tree.root, env: seed_env(args)) } }
143
+ answer { TestRunner.at_reaction_depth_zero { seeding.call(root: tree.root, env: RunOptions.seed_env(args)) } }
119
144
  end
120
145
 
121
146
  # A pure read: a listing, or the recorded pattern cases.
@@ -191,17 +216,6 @@ module Hecks
191
216
  "and rewrite #{BASELINES.join(", ")} (add --confirm)"
192
217
  end
193
218
 
194
- # @param args [Hash] `runs`, `parallel` and `seed_start`
195
- # @return [Array<String>] the script's flags for those that are named
196
- def stress_flags(args)
197
- { "--runs" => :runs, "--parallel" => :parallel, "--seed-start" => :seed_start }
198
- .filter_map { |flag, name| [flag, args[name].to_s] if args[name] }.flatten
199
- end
200
-
201
- # @param args [Hash] `fixture`, perhaps absent
202
- # @return [Hash{String => String}] the variable that names the one fixture to re-seed
203
- def seed_env(args) = args[:fixture] ? { "SEED" => args[:fixture] } : {}
204
-
205
219
  # @param args [Hash] `exclude`, `tags`, `write` and `confirm`
206
220
  # @param tree [Tree] the checkout whose spec list is written
207
221
  # @return [String] what was written, or (unconfirmed) how many files would be
@@ -6,7 +6,7 @@ require "stringio"
6
6
  module Hecks
7
7
  module Adapters
8
8
  # Runs a command-line entry point that prints and exits, and hands back what it said and how
9
- # it ended, so an adapter can reuse `Hecks::CLI::*` unchanged.
9
+ # it ended, so an adapter can reuse `Hecks::Tools::*` unchanged.
10
10
  #
11
11
  # It is the shared base for every Custodian adapter that wraps an existing CLI: the entry
12
12
  # point keeps its own printing, `exit` and `abort`, and the adapter turns the outcome into a
@@ -41,7 +41,7 @@ module Hecks
41
41
  # @raise [Error] when no complete day has passed since `since`, `aws` fails, or the
42
42
  # rate is over the budget
43
43
  def measure(**held)
44
- budget = Integer(plain(held[:budget]))
44
+ budget = whole_dollars(plain(held[:budget]))
45
45
  first = Date.iso8601(plain(held[:since]).to_s)
46
46
  last = today
47
47
  raise Error, "no complete day since #{first}; today (#{last}) is still being billed" if first >= last
@@ -55,6 +55,14 @@ module Hecks
55
55
 
56
56
  private
57
57
 
58
+ # @return [Integer] the budget as whole dollars
59
+ # @raise [Error] when none was given
60
+ def whole_dollars(budget)
61
+ raise Error, "no budget given: a whole number of dollars a month" if budget.nil?
62
+
63
+ Integer(budget)
64
+ end
65
+
58
66
  # @return [Date] the day the span ends before: today, in UTC
59
67
  def today = @today ? Date.iso8601(@today.to_s) : Time.now.utc.to_date
60
68
 
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hecks
4
+ module Adapters
5
+ class Dispatching
6
+ # The words a session is started with, laid out from a composed brief. Every sentence in it is the
7
+ # Coder bluebook's; this only orders the sections, fills in the row's key and lists the areas the
8
+ # caller knows.
9
+ class BriefText
10
+ # The sections of a brief after the outcome, in the order they are read.
11
+ SECTIONS = %w[rules verification workflow landing restraints report].freeze
12
+
13
+ # @param brief [Hash] the composed brief: its attribute values by name
14
+ def initialize(brief)
15
+ @brief = brief
16
+ end
17
+
18
+ # @return [String] the first line of the text: the outcome
19
+ def first_line = "Outcome: #{plain("outcome")}"
20
+
21
+ # @param key [String] the Work row's key, which names the worktree and branch
22
+ # @param area [Array<String>] the areas the session may edit
23
+ # @param held [Array<String>] a line for each area another started row holds
24
+ # @param frozen [Array<String>] the areas and aggregates whose shape may not move
25
+ # @param limit [Integer, nil] the most spec files a session runs per call, from the world's
26
+ # `test_scope` setting; fills `{limit}`
27
+ # @return [String] the whole text
28
+ def render(key, area: [], held: [], frozen: [], limit: nil)
29
+ parts = [first_line, labelled("Detail", plain("detail")), labelled("Area", area.join(", "))]
30
+ parts += SECTIONS.map { |name| plain(name) }
31
+ parts += [listed("coordination", held), listed("freeze", frozen)]
32
+ joined(parts).gsub("{work}", key).gsub("{limit}", limit&.to_s || "the world's spec_files_limit")
33
+ end
34
+
35
+ private
36
+
37
+ def labelled(label, text) = text.empty? ? nil : "#{label}: #{text}"
38
+
39
+ def listed(name, lines) = lines.empty? ? nil : ([plain(name)] + lines.map { |line| "- #{line}" }).join("\n")
40
+
41
+ def joined(parts) = parts.compact.reject(&:empty?).join("\n\n")
42
+
43
+ # A value is a bare string or a one-field hash, and a name is a string or a symbol.
44
+ def plain(name)
45
+ found = @brief.transform_keys(&:to_s)[name]
46
+ (found.is_a?(Hash) ? found.transform_keys(&:to_s)["value"] : found).to_s
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end