hecks 6.0.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (754) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +19 -12
  3. data/lib/hecks/adapters/driven/claude_code.rb +2 -2
  4. data/lib/hecks/adapters/driven/folder.rb +10 -1
  5. data/lib/hecks/adapters/driven/folder_overlay.rb +15 -0
  6. data/lib/hecks/adapters/driven/heki.rb +1 -1
  7. data/lib/hecks/adapters/driven/in_process_key_vault.rb +1 -1
  8. data/lib/hecks/adapters/driven/memory/outbox_rows.rb +2 -2
  9. data/lib/hecks/adapters/driven/postgres/name_guard.rb +25 -0
  10. data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -3
  11. data/lib/hecks/adapters/driven/postgres/repository.rb +1 -1
  12. data/lib/hecks/adapters/driven/postgres/shared_connection.rb +1 -1
  13. data/lib/hecks/adapters/driven/postgres.rb +3 -0
  14. data/lib/hecks/adapters/driven/postgres_era/boot.rb +28 -16
  15. data/lib/hecks/adapters/driven/postgres_era/class_methods.rb +27 -7
  16. data/lib/hecks/adapters/driven/postgres_era/dialect.rb +10 -5
  17. data/lib/hecks/adapters/driven/postgres_era/field_cache_provisioner.rb +39 -0
  18. data/lib/hecks/adapters/driven/postgres_era/journal.rb +52 -13
  19. data/lib/hecks/adapters/driven/postgres_era/lineage/chain_sql.rb +29 -49
  20. data/lib/hecks/adapters/driven/postgres_era/lineage/direct_sql.rb +73 -0
  21. data/lib/hecks/adapters/driven/postgres_era/lineage/direct_verified.json +10 -0
  22. data/lib/hecks/adapters/driven/postgres_era/lineage/direct_verified.rb +65 -0
  23. data/lib/hecks/adapters/driven/postgres_era/lineage/domain_rename.rb +77 -25
  24. data/lib/hecks/adapters/driven/postgres_era/lineage/domain_rename_state.rb +108 -0
  25. data/lib/hecks/adapters/driven/postgres_era/lineage/era_integrity.rb +11 -6
  26. data/lib/hecks/adapters/driven/postgres_era/lineage/era_store.rb +63 -5
  27. data/lib/hecks/adapters/driven/postgres_era/lineage/layered_sql.rb +64 -0
  28. data/lib/hecks/adapters/driven/postgres_era/lineage/ledger_reset.rb +150 -0
  29. data/lib/hecks/adapters/driven/postgres_era/lineage/mint_provisioning.rb +85 -0
  30. data/lib/hecks/adapters/driven/postgres_era/lineage/mint_transaction.rb +11 -7
  31. data/lib/hecks/adapters/driven/postgres_era/lineage/provisioning.rb +11 -5
  32. data/lib/hecks/adapters/driven/postgres_era/lineage/split_sql.rb +76 -0
  33. data/lib/hecks/adapters/driven/postgres_era/lineage/sql_templates.rb +9 -0
  34. data/lib/hecks/adapters/driven/postgres_era/lineage.rb +10 -2
  35. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/context.rb +23 -3
  36. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/coverage_check.rb +3 -1
  37. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/disposable_ledger.rb +119 -0
  38. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolution.rb +219 -0
  39. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/era_resolver.rb +68 -71
  40. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/held_era.rb +68 -0
  41. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/ledger_change.rb +63 -0
  42. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/merge_coordinator.rb +1 -1
  43. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/mint_decision.rb +163 -0
  44. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/mint_request.rb +24 -0
  45. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/minter.rb +59 -21
  46. data/lib/hecks/adapters/driven/postgres_era/lineage_manager/refusals.rb +24 -11
  47. data/lib/hecks/adapters/driven/postgres_era/lineage_manager.rb +40 -6
  48. data/lib/hecks/adapters/driven/postgres_era/shared_tables.rb +32 -0
  49. data/lib/hecks/adapters/driven/postgres_era.adapter +12 -0
  50. data/lib/hecks/adapters/driven/postgres_era.rb +25 -10
  51. data/lib/hecks/adapters/driven/prism.rb +0 -1
  52. data/lib/hecks/adapters/driven/sql_query_builder.rb +1 -0
  53. data/lib/hecks/adapters/driven/sqlite/dispatch_claims.rb +1 -1
  54. data/lib/hecks/adapters/driven/sqlite/name_guard.rb +25 -0
  55. data/lib/hecks/adapters/driven/sqlite/outbox.rb +2 -2
  56. data/lib/hecks/adapters/driven/sqlite/repository.rb +1 -1
  57. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +20 -0
  58. data/lib/hecks/adapters/driven/sqlite.rb +9 -1
  59. data/lib/hecks/adapters/driven/tenant_provisioner.rb +1 -1
  60. data/lib/hecks/adapters/driven/worktree_overlay.rb +117 -0
  61. data/lib/hecks/adapters/driving/cli/shorthand.rb +5 -1
  62. data/lib/hecks/adapters/driving/cli.rb +1 -1
  63. data/lib/hecks/adapters/driving/cli_runner/answers.rb +77 -22
  64. data/lib/hecks/adapters/driving/cli_runner/bang_rule.rb +35 -0
  65. data/lib/hecks/adapters/driving/cli_runner/completion_words.rb +36 -0
  66. data/lib/hecks/adapters/driving/cli_runner/json_words.rb +55 -0
  67. data/lib/hecks/adapters/driving/cli_runner/name_index.rb +63 -0
  68. data/lib/hecks/adapters/driving/cli_runner/read_context.rb +32 -0
  69. data/lib/hecks/adapters/driving/cli_runner/renamed_names.rb +49 -0
  70. data/lib/hecks/adapters/driving/cli_runner/resolution.rb +43 -17
  71. data/lib/hecks/adapters/driving/cli_runner/resume_words.rb +63 -0
  72. data/lib/hecks/adapters/driving/cli_runner/run_reference.rb +66 -0
  73. data/lib/hecks/adapters/driving/cli_runner/run_replay.rb +118 -0
  74. data/lib/hecks/adapters/driving/cli_runner/search_words.rb +35 -0
  75. data/lib/hecks/adapters/driving/cli_runner/settling.rb +6 -5
  76. data/lib/hecks/adapters/driving/cli_runner/streaming.rb +11 -10
  77. data/lib/hecks/adapters/driving/cli_runner/suggestions.rb +1 -1
  78. data/lib/hecks/adapters/driving/cli_runner/tour_words.rb +77 -0
  79. data/lib/hecks/adapters/driving/cli_runner/verb_names.rb +36 -4
  80. data/lib/hecks/adapters/driving/cli_runner/verbosity.rb +75 -0
  81. data/lib/hecks/adapters/driving/cli_runner.rb +106 -7
  82. data/lib/hecks/adapters/driving/context_line.rb +85 -0
  83. data/lib/hecks/adapters/driving/exit_status.rb +31 -0
  84. data/lib/hecks/adapters/driving/launcher_options.rb +7 -5
  85. data/lib/hecks/adapters/driving/mcp/progress_sink.rb +45 -0
  86. data/lib/hecks/adapters/driving/mcp/tool_calls.rb +7 -5
  87. data/lib/hecks/adapters/driving/mcp.rb +25 -5
  88. data/lib/hecks/adapters/driving/mcp_scope/argument_policy.rb +40 -7
  89. data/lib/hecks/adapters/driving/mcp_scope.rb +8 -7
  90. data/lib/hecks/adapters/driving/ruby/aggregate_module/hooks.rb +154 -0
  91. data/lib/hecks/adapters/driving/ruby/aggregate_module.rb +64 -93
  92. data/lib/hecks/adapters/driving/usage_log.rb +146 -0
  93. data/lib/hecks/adapters/driving/write_guard.rb +55 -0
  94. data/lib/hecks/adapters/driving.rb +0 -1
  95. data/lib/hecks/behaviors/dsl.rb +5 -1
  96. data/lib/hecks/behaviors/expectations/boot.rb +0 -1
  97. data/lib/hecks/bluebook/acknowledgements.rb +1 -1
  98. data/lib/hecks/bluebook/aggregate.rb +21 -18
  99. data/lib/hecks/bluebook/assembly/contracts/sagas.rb +2 -0
  100. data/lib/hecks/bluebook/assembly/contracts/structure.rb +18 -13
  101. data/lib/hecks/bluebook/behaviour/aggregate.rb +27 -3
  102. data/lib/hecks/bluebook/command.rb +16 -5
  103. data/lib/hecks/bluebook/declaration.rb +32 -4
  104. data/lib/hecks/bluebook/domain_port.rb +7 -3
  105. data/lib/hecks/bluebook/dsl/aggregate_builder/relationships.rb +0 -2
  106. data/lib/hecks/bluebook/dsl/aggregate_builder/renaming.rb +25 -0
  107. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +3 -0
  108. data/lib/hecks/bluebook/dsl/attribute_collector.rb +0 -1
  109. data/lib/hecks/bluebook/dsl/audience_word.rb +40 -0
  110. data/lib/hecks/bluebook/dsl/bluebook_builder/metadata.rb +56 -0
  111. data/lib/hecks/bluebook/dsl/bluebook_builder/modules.rb +80 -0
  112. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/correlation_keys.rb +51 -0
  113. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +1 -0
  114. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +17 -34
  115. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +8 -0
  116. data/lib/hecks/bluebook/dsl/command_builder.rb +13 -3
  117. data/lib/hecks/bluebook/dsl/entity_builder.rb +0 -2
  118. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +6 -4
  119. data/lib/hecks/bluebook/dsl/kinds.rb +53 -0
  120. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +9 -2
  121. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +25 -15
  122. data/lib/hecks/bluebook/dsl/translation_builder.rb +16 -1
  123. data/lib/hecks/bluebook/dsl/word_gate.rb +1 -1
  124. data/lib/hecks/bluebook/dsl.rb +1 -0
  125. data/lib/hecks/bluebook/meta_validator/judge/identity.rb +9 -4
  126. data/lib/hecks/bluebook/meta_validator/plan/category.rb +10 -2
  127. data/lib/hecks/bluebook/meta_validator/plan/verbs.rb +9 -0
  128. data/lib/hecks/bluebook/meta_validator/plan.rb +2 -1
  129. data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +3 -1
  130. data/lib/hecks/bluebook/meta_validator/reconstruction/reading.rb +7 -0
  131. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +7 -2
  132. data/lib/hecks/bluebook/meta_validator/shapes.rb +3 -0
  133. data/lib/hecks/bluebook/meta_validator/syntax_boot/disk_cache.rb +1 -1
  134. data/lib/hecks/bluebook/model_check/aggregate_checks.rb +27 -0
  135. data/lib/hecks/bluebook/model_check/ask_checks.rb +25 -0
  136. data/lib/hecks/bluebook/model_check/reaction_chains.rb +114 -0
  137. data/lib/hecks/bluebook/model_check/reaction_cycles.rb +53 -0
  138. data/lib/hecks/bluebook/model_check/reaction_depth_checks.rb +58 -0
  139. data/lib/hecks/bluebook/model_check/reaction_walk.rb +62 -0
  140. data/lib/hecks/bluebook/model_check.rb +5 -27
  141. data/lib/hecks/bluebook/process_manager.rb +20 -3
  142. data/lib/hecks/bluebook/translation.rb +5 -3
  143. data/lib/hecks/bluebook/translation_plan.rb +9 -2
  144. data/lib/hecks/ci_pipeline/adapters/ci_cache.adapter +7 -0
  145. data/lib/hecks/ci_pipeline/adapters/ci_cache.rb +39 -0
  146. data/lib/hecks/ci_pipeline/adapters/ci_runner.adapter +7 -0
  147. data/lib/hecks/ci_pipeline/adapters/ci_runner.rb +55 -0
  148. data/lib/hecks/ci_pipeline/ci_pipeline.behaviors +322 -0
  149. data/lib/hecks/ci_pipeline/ci_pipeline.bluebook +938 -0
  150. data/lib/hecks/ci_pipeline/ci_pipeline.hecksagon +12 -0
  151. data/lib/hecks/ci_pipeline/ci_pipeline.ports.hecksagon +16 -0
  152. data/lib/hecks/ci_speed/adapters/ci_reader.adapter +7 -0
  153. data/lib/hecks/ci_speed/adapters/ci_reader.rb +141 -0
  154. data/lib/hecks/ci_speed/adapters/local_runner/answer.rb +41 -0
  155. data/lib/hecks/ci_speed/adapters/local_runner/catalog.rb +89 -0
  156. data/lib/hecks/ci_speed/adapters/local_runner/checkouts.rb +89 -0
  157. data/lib/hecks/ci_speed/adapters/local_runner/launcher.rb +69 -0
  158. data/lib/hecks/ci_speed/adapters/local_runner/load_average.rb +38 -0
  159. data/lib/hecks/ci_speed/adapters/local_runner/refs.rb +39 -0
  160. data/lib/hecks/ci_speed/adapters/local_runner/refused.rb +11 -0
  161. data/lib/hecks/ci_speed/adapters/local_runner/verdict.rb +71 -0
  162. data/lib/hecks/ci_speed/adapters/local_runner.adapter +7 -0
  163. data/lib/hecks/ci_speed/adapters/local_runner.rb +168 -0
  164. data/lib/hecks/ci_speed/adapters/replayed_runner.rb +39 -0
  165. data/lib/hecks/ci_speed/ci_speed.behaviors +341 -0
  166. data/lib/hecks/ci_speed/ci_speed.bluebook +1073 -0
  167. data/lib/hecks/ci_speed/ci_speed.hecksagon +11 -0
  168. data/lib/hecks/ci_speed/ci_speed.ports.hecksagon +21 -0
  169. data/lib/hecks/ci_workflows/ci_workflows.behaviors +13 -0
  170. data/lib/hecks/ci_workflows/ci_workflows.bluebook +173 -0
  171. data/lib/hecks/ci_workflows/ci_workflows.hecksagon +15 -0
  172. data/lib/hecks/coder/coder.bluebook +385 -0
  173. data/lib/hecks/coder/coder.hecksagon +12 -0
  174. data/lib/hecks/command_names/check.rb +39 -0
  175. data/lib/hecks/command_names/extractor.rb +67 -0
  176. data/lib/hecks/command_names/index.rb +40 -0
  177. data/lib/hecks/command_names/resolution.rb +81 -0
  178. data/lib/hecks/command_names/scan.rb +54 -0
  179. data/lib/hecks/command_names/sources.rb +73 -0
  180. data/lib/hecks/command_names.rb +26 -0
  181. data/lib/hecks/composer/jobs.rb +1 -1
  182. data/lib/hecks/composer/toolbox.rb +8 -1
  183. data/lib/hecks/corpus/generated_key.rb +205 -0
  184. data/lib/hecks/corpus/listing.rb +34 -0
  185. data/lib/hecks/corpus/rust.rb +27 -11
  186. data/lib/hecks/corpus/sources.rb +2 -1
  187. data/lib/hecks/corpus.rb +37 -42
  188. data/lib/hecks/deprecation.rb +23 -0
  189. data/lib/hecks/doc/reference/readme.rb +1 -1
  190. data/lib/hecks/doc/reference/rendering.rb +2 -2
  191. data/lib/hecks/doc/reference.rb +1 -1
  192. data/lib/hecks/embryonaut_bluebook/manifest.rb +1 -1
  193. data/lib/hecks/fixer/fixer.bluebook +240 -0
  194. data/lib/hecks/fixer/fixer.hecksagon +17 -0
  195. data/lib/hecks/framework_bluebooks.rb +32 -7
  196. data/lib/hecks/fuzzing/concurrent_dispatch/world_copy.rb +1 -0
  197. data/lib/hecks/fuzzing/isolated_boot/postgres_scratch.rb +11 -12
  198. data/lib/hecks/fuzzing/isolated_boot/worlds.rb +23 -5
  199. data/lib/hecks/fuzzing/isolated_boot.rb +1 -1
  200. data/lib/hecks/fuzzing/mutation/checks.rb +3 -3
  201. data/lib/hecks/grammar/translation.bluebook +1 -1
  202. data/lib/hecks/grammar/translation_rules.json +64 -0
  203. data/lib/hecks/hecks/adapter_words.json +7 -0
  204. data/lib/hecks/hecks/adapters/area_overlap.rb +156 -0
  205. data/lib/hecks/hecks/adapters/claude_agents.rb +8 -3
  206. data/lib/hecks/hecks/adapters/codebase/batch_runs.rb +60 -0
  207. data/lib/hecks/hecks/adapters/codebase/changed_specs.rb +52 -0
  208. data/lib/hecks/hecks/adapters/codebase/codemods.rb +3 -2
  209. data/lib/hecks/hecks/adapters/codebase/conformance.rb +14 -1
  210. data/lib/hecks/hecks/adapters/codebase/corpus_queries.rb +53 -0
  211. data/lib/hecks/hecks/adapters/codebase/generated_keys.rb +31 -0
  212. data/lib/hecks/hecks/adapters/codebase/impacted_specs.rb +110 -0
  213. data/lib/hecks/hecks/adapters/codebase/language.rb +2 -2
  214. data/lib/hecks/hecks/adapters/codebase/launcher_text.rb +39 -0
  215. data/lib/hecks/hecks/adapters/codebase/minitest_runs.rb +52 -0
  216. data/lib/hecks/hecks/adapters/codebase/regeneration.rb +51 -8
  217. data/lib/hecks/hecks/adapters/codebase/run_options.rb +35 -0
  218. data/lib/hecks/hecks/adapters/codebase/scripting.rb +39 -0
  219. data/lib/hecks/hecks/adapters/codebase/search.rb +1 -1
  220. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +79 -51
  221. data/lib/hecks/hecks/adapters/codebase/spec_files/report.rb +71 -0
  222. data/lib/hecks/hecks/adapters/codebase/spec_files/shared_run.rb +73 -0
  223. data/lib/hecks/hecks/adapters/codebase/spec_files.rb +95 -0
  224. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +53 -4
  225. data/lib/hecks/hecks/adapters/codebase/test_scope.rb +105 -0
  226. data/lib/hecks/hecks/adapters/codebase/test_suite.rb +48 -34
  227. data/lib/hecks/hecks/adapters/console_capture.rb +1 -1
  228. data/lib/hecks/hecks/adapters/cost_explorer.rb +9 -1
  229. data/lib/hecks/hecks/adapters/dispatching/brief_text.rb +51 -0
  230. data/lib/hecks/hecks/adapters/dispatching/launcher.rb +97 -0
  231. data/lib/hecks/hecks/adapters/dispatching/plan.rb +82 -0
  232. data/lib/hecks/hecks/adapters/dispatching/rows.rb +66 -0
  233. data/lib/hecks/hecks/adapters/dispatching/settings.rb +81 -0
  234. data/lib/hecks/hecks/adapters/dispatching/settler.rb +40 -0
  235. data/lib/hecks/hecks/adapters/dispatching.adapter +7 -0
  236. data/lib/hecks/hecks/adapters/dispatching.rb +93 -0
  237. data/lib/hecks/hecks/adapters/doctor_reading/report.rb +27 -0
  238. data/lib/hecks/hecks/adapters/doctor_reading.adapter +7 -0
  239. data/lib/hecks/hecks/adapters/doctor_reading.rb +161 -0
  240. data/lib/hecks/hecks/adapters/git_checkout.rb +1 -1
  241. data/lib/hecks/hecks/adapters/git_commit.adapter +7 -0
  242. data/lib/hecks/hecks/adapters/git_commit.rb +61 -0
  243. data/lib/hecks/hecks/adapters/git_landing/finisher.rb +82 -0
  244. data/lib/hecks/hecks/adapters/git_landing/foreign_hold.rb +111 -0
  245. data/lib/hecks/hecks/adapters/git_landing/line.rb +171 -0
  246. data/lib/hecks/hecks/adapters/git_landing/lineup.rb +98 -0
  247. data/lib/hecks/hecks/adapters/git_landing/merger.rb +1 -1
  248. data/lib/hecks/hecks/adapters/git_landing/numbering.rb +54 -0
  249. data/lib/hecks/hecks/adapters/git_landing/rivals.rb +59 -0
  250. data/lib/hecks/hecks/adapters/git_landing/ticket.rb +156 -0
  251. data/lib/hecks/hecks/adapters/git_landing/tidy.rb +147 -0
  252. data/lib/hecks/hecks/adapters/git_landing/train.rb +104 -0
  253. data/lib/hecks/hecks/adapters/git_landing/verdict.rb +64 -0
  254. data/lib/hecks/hecks/adapters/git_landing/waiting.rb +120 -0
  255. data/lib/hecks/hecks/adapters/git_landing.rb +106 -20
  256. data/lib/hecks/hecks/adapters/git_main_pull.rb +99 -0
  257. data/lib/hecks/hecks/adapters/git_rehearsal/bench.rb +82 -0
  258. data/lib/hecks/hecks/adapters/git_rehearsal/due.rb +84 -0
  259. data/lib/hecks/hecks/adapters/git_rehearsal/impacted/skips.rb +47 -0
  260. data/lib/hecks/hecks/adapters/git_rehearsal/impacted/spec_run.rb +75 -0
  261. data/lib/hecks/hecks/adapters/git_rehearsal/impacted.rb +181 -0
  262. data/lib/hecks/hecks/adapters/git_rehearsal/line.rb +76 -0
  263. data/lib/hecks/hecks/adapters/git_rehearsal/reading.rb +24 -0
  264. data/lib/hecks/hecks/adapters/git_rehearsal/record.rb +146 -0
  265. data/lib/hecks/hecks/adapters/git_rehearsal/spec_map/corpus.rb +25 -0
  266. data/lib/hecks/hecks/adapters/git_rehearsal/spec_map/needles.rb +61 -0
  267. data/lib/hecks/hecks/adapters/git_rehearsal/spec_map.rb +105 -0
  268. data/lib/hecks/hecks/adapters/git_rehearsal/stages.rb +118 -0
  269. data/lib/hecks/hecks/adapters/git_rehearsal.adapter +7 -0
  270. data/lib/hecks/hecks/adapters/git_rehearsal.rb +141 -0
  271. data/lib/hecks/hecks/adapters/git_train/bench.rb +15 -15
  272. data/lib/hecks/hecks/adapters/git_train/branch_guard.rb +62 -0
  273. data/lib/hecks/hecks/adapters/git_train/carriage.rb +27 -28
  274. data/lib/hecks/hecks/adapters/git_train/launcher_shape.rb +75 -0
  275. data/lib/hecks/hecks/adapters/git_train/mint_step.rb +47 -0
  276. data/lib/hecks/hecks/adapters/git_train/settlement.rb +167 -0
  277. data/lib/hecks/hecks/adapters/git_train.rb +73 -15
  278. data/lib/hecks/hecks/adapters/git_worktree_add.adapter +7 -0
  279. data/lib/hecks/hecks/adapters/git_worktree_add.rb +68 -0
  280. data/lib/hecks/hecks/adapters/github_pull_requests.adapter +7 -0
  281. data/lib/hecks/hecks/adapters/github_pull_requests.rb +109 -0
  282. data/lib/hecks/hecks/adapters/host_http.rb +6 -6
  283. data/lib/hecks/hecks/adapters/in_process_boot.rb +10 -8
  284. data/lib/hecks/hecks/adapters/in_process_operations.rb +11 -17
  285. data/lib/hecks/hecks/adapters/in_process_undo.rb +17 -0
  286. data/lib/hecks/hecks/adapters/journal_store/changes.rb +13 -4
  287. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +28 -15
  288. data/lib/hecks/hecks/adapters/journal_store/examination.rb +17 -1
  289. data/lib/hecks/hecks/adapters/journal_store/held_domain/renaming.rb +45 -0
  290. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +31 -5
  291. data/lib/hecks/hecks/adapters/journal_store/held_mint.rb +128 -0
  292. data/lib/hecks/hecks/adapters/journal_store/readings/attestation.rb +1 -1
  293. data/lib/hecks/hecks/adapters/journal_store/readings/boot_status.rb +58 -0
  294. data/lib/hecks/hecks/adapters/journal_store/readings/composition.rb +39 -0
  295. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/outcomes.rb +76 -0
  296. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/postgres_reader.rb +44 -0
  297. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/reader.rb +64 -0
  298. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/report.rb +102 -0
  299. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/sqlite_reader.rb +43 -0
  300. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/stores.rb +80 -0
  301. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/subscribers.rb +72 -0
  302. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace/summary.rb +39 -0
  303. data/lib/hecks/hecks/adapters/journal_store/readings/event_trace.rb +39 -0
  304. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/command_line.rb +57 -0
  305. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/edge_guards.rb +107 -0
  306. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/inspection.rb +94 -0
  307. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/plan.rb +66 -0
  308. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/report.rb +72 -0
  309. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/store.rb +34 -0
  310. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/watermark_guards.rb +86 -0
  311. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan/world.rb +66 -0
  312. data/lib/hecks/hecks/adapters/journal_store/readings/mint_plan.rb +36 -0
  313. data/lib/hecks/hecks/adapters/journal_store/readings/projection_audit.rb +64 -0
  314. data/lib/hecks/hecks/adapters/journal_store/readings/scaffolding.rb +3 -3
  315. data/lib/hecks/hecks/adapters/journal_store/readings/sqlite_status/database_reading.rb +113 -0
  316. data/lib/hecks/hecks/adapters/journal_store/readings/sqlite_status/read_only.rb +33 -0
  317. data/lib/hecks/hecks/adapters/journal_store/readings/sqlite_status.rb +32 -0
  318. data/lib/hecks/hecks/adapters/journal_store/readings.rb +13 -1
  319. data/lib/hecks/hecks/adapters/journal_store/reconcile_report.rb +60 -0
  320. data/lib/hecks/hecks/adapters/journal_store/reconciliation.rb +121 -0
  321. data/lib/hecks/hecks/adapters/journal_store/translation_write/shape_edge.rb +59 -0
  322. data/lib/hecks/hecks/adapters/journal_store/translation_write.rb +123 -0
  323. data/lib/hecks/hecks/adapters/journal_store.rb +16 -0
  324. data/lib/hecks/hecks/adapters/landed_work.adapter +7 -0
  325. data/lib/hecks/hecks/adapters/landed_work.rb +52 -0
  326. data/lib/hecks/hecks/adapters/local_files.rb +6 -6
  327. data/lib/hecks/hecks/adapters/process_pool.rb +3 -2
  328. data/lib/hecks/hecks/adapters/push_size.rb +57 -0
  329. data/lib/hecks/hecks/adapters/qa_quiescing.adapter +7 -0
  330. data/lib/hecks/hecks/adapters/qa_quiescing.rb +57 -0
  331. data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +30 -3
  332. data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +63 -3
  333. data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +29 -6
  334. data/lib/hecks/hecks/adapters/rehearsal/subject.rb +11 -5
  335. data/lib/hecks/hecks/adapters/rust_toolchain.rb +10 -1
  336. data/lib/hecks/hecks/adapters/rust_workspace.rb +1 -1
  337. data/lib/hecks/hecks/adapters/settings_reading/disposable_ledger.rb +32 -0
  338. data/lib/hecks/hecks/adapters/settings_reading/push_nudge.rb +26 -0
  339. data/lib/hecks/hecks/adapters/settings_reading/stores.rb +76 -0
  340. data/lib/hecks/hecks/adapters/settings_reading/test_scope.rb +28 -0
  341. data/lib/hecks/hecks/adapters/settings_reading.rb +28 -2
  342. data/lib/hecks/hecks/adapters/started_work.rb +42 -0
  343. data/lib/hecks/hecks/adapters/terminal.rb +12 -10
  344. data/lib/hecks/hecks/adapters/where_reading.adapter +7 -0
  345. data/lib/hecks/hecks/adapters/where_reading.rb +64 -0
  346. data/lib/hecks/hecks/adapters/work_areas.rb +57 -0
  347. data/lib/hecks/hecks/adapters/work_limits.rb +57 -0
  348. data/lib/hecks/hecks/build/build.bluebook +576 -0
  349. data/lib/hecks/hecks/check/check.bluebook +966 -0
  350. data/lib/hecks/hecks/codebase.behaviors +61 -5
  351. data/lib/hecks/hecks/composer.behaviors +1 -1
  352. data/lib/hecks/hecks/context_map.hecksagon +1 -1
  353. data/lib/hecks/hecks/custodian.behaviors +33 -7
  354. data/lib/hecks/hecks/delegate/delegate.bluebook +355 -0
  355. data/lib/hecks/hecks/deliver/deliver.bluebook +945 -0
  356. data/lib/hecks/hecks/deploy.behaviors +1 -1
  357. data/lib/hecks/hecks/evolve/evolve.bluebook +788 -0
  358. data/lib/hecks/hecks/find/find.bluebook +81 -0
  359. data/lib/hecks/hecks/hecks.behaviors +1 -1
  360. data/lib/hecks/hecks/hecks.bluebook +0 -133
  361. data/lib/hecks/hecks/hecks.contextmap +2 -0
  362. data/lib/hecks/hecks/hecks.hecksagon +185 -29
  363. data/lib/hecks/hecks/hecks.world +35 -9
  364. data/lib/hecks/hecks/implicit_moves.json +24 -0
  365. data/lib/hecks/hecks/migrate/migrate.bluebook +1066 -0
  366. data/lib/hecks/hecks/operate/operate.bluebook +695 -0
  367. data/lib/hecks/hecks/quiesce/quiesce.bluebook +117 -0
  368. data/lib/hecks/hecks/rehearse/rehearse.bluebook +133 -0
  369. data/lib/hecks/hecks/release/release.bluebook +916 -0
  370. data/lib/hecks/hecks/serve/serve.bluebook +134 -0
  371. data/lib/hecks/hecks/shapes.json +1 -15
  372. data/lib/hecks/hecks/site.behaviors +1 -1
  373. data/lib/hecks/hecks/start/start.bluebook +194 -0
  374. data/lib/hecks/hecks/test/test.bluebook +638 -0
  375. data/lib/hecks/hecks/tickets.world +14 -0
  376. data/lib/hecks/language/bluebook/aggregate.bluebook +22 -0
  377. data/lib/hecks/language/bluebook/bluebook.bluebook +34 -0
  378. data/lib/hecks/language/bluebook/command.bluebook +35 -0
  379. data/lib/hecks/language/bluebook/process_manager.bluebook +14 -1
  380. data/lib/hecks/language/bluebook/vocabulary.bluebook +174 -54
  381. data/lib/hecks/language/hecksagon/domain_port.bluebook +1 -0
  382. data/lib/hecks/language/hecksagon/port_operation.bluebook +14 -0
  383. data/lib/hecks/language/kinds/run.kind +120 -0
  384. data/lib/hecks/language/oidc.json +10 -0
  385. data/lib/hecks/language/translation/translation_aggregate.bluebook +24 -0
  386. data/lib/hecks/module_folders.rb +31 -0
  387. data/lib/hecks/ports/key_vault.rb +1 -1
  388. data/lib/hecks/ports/persistence/append_only.rb +26 -8
  389. data/lib/hecks/ports/persistence/binding_policy.rb +3 -1
  390. data/lib/hecks/ports/persistence/codec_boundary.rb +1 -1
  391. data/lib/hecks/ports/persistence/mint_door.rb +74 -0
  392. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +6 -5
  393. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +5 -1
  394. data/lib/hecks/ports/persistence/plugins/era/era_status.rb +48 -0
  395. data/lib/hecks/ports/persistence/plugins/era/projected_bluebook.rb +127 -0
  396. data/lib/hecks/ports/persistence/plugins/era/translation/additive_shape.rb +107 -0
  397. data/lib/hecks/ports/persistence/plugins/era/translation/compose.rb +155 -0
  398. data/lib/hecks/ports/persistence/plugins/era/translation/compose_render.rb +79 -0
  399. data/lib/hecks/ports/persistence/plugins/era/translation/edge_files.rb +49 -0
  400. data/lib/hecks/ports/persistence/plugins/era/translation/edge_route.rb +61 -0
  401. data/lib/hecks/ports/persistence/plugins/era/translation/implicit_edge.rb +67 -0
  402. data/lib/hecks/ports/persistence/plugins/era/translation/reconcile.rb +130 -0
  403. data/lib/hecks/ports/persistence/plugins/era/translation/reconcile_files.rb +35 -0
  404. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +13 -5
  405. data/lib/hecks/ports/persistence/plugins/era/translation.rb +5 -0
  406. data/lib/hecks/ports/persistence/plugins/era.rb +1 -0
  407. data/lib/hecks/ports/persistence/repository_factory.rb +11 -3
  408. data/lib/hecks/ports/persistence/stored_name_guard.rb +36 -0
  409. data/lib/hecks/ports/persistence.rb +2 -0
  410. data/lib/hecks/projections/ci_pipeline/table/checks.rb +137 -0
  411. data/lib/hecks/projections/ci_pipeline/table/lookup.rb +59 -0
  412. data/lib/hecks/projections/ci_pipeline/table/refusals.rb +58 -0
  413. data/lib/hecks/projections/ci_pipeline/table/rows.rb +119 -0
  414. data/lib/hecks/projections/ci_pipeline/table/tree.rb +30 -0
  415. data/lib/hecks/projections/ci_pipeline/table/typing.rb +92 -0
  416. data/lib/hecks/projections/ci_pipeline/table.rb +112 -0
  417. data/lib/hecks/projections/ci_pipeline/workflows.rb +162 -0
  418. data/lib/hecks/projections/ci_pipeline/yaml_text.rb +104 -0
  419. data/lib/hecks/projections/deploy/box/hosting.rb +1 -1
  420. data/lib/hecks/projections/deploy/box/roll_recipe.rb +1 -1
  421. data/lib/hecks/projections/deploy/box/roll_scripts.rb +1 -1
  422. data/lib/hecks/projections/deploy/box.rb +1 -1
  423. data/lib/hecks/projections/deploy/templates/fargate/Makefile.tmpl +1 -1
  424. data/lib/hecks/projections/deploy/templates/lambda/Makefile.tmpl +3 -3
  425. data/lib/hecks/projections/undo.rb +46 -0
  426. data/lib/hecks/projections.rb +2 -0
  427. data/lib/hecks/projector/cli_projector/claims.rb +11 -0
  428. data/lib/hecks/projector/cli_projector/command_help.rb +6 -1
  429. data/lib/hecks/projector/cli_projector/command_specs.rb +11 -1
  430. data/lib/hecks/projector/cli_projector/completion.rb +87 -0
  431. data/lib/hecks/projector/cli_projector/everyday.rb +40 -0
  432. data/lib/hecks/projector/cli_projector/json_listing.rb +77 -0
  433. data/lib/hecks/projector/cli_projector/listing.rb +1 -1
  434. data/lib/hecks/projector/cli_projector/modules.rb +39 -0
  435. data/lib/hecks/projector/cli_projector/query_specs.rb +1 -0
  436. data/lib/hecks/projector/cli_projector/renames.rb +58 -0
  437. data/lib/hecks/projector/cli_projector/search.rb +74 -0
  438. data/lib/hecks/projector/cli_projector/usage.rb +23 -6
  439. data/lib/hecks/projector/cli_projector.rb +24 -1
  440. data/lib/hecks/quality_control/adapters/ci_head.adapter +8 -0
  441. data/lib/hecks/quality_control/adapters/image_roll.adapter +9 -0
  442. data/lib/hecks/quality_control/adapters/image_roll.rb +158 -0
  443. data/lib/hecks/quality_control/adapters/main_maintenance.adapter +8 -0
  444. data/lib/hecks/quality_control/adapters/main_maintenance.rb +275 -0
  445. data/lib/hecks/quality_control/adapters/pump_tools.adapter +7 -0
  446. data/lib/hecks/quality_control/adapters/pump_tools.rb +18 -0
  447. data/lib/hecks/quality_control/adapters/push_due_reader.adapter +8 -0
  448. data/lib/hecks/quality_control/adapters/push_due_reader.rb +99 -0
  449. data/lib/hecks/quality_control/adapters/qa_auto_mint.rb +183 -0
  450. data/lib/hecks/quality_control/adapters/qa_era_mint.rb +94 -0
  451. data/lib/hecks/quality_control/adapters/qa_quiesce_marker.rb +126 -0
  452. data/lib/hecks/quality_control/adapters/run_keys.rb +36 -0
  453. data/lib/hecks/quality_control/adapters/run_reader.adapter +7 -0
  454. data/lib/hecks/quality_control/adapters/run_reader.rb +188 -0
  455. data/lib/hecks/quality_control/cli/child.rb +1 -0
  456. data/lib/hecks/quality_control/cli/qa_discover_external_domains/scanning.rb +1 -1
  457. data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +3 -3
  458. data/lib/hecks/quality_control/cli/qa_event_pump/attached.rb +67 -0
  459. data/lib/hecks/quality_control/cli/qa_event_pump/consumer.rb +103 -0
  460. data/lib/hecks/quality_control/cli/qa_event_pump/cursors.rb +60 -0
  461. data/lib/hecks/quality_control/cli/qa_event_pump/reactions.rb +46 -0
  462. data/lib/hecks/quality_control/cli/qa_event_pump/reader.rb +30 -0
  463. data/lib/hecks/quality_control/cli/qa_event_pump.rb +76 -0
  464. data/lib/hecks/quality_control/cli/qa_fix_main_bug/publishing.rb +79 -0
  465. data/lib/hecks/quality_control/cli/qa_fix_main_bug.rb +167 -0
  466. data/lib/hecks/quality_control/cli/qa_generated_domains/evaluation.rb +1 -1
  467. data/lib/hecks/quality_control/cli/qa_generated_domains/promotion.rb +3 -3
  468. data/lib/hecks/quality_control/cli/qa_main_gate/gate_run.rb +52 -0
  469. data/lib/hecks/quality_control/cli/qa_main_gate/logging.rb +70 -0
  470. data/lib/hecks/quality_control/cli/qa_main_gate/shell.rb +47 -0
  471. data/lib/hecks/quality_control/cli/qa_main_gate/sweeping.rb +59 -0
  472. data/lib/hecks/quality_control/cli/qa_main_gate/worktree.rb +62 -0
  473. data/lib/hecks/quality_control/cli/qa_main_gate.rb +135 -0
  474. data/lib/hecks/quality_control/cli/qa_postgres_role.rb +1 -1
  475. data/lib/hecks/quality_control/cli/qa_pr_check/checking.rb +2 -3
  476. data/lib/hecks/quality_control/cli/qa_push_nudge.rb +48 -0
  477. data/lib/hecks/quality_control/cli/qa_seed_angles/seed.rb +1 -1
  478. data/lib/hecks/quality_control/cli/qa_sweep/seat.rb +1 -1
  479. data/lib/hecks/quality_control/cli/qa_tick/event_pump_step.rb +34 -0
  480. data/lib/hecks/quality_control/cli/qa_tick/output.rb +16 -1
  481. data/lib/hecks/quality_control/cli/qa_tick/push_nudge_step.rb +28 -0
  482. data/lib/hecks/quality_control/cli/qa_tick/quiesce_guard.rb +51 -0
  483. data/lib/hecks/quality_control/cli/qa_tick.rb +36 -8
  484. data/lib/hecks/quality_control/quality_control.behaviors +65 -0
  485. data/lib/hecks/quality_control/quality_control.bluebook +1131 -11
  486. data/lib/hecks/quality_control/quality_control.hecksagon +11 -0
  487. data/lib/hecks/quality_control/quality_control.ports.hecksagon +138 -0
  488. data/lib/hecks/query_ir/touchpoints.rb +5 -7
  489. data/lib/hecks/refused.rb +21 -0
  490. data/lib/hecks/release/approval.rb +6 -3
  491. data/lib/hecks/release/conditions.rb +46 -0
  492. data/lib/hecks/release/runner/gem_publisher.rb +4 -4
  493. data/lib/hecks/release/version_commit.rb +48 -0
  494. data/lib/hecks/runtime/command_interpreter/hydration.rb +5 -4
  495. data/lib/hecks/runtime/command_interpreter/persisting.rb +11 -3
  496. data/lib/hecks/runtime/command_interpreter.rb +2 -2
  497. data/lib/hecks/runtime/command_rules/admissibility.rb +0 -2
  498. data/lib/hecks/runtime/command_rules/emission.rb +0 -1
  499. data/lib/hecks/runtime/dependency_planning/expression_reads.rb +0 -1
  500. data/lib/hecks/runtime/dispatcher/planning.rb +24 -0
  501. data/lib/hecks/runtime/dispatcher/routing.rb +6 -0
  502. data/lib/hecks/runtime/dispatcher/value_routing.rb +54 -0
  503. data/lib/hecks/runtime/dispatcher.rb +7 -1
  504. data/lib/hecks/runtime/dry_run_plan.rb +60 -0
  505. data/lib/hecks/runtime/entity_element/location.rb +0 -1
  506. data/lib/hecks/runtime/entity_element/mutations.rb +0 -1
  507. data/lib/hecks/runtime/entity_interpreter/locating.rb +5 -0
  508. data/lib/hecks/runtime/entity_interpreter.rb +0 -1
  509. data/lib/hecks/runtime/errors.rb +26 -0
  510. data/lib/hecks/runtime/instance.rb +0 -1
  511. data/lib/hecks/runtime/invocation_builder.rb +0 -1
  512. data/lib/hecks/runtime/outbox/consumer_runner.rb +9 -1
  513. data/lib/hecks/runtime/outbox/relay.rb +25 -4
  514. data/lib/hecks/runtime/outbox/runnable.rb +3 -1
  515. data/lib/hecks/runtime/outbox.rb +6 -2
  516. data/lib/hecks/runtime/policy_interpreter/fan_out.rb +18 -2
  517. data/lib/hecks/runtime/policy_interpreter.rb +17 -9
  518. data/lib/hecks/runtime/port_operation_interpreter.rb +21 -7
  519. data/lib/hecks/runtime/query_interpreter/arguments.rb +6 -5
  520. data/lib/hecks/runtime/reaction_invocation.rb +0 -1
  521. data/lib/hecks/runtime/refusal_wording.rb +12 -1
  522. data/lib/hecks/runtime/registry/context_maps.rb +1 -5
  523. data/lib/hecks/runtime/registry/declarations.rb +34 -4
  524. data/lib/hecks/runtime/registry/hecksagon_rules.rb +15 -1
  525. data/lib/hecks/runtime/registry/runtime_state.rb +10 -0
  526. data/lib/hecks/runtime/registry/world_defaults.rb +24 -2
  527. data/lib/hecks/runtime/registry/world_names.rb +99 -0
  528. data/lib/hecks/runtime/registry.rb +33 -27
  529. data/lib/hecks/runtime/saga_interpreter/compensation.rb +10 -0
  530. data/lib/hecks/runtime/saga_interpreter/correlation.rb +29 -3
  531. data/lib/hecks/runtime/saga_interpreter/delivery.rb +0 -1
  532. data/lib/hecks/runtime/saga_interpreter/lifecycle.rb +1 -1
  533. data/lib/hecks/runtime/saga_interpreter.rb +46 -2
  534. data/lib/hecks/runtime/value/coercion.rb +36 -8
  535. data/lib/hecks/rust_build/conformance.rb +16 -5
  536. data/lib/hecks/rust_build/parser.rb +25 -0
  537. data/lib/hecks/rust_build/project_rust/codegen_run.rb +45 -12
  538. data/lib/hecks/rust_build/project_rust/declared.rb +80 -0
  539. data/lib/hecks/rust_build/project_rust/features_header.rb +22 -0
  540. data/lib/hecks/rust_build/project_rust/manifest.rb +96 -0
  541. data/lib/hecks/rust_build/project_rust/meta.rb +36 -0
  542. data/lib/hecks/rust_build/project_rust.rb +28 -90
  543. data/lib/hecks/rust_build/write_if_changed.rb +19 -4
  544. data/lib/hecks/rust_build.rb +2 -1
  545. data/lib/hecks/rust_format.rb +32 -2
  546. data/lib/hecks/secrets.rb +111 -0
  547. data/lib/hecks/shape_ledger/edge_hygiene.rb +170 -0
  548. data/lib/hecks/shape_ledger/scope.rb +51 -0
  549. data/lib/hecks/shape_ledger/status.rb +89 -0
  550. data/lib/hecks/shape_ledger.rb +78 -33
  551. data/lib/hecks/site/bluebook/site.bluebook +1 -0
  552. data/lib/hecks/storehouse/audit.rb +34 -4
  553. data/lib/hecks/storehouse/callers.rb +8 -0
  554. data/lib/hecks/storehouse/dispatching.rb +14 -3
  555. data/lib/hecks/storehouse/identity.rb +41 -0
  556. data/lib/hecks/storehouse/querying.rb +7 -7
  557. data/lib/hecks/storehouse.rb +28 -10
  558. data/lib/hecks/tickets/bluebook/adapters/work_areas.adapter +7 -0
  559. data/lib/hecks/tickets/bluebook/adapters/work_limits.adapter +7 -0
  560. data/lib/hecks/tickets/bluebook/tickets.behaviors +70 -0
  561. data/lib/hecks/tickets/bluebook/tickets.bluebook +323 -28
  562. data/lib/hecks/tickets/bluebook/tickets.hecksagon +7 -0
  563. data/lib/hecks/tickets/bluebook/tickets.ports.hecksagon +17 -0
  564. data/lib/hecks/{cli → tools}/behaviors.rb +1 -1
  565. data/lib/hecks/{cli → tools}/canonicalise.rb +1 -1
  566. data/lib/hecks/{cli → tools}/check_engine_agreement.rb +1 -1
  567. data/lib/hecks/{cli → tools}/check_era.rb +6 -6
  568. data/lib/hecks/tools/ci_gates.rb +8 -2
  569. data/lib/hecks/tools/ci_workflows.rb +98 -0
  570. data/lib/hecks/{cli → tools}/console.rb +1 -1
  571. data/lib/hecks/{cli → tools}/deploy_template_diff.rb +1 -1
  572. data/lib/hecks/{cli → tools}/doc_coverage.rb +2 -2
  573. data/lib/hecks/{cli → tools}/document.rb +1 -1
  574. data/lib/hecks/{cli → tools}/domain_stub.rb +1 -1
  575. data/lib/hecks/{cli → tools}/domain_writer.rb +1 -1
  576. data/lib/hecks/tools/downstream_model_check.rb +122 -0
  577. data/lib/hecks/tools/evolve_run.rb +2 -2
  578. data/lib/hecks/{cli → tools}/expected_era.rb +1 -1
  579. data/lib/hecks/{cli → tools}/expression_projection.rb +1 -1
  580. data/lib/hecks/{cli → tools}/follow.rb +1 -1
  581. data/lib/hecks/tools/fuzz_sweep/options.rb +40 -5
  582. data/lib/hecks/tools/fuzz_sweep/pool.rb +12 -1
  583. data/lib/hecks/tools/fuzz_sweep/shards.rb +155 -0
  584. data/lib/hecks/tools/fuzz_sweep.rb +11 -5
  585. data/lib/hecks/tools/gate.rb +38 -29
  586. data/lib/hecks/tools/gate_memo/local_files.rb +33 -0
  587. data/lib/hecks/tools/gate_memo/rehearsal.rb +54 -0
  588. data/lib/hecks/tools/gate_memo/ruby_files.rb +152 -0
  589. data/lib/hecks/tools/gate_memo/session.rb +114 -0
  590. data/lib/hecks/tools/gate_memo/standalone.rb +67 -0
  591. data/lib/hecks/tools/gate_memo.rb +196 -0
  592. data/lib/hecks/tools/gate_report.rb +56 -0
  593. data/lib/hecks/{cli → tools}/history.rb +1 -1
  594. data/lib/hecks/{cli → tools}/interview_agent.rb +1 -1
  595. data/lib/hecks/{cli → tools}/interview_aggregate.rb +1 -1
  596. data/lib/hecks/{cli → tools}/interview_draft.rb +1 -1
  597. data/lib/hecks/{cli → tools}/interview_record.rb +1 -1
  598. data/lib/hecks/{cli → tools}/interview_run.rb +2 -2
  599. data/lib/hecks/{cli → tools}/interview_session/agent_state.rb +1 -1
  600. data/lib/hecks/{cli → tools}/interview_session/catalog.rb +1 -1
  601. data/lib/hecks/{cli → tools}/interview_session/manual_findings.rb +1 -1
  602. data/lib/hecks/{cli → tools}/interview_session/proposals.rb +1 -1
  603. data/lib/hecks/{cli → tools}/interview_session.rb +2 -2
  604. data/lib/hecks/{cli → tools}/interview_shape/lifecycle.rb +1 -1
  605. data/lib/hecks/{cli → tools}/interview_shape.rb +1 -1
  606. data/lib/hecks/{cli → tools}/ir.rb +1 -1
  607. data/lib/hecks/tools/lanes/files.rb +1 -1
  608. data/lib/hecks/tools/lanes/watch_workflow.rb +6 -8
  609. data/lib/hecks/tools/lanes/workflow.rb +1 -1
  610. data/lib/hecks/tools/lanes.rb +1 -1
  611. data/lib/hecks/{cli → tools}/mcp.rb +1 -1
  612. data/lib/hecks/{cli → tools}/model_check/examination.rb +1 -1
  613. data/lib/hecks/{cli → tools}/model_check/sources.rb +1 -1
  614. data/lib/hecks/{cli → tools}/model_check.rb +1 -1
  615. data/lib/hecks/tools/move_disables/reasons.rb +35 -0
  616. data/lib/hecks/tools/move_disables.rb +211 -0
  617. data/lib/hecks/tools/move_former_name.rb +105 -0
  618. data/lib/hecks/{cli → tools}/pattern_cases.rb +1 -1
  619. data/lib/hecks/{cli → tools}/persistence_notice.rb +1 -1
  620. data/lib/hecks/{cli → tools}/present.rb +1 -1
  621. data/lib/hecks/{cli → tools}/project_cli/launcher_source.rb +32 -22
  622. data/lib/hecks/{cli → tools}/project_cli/templates.rb +22 -15
  623. data/lib/hecks/{cli → tools}/project_cli.rb +11 -7
  624. data/lib/hecks/{cli → tools}/project_diagrams.rb +3 -3
  625. data/lib/hecks/{cli → tools}/project_glossary.rb +2 -2
  626. data/lib/hecks/{cli → tools}/reference.rb +2 -2
  627. data/lib/hecks/{cli → tools}/refresh_projections.rb +1 -1
  628. data/lib/hecks/{cli → tools}/refresh_rspec_runtime_baseline.rb +1 -1
  629. data/lib/hecks/tools/regeneration_run/pool.rb +148 -0
  630. data/lib/hecks/tools/regeneration_run/scratch.rb +76 -0
  631. data/lib/hecks/tools/regeneration_run.rb +125 -103
  632. data/lib/hecks/{cli → tools}/release.rb +1 -1
  633. data/lib/hecks/{cli → tools}/release_gem.rb +1 -1
  634. data/lib/hecks/{cli → tools}/rspec_io_parallel_files.rb +1 -1
  635. data/lib/hecks/{cli → tools}/rspec_shard_files.rb +1 -1
  636. data/lib/hecks/{cli → tools}/run.rb +9 -2
  637. data/lib/hecks/{cli → tools}/run_expectations.rb +1 -1
  638. data/lib/hecks/{cli → tools}/seed_semantics_corpus.rb +4 -4
  639. data/lib/hecks/{cli → tools}/serve_query_ir_mcp.rb +1 -1
  640. data/lib/hecks/{cli → tools}/shape.rb +3 -2
  641. data/lib/hecks/{cli → tools}/smoke_http/checks.rb +1 -1
  642. data/lib/hecks/{cli → tools}/smoke_http/settings.rb +1 -1
  643. data/lib/hecks/{cli → tools}/smoke_http/transport.rb +1 -1
  644. data/lib/hecks/{cli → tools}/smoke_http.rb +1 -1
  645. data/lib/hecks/{cli → tools}/smoke_test.rb +1 -1
  646. data/lib/hecks/{cli → tools}/spec_example.rb +1 -1
  647. data/lib/hecks/tools/stage_progress.rb +54 -0
  648. data/lib/hecks/{cli → tools}/statements.rb +1 -1
  649. data/lib/hecks/{cli → tools}/stores.rb +1 -1
  650. data/lib/hecks/{cli → tools}/stress_concurrency_specs/reporting.rb +1 -1
  651. data/lib/hecks/{cli → tools}/stress_concurrency_specs/usage.rb +4 -4
  652. data/lib/hecks/{cli → tools}/stress_concurrency_specs.rb +3 -3
  653. data/lib/hecks/tools/tenant_provisioning.rb +23 -0
  654. data/lib/hecks/tools/tools_doc.rb +10 -8
  655. data/lib/hecks/tools/translation_audit/edges.rb +21 -16
  656. data/lib/hecks/tools/translation_audit/verdicts.rb +1 -1
  657. data/lib/hecks/tools/translation_audit.rb +1 -1
  658. data/lib/hecks/tools/translation_scaffold.rb +1 -1
  659. data/lib/hecks/tools.rb +4 -1
  660. data/lib/hecks/version.rb +1 -1
  661. data/lib/hecks/vocabulary.rb +61 -31
  662. data/lib/hecks/workflow_pagination/judge.rb +48 -0
  663. data/lib/hecks/workflow_pagination/statement.rb +50 -0
  664. data/lib/hecks/workflow_pagination.rb +58 -0
  665. data/lib/hecks.rb +2 -0
  666. data/lib/rubocop/cop/hecks/bare_event_and_query_names.rb +58 -0
  667. data/lib/rubocop/cop/hecks/correlates_by_aggregate.rb +39 -0
  668. data/lib/rubocop/cop/hecks/creating_command_sets.rb +75 -0
  669. data/lib/rubocop/cop/hecks/invariant_expression_language.rb +47 -0
  670. data/lib/rubocop/cop/hecks/lifecycle_needs_attribute.rb +58 -0
  671. data/lib/rubocop/cop/hecks/no_id_string_attribute.rb +49 -0
  672. data/lib/rubocop/cop/hecks/one_terminal_mark_per_lifecycle.rb +47 -0
  673. data/lib/rubocop/cop/hecks/value_object_shorthand.rb +56 -0
  674. data/prebuilt/13c04bdc5970295b310f0a980d397ba722232c8da99cc1a0cdb383249921e871.marshal +0 -0
  675. data/prebuilt/e3857b77f47d9ecc1787b2e1f5136364f3cb3444ef4aea5479f3b98167affea2.marshal +0 -0
  676. data/qa/settings.yml +23 -0
  677. data/rust/.gitignore +0 -6
  678. data/rust/Cargo.toml +2 -1
  679. data/rust/build/Cargo.toml +1 -1
  680. data/rust/build/src/binding_pass.rs +57 -4
  681. data/rust/build/src/pipeline.rs +6 -4
  682. data/rust/build/src/resolve.rs +1 -0
  683. data/rust/codegen/Cargo.toml +1 -1
  684. data/rust/codegen/src/domain_generator.rs +3 -0
  685. data/rust/codegen/src/json_codec.rs +182 -23
  686. data/rust/codegen/src/one_of_references.rs +1 -0
  687. data/rust/codegen/src/queries.rs +20 -2
  688. data/rust/codegen/src/registry.rs +21 -5
  689. data/rust/expr/Cargo.toml +1 -1
  690. data/rust/host/Cargo.toml +1 -1
  691. data/rust/host/HECKS_RELEASE +1 -1
  692. data/rust/host/core/Cargo.toml +1 -1
  693. data/rust/host/src/bin/mint_harness.rs +1 -0
  694. data/rust/host/src/boot.rs +1 -0
  695. data/rust/host/src/store/mint.rs +40 -6
  696. data/rust/lsp/Cargo.toml +1 -1
  697. data/rust/parser/Cargo.toml +1 -1
  698. data/rust/parser/src/build/correlation_keys.rs +125 -0
  699. data/rust/parser/src/build/mod.rs +1 -0
  700. data/rust/parser/src/emit.rs +55 -3
  701. data/rust/parser/src/ir.rs +33 -1
  702. data/rust/parser/src/keywords.rs +289 -1
  703. data/rust/parser/src/main.rs +2 -0
  704. data/rust/parser/src/parse/aggregate.rs +10 -1
  705. data/rust/parser/src/parse/audience.rs +65 -0
  706. data/rust/parser/src/parse/command.rs +14 -0
  707. data/rust/parser/src/parse/declaration.rs +97 -0
  708. data/rust/parser/src/parse/domain_port.rs +6 -0
  709. data/rust/parser/src/parse/mod.rs +1 -0
  710. data/rust/parser/src/parse/process_manager.rs +17 -10
  711. data/rust/parser/src/parse/world.rs +12 -8
  712. data/rust/parser/src/render_ruby.rs +9 -0
  713. data/rust/parser/src/sentence/format.rs +3 -0
  714. data/rust/parser/src/sentence/process.rs +6 -2
  715. data/rust/src/exemplar/json.rs +17 -0
  716. data/rust/src/kernel/cli.rs +27 -3
  717. data/rust/src/kernel/dispatch.rs +4 -2
  718. data/rust/src/kernel/json.rs +62 -0
  719. data/rust/src/kernel/orchestrate.rs +28 -3
  720. data/rust/src/kernel/orchestrate_guard_tests.rs +12 -12
  721. data/rust/web/Cargo.toml +1 -1
  722. metadata +389 -96
  723. data/lib/hecks/cli/command_table.rb +0 -72
  724. data/lib/hecks/cli/launcher_words.rb +0 -168
  725. data/lib/hecks/cli.rb +0 -133
  726. data/lib/hecks/hecks/agents.bluebook +0 -246
  727. data/lib/hecks/hecks/codebase.bluebook +0 -3209
  728. data/lib/hecks/hecks/custodian.bluebook +0 -1300
  729. data/lib/hecks/hecks/ledger.bluebook +0 -190
  730. data/lib/hecks/hecks/rehearsal.bluebook +0 -437
  731. data/lib/hecks/hecks/tooling.bluebook +0 -1234
  732. data/lib/hecks/hecks/translations/2-148748.bluebook +0 -2
  733. data/lib/hecks/hecks/translations/2-15a2e4.bluebook +0 -2
  734. data/lib/hecks/hecks/translations/2-1b447c.bluebook +0 -5
  735. data/lib/hecks/hecks/translations/2-240474.bluebook +0 -2
  736. data/lib/hecks/hecks/translations/2-44446d.bluebook +0 -2
  737. data/lib/hecks/hecks/translations/2-46ca26.bluebook +0 -2
  738. data/lib/hecks/hecks/translations/2-473eab.bluebook +0 -2
  739. data/lib/hecks/hecks/translations/2-75cc28.bluebook +0 -2
  740. data/lib/hecks/hecks/translations/2-781c07.bluebook +0 -2
  741. data/lib/hecks/hecks/translations/2-84c18b.bluebook +0 -2
  742. data/lib/hecks/hecks/translations/2-aa5fff.bluebook +0 -2
  743. data/lib/hecks/hecks/translations/2-bfdb48.bluebook +0 -2
  744. data/lib/hecks/hecks/translations/2-cd96d8.bluebook +0 -10
  745. data/lib/hecks/hecks/translations/2-d43f71.bluebook +0 -2
  746. data/lib/hecks/hecks/translations/2-eea577.bluebook +0 -2
  747. data/lib/hecks/hecks/translations/2-f53248.bluebook +0 -2
  748. data/lib/hecks/hecks/translations/2-fbb677.bluebook +0 -2
  749. data/lib/hecks/hecks/translations/2-ffdf12.bluebook +0 -6
  750. data/lib/hecks/quality_control/adapters/clearance_recorder.rb +0 -36
  751. data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +0 -56
  752. data/prebuilt/31cf81e12f16236ad26249be590cfea3799c9db67432e6a4ef54b801c355b6ae.marshal +0 -0
  753. data/prebuilt/68ecb2bd3abb1a221007db4f2b0375834c13aaccac8f2b99778e8517f11aa113.marshal +0 -0
  754. data/prebuilt/verdicts-0328c2403383837d780ad5ed81d1da351c56436b894cf9015b5d56b8f1f1bf10.json +0 -1
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module Hecks
6
+ module Translation
7
+ # Carries out an admitted `Reconcile` plan on the translations directory, and puts the files
8
+ # back when the audit of what was written refuses.
9
+ module ReconcileFiles
10
+ module_function
11
+
12
+ # Writes the plan's composed edge and deletes the edge files it supersedes.
13
+ #
14
+ # @param plan [Reconcile::Plan] a plan with status `:write`
15
+ # @return [Hash{String => String, nil}] each touched path with the text it held, nil if absent
16
+ def write!(plan)
17
+ originals = [plan.write_path, *plan.removals].compact.to_h { |path| [path, read_if_present(path)] }
18
+ File.write(plan.write_path, plan.text) if plan.write_path
19
+ plan.removals.each { |path| FileUtils.rm_f(path) }
20
+ originals
21
+ end
22
+
23
+ # Puts each touched file back as `write!` found it.
24
+ #
25
+ # @param originals [Hash{String => String, nil}] what `write!` returned
26
+ def restore!(originals)
27
+ originals.each do |path, text|
28
+ text ? File.write(path, text) : FileUtils.rm_f(path)
29
+ end
30
+ end
31
+
32
+ def read_if_present(path) = File.exist?(path) ? File.read(path) : nil
33
+ end
34
+ end
35
+ end
@@ -1,4 +1,5 @@
1
1
  require_relative "../../storage_shape"
