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
@@ -13,17 +13,40 @@ module Hecks
13
13
  # Checks every argument in `args`, nested or not, and refuses the first one the policy
14
14
  # forbids.
15
15
  #
16
+ # Read-only questions whose `path` names one file of the checkout. `path` is denied by name
17
+ # for every other command, since it can name a place to write; these reads are allowed it,
18
+ # and admit_path! still confines it to the checkout.
19
+ READ_PATH_QUESTIONS = %w[codebase.read_source codebase.outline].freeze
20
+
21
+ # The line window those reads take: plain numbers that name no place, so they pass.
22
+ READ_WINDOW_ARGUMENTS = %w[from to top].freeze
23
+
24
+ # The boundary between a lower-case letter or digit and the upper-case letter after it.
25
+ CAMEL_BOUNDARY = /([a-z\d])([A-Z])/
26
+
16
27
  # @param args [Hash, Array, nil] the arguments as the caller gave them
17
28
  # @param label [String] how the server describes its mode, for the refusal
29
+ # @param question [String, nil] the query asked, when the arguments are a question's
18
30
  # @raise [Runtime::TypeMismatch] on the first argument refused
19
- def admit!(args, label)
20
- each_argument(args) do |name, value|
21
- if DENIED_ARGUMENTS.include?(name)
22
- refuse!(name, label, "never passes it on: it names a host, a binary, an output or a change of state")
23
- end
24
- admit_path!(name, value, label) if PATH_ARGUMENTS.include?(name)
25
- admit_ref!(name, value, label) if REF_ARGUMENTS.include?(name)
31
+ def admit!(args, label, question = nil)
32
+ read_question = READ_PATH_QUESTIONS.include?(snake_question(question))
33
+ each_argument(args) { |name, value| admit_one!(name, value, label, read_question) }
34
+ end
35
+
36
+ # Whether an argument is a line window the read questions take, which names no place.
37
+ def window?(name, read_question) = read_question && READ_WINDOW_ARGUMENTS.include?(name)
38
+
39
+ # Checks one argument by its name: a read path is allowed its path, and anything else is
40
+ # refused, confined to the checkout, or checked as a ref.
41
+ def admit_one!(name, value, label, read_question)
42
+ return if window?(name, read_question)
43
+ return admit_path!(name, value, label) if name == "path" && read_question
44
+
45
+ if DENIED_ARGUMENTS.include?(name)
46
+ refuse!(name, label, "never passes it on: it names a host, a binary, an output or a change of state")
26
47
  end
48
+ admit_path!(name, value, label) if PATH_ARGUMENTS.include?(name)
49
+ admit_ref!(name, value, label) if REF_ARGUMENTS.include?(name)
27
50
  end
28
51
 
29
52
  # Yields every argument name with its value, descending into nested objects and lists, so
@@ -47,6 +70,16 @@ module Hecks
47
70
  value.fetch("value") { value.fetch(:value, value) }
48
71
  end
49
72
 
73
+ # The question as `Aggregate.query` or `aggregate_run.query` names it, in the snake form
74
+ # `READ_PATH_QUESTIONS` uses.
75
+ def snake_question(question)
76
+ parts = question.to_s.split(".")
77
+ parts.map { |part| snake_part(part) }.join(".")
78
+ end
79
+
80
+ # One part of a question name, in snake form: `ReadSource` is `read_source`.
81
+ def snake_part(part) = part.gsub(CAMEL_BOUNDARY, '\1_\2').downcase
82
+
50
83
  def refuse!(name, label, why)
51
84
  raise Runtime::TypeMismatch, "argument: #{name.inspect} is refused: this server runs in #{label} and #{why}"
52
85
  end
@@ -31,9 +31,9 @@ module Hecks
31
31
  # write, a port to open, a store to switch to, or flips a command from a preview to a
32
32
  # change of state.
