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
@@ -30,7 +30,7 @@ module Hecks
30
30
  # @return [Boolean] true when the row was pending and is now claimed; false when it is
31
31
  # unknown or another claimer got there first
32
32
  # @raise [SQLite3::Exception] if the update fails
33
- def outbox_claim(id) # rubocop:disable Naming/PredicateMethod -- the outbox port's verb
33
+ def outbox_claim(id)
34
34
  @db.execute(
35
35
  "UPDATE hecks_outbox SET status = 'claimed', attempts = attempts + 1, claimed_at = ? " \
36
36
  "WHERE id = ? AND status = 'pending'",
@@ -48,7 +48,7 @@ module Hecks
48
48
  # @param error [String, nil] the failure description, or nil to store NULL
49
49
  # @return [Boolean] true when exactly one row was updated; false when no row has `id`
50
50
  # @raise [SQLite3::Exception] if the update fails
51
- def outbox_settle(id, status:, error: nil) # rubocop:disable Naming/PredicateMethod -- the outbox port's verb
51
+ def outbox_settle(id, status:, error: nil)
52
52
  @db.execute(
53
53
  "UPDATE hecks_outbox SET status = ?, error = ?, settled_at = ? WHERE id = ?",
54
54
  [status.to_s, error, Time.now.utc.iso8601, id]
@@ -97,7 +97,7 @@ module Hecks
97
97
  # @param id [String, Object] the aggregate identity, journalled as `id.to_s`
98
98
  # @return [Boolean] always true
99
99
  # @raise [SQLite3::Exception] if either statement fails
100
- def delete(id) # rubocop:disable Naming/PredicateMethod -- the repository port's verb, not a question
100
+ def delete(id)
101
101
  entry = Ports::Persistence::Entry.new(operation: "delete", id: id.to_s, state: nil)
102
102
  append(entry)
103
103
  project(entry)
@@ -15,10 +15,30 @@ module Hecks
15
15
  @db.execute(
16
16
  "CREATE TABLE IF NOT EXISTS #{quoted_table} (id TEXT PRIMARY KEY#{", " unless columns.empty?}#{columns.join(", ")})"
17
17
  )
18
+ ensure_aggregate_columns!
18
19
  # Called here so D1, which reuses this module, gets automatic indexing too.
19
20
  ensure_indexes!
20
21
  end
21
22
 
23
+ # CREATE TABLE IF NOT EXISTS never adds a column to an existing table, so an attribute the
24
+ # aggregate gained after its table was made gets its column here: nullable, since every row
25
+ # written before it holds no value. It only adds; a column the aggregate dropped is kept.
26
+ # SQLite column names are case-insensitive, so presence is compared that way too.
27
+ def ensure_aggregate_columns!
28
+ present = @db.execute("PRAGMA table_info(#{quoted_table})").map { |row| row["name"].to_s.downcase }
29
+ persisted_fields.reject { |field| present.include?(field[:name].to_s.downcase) }.each do |field|
30
+ add_column_once!(field)
31
+ end
32
+ end
33
+
34
+ # Another process or isolate may add the same column between the read and this ALTER;
35
+ # that duplicate is the outcome wanted, so only that error is let through.
36
+ def add_column_once!(field)
37
+ @db.execute("ALTER TABLE #{quoted_table} ADD COLUMN #{quote_ident(field[:name])} #{field[:sql_type]}")
38
+ rescue StandardError => e
39
+ raise unless e.message.include?("duplicate column name")
40
+ end
41
+
22
42
  def create_event_table!
23
43
  @db.execute(Ddl::EVENTS)
24
44
  # Backs #events_for's per-record lookup (a `corrects` command's history read).
@@ -3,6 +3,7 @@ require "fileutils"
3
3
 
4
4
  require_relative "sql_query_builder"
5
5
  require_relative "sqlite/schema_builder"
6
+ require_relative "sqlite/name_guard"
6
7
  require_relative "sqlite/codec"
7
8
  require_relative "sqlite/dialect"
8
9
  require_relative "sqlite/events"
@@ -28,6 +29,7 @@ module Hecks
28
29
  class Sqlite
29
30
  include SqlQueryBuilder
30
31
  include SchemaBuilder
32
+ include NameGuard
31
33
  include Codec
32
34
  include Repository
33
35
  include Journal
@@ -70,6 +72,7 @@ module Hecks
70
72
  # Scopes saga rows; falls back to the aggregate's name for a directly built adapter.
71
73
  @domain = settings.fetch(:domain) { aggregate.name }.to_s
72
74
  open_database
75
+ refuse_orphaned_rows!
73
76
  create_tables!
74
77
  end
75
78
 
@@ -85,7 +88,9 @@ module Hecks
85
88
  def transaction(&)
86
89
  return yield if @db.transaction_active?
87
90
 
88
- @db.transaction(&)
91
+ # Immediate, so the write lock is taken up front: a deferred transaction that reads and then
92
+ # writes fails at once when another process holds the file, and the busy timeout never runs.
93
+ @db.transaction(:immediate, &)
89
94
  end
90
95
 
91
96
  # Names the aggregate's table; the journal table and outbox rows are keyed off it.
@@ -98,6 +103,9 @@ module Hecks
98
103
  def open_database
99
104
  FileUtils.mkdir_p(File.dirname(@path))
100
105
  @db = SQLite3::Database.new(@path)
106
+ # Several processes may boot one journal at once (the gate's checks do), so a busy file
107
+ # is waited for rather than refused as "database is locked".
108
+ @db.busy_timeout = 10_000
101
109
  @db.results_as_hash = true
102
110
  # The append is the recovery commit point, so the fsync policy is explicit.
103
111
  @db.execute("PRAGMA synchronous = FULL")
@@ -37,7 +37,7 @@ module Hecks
37
37
  # @param adapter [String, Hash, nil] the adapter the overlay binds; PostgresEra when none
38
38
  # @return [Hash{Symbol => Object}] `:slug`, `:domain`, `:realm`, `:schema` and `:output`
39
39
  # @raise [Refused] when a value is outside its allow-list or the path leaves `environments/`
40
- def write_overlay(slug:, domain:, realm:, schema:, database:, directory:, adapter: nil, **) # rubocop:disable Metrics/ParameterLists -- one keyword per command attribute
40
+ def write_overlay(slug:, domain:, realm:, schema:, database:, directory:, adapter: nil, **)
41
41
  values = { slug: unwrap(slug), domain: unwrap(domain), realm: unwrap(realm),
42
42
  schema: unwrap(schema), database: unwrap(database),
43
43
  adapter: adapter_name(adapter) }
@@ -0,0 +1,117 @@
1
+ module Hecks
2
+ module Adapters
3
+ # Says, once per process, when a linked worktree lacks the gitignored overlay files its main
4
+ # checkout keeps. Those files exist only in the main checkout, so a command run from a
5
+ # worktree stores in Memory without saying so. This warns; it never blocks the command.
6
+ module WorktreeOverlay
7
+ # The line a linked worktree's `.git` file holds, naming the directory in the main checkout.
8
+ GITDIR_LINE = /\Agitdir: (.+)\s*\z/
9
+
10
+ # Where the overlay files live, relative to a checkout's root.
11
+ OVERLAY_PATTERNS = ["lib/hecks/hecks/*.local.hecksagon", "lib/hecks/hecks/*.local.world",
12
+ "environments/local.hecksagon", "environments/local.world"].freeze
13
+
14
+ module_function
15
+
16
+ # Warns on standard error the first time a domain loads from a linked worktree that lacks
17
+ # overlay files of its main checkout. Nothing is printed again in the same process.
18
+ #
19
+ # @param directory [String] the domain directory being loaded
20
+ # @param err [#puts] where the warning goes
21
+ # @return [String, nil] the warning printed, or nil when there was nothing to say
22
+ def warn_once(directory, err: $stderr)
23
+ return if @warned
24
+
25
+ text = warning_for(directory)
26
+ return unless text
27
+
28
+ @warned = true
29
+ err.puts(text)
30
+ text
31
+ end
32
+
33
+ # The warning for a directory inside a linked worktree, or nil when none applies.
34
+ #
35
+ # @param directory [String] a directory inside a checkout
36
+ # @return [String, nil]
37
+ def warning_for(directory)
38
+ _main, files = gap(directory)
39
+ message(files)
40
+ end
41
+
42
+ # The main checkout a linked worktree was made from, and the overlay files that checkout
43
+ # holds and this worktree lacks. Nothing is returned for a checkout that is not a worktree.
44
+ #
45
+ # @param directory [String] a directory inside a checkout
46
+ # @return [Array(String, Array<String>), Array(nil, Array)] the main checkout's root, then the
47
+ # relative paths of the overlay files it holds and the worktree lacks
48
+ def gap(directory)
49
+ worktree = checkout_root(directory)
50
+ main = worktree && main_checkout(worktree)
51
+ return [nil, []] unless main
52
+
53
+ [main, missing(overlay_files(main), overlay_files(worktree))]
54
+ end
55
+
56
+ # Relative paths of the overlay files that a checkout holds.
57
+ #
58
+ # @param root [String] a checkout's root
59
+ # @return [Array<String>] sorted relative paths
60
+ def overlay_files(root)
61
+ OVERLAY_PATTERNS.flat_map { |pattern| Dir.glob(File.join(root, pattern)) }
62
+ .map { |path| path.delete_prefix("#{root}/") }
63
+ .sort
64
+ end
65
+
66
+ # The overlay files the main checkout holds and the worktree does not.
67
+ #
68
+ # @param main [Array<String>] relative paths in the main checkout
69
+ # @param worktree [Array<String>] relative paths in the worktree
70
+ # @return [Array<String>]
71
+ def missing(main, worktree)
72
+ main - worktree
73
+ end
74
+
75
+ # The one-line warning naming the files and the store they change.
76
+ #
77
+ # @param files [Array<String>] relative paths the worktree lacks
78
+ # @return [String, nil] the warning, or nil when no file is missing
79
+ def message(files)
80
+ return if files.empty?
81
+
82
+ "hecks: this worktree lacks #{files.join(", ")} from the main checkout; " \
83
+ "bluebooks that use them store in Memory here, not in the main checkout's store"
84
+ end
85
+
86
+ # The root of the checkout a directory is in, and whether that checkout is a linked worktree.
87
+ #
88
+ # @param directory [String]
89
+ # @return [String, nil] the root when it is a linked worktree, else nil
90
+ def checkout_root(directory)
91
+ root = ascend_to_git(File.expand_path(directory))
92
+ root if root && File.file?(File.join(root, ".git"))
93
+ end
94
+
95
+ # The main checkout a linked worktree was made from, found through its `.git` file.
96
+ #
97
+ # @param worktree [String] a linked worktree's root
98
+ # @return [String, nil]
99
+ def main_checkout(worktree)
100
+ gitdir = File.read(File.join(worktree, ".git"))[GITDIR_LINE, 1]
101
+ return unless gitdir
102
+
103
+ common = File.expand_path("../..", File.expand_path(gitdir, worktree))
104
+ File.dirname(common)
105
+ end
106
+
107
+ # Walks up from a directory to the first one holding a `.git` entry.
108
+ #
109
+ # @param directory [String] an absolute path
110
+ # @return [String, nil]
111
+ def ascend_to_git(directory)
112
+ root = Pathname.new(directory).ascend.find { |dir| dir.join(".git").exist? }
113
+ root&.to_s
114
+ end
115
+ end
116
+ end
117
+ end
@@ -4,6 +4,10 @@ module Hecks
4
4
  module Cli
5
5
  # Rewrites the shorthand spellings of a command line into plain `name=value` words.
6
6
  module Shorthand
7
+ # The declared types a bare `--name` flag may stand for: a plain Boolean, or a `Switch`,
8
+ # which wraps one.
9
+ BOOLEAN_TYPES = %w[Boolean Switch].freeze
10
+
7
11
  module_function
8
12
 
9
13
  # Rewrites the short forms into `name=value`: `--name` for a Boolean (a following `yes`,
@@ -58,7 +62,7 @@ module Hecks
58
62
  def flag(name, options)
59
63
  name = name.tr("-", "_") unless options.key?(name) || options.keys.any? { |key| key.start_with?("#{name}.") }
60
64
  path = options.key?(name) ? name : Cli.expand(name, options)
61
- return path if options.dig(path, :type) == "Boolean"
65
+ return path if BOOLEAN_TYPES.include?(options.dig(path, :type))
62
66
 
63
67
  raise Runtime::NotFound, "--#{name} is a flag, but this command has no Boolean argument #{name.inspect}"
64
68
  end
@@ -75,7 +75,7 @@ module Hecks
75
75
  case type
76
76
  when "Integer" then Integer(value)
77
77
  when "Float" then Float(value)
78
- when "Boolean" then boolean(value)
78
+ when "Boolean", "Switch" then boolean(value)
79
79
  else value
80
80
  end
81
81
  rescue ArgumentError
@@ -1,4 +1,6 @@
1
1
  require "json"
2
+ require_relative "run_reference"
3
+ require_relative "read_context"
2
4
 
3
5
  module Hecks
4
6
  module Adapters
@@ -9,41 +11,67 @@ module Hecks
9
11
  module Answers
10
12
  # What a dispatch needs beyond the spec: the parsed arguments, whether `--wait` was given,
11
13
  # and the bluebook and launcher setting the command belongs to.
12
- Invocation = Struct.new(:args, :wait, :bluebook, :launcher, :text)
14
+ Invocation = Struct.new(:args, :wait, :bluebook, :launcher, :text, :plan)
13
15
 
14
16
  # The flag that asks for a command's recorded output as plain text and nothing else.
15
17
  TEXT = "--text".freeze
16
18
 
19
+ # The flag that asks what a command would write and announce, writing nothing.
20
+ PLAN = "--plan".freeze
21
+
17
22
  # Parses one resolved command's arguments, runs it as a query or command, and turns the
18
- # outcome, or the domain's refusal, into `[json_or_message, status]`. With `--wait`, a
19
- # question whose report names a gap (`LauncherOptions.gap_reported?`) answers status 1.
23
+ # outcome, or the domain's refusal, into `[json_or_message, status]`. A word the command
24
+ # does not take, a value its type cannot hold or a flag it lacks is a line that could
25
+ # not be read (`ExitStatus::USAGE`); everything the domain says no to, a missing record
26
+ # included, is `REFUSED`. With `--wait`, a question whose report names a gap
27
+ # (`LauncherOptions.gap_reported?`) is refused too.
20
28
  #
21
29
  # @param bluebook [Bluebook::Declaration] the bluebook the command belongs to
22
30
  # @param launcher [Hash, nil] the bluebook's `launcher` world setting; nil when not opted
23
31
  # in
24
- def dispatch(runtime, spec, name, rest, program, asking, bluebook: nil, launcher: nil) # rubocop:disable Metrics/ParameterLists -- the signature is what `call` passes
25
- args, wait, text = command_line(spec, rest, launcher)
26
- return answer_query(runtime, spec, args, wait, launcher) if spec[:kind] == :query
32
+ def dispatch(runtime, spec, name, rest, program, asking, bluebook: nil, launcher: nil)
33
+ plan = rest.include?(PLAN)
34
+ args, wait, text = command_line(spec, plan ? rest - [PLAN] : rest, launcher)
35
+ run(runtime, spec, Invocation.new(args, wait, bluebook, launcher, text, plan), name, program, asking)
36
+ rescue Runtime::NotFound, Runtime::TypeMismatch => e
37
+ [help_pointer(e, name, program, asking), ExitStatus::USAGE]
38
+ end
39
+
40
+ # Runs a parsed line as a query or a command, and shapes the domain's refusal.
41
+ # @api private
42
+ def run(runtime, spec, invocation, name, program, asking)
43
+ return plan_or_refuse(runtime, spec, invocation, name) if invocation.plan
44
+ return answer_query(runtime, spec, invocation.args, invocation.wait, invocation.launcher) if spec[:kind] == :query
27
45
 
28
- run_command(runtime, spec, Invocation.new(args, wait, bluebook, launcher, text))
46
+ run_command(runtime, spec, invocation)
29
47
  rescue Runtime::NotFound, Runtime::TypeMismatch => e
30
- # A bad argument and a missing record both need the same next step: read the help.
31
- ["#{e.message}\n\n #{program} #{"query " if asking}#{name} --help", 1]
48
+ # A missing record needs the same next step as a bad argument: read the help.
49
+ [help_pointer(e, name, program, asking), ExitStatus::REFUSED]
32
50
  rescue *Runtime::DOMAIN_REFUSALS => e
33
51
  # The refusal is the bluebook's own sentence, verbatim.
34
- [e.message, 1]
52
+ [coded(e), ExitStatus::REFUSED]
35
53
  rescue StandardError => e
36
54
  # So is a wrapped tool's, when a question's adapter refuses to answer.
37
55
  raise unless tool_refusal?(e)
38
56
 
39
- [e.message, 1]
57
+ [e.message, ExitStatus::REFUSED]
58
+ end
59
+
60
+ # A refusal's text, led by its stable code so a script can branch on it.
61
+ # @api private
62
+ def coded(error) = "[#{error.code}] #{error.message}"
63
+
64
+ # An error's message, then the line that prints the command's help.
65
+ # @api private
66
+ def help_pointer(error, name, program, asking)
67
+ "#{coded(error)}\n\n #{program} #{"query " if asking}#{name} --help"
40
68
  end
41
69
 
42
70
  # The parsed arguments of a command line, whether to wait for the reactions, and whether
43
71
  # `--text` asked for the recorded output alone (which waits).
44
72
  def command_line(spec, rest, launcher)
45
73
  text = launcher ? rest.include?(TEXT) : false
46
- rest, wait = LauncherOptions.take_wait(spec, rest - [TEXT]) if launcher
74
+ rest, wait = LauncherOptions.take_wait(spec, launcher ? rest - [TEXT] : rest)
47
75
  [Cli.arguments(spec, rest), text || wait || LauncherOptions.settled?(launcher, spec), text]
48
76
  end
49
77
 
@@ -55,16 +83,43 @@ module Hecks
55
83
  ancestor_names.include?(CliRunner::TOOL_REFUSAL)
56
84
  end
57
85
 
86
+ # Answers `--plan`: a command's plan, or usage for a query, which writes nothing to plan.
87
+ # @api private
88
+ def plan_or_refuse(runtime, spec, invocation, name)
89
+ return plan_refused_for_query(name) if spec[:kind] == :query
90
+
91
+ plan_answer(runtime, spec, invocation)
92
+ end
93
+
94
+ # Lists what a command would write and announce, writing nothing. A refusal the real run
95
+ # would give is answered as that refusal.
96
+ # @api private
97
+ def plan_answer(runtime, spec, invocation)
98
+ lines = runtime.plan_flat(spec[:command], **normalized_request(spec, invocation.args))
99
+ [lines.empty? ? "would not write or announce anything" : lines.join("\n"), ExitStatus::ANSWERED]
100
+ rescue *Runtime::DOMAIN_REFUSALS, Runtime::NotFound, Runtime::TypeMismatch => e
101
+ [coded(e), ExitStatus::REFUSED]
102
+ end
103
+
104
+ # A query has nothing to write, so `--plan` on one is a usage mistake.
105
+ # @api private
106
+ def plan_refused_for_query(name)
107
+ ["hecks: #{name} is a query and writes nothing, so --plan has nothing to show", ExitStatus::USAGE]
108
+ end
109
+
58
110
  # Runs a command and answers its outcome, settled when `--wait` asks for it.
59
111
  def run_command(runtime, spec, invocation)
60
- args, minted = LauncherOptions.run_key(runtime, spec, invocation.args, invocation.launcher)
112
+ args, minted = RunReference.prepare(runtime, spec, invocation.args, invocation.launcher)
113
+ replayed = RunReplay.answer(runtime, spec, args)
114
+ return replayed if replayed
115
+
61
116
  handle = runtime.dispatch_flat(spec[:command], normalized_request(spec, args))
62
- extra = refusals_and_run(handle, minted)
117
+ extra = refusals_and_run(handle, minted, args)
63
118
  if invocation.wait
64
119
  return settled(runtime, spec, handle, invocation.bluebook, invocation.launcher, extra, text: invocation.text)
65
120
  end
66
121
 
67
- [JSON.pretty_generate(outcome(handle, extra)), 0]
122
+ [JSON.pretty_generate(outcome(handle, extra)), ExitStatus::ANSWERED]
68
123
  end
69
124
 
70
125
  # The request a command takes from its parsed arguments.
@@ -73,8 +128,8 @@ module Hecks
73
128
  end
74
129
 
75
130
  # The refused reactions of the dispatch, led by the minted run key when one was.
76
- def refusals_and_run(handle, minted)
77
- extra = refused_answer(handle)
131
+ def refusals_and_run(handle, minted, args = {})
132
+ extra = refused_answer(handle).merge(ids: RunReference.ids(args, handle.id))
78
133
  minted ? { run: minted }.merge(extra) : extra
79
134
  end
80
135
 
@@ -92,12 +147,12 @@ module Hecks
92
147
  # questions that refuse a run they do not hold
93
148
  # @return [Array(String, Integer)] the answer and the status
94
149
  def answer_query(runtime, spec, args, wait, launcher = nil)
95
- rows = runtime.query(spec[:command], **args)
96
- return [unknown_run(args), 1] if rows.empty? && LauncherOptions.unknown_run?(launcher, spec)
150
+ rows = runtime.query(spec[:command], **ReadContext.fill(spec, args))
151
+ return [unknown_run(args), ExitStatus::REFUSED] if rows.empty? && LauncherOptions.unknown_run?(launcher, spec)
97
152
 
98
153
  text = text_answer(spec, rows)
99
154
  [text || JSON.pretty_generate(rows.map { |row| Json.materialize(row) }),
100
- wait && LauncherOptions.gap_reported?(text) ? 1 : 0]
155
+ wait && LauncherOptions.gap_reported?(text) ? ExitStatus::REFUSED : ExitStatus::ANSWERED]
101
156
  end
102
157
 
103
158
  # What a question about one run answers when the process holds no such run, for a
@@ -151,8 +206,8 @@ module Hecks
151
206
 
152
207
  # Shapes a port operation's outcome, which has no state: each event with its full payload.
153
208
  #
154
- # The answer lives only in the payloads, so names alone would drop it. Exit status stays 0
155
- # for refusal events too, since a healthy no is an answer, not a misuse.
209
+ # The answer lives only in the payloads, so names alone would drop it. The status stays
210
+ # `ANSWERED` for refusal events too, since a healthy no is an answer, not a misuse.
156
211
  def answered(handle)
157
212
  # A port operation hydrates no instance, so the handle's `id` is nil by design.
158
213
  { id: handle.id || handle.events.first&.id,
@@ -0,0 +1,35 @@
1
+ module Hecks
2
+ module Adapters
3
+ module Driving
4
+ module CliRunner
5
+ # The bang rule: a line that writes says so with `!`, and a command written without it is
6
+ # refused, naming the spelling that writes. Extended into `CliRunner`.
7
+ module BangRule
8
+ # The word a line names as typed, before the launcher's own rewrites.
9
+ def typed_word(argv)
10
+ CliRunner::QUERY_WORDS.include?(argv.first) ? argv[1] : argv.first
11
+ end
12
+
13
+ # The answer a line gets before any command runs: its help, or its refusal for a
14
+ # command written without its bang.
15
+ def early_answer(scope, cli, line)
16
+ return [command_help(scope, line[:name], line[:asking]), ExitStatus::ANSWERED] if line[:argv][1..].include?("--help")
17
+
18
+ bang_less_refusal(cli, line[:asking], line[:word], line[:name], scope[:program])
19
+ end
20
+
21
+ # A command written without its `!` is refused. A query, and a name that is not a
22
+ # command, pass.
23
+ #
24
+ # @return [Array(String, Integer), nil] the refusal and its usage status, or nil
25
+ def bang_less_refusal(cli, asking, word, name, program)
26
+ return nil if asking || word.nil? || word.end_with?("!")
27
+ return nil unless cli[:names][:command].key?(name)
28
+
29
+ ["#{program}: #{word} is a command and writes; write it as #{word}!", ExitStatus::USAGE]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,36 @@
1
+ module Hecks
2
+ module Adapters
3
+ module Driving
4
+ module CliRunner
5
+ # The launcher word `completion <shell>` (ADR 0163, plan step 7): the script that completes
6
+ # the launcher's words in that shell, written from the same listing the help prints.
7
+ module CompletionWords
8
+ # The answer to `completion <shell>`: the script on stdout, or the usage line when the
9
+ # shell is missing or not one this projection writes.
10
+ def completion_answer(scope, argv)
11
+ return unless argv.first == "completion"
12
+
13
+ shell = argv[1]
14
+ script = script_for(scope, shell)
15
+ return { answer: ["usage: #{scope[:program]} completion <#{shells_word}>", ExitStatus::USAGE] } unless script
16
+
17
+ { answer: [script, ExitStatus::ANSWERED] }
18
+ end
19
+
20
+ # The script for one shell, or nil when the projection writes none for it.
21
+ def script_for(scope, shell)
22
+ return unless Projector::CliProjector::Completion::SHELLS.include?(shell)
23
+
24
+ words = Projector::CliProjector.completion_words(scope[:bluebook], scope[:cli], scope[:shown])
25
+ Projector::CliProjector.completion_script(shell, scope[:program], words)
26
+ end
27
+
28
+ # The shells named in the usage line.
29
+ def shells_word
30
+ Projector::CliProjector::Completion::SHELLS.join("|")
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,55 @@
1
+ module Hecks
2
+ module Adapters
3
+ module Driving
4
+ module CliRunner
5
+ # The launcher's `--json` flag (ADR 0163, plan step 9): `hecks --json` and
6
+ # `hecks <module> --json` print the listing's entries as JSON, from the same projection the
7
+ # help prints. Extended into `CliRunner`.
8
+ module JsonWords
9
+ JSON_FLAG = "--json".freeze
10
+
11
+ # The answer to a line that asks for the listing as JSON, or nil when it does not.
12
+ #
13
+ # @param scope [Hash] the runner's scope for the line: the bluebook, its projection, the
14
+ # launcher and the options the help is shown with
15
+ # @param argv [Array<String>] the words of the line
16
+ # @return [Hash, nil] the answer, or nil when the line does not carry the flag
17
+ def json_answer(scope, argv)
18
+ return unless argv.include?(JSON_FLAG)
19
+
20
+ words = argv.reject { |word| word == JSON_FLAG }
21
+ module_word = words.find { |word| !word.start_with?("--") }
22
+ return { answer: [json_text(scope, module_word, words), ExitStatus::ANSWERED] } if known_or_none?(scope, module_word)
23
+
24
+ { answer: ["usage: #{scope[:program]} [<module>] --json", ExitStatus::USAGE] }
25
+ end
26
+
27
+ # The JSON text for the listing, limited to the module named, if any.
28
+ def json_text(scope, module_word, words)
29
+ name = module_word && Projector::CliProjector.module_named(scope[:bluebook], module_word)
30
+ options = json_options(scope, words).merge(module: name)
31
+ Projector::CliProjector.json_listing(scope[:bluebook], scope[:cli][:commands], scope[:cli][:questions], options)
32
+ end
33
+
34
+ # The listing's options for JSON: the audience the help shows, or with `--all` the
35
+ # maintainer's audience and the internal entries too.
36
+ def json_options(scope, words)
37
+ return scope[:shown] unless words.include?("--all")
38
+
39
+ search_options(scope, true)
40
+ end
41
+
42
+ # Whether a line names no module, or a module the bluebook declares.
43
+ def known_or_none?(scope, word)
44
+ word.nil? || known_module?(scope, word)
45
+ end
46
+
47
+ # Whether a word names a module of the bluebook.
48
+ def known_module?(scope, word)
49
+ !Projector::CliProjector.module_named(scope[:bluebook], word).nil?
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,63 @@
1
+ require "json"
2
+ require_relative "../usage_cache"
3
+
4
+ module Hecks
5
+ module Adapters
6
+ module Driving
7
+ module CliRunner
8
+ # Every name the launcher accepts, by the scope it is typed in, for a check that reads text
9
+ # rather than running a line. Extended into `CliRunner`.
10
+ #
11
+ # The index is the projection's own name table: the same one `hecks --all` lists from and
12
+ # `resolve` looks a typed word up in, so a name the launcher would refuse is not in it. It
13
+ # is worked out once and remembered through `UsageCache`, which keys it to the declarations
14
+ # and the code that projects them.
15
+ module NameIndex
16
+ # The command line a remembered index stands for, which no real line can be.
17
+ CACHE_LINE = ["--name-index"].freeze
18
+
19
+ # The scope of the program's own bluebook; an attached bluebook's scope is its first word
20
+ # (`deploy` for `hecks deploy ...`).
21
+ OWN_SCOPE = "".freeze
22
+
23
+ # @param runtime [#registry] a booted domain, or what `Hecks.describe` answers
24
+ # @param program [String] how the caller is invoked
25
+ # @return [Hash{String => Hash}] per scope: `"command"` and `"question"` map each accepted
26
+ # spelling to the name as listed, and `"modules"` lists the module words
27
+ def name_index(runtime:, program: "hecks")
28
+ text, = UsageCache.fetch(runtime, CACHE_LINE, program, audience: "maintainer") do
29
+ [JSON.generate(scopes_of(runtime, program)), 0]
30
+ end
31
+ JSON.parse(text)
32
+ end
33
+
34
+ # @return [Hash{String => Hash}] every scope's table, worked out from the projections
35
+ def scopes_of(runtime, program)
36
+ own = { OWN_SCOPE => scope_table(runtime, [], program) }
37
+ attached_bluebooks(runtime).each_with_object(own) do |name, scopes|
38
+ word = Naming.snake(name)
39
+ scopes[word] = scope_table(runtime, [word], program)
40
+ end
41
+ end
42
+
43
+ # @return [Hash] one scope's `"command"`, `"question"` and `"modules"` tables
44
+ def scope_table(runtime, argv, program)
45
+ bluebook, _, program = bluebook_for(runtime, argv, program)
46
+ launcher = LauncherOptions.settings(runtime, bluebook.name)
47
+ options = LauncherOptions.projection(launcher, program).merge(audience(runtime, launcher, maintainer: true))
48
+ cli = Projector.call(:cli, bluebook: bluebook, options: options)
49
+ { "command" => listed(cli, :command, :commands), "question" => listed(cli, :question, :questions),
50
+ "modules" => Projector::CliProjector.module_names(bluebook).map { |name| Naming.snake(name) } }
51
+ end
52
+
53
+ # @return [Hash{String => String}] each spelling of a kind, with the name as listed
54
+ def listed(cli, kind, specs)
55
+ cli[:names][kind].to_h do |spelling, id|
56
+ [spelling, Projector::CliProjector.verb_form(cli[specs][id] || {}, spelling)]
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,32 @@
1
+ module Hecks
2
+ module Adapters
3
+ module Driving
4
+ module CliRunner
5
+ # The session's checkout, for reads only. A read of a checkout's state that names no checkout
6
+ # takes the one the session set in `HECKS_CHECKOUT`; a command never does. A command names its
7
+ # own target, because a write must land where it was asked to, not where the session last was.
8
+ module ReadContext
9
+ # The environment variable a session sets to name its checkout.
10
+ VARIABLE = "HECKS_CHECKOUT".freeze
11
+
12
+ # The aggregate whose queries read a checkout's state.
13
+ READS = /Workspace\./
14
+
15
+ module_function
16
+
17
+ # @param spec [Hash] the resolved question or command
18
+ # @param args [Hash] the parsed arguments, keyed by name
19
+ # @param env [Hash] the process environment
20
+ # @return [Hash] the arguments, with checkout set from the session when a read names none
21
+ def fill(spec, args, env: ENV)
22
+ checkout = env[VARIABLE]
23
+ return args if checkout.nil? || checkout.empty? || args.key?(:checkout)
24
+ return args unless spec[:kind] == :query && spec[:command].to_s.match?(READS)
25
+
26
+ args.merge(checkout: { value: checkout })
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end