2
+ require_relative "../../projected_bluebook"
2
3
  require_relative "path_diff"
3
4
 
4
5
  module Hecks
@@ -9,14 +10,19 @@ module Hecks
9
10
  module Differ
10
11
  include PathDiff
11
12
 
12
- # Diffs two bluebook IRs into the edge's declarations.
13
+ # Diffs two storage shapes into the edge's declarations. Either side is a storage shape, a
14
+ # `Runtime::ProjectedBluebook` over one, or a declared bluebook, which is projected first.
13
15
  #
14
- # @param held_bluebook [Bluebook::Declaration] the era being translated from
15
- # @param current_bluebook [Bluebook::Declaration] the era being translated to
16
+ # @param held_bluebook [Hash, Runtime::ProjectedBluebook, Bluebook::Declaration] the era
17
+ # being translated from
18
+ # @param current_bluebook [Hash, Runtime::ProjectedBluebook, Bluebook::Declaration] the era
19
+ # being translated to
16
20
  # @return [Hash{Symbol => Object}] `:aggregates` (Array<Scaffold::ScaffoldedAggregate>),
17
21
  # `:retired` (Array<String>, vanished names with no successor), `:unclaimed`
18
22
  # (Array<String>, vanished names left ambiguous)
19
23
  def diff(held_bluebook, current_bluebook)