33
33
  DENIED_ARGUMENTS = %w[
34
- adapter artifact brief claimed confirm expected from gem_only header health_path host live no_wait npm_local
35
- npm_only output path payload payload_file port prebuilt remote row rust_binary scheme stage_dir state_path
36
- stdio url write
34
+ adapter artifact brief claimed confirm expected force from gem_only header health_path host live
35
+ no_wait npm_local npm_only output path payload payload_file port prebuilt remote row rust_binary
36
+ scheme stage_dir state_path stdio url write
37
37
  ].freeze
38
38
 
39
39
  # Argument names whose values are paths (a comma-separated list for some). A restricted
@@ -41,11 +41,11 @@ module Hecks
41
41
  # passes them on only when each resolves, symlinks followed, inside `Storehouse::BOOT_ROOT`,
42
42
  # and holds no colon: `host:repo` and `https://host/x` would otherwise pass as relative
43
43
  # paths.
44
- PATH_ARGUMENTS = %w[checkout dir directory domain domains file fixture paths repo root script].freeze
44
+ PATH_ARGUMENTS = %w[checkout dir directory domain domains file files fixture paths repo root script].freeze
45
45
 
46
46
  # Argument names whose values are git refs: plain names only, so a value cannot read as an
47
47
  # option to git.
48
- REF_ARGUMENTS = %w[branch commit onto ref].freeze
48
+ REF_ARGUMENTS = %w[base branch commit onto ref].freeze
49
49
 
50
50
  # What a plain git ref looks like: no leading dash, no `..`, no spaces.
51
51
  PLAIN_REF = %r{\A[A-Za-z0-9][A-Za-z0-9._/~^@-]*\z}
@@ -155,11 +155,12 @@ module Hecks
155
155
  # files should name it in `DENIED_ARGUMENTS` or `PATH_ARGUMENTS` (ADR 0089).
156
156
  #
157
157
  # @param args [Hash, Array, nil] the arguments as the caller gave them, nested or not
158
+ # @param question [String, nil] the query asked, when these are a question's arguments
158
159
  # @raise [Runtime::TypeMismatch] on the first argument refused
159
- def admit_arguments!(args)
160
+ def admit_arguments!(args, question = nil)
160
161
  return unless restricted?
161
162
 
162
- ArgumentPolicy.admit!(args, mode_label)
163
+ ArgumentPolicy.admit!(args, mode_label, question)
163
164
  end
164
165
 
165
166
  # The one domain a restricted server serves, when it serves exactly one: a call may leave
