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,168 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hecks/ci_speed/adapters/local_runner/refused"
4
+ require "hecks/ci_speed/adapters/local_runner/refs"
5
+ require "hecks/ci_speed/adapters/local_runner/catalog"
6
+ require "hecks/ci_speed/adapters/local_runner/checkouts"
7
+ require "hecks/ci_speed/adapters/local_runner/launcher"
8
+ require "hecks/ci_speed/adapters/local_runner/load_average"
9
+ require "hecks/ci_speed/adapters/local_runner/verdict"
10
+ require "hecks/ci_speed/adapters/local_runner/answer"
11
+
12
+ module Hecks
13
+ module Adapters
14
+ # The `LocalRunner` port's adapter: times a definition's steps in two temporary checkouts, one
15
+ # of the base ref and one of the candidate ref, and answers with the numbers.
16
+ #
17
+ # Each side first runs every step once untimed, so the build caches a fresh checkout lacks are
18
+ # paid before timing starts. The steps then run interleaved, base then candidate then base
19
+ # again, so a change in the machine's load while the experiment runs lands on both sides. A
20
+ # step the machine cannot stand in for is named in `unmeasured` and left out of both sides.
21
+ # Both checkouts are removed when the run ends, however it ends, and the checkout that asked
22
+ # is never written.
23
+ class LocalRunner
24
+ # The sides of an experiment, in the order a round samples them.
25
+ SIDES = %i[base candidate].freeze
26
+
27
+ # What a step's `needs` can be and still run on this machine.
28
+ LOCAL_NEEDS = %w[none].freeze
29
+
30
+ # The samples taken when an experiment names no number.
31
+ DEFAULT_REPEATS = 3
32
+
33
+ # One side of an experiment: which it is, its checkout, and the launcher that runs its steps.
34
+ Side = Struct.new(:name, :path, :launcher)
35
+
36
+ # @return [Array<Hash>] every sample in the order it was taken: its round, side, seconds and
37
+ # the checkout it ran in
38
+ attr_reader :trail
39
+
40
+ # @return [Array<Hash>] the untimed pass in each checkout before sampling began: its side
41
+ # and the seconds it took, which no verdict uses
42
+ attr_reader :warm_up
43
+
44
+ # @param registry [Runtime::Registry, nil] the booted registry whose CiSpeed bluebook holds
45
+ # the definitions; unused when `catalog` is given
46
+ # @param catalog [Catalog, nil] the definitions to read instead of the bluebook's rows
47
+ # @param root [String, nil] the checkout that asks, whose refs are resolved and whose
48
+ # generated tree is copied; this repository when nil
49
+ # @param scratch [String, nil] where the temporary checkouts are made; `$CLAUDE_JOB_DIR/tmp`
50
+ # when that is set, else the system's temporary directory
51
+ def initialize(registry: nil, catalog: nil, root: nil, scratch: nil)
52
+ @registry = registry
53
+ @catalog = catalog
54
+ @root = root || File.expand_path("../../../..", __dir__)
55
+ @scratch = scratch || job_scratch
56
+ @trail = []
57
+ @warm_up = []
58
+ end
59
+
60
+ # Runs the experiment named by `held`.
61
+ #
62
+ # @param held [Hash] the `Experiment` record: `measures`, `cache_state`, `base_ref`,
63
+ # `candidate_ref`, `repeats` and `lever` when set
64
+ # @return [Hash{Symbol => Hash}] the answer, each field in the shape `Experiment::Complete`
65
+ # takes: the times, the spread and saving, the load, what went unmeasured, the verdict,
66
+ # what it rests on, and the lever to tell with the estimate it should hold
67
+ # @raise [Refused] when the definition is unknown, disagrees with the experiment about the
68
+ # cache state, no step can be measured, a ref does not resolve, or a step ends badly
69
+ def measure(**held)
70
+ asked = held.transform_values { |value| value.is_a?(Hash) ? value[:value] : value }
71
+ definition = definition_for(asked)
72
+ shas = Refs.resolve(@root, asked)
73
+ load = LoadAverage.now
74
+ sampled = sample_both(definition, shas, asked[:repeats] || DEFAULT_REPEATS)
75
+ answer(asked, definition, sampled, load)
76
+ end
77
+
78
+ private
79
+
80
+ def definition_for(asked)
81
+ definition = catalog.fetch(asked.fetch(:measures))
82
+ return definition if definition.cache_state == asked.fetch(:cache_state)
83
+
84
+ raise Refused, "#{definition.name} measures cache state #{definition.cache_state}, " \
85
+ "but the experiment stands for #{asked.fetch(:cache_state)}"
86
+ end
87
+
88
+ def catalog
89
+ @catalog ||= Catalog.from_bluebook(@registry&.bluebook("CiSpeed") || raise(Refused, "no CiSpeed bluebook is booted"))
90
+ end
91
+
92
+ # Checks the two sides out, works out which steps both can run, and samples them interleaved.
93
+ def sample_both(definition, shas, repeats)
94
+ copy_from = @root if definition.generated_tree?
95
+ refuse_missing_tree(copy_from)
96
+ Checkouts.with(root: @root, shas: shas, scratch: @scratch) do |paths|
97
+ sides = paths.map { |name, path| Side.new(name, path, Launcher.new(path)) }
98
+ steps, unmeasured = measurable(definition.steps, sides)
99
+ warm(sides, steps, copy_from)
100
+ { unmeasured: unmeasured, samples: rounds(sides, steps, copy_from, repeats) }
101
+ end
102
+ end
103
+
104
+ # Runs every step once in each checkout before anything is timed. A fresh checkout holds no
105
+ # build caches, and the first run in it would pay for them on one side of the first pair.
106
+ def warm(sides, steps, copy_from)
107
+ sides.each do |side|
108
+ Checkouts.reset_generated_tree(side.path, copy_from)
109
+ seconds = steps.sum { |step| side.launcher.time(step) }
110
+ @warm_up << { side: side.name, seconds: seconds }
111
+ end
112
+ end
113
+
114
+ # Splits steps into those both sides can run here and a note for each that cannot.
115
+ def measurable(steps, sides)
116
+ notes = []
117
+ kept = steps.select do |step|
118
+ reason = unmeasurable(step, sides)
119
+ notes << "#{step.name}: #{reason}" if reason
120
+ reason.nil?
121
+ end
122
+ raise Refused, "no step could be measured here: #{notes.join("; ")}" if kept.empty?
123
+
124
+ [kept, notes]
125
+ end
126
+
127
+ def unmeasurable(step, sides)
128
+ return "needs #{step.needs}, which a local run does not stand in for" unless LOCAL_NEEDS.include?(step.needs)
129
+
130
+ sides.each do |side|
131
+ return "#{step.verb} or an argument it is given is unknown to the #{side.name} ref" unless side.launcher.knows?(step)
132
+ end
133
+ nil
134
+ end
135
+
136
+ # One round samples each side once, base first, and the rounds follow one another.
137
+ def rounds(sides, steps, copy_from, repeats)
138
+ taken = Array.new(repeats) { |round| sides.map { |side| sample(round, side, steps, copy_from) } }
139
+ taken.flatten.group_by { |sample| sample[:side] }.transform_values { |own| own.map { |one| one[:seconds] } }
140
+ end
141
+
142
+ def refuse_missing_tree(copy_from)
143
+ return if copy_from.nil? || File.directory?(File.join(copy_from, Checkouts::GENERATED_TREE))
144
+
145
+ raise Refused, "the definition needs a generated tree, and #{copy_from} holds none at #{Checkouts::GENERATED_TREE}"
146
+ end
147
+
148
+ def sample(round, side, steps, copy_from)
149
+ Checkouts.reset_generated_tree(side.path, copy_from)
150
+ seconds = steps.sum { |step| side.launcher.time(step) }
151
+ taken = { round: round, side: side.name, seconds: seconds, checkout: side.path }
152
+ @trail << taken
153
+ taken
154
+ end
155
+
156
+ def answer(asked, definition, sampled, load)
157
+ verdict = Verdict.new(base: sampled[:samples].fetch(:base), candidate: sampled[:samples].fetch(:candidate))
158
+ Answer.build(asked: asked, definition: definition.name, verdict: verdict, load: load,
159
+ unmeasured: sampled[:unmeasured])
160
+ end
161
+
162
+ def job_scratch
163
+ job = ENV.fetch("CLAUDE_JOB_DIR", nil)
164
+ File.join(job, "tmp") if job && !job.empty?
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hecks/ci_speed/adapters/local_runner"
4
+
5
+ module Hecks
6
+ module Adapters
7
+ # A `LocalRunner` that replays samples recorded here instead of running anything, for
8
+ # `ci_speed.behaviors`: a behaviors boot must be deterministic and fast, and the real adapter
9
+ # makes two checkouts and times real work. The verdict, the saving and the estimate are worked
10
+ # out by the real adapter's own `Verdict` and `Answer`, so only the timing is replaced.
11
+ class ReplayedRunner
12
+ # The samples each experiment name replays, in seconds, as base and candidate.
13
+ RECORDINGS = {
14
+ "wide_win" => { base: [120.0, 122.0, 124.0], candidate: [90.0, 91.0, 92.0] },
15
+ "within_noise" => { base: [120.0, 126.0, 123.0], candidate: [121.0, 124.0, 122.0] },
16
+ "wide_loss" => { base: [90.0, 91.0, 92.0], candidate: [120.0, 122.0, 124.0] }
17
+ }.freeze
18
+
19
+ # The load average every replay reports.
20
+ LOAD = 2.5
21
+
22
+ # @param aggregate [Object, nil] unused
23
+ def initialize(aggregate: nil); end
24
+
25
+ # @param held [Hash] the `Experiment` record
26
+ # @return [Hash{Symbol => Hash}] the answer, as the real adapter words it
27
+ # @raise [LocalRunner::Refused] when nothing is recorded for the experiment's name
28
+ def measure(**held)
29
+ asked = held.transform_values { |value| value.is_a?(Hash) ? value[:value] : value }
30
+ samples = RECORDINGS.fetch(asked.fetch(:name)) do
31
+ raise LocalRunner::Refused, "no samples are recorded for #{asked[:name]}; recorded: #{RECORDINGS.keys.join(", ")}"
32
+ end
33
+ verdict = LocalRunner::Verdict.new(**samples)
34
+ LocalRunner::Answer.build(asked: asked, definition: asked.fetch(:measures), verdict: verdict, load: LOAD,
35
+ unmeasured: [])
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,341 @@
1
+ Hecks.behaviors "CiSpeed" do
2
+ vision "A run is written down as it finished, and a change is kept only when a following run of its cache state beat the baseline by the margin."
3
+
4
+ # `ci_speed.hecksagon` binds every aggregate to Memory and attaches Governance, so a boot of these
5
+ # files passes the memory-only guard and the role check.
6
+ loads "../../../spec/fixtures/ci_speed/ci_speed.hecksagon", "ci_speed.bluebook", "ci_speed.ports.hecksagon"
7
+
8
+ test "Observe writes down a run as it finished" do
9
+ tests "Observe", on: "Run"
10
+ input run_id: { value: "1001" }, commit: { value: "93f8e68c6" }, wall_seconds: { value: 240 },
11
+ cache_state: { value: "miss" }, conclusion: { value: "success" }, budget_seconds: { value: 180 },
12
+ longest_pole: { value: "rspec" }
13
+ expect emits: ["RunObserved"]
14
+ end
15
+
16
+ test "RecordJob refuses a job time once the run is analysed" do
17
+ tests "RecordJob", on: "Run"
18
+ setup "CiSpeed::Run.Observe", run_id: { value: "1401" }, commit: { value: "93f8e68c6" },
19
+ wall_seconds: { value: 150 }, cache_state: { value: "hit" }, conclusion: { value: "success" },
20
+ budget_seconds: { value: 180 }, longest_pole: { value: "rspec" }
21
+ setup "CiSpeed::Run.AnalyzeWarmUnderBudget", run: "1401", seconds: { value: 150 }
22
+ input run: "1401", job: { value: "rspec" }, seconds: { value: 90 }, critical: { value: "yes" }
23
+ expect refused: "a run's job times are written before it is analysed"
24
+ end
25
+
26
+ test "AnalyzeWarmUnderBudget refuses a cache-miss run" do
27
+ tests "AnalyzeWarmUnderBudget", on: "Run"
28
+ setup "CiSpeed::Run.Observe", run_id: { value: "1301" }, commit: { value: "93f8e68c6" },
29
+ wall_seconds: { value: 150 }, cache_state: { value: "miss" }, conclusion: { value: "success" },
30
+ budget_seconds: { value: 180 }, longest_pole: { value: "rspec" }
31
+ input run: "1301", seconds: { value: 150 }
32
+ expect refused: "a warm run is a cache hit that finished within budget"
33
+ end
34
+
35
+ # A cache-miss run over budget proposes a lever for its longest pole, and its over-budget
36
+ # verdict is witnessed by the Budget.
37
+ test "A cache-miss run over budget proposes a lever for its longest pole" do
38
+ tests "AnalyzeMissOverBudget", on: "Run"
39
+ setup "CiSpeed::Budget.Open", name: { value: "main" }, target_seconds: { value: 180 }
40
+ setup "CiSpeed::Run.Observe", run_id: { value: "1002" }, commit: { value: "93f8e68c6" },
41
+ wall_seconds: { value: 240 }, cache_state: { value: "miss" }, conclusion: { value: "success" },
42
+ budget_seconds: { value: 180 }, longest_pole: { value: "rspec" }
43
+ setup "CiSpeed::Run.RecordJob", run: "1002", job: { value: "rspec" }, seconds: { value: 200 },
44
+ critical: { value: "yes" }
45
+ input run: "1002", seconds: { value: 240 }, pole: { value: "rspec" }
46
+ expect emits: %w[MissRunOverBudget MissRunWitnessed LeverProposed]
47
+ end
48
+
49
+ # A lever is kept when a following run of the same cache state beats its baseline by the margin.
50
+ test "Keep keeps an attempted lever that a same-cache run beat by the margin" do
51
+ tests "Keep", on: "Lever"
52
+ setup "CiSpeed::Lever.Propose", name: { value: "postgres_io" },
53
+ change: { value: "postgres io specs on fewer shards" }, pole: { value: "postgres_io" },
54
+ affects: { value: "miss" }, expected_seconds: { value: 30 }, basis: { value: "unestimated" }, inputs: { value: "" }
55
+ setup "CiSpeed::Lever.Attempt", lever: "postgres_io", baseline_run: { value: "1100" },
56
+ baseline_seconds: { value: 300 }, baseline_cache: { value: "miss" }
57
+ input lever: "postgres_io", following_run: { value: "1101" }, following_seconds: { value: 250 },
58
+ following_cache: { value: "miss" }, evidence: { value: "1a2b3c4d" }, saved_seconds: { value: 50 }
59
+ expect emits: ["LeverKept"]
60
+ end
61
+
62
+ test "Keep refuses a saving that is not the baseline less the following time" do
63
+ tests "Keep", on: "Lever"
64
+ setup "CiSpeed::Lever.Propose", name: { value: "postgres_io" },
65
+ change: { value: "postgres io specs on fewer shards" }, pole: { value: "postgres_io" },
66
+ affects: { value: "miss" }, expected_seconds: { value: 30 }, basis: { value: "unestimated" }, inputs: { value: "" }
67
+ setup "CiSpeed::Lever.Attempt", lever: "postgres_io", baseline_run: { value: "1100" },
68
+ baseline_seconds: { value: 300 }, baseline_cache: { value: "miss" }
69
+ input lever: "postgres_io", following_run: { value: "1101" }, following_seconds: { value: 250 },
70
+ following_cache: { value: "miss" }, evidence: { value: "1a2b3c4d" }, saved_seconds: { value: 10 }
71
+ expect refused: "a kept lever says what it really saved"
72
+ end
73
+
74
+ # A following run that is not faster by the margin reverts the lever.
75
+ test "Revert reverts an attempted lever that the following run did not beat" do
76
+ tests "Revert", on: "Lever"
77
+ setup "CiSpeed::Lever.Propose", name: { value: "rspec_4_shards" },
78
+ change: { value: "rspec on fewer shards" }, pole: { value: "rspec" },
79
+ affects: { value: "miss" }, expected_seconds: { value: 30 }, basis: { value: "unestimated" }, inputs: { value: "" }
80
+ setup "CiSpeed::Lever.Attempt", lever: "rspec_4_shards", baseline_run: { value: "1200" },
81
+ baseline_seconds: { value: 300 }, baseline_cache: { value: "miss" }
82
+ input lever: "rspec_4_shards", following_run: { value: "1201" }, following_seconds: { value: 295 },
83
+ following_cache: { value: "miss" }
84
+ expect emits: ["LeverReverted"]
85
+ end
86
+
87
+ test "Keep refuses a following run of a different cache state" do
88
+ tests "Keep", on: "Lever"
89
+ setup "CiSpeed::Lever.Propose", name: { value: "postgres_io" },
90
+ change: { value: "postgres io specs on fewer shards" }, pole: { value: "postgres_io" },
91
+ affects: { value: "both" }, expected_seconds: { value: 30 }, basis: { value: "unestimated" }, inputs: { value: "" }
92
+ setup "CiSpeed::Lever.Attempt", lever: "postgres_io", baseline_run: { value: "1100" },
93
+ baseline_seconds: { value: 300 }, baseline_cache: { value: "miss" }
94
+ input lever: "postgres_io", following_run: { value: "1101" }, following_seconds: { value: 200 },
95
+ following_cache: { value: "hit" }, evidence: { value: "1a2b3c4d" }, saved_seconds: { value: 100 }
96
+ expect refused: "a following run is of the cache state the lever was measured on"
97
+ end
98
+
99
+ test "Attempt refuses a lever measured on a cache state it does not affect" do
100
+ tests "Attempt", on: "Lever"
101
+ setup "CiSpeed::Lever.Propose", name: { value: "feature_binaries" },
102
+ change: { value: "feature binaries built in legs" }, pole: { value: "feature_binaries" },
103
+ affects: { value: "hit" }, expected_seconds: { value: 40 }, basis: { value: "unestimated" }, inputs: { value: "" }
104
+ input lever: "feature_binaries", baseline_run: { value: "1300" }, baseline_seconds: { value: 300 },
105
+ baseline_cache: { value: "miss" }
106
+ expect refused: "a lever is measured on the cache state it affects"
107
+ end
108
+
109
+ test "Reconsider refuses a reverted lever whose inputs have not changed" do
110
+ tests "Reconsider", on: "Lever"
111
+ setup "CiSpeed::Lever.Propose", name: { value: "rspec_4_shards" },
112
+ change: { value: "rspec on fewer shards" }, pole: { value: "rspec" },
113
+ affects: { value: "miss" }, expected_seconds: { value: 30 }, basis: { value: "unestimated" }, inputs: { value: "abc123" }
114
+ setup "CiSpeed::Lever.Attempt", lever: "rspec_4_shards", baseline_run: { value: "1200" },
115
+ baseline_seconds: { value: 300 }, baseline_cache: { value: "miss" }
116
+ setup "CiSpeed::Lever.Revert", lever: "rspec_4_shards", following_run: { value: "1201" },
117
+ following_seconds: { value: 295 }, following_cache: { value: "miss" }
118
+ input lever: "rspec_4_shards", new_inputs: { value: "abc123" }
119
+ expect refused: "a reverted lever is retried only when its inputs have changed"
120
+ end
121
+
122
+ test "Recall keeps a lever that history settled, with the commit that settled it" do
123
+ tests "Recall", on: "Lever"
124
+ setup "CiSpeed::Lever.Propose", name: { value: "host_test_build" },
125
+ change: { value: "host test build warmed into its own cache" }, pole: { value: "host_test_build" },
126
+ affects: { value: "both" }, expected_seconds: { value: 0 }, basis: { value: "unestimated" }, inputs: { value: "" }
127
+ input lever: "host_test_build", evidence: { value: "504f0e0d8" }
128
+ expect emits: ["LeverLearned"]
129
+ end
130
+
131
+ test "Complete refuses while the latest cache-miss run is over budget" do
132
+ tests "Complete", on: "Budget"
133
+ setup "CiSpeed::Budget.Open", name: { value: "main" }, target_seconds: { value: 180 }
134
+ setup "CiSpeed::Budget.WitnessWarm", budget: "main", seconds: { value: 150 }
135
+ setup "CiSpeed::Budget.WitnessMiss", budget: "main", seconds: { value: 200 }
136
+ input budget: "main"
137
+ expect refused: "both cache states are under budget"
138
+ end
139
+
140
+ # The effort completes once the latest warm run and the latest cache-miss run are both under
141
+ # budget. The warm verdict is witnessed by its own policy in setup.
142
+ test "A cache-miss run under budget completes the effort when the warm run is under budget" do
143
+ tests "AnalyzeMissUnderBudget", on: "Run"
144
+ setup "CiSpeed::Budget.Open", name: { value: "main" }, target_seconds: { value: 180 }
145
+ setup "CiSpeed::Run.Observe", run_id: { value: "1201" }, commit: { value: "93f8e68c6" },
146
+ wall_seconds: { value: 150 }, cache_state: { value: "hit" }, conclusion: { value: "success" },
147
+ budget_seconds: { value: 180 }, longest_pole: { value: "rspec" }
148
+ setup "CiSpeed::Run.AnalyzeWarmUnderBudget", run: "1201", seconds: { value: 150 }
149
+ setup "CiSpeed::Run.Observe", run_id: { value: "1202" }, commit: { value: "93f8e68c6" },
150
+ wall_seconds: { value: 170 }, cache_state: { value: "miss" }, conclusion: { value: "success" },
151
+ budget_seconds: { value: 180 }, longest_pole: { value: "rspec" }
152
+ input run: "1202", seconds: { value: 170 }
153
+ expect emits: %w[MissRunUnderBudget MissRunWitnessed BudgetMet]
154
+ end
155
+
156
+ # The backlog is what drives the attempts: the biggest expected saving is tried first.
157
+ test "Next is the proposed lever with the biggest expected saving" do
158
+ tests "Next", on: "Lever", kind: :query
159
+ setup "CiSpeed::Lever.Propose", name: { value: "small_win" }, change: { value: "a small change" },
160
+ pole: { value: "rspec" }, affects: { value: "both" }, expected_seconds: { value: 20 },
161
+ basis: { value: "run 40438675259 job times" }, inputs: { value: "" }
162
+ setup "CiSpeed::Lever.Propose", name: { value: "big_win" }, change: { value: "a big change" },
163
+ pole: { value: "rspec" }, affects: { value: "both" }, expected_seconds: { value: 90 },
164
+ basis: { value: "run 40438675259 job times" }, inputs: { value: "" }
165
+ setup "CiSpeed::Lever.Propose", name: { value: "middling_win" }, change: { value: "a middling change" },
166
+ pole: { value: "rspec" }, affects: { value: "both" }, expected_seconds: { value: 50 },
167
+ basis: { value: "run 40438675259 job times" }, inputs: { value: "" }
168
+ expect count: 1, name: { value: "big_win" }
169
+ end
170
+
171
+ test "Reestimate revises the saving a proposed lever is expected to make" do
172
+ tests "Reestimate", on: "Lever"
173
+ setup "CiSpeed::Lever.Propose", name: { value: "fuzz_sqlite" }, change: { value: "split the fuzz sqlite job" },
174
+ pole: { value: "checks_fuzz_sqlite" }, affects: { value: "hit" }, expected_seconds: { value: 0 },
175
+ basis: { value: "unestimated" }, inputs: { value: "" }
176
+ input lever: "fuzz_sqlite", new_expected_seconds: { value: 60 },
177
+ new_basis: { value: "run 40438675259: the job ran 191s, the next slowest 183s" }
178
+ expect emits: ["LeverReestimated"]
179
+ end
180
+
181
+ test "Reestimate refuses an estimate that says nothing about what it rests on" do
182
+ tests "Reestimate", on: "Lever"
183
+ setup "CiSpeed::Lever.Propose", name: { value: "fuzz_sqlite" }, change: { value: "split the fuzz sqlite job" },
184
+ pole: { value: "checks_fuzz_sqlite" }, affects: { value: "hit" }, expected_seconds: { value: 0 },
185
+ basis: { value: "unestimated" }, inputs: { value: "" }
186
+ input lever: "fuzz_sqlite", new_expected_seconds: { value: 60 }, new_basis: { value: "unestimated" }
187
+ expect refused: "a revised estimate says what it rests on"
188
+ end
189
+
190
+ # Meeting 180 seconds is a milestone: the target drops and the backlog goes on.
191
+ test "Reopen sets a lower target once the last one is met" do
192
+ tests "Reopen", on: "Budget"
193
+ setup "CiSpeed::Budget.Open", name: { value: "main" }, target_seconds: { value: 180 }
194
+ setup "CiSpeed::Budget.WitnessWarm", budget: "main", seconds: { value: 150 }
195
+ setup "CiSpeed::Budget.WitnessMiss", budget: "main", seconds: { value: 170 }
196
+ input budget: "main", new_target_seconds: { value: 150 }
197
+ expect emits: ["BudgetReopened"]
198
+ end
199
+
200
+ test "Reopen refuses a target that is not lower than the one met" do
201
+ tests "Reopen", on: "Budget"
202
+ setup "CiSpeed::Budget.Open", name: { value: "main" }, target_seconds: { value: 180 }
203
+ setup "CiSpeed::Budget.WitnessWarm", budget: "main", seconds: { value: 150 }
204
+ setup "CiSpeed::Budget.WitnessMiss", budget: "main", seconds: { value: 170 }
205
+ input budget: "main", new_target_seconds: { value: 200 }
206
+ expect refused: "a new target is lower than the one met"
207
+ end
208
+
209
+ # The experiments below are answered by `spec/fixtures/ci_speed/replayed_runner.adapter`, which
210
+ # replays recorded samples under the experiment's name (`wide_win`, `within_noise`, `wide_loss`)
211
+ # and refuses any other name. The real `LocalRunner` makes two checkouts and times real work, so
212
+ # `spec/ci_speed_local_runner_spec.rb` holds it instead.
213
+ test "Request refuses a candidate that is the same ref as its base" do
214
+ tests "Request", on: "Experiment"
215
+ input name: { value: "same_ref" }, lever: { value: "" }, measures: { value: "regenerate_corpus_cold" },
216
+ cache_state: { value: "miss" }, base_ref: { value: "HEAD" }, candidate_ref: { value: "HEAD" },
217
+ repeats: { value: 3 }
218
+ expect refused: "a candidate is a different ref from its base"
219
+ end
220
+
221
+ test "Request refuses a single sample, which has no spread to judge it by" do
222
+ tests "Request", on: "Experiment"
223
+ input name: { value: "one_sample" }, lever: { value: "" }, measures: { value: "regenerate_corpus_cold" },
224
+ cache_state: { value: "miss" }, base_ref: { value: "HEAD~1" }, candidate_ref: { value: "HEAD" },
225
+ repeats: { value: 1 }
226
+ expect refused: "an experiment is repeated at least twice"
227
+ end
228
+
229
+ test "A measured faster result completes" do
230
+ tests "Request", on: "Experiment"
231
+ input name: { value: "wide_win" }, lever: { value: "" }, measures: { value: "regenerate_corpus_cold" },
232
+ cache_state: { value: "miss" }, base_ref: { value: "HEAD~1" }, candidate_ref: { value: "HEAD" },
233
+ repeats: { value: 3 }
234
+ expect emits: %w[ExperimentRequested ExperimentAnswered ExperimentMeasured]
235
+ end
236
+
237
+ test "A result inside the spread is inconclusive and re-estimates nothing" do
238
+ tests "Request", on: "Experiment"
239
+ setup "CiSpeed::Lever.Propose", name: { value: "parallel_rustfmt" },
240
+ change: { value: "rustfmt on one thread per core" }, pole: { value: "generated_rust" },
241
+ affects: { value: "miss" }, expected_seconds: { value: 0 }, basis: { value: "unestimated" }, inputs: { value: "" }
242
+ input name: { value: "within_noise" }, lever: { value: "parallel_rustfmt" },
243
+ measures: { value: "regenerate_corpus_cold" }, cache_state: { value: "miss" },
244
+ base_ref: { value: "HEAD~1" }, candidate_ref: { value: "HEAD" }, repeats: { value: 3 }
245
+ expect emits: %w[ExperimentRequested ExperimentAnswered ExperimentMeasured]
246
+ end
247
+
248
+ test "A faster conclusive result re-estimates the lever it names" do
249
+ tests "Request", on: "Experiment"
250
+ setup "CiSpeed::Lever.Propose", name: { value: "parallel_rustfmt" },
251
+ change: { value: "rustfmt on one thread per core" }, pole: { value: "generated_rust" },
252
+ affects: { value: "miss" }, expected_seconds: { value: 0 }, basis: { value: "unestimated" }, inputs: { value: "" }
253
+ input name: { value: "wide_win" }, lever: { value: "parallel_rustfmt" },
254
+ measures: { value: "regenerate_corpus_cold" }, cache_state: { value: "miss" },
255
+ base_ref: { value: "HEAD~1" }, candidate_ref: { value: "HEAD" }, repeats: { value: 3 }
256
+ expect emits: %w[ExperimentRequested ExperimentAnswered ExperimentMeasured LeverReestimated]
257
+ end
258
+
259
+ test "The lever carries what the experiment measured, as its estimate" do
260
+ tests "Next", on: "Lever", kind: :query
261
+ setup "CiSpeed::Lever.Propose", name: { value: "parallel_rustfmt" },
262
+ change: { value: "rustfmt on one thread per core" }, pole: { value: "generated_rust" },
263
+ affects: { value: "miss" }, expected_seconds: { value: 0 }, basis: { value: "unestimated" }, inputs: { value: "" }
264
+ setup "CiSpeed::Experiment.Request", name: { value: "wide_win" }, lever: { value: "parallel_rustfmt" },
265
+ measures: { value: "regenerate_corpus_cold" }, cache_state: { value: "miss" },
266
+ base_ref: { value: "HEAD~1" }, candidate_ref: { value: "HEAD" }, repeats: { value: 3 }
267
+ expect count: 1, name: { value: "parallel_rustfmt" }, expected_seconds: { value: 31 }
268
+ end
269
+
270
+ test "A slower result says nothing to the backlog" do
271
+ tests "Request", on: "Experiment"
272
+ setup "CiSpeed::Lever.Propose", name: { value: "parallel_rustfmt" },
273
+ change: { value: "rustfmt on one thread per core" }, pole: { value: "generated_rust" },
274
+ affects: { value: "miss" }, expected_seconds: { value: 0 }, basis: { value: "unestimated" }, inputs: { value: "" }
275
+ input name: { value: "wide_loss" }, lever: { value: "parallel_rustfmt" },
276
+ measures: { value: "regenerate_corpus_cold" }, cache_state: { value: "miss" },
277
+ base_ref: { value: "HEAD~1" }, candidate_ref: { value: "HEAD" }, repeats: { value: 3 }
278
+ expect emits: %w[ExperimentRequested ExperimentAnswered ExperimentMeasured]
279
+ end
280
+
281
+ test "Request is faulted when the runner refuses it" do
282
+ tests "Request", on: "Experiment"
283
+ input name: { value: "unrecorded" }, lever: { value: "" }, measures: { value: "regenerate_corpus_cold" },
284
+ cache_state: { value: "miss" }, base_ref: { value: "HEAD~1" }, candidate_ref: { value: "HEAD" },
285
+ repeats: { value: 3 }
286
+ expect emits: %w[ExperimentRequested ExperimentRefused ExperimentFaulted]
287
+ end
288
+
289
+ test "A fault records why" do
290
+ tests "Outcome", on: "Experiment", kind: :query
291
+ setup "CiSpeed::Experiment.Request", name: { value: "unrecorded" }, lever: { value: "" },
292
+ measures: { value: "regenerate_corpus_cold" }, cache_state: { value: "miss" },
293
+ base_ref: { value: "HEAD~1" }, candidate_ref: { value: "HEAD" }, repeats: { value: 3 }
294
+ input name: { value: "unrecorded" }
295
+ expect count: 1, status: "faulted",
296
+ refusal: { value: "Hecks::Adapters::LocalRunner::Refused: no samples are recorded for unrecorded; " \
297
+ "recorded: wide_win, within_noise, wide_loss" }
298
+ end
299
+
300
+ # A verdict has to say what the numbers say. The record here is faulted, not requested, because
301
+ # the givens are checked before the lifecycle, and they are what is held to account.
302
+ test "Complete refuses a faster verdict whose saving is not larger than the spread" do
303
+ tests "Complete", on: "Experiment"
304
+ setup "CiSpeed::Experiment.Request", name: { value: "unrecorded" }, lever: { value: "" },
305
+ measures: { value: "regenerate_corpus_cold" }, cache_state: { value: "miss" },
306
+ base_ref: { value: "HEAD~1" }, candidate_ref: { value: "HEAD" }, repeats: { value: 3 }
307
+ input experiment: "unrecorded", base_seconds: { value: 120.0 }, candidate_seconds: { value: 118.0 },
308
+ spread_seconds: { value: 6.0 }, saved_seconds: { value: 2.0 }, load: { value: 2.5 },
309
+ unmeasured: { value: "" }, verdict: { value: "faster" }, basis: { value: "a guess" },
310
+ reestimates: { value: "" }, expected_seconds: { value: 2 }
311
+ expect refused: "a faster verdict needs a saving larger than the spread"
312
+ end
313
+
314
+ test "Complete refuses an estimate on a result that is not faster" do
315
+ tests "Complete", on: "Experiment"
316
+ setup "CiSpeed::Experiment.Request", name: { value: "unrecorded" }, lever: { value: "" },
317
+ measures: { value: "regenerate_corpus_cold" }, cache_state: { value: "miss" },
318
+ base_ref: { value: "HEAD~1" }, candidate_ref: { value: "HEAD" }, repeats: { value: 3 }
319
+ input experiment: "unrecorded", base_seconds: { value: 120.0 }, candidate_seconds: { value: 118.0 },
320
+ spread_seconds: { value: 6.0 }, saved_seconds: { value: 2.0 }, load: { value: 2.5 },
321
+ unmeasured: { value: "" }, verdict: { value: "inconclusive" }, basis: { value: "a guess" },
322
+ reestimates: { value: "" }, expected_seconds: { value: 2 }
323
+ expect refused: "only a faster verdict carries an estimate"
324
+ end
325
+
326
+ test "Record keeps a finding, with its cause and the remedy still to try" do
327
+ tests "Record", on: "Finding"
328
+ input name: { value: "cache_download_stall" }, status: { value: "untried" },
329
+ symptom: { value: "one gem cache download stopped at 91% for about 80 seconds" },
330
+ cause: { value: "the cache service, seen once" },
331
+ remedy: { value: "set SEGMENT_DOWNLOAD_TIMEOUT_MINS to about a minute and check what a timeout does" }
332
+ expect emits: %w[FindingRecorded]
333
+ end
334
+
335
+ test "Record refuses a finding with no name" do
336
+ tests "Record", on: "Finding"
337
+ input name: { value: "" }, status: { value: "open" },
338
+ symptom: { value: "a symptom" }, cause: { value: "a cause" }, remedy: { value: "a remedy" }
339
+ expect refused: "must match"
340
+ end
341
+ end