24
+ held_bluebook = Runtime::ProjectedBluebook.wrap(held_bluebook)
25
+ current_bluebook = Runtime::ProjectedBluebook.wrap(current_bluebook)
20
26
  held_shapes = projections(held_bluebook)
21
27
  current_shapes = projections(current_bluebook)
22
28
 
@@ -40,9 +46,11 @@ module Hecks
40
46
  ScaffoldedAggregate.new(name: aggregate.name, was: was, rules: rules)
41
47
  end
42
48
 
43
- # Projects a bluebook's storage shape, indexing its aggregates by name.
49
+ # A side's storage shape, its aggregates indexed by name: a view's stored shape as it is, a
50
+ # declared bluebook's as `StorageShape.project` answers it.
44
51
  def projections(bluebook)
45
- Runtime::StorageShape.project(bluebook)["aggregates"].to_h { |shape| [shape["name"], shape] }
52
+ shape = bluebook.is_a?(Runtime::ProjectedBluebook) ? bluebook.projection : Runtime::StorageShape.project(bluebook)
53
+ shape["aggregates"].to_h { |aggregate| [aggregate["name"], aggregate] }
46
54
  end
47
55
 
48
56
  # Pairs vanished aggregates with new ones whose full shape reappears under exactly one
@@ -7,5 +7,10 @@ end
7
7
 