@@ -0,0 +1,154 @@
1
+ module Hecks
2
+ module Adapters
3
+ module Driving
4
+ module Ruby
5
+ module AggregateModule
6
+ # The hooks an aggregate module lands on: a port declared inside a repeat boot, the bare and
7
+ # qualified binding calls a `.hecksagon` and a `.world` make, and constant lookup. Each is a
8
+ # module function, called as `Hooks.name` from the blocks that define the module's methods, since
9
+ # a block defined with `define_singleton_method` runs with the module as `self`.
10
+ module Hooks
11
+ # What `bound_outcome` answers for a call that is not a binding, so `super` handles it.
12
+ UNBOUND = Object.new.freeze
13
+
14
+ # What `bound_outcome` answers for a call that recorded a binding, so the module answers itself.
15
+ BOUND = Object.new.freeze
16
+
17
+ module_function
18
+
19
+ # Defines `port`, which declares a port on the aggregate during a repeat boot.
20
+ #
21
+ # @param mod [Module] the aggregate module
22
+ # @param domain [String] the domain the aggregate belongs to
23
+ # @param aggregate [Bluebook::Aggregate] the aggregate
24
+ # @param fqn [String] the aggregate's qualified name
25
+ # @return [void]
26
+ def define_port_hook(mod, domain, aggregate, fqn)
27
+ mod.define_singleton_method(:port) do |name, &block|
28
+ Hooks.attach_port(name, domain, aggregate, fqn, &block)
29
+ self
30
+ end
31
+ end
32
+
33
+ # Defines `ask_via`, the repeat-boot form of `BindingProxy#ask_via`.
34
+ #
35
+ # @param mod [Module] the aggregate module
36
+ # @param domain [String] the domain the aggregate belongs to
37
+ # @param aggregate [Bluebook::Aggregate] the aggregate
38
+ # @return [void]
39
+ def define_ask_via(mod, domain, aggregate)
40
+ mod.define_singleton_method(:ask_via) do |name, port:|
41
+ declaration = Hecks.current_registry&.bluebook(domain)
42
+ Bluebook::AskResolution.pick!(declaration, aggregate.hecks_name, name, port)
43
+ self
44
+ end
45
+ end
46
+
47
+ # Defines `method_missing`: a bare call starts a Privacy marking chain, and a qualified
48
+ # call records a binding. Anything else falls through to `super`.
49
+ #
50
+ # @param mod [Module] the aggregate module
51
+ # @param fqn [String] the aggregate's qualified name
52
+ # @return [void]
53
+ def define_method_missing(mod, fqn)
54
+ mod.define_singleton_method(:method_missing) do |verb, *args, **kwargs, &block|
55
+ outcome = Hooks.bound_outcome(fqn, verb, args, kwargs, block)
56
+ return super(verb, *args, **kwargs, &block) if outcome.equal?(Hooks::UNBOUND)
57
+
58
+ outcome.equal?(Hooks::BOUND) ? self : outcome
59
+ end
60
+ end
61
+
62
+ # Defines `respond_to_missing?`, answering true while a `.hecksagon` or `.world` is being declared.
63
+ #
64
+ # @param mod [Module] the aggregate module
65
+ # @return [void]
66
+ def define_respond_to_missing(mod)
67
+ mod.define_singleton_method(:respond_to_missing?) do |name, include_private = false|
68
+ !Bluebook::DSL::HecksagonBuilder.collector.nil? || !Bluebook::DSL::WorldBuilder.current.nil? ||
69
+ super(name, include_private)
70
+ end
71
+ end
72
+
73
+ # Defines `const_missing`. It uses `aggregate.hecks_name`, not the qualified name: qualifying it
74
+ # would make `Account::Debit`'s meaning depend on whether a stale module from an earlier boot is
75
+ # still on this process.
76
+ #
77
+ # @param mod [Module] the aggregate module
78
+ # @param aggregate [Bluebook::Aggregate] the aggregate
79
+ # @return [void]
80
+ def define_const_missing(mod, aggregate)
81
+ mod.define_singleton_method(:const_missing) do |name|
82
+ resolver = Bluebook::DSL::ConstShim.resolver
83
+ return resolver.call("#{aggregate.hecks_name}::#{name}") if resolver
84
+
85
+ super(name)
86
+ end
87
+ end
88
+
89
+ # Declares a port on an aggregate during a repeat boot, and registers it with the live registry.
90
+ # Re-resolves the aggregate via `Hecks.current_registry` rather than the closed-over `aggregate`,
91
+ # which can be stale from an earlier boot.
92
+ #
93
+ # @raise [Bluebook::DSL::Malformed] when called outside a boot
94
+ def attach_port(name, domain, aggregate, fqn, &block)
95
+ current = current_aggregate(name, domain, aggregate, fqn)
96
+ built = Bluebook::DSL::ConstShim.with(->(const) { const }) do
97
+ Bluebook::DSL::DomainPortBuilder.build(name, owner: current.hecks_name, &block)
98
+ end
99
+ # A `verb`-shaped port is a plain `Port`, the same struct `Hecks.port` registers. It belongs to
100
+ # no aggregate IR, so it takes the registry's `add_port` directly. Mirrors `DSL::BindingProxy#port`,
101
+ # which handles the identical shape on a domain's first in-process boot.
102
+ return Hecks.current_registry.add_port(built) if built.is_a?(Bluebook::Port)
103
+
104
+ reference_operations(built, current)
105
+ current.add_port(built)
106
+ end
107
+
108
+ # @return [Bluebook::Aggregate] the live registry's copy of the aggregate
109
+ # @raise [Bluebook::DSL::Malformed] when no boot is in progress
110
+ def current_aggregate(name, domain, aggregate, fqn)
111
+ Hecks.current_registry&.bluebook(domain)&.aggregate(aggregate.hecks_name) or
112
+ raise Bluebook::DSL::Malformed, "#{fqn}.port(#{name.inspect}) called outside a boot"
113
+ end
114
+
115
+ # Points each reference attribute of a port's operations at the aggregate that declares it.
116
+ def reference_operations(built, current)
117
+ built.operations.each do |operation|
118
+ operation.attributes.select(&:reference?).each { |attribute| attribute.type.declared_in = current }
119
+ end
120
+ end
121
+
122
+ # Answers what a method-missing call means: a bare call's attribute path, the world's record of
123
+ # a setting, a recorded binding (BOUND), or nothing to bind (UNBOUND).
124
+ #
125
+ # @return [Object] the answer, or BOUND or UNBOUND
126
+ def bound_outcome(fqn, verb, args, kwargs, block)
127
+ return Bluebook::DSL::AttributePath.new(fqn, [verb.to_s]) if bare_call?(args, kwargs, block)
128
+
129
+ collector = Bluebook::DSL::HecksagonBuilder.collector
130
+ world = Bluebook::DSL::WorldBuilder.current
131
+ # Inside a `.world` block the same qualified spelling records a world setting.
132
+ return world.record_binding(verb, args, kwargs, block) if world && !collector
133
+ return UNBOUND unless collector
134
+
135
+ collector << bind_for(fqn, verb, args, kwargs)
136
+ block&.call
137
+ BOUND
138
+ end
139
+
140
+ # @return [Boolean] whether the call names no arguments and no block, so it is a bare attribute path
141
+ def bare_call?(args, kwargs, block)
142
+ args.empty? && kwargs.empty? && !block
143
+ end
144
+
145
+ # @return [Bluebook::Bind] the binding a qualified call declares
146
+ def bind_for(fqn, verb, args, kwargs)
147
+ Bluebook::Bind.new(aggregate: fqn, verb: verb.to_s, adapter: args.first.to_s, role: kwargs[:role]&.to_s)
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
@@ -8,6 +8,7 @@ require_relative "../handle"
8
8
  require_relative "bulk_verbs"