8
8
  require_relative "translation/rule_compiler"
9
9
  require_relative "translation/scaffold"
10
+ require_relative "translation/implicit_edge"
10
11
  require_relative "translation/audit"
12
+ require_relative "translation/compose"
13
+ require_relative "translation/edge_files"
14
+ require_relative "translation/reconcile"
15
+ require_relative "translation/reconcile_files"
11
16
  require_relative "translation/reattest"
@@ -1,5 +1,6 @@
1
1
  require_relative "../plugin"
2
2
  require_relative "era/era_check"
3
+ require_relative "era/era_status"
3
4
  require_relative "era/era_guard"
4
5
  require_relative "era/era_tamper"
5
6
  require_relative "era/storage_shape"
@@ -43,7 +43,7 @@ module Hecks
43
43
  # @param bind [Bluebook::Bind] the bind naming the adapter
44
44
  # @param settings_verb [String] the verb whose settings configure the adapter
45
45
  # @return [Hash] the declared settings, under the adapter's own declared defaults, plus
46
- # the domain, resolved era and superseding era
46
+ # the domain, resolved era, superseding era and whether the shape is unminted
47
47
  def adapter_settings(registry, domain, aggregate, bind, settings_verb)
48
48
  registry.check_verb(bind)
49
49
  settings = registry.binding_settings(domain, settings_verb, bind.adapter)