9
9
  require_relative "query_rows"
10
10
  require_relative "../../../naming"
11
+ require_relative "aggregate_module/hooks"
11
12
 
12
13
  module Hecks
13
14
  module Adapters
@@ -19,22 +20,48 @@ module Hecks
19
20
  # Builds one aggregate module: creating-command methods, query methods,
20
21
  # find/all/count/events, project/docs/narrate, and the port/binding hooks.
21
22
  #
22
- # Kept as one method: `:port`/`:method_missing`/`:const_missing` below
23
- # cross-reference each other and would lose that thread if split up.
24
- # rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
23
+ # Each concern is a helper that defines its methods on the module and closes over the same
24
+ # arguments. The hooks live in `AggregateModule::Hooks`, which the module's blocks call by name.
25
25
  def aggregate_module(dispatcher, domain, aggregate)
26
26
  fqn = "#{domain}::#{aggregate.hecks_name}"
27
27
  mod = Module.new
28
28
 
29
+ warn_shadowed_attributes(aggregate)
30
+ define_surface(mod, dispatcher, domain, aggregate, fqn)
31
+ Hooks.define_port_hook(mod, domain, aggregate, fqn)
32
+ Hooks.define_ask_via(mod, domain, aggregate)
33
+ Hooks.define_method_missing(mod, fqn)
34
+ Hooks.define_respond_to_missing(mod)
35
+ Hooks.define_const_missing(mod, aggregate)
36
+ mod
37
+ end
38
+
39
+ private
40
+
41
+ # Warns for each attribute that shadows a built-in, since no reader is defined for it.
42
+ def warn_shadowed_attributes(aggregate)
29
43
  aggregate.attributes.each do |attribute|
30
44
  next unless RESERVED.include?(attribute.name.to_sym)
31
45
 
32
46
  warn "[hecks] #{aggregate.hecks_name}##{attribute.name} shadows a built-in — no reader defined"