@@ -52,8 +52,16 @@ module Hecks
52
52
  settings = registry.with_adapter_defaults(bind.adapter, aggregate, settings)
53
53
  # domain, resolved era and superseding era ride along outside the declared
54
54
  # settings: a lineage adapter needs them to journal per domain, per-era.
55
- settings.merge(domain: domain.to_s, era: registry.resolved_eras[domain.to_s],
56
- superseded_by: registry.superseded_eras[domain.to_s])
55
+ settings.merge(boot_marks(registry, domain))
56
+ end
57
+
58
+ # The per-domain marks the boot gate left on the registry, merged into an adapter's settings.
59
+ #
60
+ # @return [Hash] the domain, resolved era, superseding era and whether the shape is unminted
61
+ def boot_marks(registry, domain)
62
+ name = domain.to_s
63
+ { domain: name, era: registry.resolved_eras[name], superseded_by: registry.superseded_eras[name],
64
+ unminted: registry.unminted_eras.key?(name) }
57
65
  end
58
66
  end
59
67
  end
@@ -0,0 +1,36 @@
1
+ require_relative "../../runtime/errors"
2
+
3
+ module Hecks
4
+ module Ports
5
+ module Persistence
6
+ # Refuses the boot that would store an aggregate in a new, empty table beside rows an earlier
7
+ # name still holds. A renamed aggregate's rows are found by its `stored_as`; if that line is
8
+ # missing or wrong, the adapter would create the empty table the new name implies and the
9
+ # rows would seem gone. This names the table the rows are in instead, and creates nothing.
10
+ module StoredNameGuard
11
+ module_function
12
+
13
+ # @param aggregate [Bluebook::Aggregate] the aggregate about to be stored
14
+ # @param row_count [#call] given a table's base name, the rows it holds (0 when absent)
15
+ # @return [void]
16
+ # @raise [Runtime::WiringError] when the aggregate's own table holds no rows and a prior
17
+ # name's table does
18
+ def check!(aggregate, row_count:)
19
+ return if row_count.call(aggregate.storage_name).positive?
20
+
21
+ held = aggregate.prior_storage_names.to_h { |name| [name, row_count.call(name)] }.select { |_, rows| rows.positive? }
22
+ return if held.empty?
23
+
24
+ raise Runtime::WiringError, refusal(aggregate, held)
25
+ end
26
+
27
+ def refusal(aggregate, held)
28
+ name, rows = held.first
29
+ "cannot boot #{aggregate.name}: it would be stored in #{aggregate.storage_name.inspect}, which holds no rows, " \
30
+ "but #{name.inspect} holds rows (#{rows}) from an earlier name. Point the world at them with " \
31
+ "`stored_as #{aggregate.name}: #{name.inspect}`, or move the rows first. Nothing was created."
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -2,6 +2,8 @@ require_relative "persistence/constants"
2
2
  require_relative "persistence/binding_policy"