33
47
  end
48
+ end
34
49
 
35
- # `!` marks a creating command (Ruby's mutate-and-may-refuse convention).
36
- # Without it, a query sharing the same business name (e.g. Account's
37
- # "Open") would collide with the creating command's own bare name.
50
+ # The module's everyday surface: its commands, its identity, its projections, and its reads.
51
+ def define_surface(mod, dispatcher, domain, aggregate, fqn)
52
+ define_creating_commands(mod, dispatcher, domain, aggregate, fqn)
53
+ define_reflection(mod, dispatcher, domain, aggregate, fqn)
54
+ define_names(mod, aggregate)
55
+ define_projection(mod, aggregate)
56
+ define_narration(mod, dispatcher, domain, aggregate)
57
+ define_finders(mod, dispatcher, domain, aggregate)
58
+ define_tallies(mod, dispatcher, domain, aggregate, fqn)
59
+ end
60
+
61
+ # `!` marks a creating command (Ruby's mutate-and-may-refuse convention).
62
+ # Without it, a query sharing the same business name (e.g. Account's
63
+ # "Open") would collide with the creating command's own bare name.
64
+ def define_creating_commands(mod, dispatcher, domain, aggregate, fqn)
38
65
  aggregate.commands.select(&:creates?).each do |command|
39
66
  mod.define_singleton_method("#{Naming.snake(command.hecks_name)}!") do |**args|
40
67
  Handle.new(dispatcher: dispatcher, domain: domain, aggregate: aggregate,
@@ -47,13 +74,27 @@ module Hecks
47
74
  # A query is a bare module method (no `!`): it reads and returns the raw rows
48
75
  # `dispatcher.query` answers, as `QueryRows` so a bulk run can name the query.
49
76
  BulkVerbs.define_queries(mod, dispatcher, fqn, aggregate)
77
+ end
78
+
79
+ # The module's own identity: its FQN, its IR, and its repository.
80
+ def define_reflection(mod, dispatcher, domain, aggregate, fqn)
81
+ mod.define_singleton_method(:fqn) { fqn }
82
+ mod.define_singleton_method(:ir) { aggregate }
83
+ mod.define_singleton_method(:repository) { dispatcher.registry.repository(domain, aggregate) }
84
+ end
50
85
 
51
- mod.define_singleton_method(:fqn) { fqn }
52
- mod.define_singleton_method(:ir) { aggregate }
86
+ # The names of the aggregate's commands and queries.
87
+ def define_names(mod, aggregate)
88
+ mod.define_singleton_method(:commands) do
89
+ aggregate.commands.map { |c| "#{Naming.snake(c.hecks_name)}!" }.sort
90
+ end
91
+ mod.define_singleton_method(:queries) { aggregate.queries.map { |q| Naming.snake(q.hecks_name) }.sort }
92
+ end
53
93
 
54
- # Every construct emits its own IR, so an aggregate is a legitimate
55
- # `project` target too. A bluebook-scoped target refuses here via
56
- # `Projector.admits!` rather than answering a confidently empty result.
94
+ # Every construct emits its own IR, so an aggregate is a legitimate
95
+ # `project` target too. A bluebook-scoped target refuses here via
96
+ # `Projector.admits!` rather than answering a confidently empty result.
97
+ def define_projection(mod, aggregate)
57
98
  mod.define_singleton_method(:project) do |target, out: nil, **options|
58
99
  key = Projector.key_for(target)
59
100
  artifact = Projector.call(key, bluebook: aggregate, options: options)
@@ -61,24 +102,22 @@ module Hecks
61
102
 
62
103
  Projector.write(artifact, out, as: Projector.emits_for(key))
63
104
  end
64
- mod.define_singleton_method(:repository) { dispatcher.registry.repository(domain, aggregate) }
65
- mod.define_singleton_method(:commands) do
66
- aggregate.commands.map { |c| "#{Naming.snake(c.hecks_name)}!" }.sort
67
- end
68
- mod.define_singleton_method(:queries) { aggregate.queries.map { |q| Naming.snake(q.hecks_name) }.sort }
69
- # This bluebook's own `:docs` projection, narrowed to this aggregate.
105
+ end
106
+
107
+ # This bluebook's own `:docs` and `:narrate` projections, narrowed to this aggregate.
108
+ def define_narration(mod, dispatcher, domain, aggregate)
70
109
  mod.define_singleton_method(:docs) do |**options|
71
110
  Projector.call(:docs, bluebook: dispatcher.registry.bluebook(domain),
72
111
  options: options.merge(aggregate: aggregate.hecks_name))
73
112
  end
74
- # Same narrowing as `:docs`, aimed at `:narrate`.
75
113
  mod.define_singleton_method(:narrate) do |**options|
76
114
  Projector.call(:narrate, bluebook: dispatcher.registry.bluebook(domain),
77
115
  options: options.merge(aggregate: aggregate.hecks_name))
78
116
  end
79
- mod.define_singleton_method(:count) { dispatcher.registry.repository(domain, aggregate).count }
80
- mod.define_singleton_method(:events) { dispatcher.events.select { |event| event.aggregate == fqn } }
117
+ end
81
118
 
119
+ # `find` and `all` read the aggregate's repository and wrap each instance in a handle.
120
+ def define_finders(mod, dispatcher, domain, aggregate)
82
121
  mod.define_singleton_method(:find) do |id|
83
122
  found = dispatcher.registry.repository(domain, aggregate).find(id)
84
123
  found && Handle.new(dispatcher: dispatcher, domain: domain, aggregate: aggregate, instance: found)
@@ -90,80 +129,12 @@ module Hecks
90
129
  Handle.new(dispatcher: dispatcher, domain: domain, aggregate: aggregate, instance: instance)
91
130
  end
92
131
  end
132
+ end
93
133
 
94
- # Re-resolves via `Hecks.current_registry` rather than the closed-over
95
- # `aggregate`: this module can be stale from an earlier boot, and its own
96
- # `aggregate` would silently port a discarded one instead of the live one.
97
- mod.define_singleton_method(:port) do |name, &block|
98
- current = Hecks.current_registry&.bluebook(domain)&.aggregate(aggregate.hecks_name) or
99
- raise Bluebook::DSL::Malformed, "#{fqn}.port(#{name.inspect}) called outside a boot"
100
-
101
- built = Bluebook::DSL::ConstShim.with(->(const) { const }) do
102
- Bluebook::DSL::DomainPortBuilder.build(name, owner: current.hecks_name, &block)
103
- end
104
-
105
- # A `verb`-shaped port is a plain `Port`, the same struct `Hecks.port` registers —
106
- # it belongs to no aggregate IR the way an operations-shaped `DomainPort` does, so
107
- # it takes the registry's `add_port` directly. Mirrors `DSL::BindingProxy#port`,
108
- # which handles the identical shape on a domain's first in-process boot (before
109
- # this facade constant exists); this method is what a repeat boot reaches instead.
110
- if built.is_a?(Bluebook::Port)
111
- Hecks.current_registry.add_port(built)
112
- return self
113
- end
114
-
115
- built.operations.each do |operation|
116
- operation.attributes.select(&:reference?).each { |attribute| attribute.type.declared_in = current }
117
- end
118
- current.add_port(built)
119
- self
120
- end
121
-
122
- # `BindingProxy#ask_via` for a repeat boot, when this module stands where the proxy is.
123
- mod.define_singleton_method(:ask_via) do |name, port:|
124
- declaration = Hecks.current_registry&.bluebook(domain)
125
- Bluebook::AskResolution.pick!(declaration, aggregate.hecks_name, name, port)
126
- self
127
- end
128
-
129
- mod.define_singleton_method(:method_missing) do |verb, *args, **kwargs, &block|
130
- # A bare call starts a Privacy marking chain (see
131
- # `BindingProxy#method_missing`), reached here when the module is already
132
- # installed (a second in-process boot) rather than at parse time.
133
- return Bluebook::DSL::AttributePath.new(fqn, [verb.to_s]) if args.empty? && kwargs.empty? && !block
134
-
135
- collector = Bluebook::DSL::HecksagonBuilder.collector
136
- world = Bluebook::DSL::WorldBuilder.current
137
- # Inside a `.world` block the same qualified spelling records a world setting.
138
- return world.record_binding(verb, args, kwargs, block) if world && !collector
139
- return super(verb, *args, **kwargs, &block) unless collector
140
-
141
- collector << Bluebook::Bind.new(
142
- aggregate: fqn,
143
- verb: verb.to_s,
144
- adapter: args.first.to_s,
145
- role: kwargs[:role]&.to_s
146
- )
147
- block&.call
148
- self
149
- end
150
-
151
- mod.define_singleton_method(:respond_to_missing?) do |name, include_private = false|
152
- !Bluebook::DSL::HecksagonBuilder.collector.nil? || !Bluebook::DSL::WorldBuilder.current.nil? ||
153
- super(name, include_private)
154
- end
155
-
156
- # Uses `aggregate.hecks_name`, not the qualified `fqn`: qualifying it here
157
- # would make `Account::Debit`'s meaning depend on whether a stale module
158
- # from an earlier boot happens to be sitting on this process.
159
- mod.define_singleton_method(:const_missing) do |name|
160
- resolver = Bluebook::DSL::ConstShim.resolver
161
- return resolver.call("#{aggregate.hecks_name}::#{name}") if resolver
162
-
163
- super(name)
164
- end
165
-
166
- mod
134
+ # `count` and `events` read what the aggregate has stored and emitted.
135
+ def define_tallies(mod, dispatcher, domain, aggregate, fqn)
136
+ mod.define_singleton_method(:count) { dispatcher.registry.repository(domain, aggregate).count }
137
+ mod.define_singleton_method(:events) { dispatcher.events.select { |event| event.aggregate == fqn } }
167
138
  end
168
139
  end
169
140
  end
@@ -0,0 +1,146 @@
1
+ require "fileutils"
2
+ require "json"
3
+ require_relative "usage_cache"
4
+
5
+ module Hecks
6
+ module Adapters
7
+ module Driving
8
+ # Keeps a local record of the commands and queries a launcher runs, so the everyday list and
9
+ # the timing of a deprecation rest on what people type rather than on a guess.
10
+ #
11
+ # A run appends one JSON line to `usage.jsonl` in the directory `UsageCache` already uses:
12
+ # the name as typed, the name it resolved to, the exit status, the duration in milliseconds
13
+ # and the date. No arguments, values or paths are written. The record is on unless
14
+ # `HECKS_USAGE=off` is set or a `usage.off` marker sits in that directory. The first run that
15
+ # writes prints one line on standard error saying so, then leaves a `usage.noticed` marker.
16
+ # Writing never fails the command it records.
17
+ module UsageLog
18
+ # The file each run appends its line to.
19
+ FILE = "usage.jsonl".freeze
20
+ # The variable that turns the record off when set to `off`.
21
+ OPT_OUT_VARIABLE = "HECKS_USAGE".freeze
22
+ # The marker file that turns the record off.
23
+ OPT_OUT_MARKER = "usage.off".freeze
24
+ # The marker file that says the first-run notice has been printed.
25
+ NOTICE_MARKER = "usage.noticed".freeze
26
+ # The line printed once, on the first run that writes.
27
+ NOTICE = "hecks keeps a local record of the commands it runs in %s; set HECKS_USAGE=off to stop.".freeze
28
+ # The window `summary` counts when none is given, in days.
29
+ DEFAULT_WINDOW = 30
30
+ # Seconds in a day.
31
+ DAY = 24 * 60 * 60
32
+
33
+ module_function
34
+
35
+ # Appends the line for one run, unless the record is off.
36
+ #
37
+ # @param argv [Array<String>] the command line as typed
38
+ # @param resolved [String, nil] the name the runner resolved it to
39
+ # @param status [Integer] the exit status the run answered
40
+ # @param started [Float] the monotonic clock reading when the run began
41
+ # @return [void]
42
+ def record(argv:, resolved:, status:, started:)
43
+ return unless enabled?
44
+
45
+ FileUtils.mkdir_p(directory)
46
+ notice
47
+ append(line(argv, resolved, status, started))
48
+ rescue StandardError
49
+ nil
50
+ end
51
+
52
+ # @return [Boolean] whether a run is recorded
53
+ def enabled?
54
+ ENV[OPT_OUT_VARIABLE].to_s != "off" && !File.exist?(marker(OPT_OUT_MARKER))
55
+ end
56
+
57
+ # Prints the first-run line once, then leaves its marker.
58
+ def notice
59
+ return if File.exist?(marker(NOTICE_MARKER))
60
+
61
+ warn(format(NOTICE, path))
62
+ FileUtils.touch(marker(NOTICE_MARKER))
63
+ end
64
+
65
+ # The entry for one run.
66
+ #
67
+ # @return [Hash] the fields `record` writes
68
+ def line(argv, resolved, status, started)
69
+ { "typed" => typed(argv), "resolved" => resolved, "status" => status,
70
+ "ms" => ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - started) * 1000).round,
71
+ "date" => Time.now.utc.strftime("%Y-%m-%d") }
72
+ end
73
+
74
+ # The name the person typed: the first word that is not a flag, past a `query` word.
75
+ #
76
+ # @return [String, nil]
77
+ def typed(argv)
78
+ words = argv.reject { |word| word.start_with?("-") }
79
+ words.shift if CliRunner::QUERY_WORDS.include?(words.first)
80
+ words.first
81
+ end
82
+
83
+ # Writes one entry as a line of the file.
84
+ def append(entry)
85
+ File.open(path, "a") { |file| file.puts(JSON.generate(entry)) }
86
+ end
87
+
88
+ # The entries on file, oldest first. A line that does not parse is skipped.
89
+ #
90
+ # @return [Array<Hash>]
91
+ def entries
92
+ File.readlines(path).filter_map { |line| JSON.parse(line) }
93
+ rescue SystemCallError, JSON::ParserError
94
+ []
95
+ end
96
+
97
+ # Counts the runs in the window and names the known ones that did not run in it.
98
+ #
99
+ # @param known [Array<String>] every name the launcher answers to, as the projection names
100
+ # them
101
+ # @param window [Integer] how many days back a run counts
102
+ # @return [String] the text `hecks usage` prints
103
+ def summary(known:, window: DEFAULT_WINDOW)
104
+ counts = counts_since(window)
105
+ unrun = known.sort - counts.keys
106
+ ["runs in the last #{window} days, most used first:", *tally_lines(counts),
107
+ "", "never run in that window:", *unrun.map { |name| " #{name}" }].join("\n")
108
+ end
109
+
110
+ # How often each resolved name ran since the window opened.
111
+ #
112
+ # @return [Hash{String => Integer}]
113
+ def counts_since(window)
114
+ since = (Time.now.utc - (window * DAY)).strftime("%Y-%m-%d")
115
+ resolved_names(entries.select { |entry| entry["date"].to_s >= since })
116
+ end
117
+
118
+ # @return [Hash{String => Integer}] how many runs resolved to each name
119
+ def resolved_names(runs)
120
+ runs.map { |entry| entry["resolved"] }.compact.tally
121
+ end
122
+
123
+ # @return [Array<String>] one line per name that ran, most used first
124
+ def tally_lines(counts)
125
+ ranked = counts.sort_by { |name, count| [-count, name] }
126
+ ranked.map { |name, count| format(" %<count>4d %<name>s", count: count, name: name) }
127
+ end
128
+
129
+ # @return [String] the file the record lives in
130
+ def path
131
+ File.join(directory, FILE)
132
+ end
133
+
134
+ # @return [String] the directory the record lives in: the usage cache's own
135
+ def directory
136
+ UsageCache.directory
137
+ end
138
+
139
+ # @return [String] a marker file in the directory
140
+ def marker(name)
141
+ File.join(directory, name)
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end