3
3
  require_relative "persistence/plugin"
4
4
  require_relative "persistence/repository_factory"
5
+ require_relative "persistence/mint_door"
6
+ require_relative "persistence/stored_name_guard"
5
7
  require_relative "persistence/append_only"
6
8
  require_relative "persistence/execution"
7
9
  require_relative "persistence/remote_runtime"
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "tree"
4
+
5
+ module Hecks
6
+ module Projections
7
+ module CiPipeline
8
+ class Table
9
+ # What no single row can show: a workflow nothing starts, secrets no caller can pass, a
10
+ # shard count that is not one a matrix can have, jobs that wait on one another in a circle,
11
+ # and a command that names a shard total its job does not have.
12
+ class Checks
13
+ # The text a step's command writes where its job's shard total belongs.
14
+ SHARD_TOKEN = "%{shard_total}"
15
+
16
+ # One scope of a job's `permissions:` line: a scope, a colon and what is allowed.
17
+ PERMISSION = /\A[a-z-]+: (read|write|none)\z/
18
+
19
+ # A command that begins with whitespace, which a literal block cannot carry.
20
+ LEADING_SPACE = /\A\s/
21
+
22
+ # @param workflows [Array<Tree::Workflow>] the joined workflows
23
+ # @param vocabulary [Hash{Symbol => Object}] the closed sets and patterns
24
+ # @param problems [Array<String>] collects each problem found, one line each
25
+ def initialize(workflows, vocabulary, problems)
26
+ @workflows = workflows
27
+ @vocabulary = vocabulary
28
+ @problems = problems
29
+ end
30
+
31
+ # @return [void]
32
+ def call
33
+ @workflows.each do |workflow|
34
+ check_workflow(workflow)
35
+ workflow.jobs.each { |job| check_job(job) }
36
+ check_cycles(workflow)
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def check_workflow(workflow)
43
+ events = @vocabulary.fetch(:trigger)
44
+ problem(workflow, "has no Trigger row; an event is one of #{events.join(", ")}") if workflow.triggers.empty?
45
+ if workflow.secrets.any? && !workflow.triggers.include?("workflow_call")
46
+ problem(workflow, "has Secret rows but no workflow_call Trigger; only a called workflow takes secrets")
47
+ end
48
+ return unless workflow.cancel_in_progress && workflow.concurrency_group.empty?
49
+
50
+ problem(workflow, "cancels in progress without a concurrency_group to cancel within")
51
+ end
52
+
53
+ def check_job(job)
54
+ check_time_limit(job)
55
+ check_shard_total(job)
56
+ check_shard_axis(job)
57
+ check_shard_token(job)
58
+ check_permissions(job)
59
+ job.steps.select { |step| step.run.match?(LEADING_SPACE) }.each do |step|
60
+ problem(step, "starts its command with whitespace, which a block scalar cannot carry")
61
+ end
62
+ end
63
+
64
+ def check_time_limit(job)
65
+ return if job.timeout_minutes.to_i.positive?
66
+
67
+ problem(job, "has timeout_minutes #{job.timeout_minutes.inspect}; a job has a positive time limit")
68
+ end
69
+
70
+ def check_shard_total(job)
71
+ return unless job.shard_total < 1
72
+
73
+ problem(job, "has shard_total #{job.shard_total}; a sharded job has at least one shard")
74
+ end
75
+
76
+ def check_shard_axis(job)
77
+ if job.shard_total > 1 && job.shard_axis.empty?
78
+ problem(job, "has shard_total #{job.shard_total} and no shard_axis; the matrix needs a name")
79
+ elsif job.shard_total <= 1 && !job.shard_axis.empty?
80
+ problem(job, "has shard_axis #{job.shard_axis.inspect} but shard_total #{job.shard_total}; " \
81
+ "a job with one shard has no matrix")
82
+ end
83
+ end
84
+
85
+ def check_shard_token(job)
86
+ return if job.shard_total > 1
87
+
88
+ job.steps.select { |step| step.run.include?(SHARD_TOKEN) }.each do |step|
89
+ problem(step, "writes #{SHARD_TOKEN} but its job has no shards")
90
+ end
91
+ end
92
+
93
+ def check_permissions(job)
94
+ scopes = job.permissions.split(", ")
95
+ scopes.grep_v(PERMISSION).each do |scope|
96
+ problem(job, "has permissions scope #{scope.inspect}; a scope is `<name>: read`, `write` or `none`, " \
97
+ "separated by a comma and a space")
98
+ end
99
+ end
100
+
101
+ # Each cycle among a workflow's jobs, named once from the first job in it.
102
+ def check_cycles(workflow)
103
+ needs = needs_among(workflow)
104
+ reported = []
105
+ needs.each_key do |name|
106
+ cycle = cycle_from(name, needs) or next
107
+ next if reported.include?(cycle.sort)
108
+
109
+ reported << cycle.sort
110
+ problem(workflow, "has jobs that need each other in a circle: #{[*cycle, cycle.first].join(" -> ")}")
111
+ end
112
+ end
113
+
114
+ # @return [Hash{String => Array<String>}] each job's name to the declared jobs it needs
115
+ def needs_among(workflow)
116
+ names = workflow.jobs.map(&:name)
117
+ workflow.jobs.to_h { |job| [job.name, job.needs & names] }
118
+ end
119
+
120
+ # @return [Array<String>, nil] the jobs of a cycle that begins and ends at `start`
121
+ def cycle_from(start, needs, path = [start])
122
+ needs.fetch(path.last).each do |next_job|
123
+ return path if next_job == start
124
+ next if path.include?(next_job)
125
+
126
+ found = cycle_from(start, needs, [*path, next_job])
127
+ return found if found
128
+ end
129
+ nil
130
+ end
131
+
132
+ def problem(row, text) = @problems << "#{row.label} #{text}"
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hecks
4
+ module Projections
5
+ module CiPipeline
6
+ class Table
7
+ # How a row finds what it belongs to: the workflow, job and step its fields name, and the
8
+ # refusal, naming what is declared, when there is none. Mixed into `Rows`, which holds the
9
+ # joined workflows in `@workflows` and the problems in `@problems`.
10
+ module Lookup
11
+ private
12
+
13
+ def workflow_of(row)
14
+ found = @workflows.find { |workflow| workflow.name == row[:workflow] }
15
+ return found if found
16
+
17
+ problem(row, "names workflow #{row[:workflow].inspect}, which no Workflow row declares; " \
18
+ "its workflows are #{@workflows.map(&:name).join(", ")}")
19
+ nil
20
+ end
21
+
22
+ def job_of(row)
23
+ workflow = workflow_of(row) or return
24
+ found = workflow.jobs.find { |job| job.name == row[:job] }
25
+ return found if found
26
+
27
+ problem(row, "names job #{row[:job].inspect}, which workflow #{row[:workflow]} does not declare; " \
28
+ "its jobs are #{workflow.jobs.map(&:name).join(", ")}")
29
+ nil
30
+ end
31
+
32
+ def step_of(job, row)
33
+ found = job.steps.find { |candidate| candidate.name == row[:step] }
34
+ return found if found
35
+
36
+ problem(row, "names step #{row[:step].inspect}, which job #{row[:job]} does not declare; " \
37
+ "its steps are #{job.steps.map(&:name).join(", ")}")
38
+ nil
39
+ end
40
+
41
+ def check_pattern(row, pattern, field, reason)
42
+ regexp = @vocabulary.fetch(:patterns).fetch(pattern)
43
+ return if row[field].is_a?(String) && regexp.match?(row[field])
44
+
45
+ problem(row, "has #{field} #{row[field].inspect}; #{reason}, matching #{regexp.source}")
46
+ end
47
+
48
+ def twice(row, declared)
49
+ return unless declared
50
+
51
+ problem(row, "is declared twice")
52
+ end
53
+
54
+ def problem(row, text) = @problems << "#{row.fetch(:label)} #{text}"
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hecks
4
+ module Projections
5
+ module CiPipeline
6
+ class Table
7
+ # The refusals a row earns from the bluebook's closed sets and from what its job declares,
8
+ # each naming the row and listing what is valid. Mixed into `Rows`, which holds the
9
+ # vocabulary in `@vocabulary` and the problems in `@problems`.
10
+ module Refusals
11
+ private
12
+
13
+ def refuse_event(row)
14
+ events = @vocabulary.fetch(:trigger)
15
+ return if events.include?(row[:event])
16
+
17
+ problem(row, "has event #{row[:event].inspect}; an event is one of #{events.join(", ")}")
18
+ end
19
+
20
+ def refuse_unknown_need(row)
21
+ names = workflow_of(row).jobs.map(&:name)
22
+ return if names.include?(row[:needs])
23
+
24
+ problem(row, "names job #{row[:needs].inspect}, which workflow #{row[:workflow]} does not declare; " \
25
+ "its jobs are #{names.join(", ")}")
26
+ end
27
+
28
+ # A step uses an action or runs a command, and an action is one the bluebook admits.
29
+ def refuse_uses(row)
30
+ uses = row[:uses]
31
+ refuse_both(row) unless uses.empty? || row[:run].empty?
32
+ refuse_neither(row) if uses.empty? && row[:run].empty?
33
+ refuse_action(row) unless uses.empty?
34
+ end
35
+
36
+ def refuse_both(row)
37
+ problem(row, "has both uses and run; a step uses an action or runs a command, not both")
38
+ end
39
+
40
+ def refuse_neither(row)
41
+ problem(row, "has neither uses nor run; a step uses an action or runs a command")
42
+ end
43
+
44
+ def refuse_action(row)
45
+ actions = @vocabulary.fetch(:uses)
46
+ return if actions.include?(row[:uses])
47
+
48
+ problem(row, "has uses #{row[:uses].inspect}; uses is one of #{actions.join(", ")}")
49
+ end
50
+
51
+ def refuse_input_of_command(row)
52
+ problem(row, "names a step that runs a command; only a step that uses an action takes inputs")
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "tree"
4
+ require_relative "typing"
5
+ require_relative "lookup"
6
+ require_relative "refusals"
7
+
8
+ module Hecks
9
+ module Projections
10
+ module CiPipeline
11
+ class Table
12
+ # Joins the declared member rows into a tree of workflows, jobs and steps: each row is
13
+ # joined to its workflow and job by name, and each closed-set value is checked against
14
+ # the CiPipeline bluebook's vocabulary. A row that names what is not declared is refused,
15
+ # with what is declared listed.
16
+ class Rows
17
+ include Lookup
18
+ include Refusals
19
+
20
+ # The bluebook value objects whose pattern a field's text must match, by name.
21
+ PATTERNS = { workflow: %w[Workflow WorkflowName], secret: %w[Workflow SecretName],
22
+ env: %w[JobSpec EnvName], output: %w[JobSpec OutputKey], step_id: %w[JobSpec StepId],
23
+ shard_axis: %w[JobSpec ShardAxis] }.freeze
24
+
25
+ # The row objects in the order they are joined, each with the method that joins one row.
26
+ JOINS = { "Trigger" => :join_trigger, "Secret" => :join_secret, "Job" => :join_job,
27
+ "Need" => :join_need, "Output" => :join_output, "Env" => :join_env,
28
+ "Step" => :join_step, "StepInput" => :join_input }.freeze
29
+
30
+ # @return [Array<Tree::Workflow>] the workflows, in the order declared
31
+ attr_reader :workflows
32
+
33
+ # @param rows [Hash{String => Array<Hash{Symbol => Object}>}] each object's declared rows
34
+ # @param vocabulary [Hash{Symbol => Object}] the closed sets and patterns
35
+ # @param problems [Array<String>] collects each problem found, one line each
36
+ def initialize(rows, vocabulary, problems)
37
+ @vocabulary = vocabulary
38
+ @problems = problems
39
+ @typed = type_all(rows, Typing.new(problems))
40
+ @workflows = []
41
+ @typed.fetch("Workflow").each { |row| @workflows << build_workflow(row) }
42
+ JOINS.each { |object, join| @typed.fetch(object).each { |row| send(join, row) } }
43
+ end
44
+
45
+ private
46
+
47
+ def type_all(rows, typing)
48
+ rows.to_h { |object, members| [object, members.each_with_index.map { |row, i| typing.call(object, row, i) }] }
49
+ end
50
+
51
+ def build_workflow(row)
52
+ check_pattern(row, :workflow, :name, "a workflow is named by its file")
53
+ twice(row, @workflows.any? { |workflow| workflow.name == row[:name] })
54
+ fields = row.slice(:label, :name, :display_name, :note, :concurrency_group, :cancel_in_progress)
55
+ Tree::Workflow.new(**fields, triggers: [], secrets: [], jobs: [])
56
+ end
57
+
58
+ def join_trigger(row)
59
+ workflow = workflow_of(row) or return
60
+ refuse_event(row)
61
+ twice(row, workflow.triggers.include?(row[:event]))
62
+ workflow.triggers << row[:event]
63
+ end
64
+
65
+ def join_secret(row)
66
+ workflow = workflow_of(row) or return
67
+ check_pattern(row, :secret, :name, "a secret is named in capitals")
68
+ twice(row, workflow.secrets.any? { |secret| secret.name == row[:name] })
69
+ workflow.secrets << Tree::Secret.new(row[:name], row[:required])
70
+ end
71
+
72
+ def join_job(row)
73
+ workflow = workflow_of(row) or return
74
+ twice(row, workflow.jobs.any? { |job| job.name == row[:name] })
75
+ check_pattern(row, :shard_axis, :shard_axis, "a matrix is named in lower case") unless row[:shard_axis].empty?
76
+ fields = row.slice(:label, :name, :runner, :timeout_minutes, :permissions, :condition, :shard_total,
77
+ :shard_axis, :note)
78
+ workflow.jobs << Tree::Job.new(**fields, needs: [], outputs: [], env: [], steps: [])
79
+ end
80
+
81
+ def join_need(row)
82
+ job = job_of(row) or return
83
+ refuse_unknown_need(row)
84
+ twice(row, job.needs.include?(row[:needs]))
85
+ job.needs << row[:needs]
86
+ end
87
+
88
+ def join_output(row) = join_pair(row, :output, :outputs, "an output is named by a key")
89
+
90
+ def join_env(row) = join_pair(row, :env, :env, "a variable is named in capitals")
91
+
92
+ def join_pair(row, pattern, list, reason)
93
+ job = job_of(row) or return
94
+ check_pattern(row, pattern, :key, reason)
95
+ twice(row, job[list].any? { |pair| pair.key == row[:key] })
96
+ job[list] << Tree::Pair.new(row[:key], row[:value])
97
+ end
98
+
99
+ def join_step(row)
100
+ job = job_of(row) or return
101
+ twice(row, job.steps.any? { |step| step.name == row[:name] })
102
+ check_pattern(row, :step_id, :id, "an id is lower case") unless row[:id].empty?
103
+ refuse_uses(row)
104
+ fields = row.slice(:label, :name, :title, :id, :uses, :run, :condition, :note)
105
+ job.steps << Tree::Step.new(**fields, inputs: [])
106
+ end
107
+
108
+ def join_input(row)
109
+ job = job_of(row) or return
110
+ step = step_of(job, row) or return
111
+ twice(row, step.inputs.any? { |pair| pair.key == row[:key] })
112
+ refuse_input_of_command(row) if step.uses.empty?
113
+ step.inputs << Tree::Pair.new(row[:key], row[:value])
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hecks
4
+ module Projections
5
+ module CiPipeline
6
+ class Table
7
+ # The workflows a table of rows joins into: each workflow holds its triggers, secrets and
8
+ # jobs, each job its needs, outputs, environment and steps, each step its `with:` inputs.
9
+ module Tree
10
+ # One workflow file with the rows that belong to it.
11
+ Workflow = Struct.new(:label, :name, :display_name, :note, :concurrency_group, :cancel_in_progress,
12
+ :triggers, :secrets, :jobs, keyword_init: true)
13
+
14
+ # One secret a called workflow takes.
15
+ Secret = Struct.new(:name, :required)
16
+
17
+ # One job with the rows that belong to it.
18
+ Job = Struct.new(:label, :name, :runner, :timeout_minutes, :permissions, :condition, :shard_total,
19
+ :shard_axis, :note, :needs, :outputs, :env, :steps, keyword_init: true)
20
+
21
+ # One step with its `with:` inputs.
22
+ Step = Struct.new(:label, :name, :title, :id, :uses, :run, :condition, :note, :inputs, keyword_init: true)
23
+
24
+ # A key and its value: a job output, an environment variable or a step input.
25
+ Pair = Struct.new(:key, :value)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hecks
4
+ module Projections
5
+ module CiPipeline
6
+ class Table
7
+ # Checks the fields of each declared row and their types, and fills the defaults, so a row
8
+ # reaches the join as a hash of every field its object may carry.
9
+ class Typing
10
+ # The fields a row of each object may carry, with the Ruby class each takes (`:bool` is
11
+ # true or false). The order is the order the objects are joined in.
12
+ SHAPES = {
13
+ "Workflow" => { name: String, display_name: String, note: String, concurrency_group: String,
14
+ cancel_in_progress: :bool },
15
+ "Trigger" => { workflow: String, event: String },
16
+ "Secret" => { workflow: String, name: String, required: :bool },
17
+ "Job" => { workflow: String, name: String, runner: String, timeout_minutes: Integer,
18
+ permissions: String, condition: String, shard_total: Integer, shard_axis: String,
19
+ note: String },
20
+ "Need" => { workflow: String, job: String, needs: String },
21
+ "Output" => { workflow: String, job: String, key: String, value: String },
22
+ "Env" => { workflow: String, job: String, key: String, value: String },
23
+ "Step" => { workflow: String, job: String, name: String, title: String, id: String, uses: String,
24
+ run: String, condition: String, note: String },
25
+ "StepInput" => { workflow: String, job: String, step: String, key: String, value: String }
26
+ }.freeze
27
+
28
+ # The fields a row must name; every other field has a default.
29
+ REQUIRED = {
30
+ "Workflow" => %i[name display_name], "Trigger" => %i[workflow event],
31
+ "Secret" => %i[workflow name], "Job" => %i[workflow name runner timeout_minutes],
32
+ "Need" => %i[workflow job needs], "Output" => %i[workflow job key value],
33
+ "Env" => %i[workflow job key value], "Step" => %i[workflow job name],
34
+ "StepInput" => %i[workflow job step key value]
35
+ }.freeze
36
+
37
+ # The shard total of a job that is not split into legs.
38
+ UNSHARDED = 1
39
+
40
+ # The fields whose values name the row, in the order a label lists them.
41
+ IDENTITY = %i[workflow job step name event needs key].freeze
42
+
43
+ # @param problems [Array<String>] collects each problem found, one line each
44
+ def initialize(problems)
45
+ @problems = problems
46
+ end
47
+
48
+ # @param object [String] the row object's name, such as `Step`
49
+ # @param member [Hash{Symbol => Object}] the declared fields of one row
50
+ # @param index [Integer] the row's position, for a label when the row names nothing
51
+ # @return [Hash{Symbol => Object}] the row's `:label`, and each field, defaults filled
52
+ def call(object, member, index)
53
+ label = label_of(object, member, index)
54
+ shape = SHAPES.fetch(object)
55
+ refuse(label, member, shape, REQUIRED.fetch(object))
56
+ fields = shape.to_h { |key, type| [key, member.fetch(key) { default(object, key, type) }] }
57
+ { label: label, **fields }
58
+ end
59
+
60
+ private
61
+
62
+ def refuse(label, member, shape, required)
63
+ (member.keys - shape.keys).each do |key|
64
+ problem(label, "has no field #{key}; fields are #{shape.keys.join(", ")}")
65
+ end
66
+ member.slice(*shape.keys).each { |key, value| check_type(label, key, value, shape.fetch(key)) }
67
+ (required - member.keys).each { |key| problem(label, "has no #{key}") }
68
+ end
69
+
70
+ def label_of(object, member, index)
71
+ identity = member.values_at(*IDENTITY).compact
72
+ "#{object} #{identity.empty? ? "row #{index + 1}" : identity.join("/")}"
73
+ end
74
+
75
+ def default(object, key, type)
76
+ return UNSHARDED if object == "Job" && key == :shard_total
77
+
78
+ { String => "", Integer => nil, bool: false }.fetch(type)
79
+ end
80
+
81
+ def check_type(label, key, value, expected)
82
+ return if expected == :bool ? [true, false].include?(value) : value.is_a?(expected)
83
+
84
+ problem(label, "has #{key} #{value.inspect}; #{key} is #{expected == :bool ? "true or false" : "a #{expected}"}")
85
+ end
86
+
87
+ def problem(label, text) = @problems << "#{label} #{text}"
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end