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
@@ -35,7 +35,7 @@ module Hecks
35
35
  def merge_chain(registry, bluebook, held)
36
36
  raise Runtime::WiringError, "nothing to merge — #{bluebook.name} stands at era 1" if held.size < 2
37
37
 
38
- edge_chain(registry, bluebook, held[0..-2], held.last[:label])
38
+ edge_chain(registry, bluebook, held[0..-2], held.last[:label], target: held.last)
39
39
  end
40
40
 
41
41
  # The audit the merge runs over the merged heads, answering every violation found.
@@ -0,0 +1,163 @@
1
+ require_relative "../../../../ports/persistence/plugins/era/translation/implicit_edge"
2
+ require_relative "../../../../ports/persistence/plugins/era/translation/scaffold"
3
+ require_relative "../../../../ports/persistence/plugins/era/storage_shape"
4
+ require_relative "../../../../shape_ledger"
5
+
6
+ module Hecks
7
+ module Adapters
8
+ class PostgresEra
9
+ module LineageManager
10
+ # The decision a mint and a rehearsal both make: which translation edge leads the held era
11
+ # to the current shape, and whether a mint would go ahead on it. It reads only what its
12
+ # caller hands it and writes nothing, so the same inputs reach the same verdict on either
13
+ # path.
14
+ module MintDecision
15
+ # The implicit moves the framework keeps beside its shape ledger. A bluebook the framework
16
+ # holds, such as QualityControl, has its moves recorded here, not beside its own files.
17
+ FRAMEWORK_MOVES = File.join(File.expand_path("../../../../hecks", __dir__),
18
+ ShapeLedger::IMPLICIT_FILE).freeze
19
+
20
+ # What a decision concludes. `verdict` is `would_mint`, `needs_edge` (the change needs
21
+ # a rule) or `refused`; `reason` names why it is not `would_mint`; `edge` is the edge a
22
+ # mint would use and is nil unless `would_mint`; `source` is `file` or `implicit`; `edges`
23
+ # lists the edges that lead the held era to the current shape; `diff` is the shape diff;
24
+ # `watermark` is the one decided at.
25
+ Verdict = Data.define(:verdict, :reason, :edge, :edges, :source, :diff, :watermark)
26
+
27
+ module_function
28
+
29
+ # @param held [Array<Hash>] the held eras, oldest first; the last is the era a mint
30
+ # leaves.
31
+ # Each carries `label` and `declaration`, the storage shape it holds as a bluebook view
32
+ # (see `held_for_decision`)
33
+ # @param bluebook [Bluebook::Declaration] the current bluebook
34
+ # @param edge_source [Hash] `translations`, the loaded edges, and `recorded`, the recorded
35
+ # implicit moves as `[from, to]` pairs (see `recorded_moves`)
36
+ # @param watermark [Integer] the ledger watermark the decision reads
37
+ # @param rows [Array<String>] the refusals an audit ran over the decided edge; empty when
38
+ # none, or when no audit has run yet
39
+ # @return [Verdict]
40
+ def decide(held:, bluebook:, edge_source:, watermark:, rows:)
41
+ latest = held.last
42
+ edges = leading(edge_source[:translations], bluebook, latest[:label])
43
+ found = if edges.empty?
44
+ implicit(latest, bluebook, edge_source[:recorded], watermark)
45
+ else
46
+ written(edges, latest, bluebook, watermark)
47
+ end
48
+ rows.empty? ? found : audit_refusal(found)
49
+ end
50
+
51
+ # The decision for the era a mint would leave, reading the held era's stored shape here,
52
+ # so a caller holding only the era's record reaches the same verdict as a mint does.
53
+ #
54
+ # @param latest [Hash] the held era, as `Lineage#eras` answers it
55
+ # @param bluebook [Bluebook::Declaration] the current bluebook
56
+ # @param translations [Array<Object>] the edges the registry loaded
57
+ # @param directory [String, nil] the domain's bluebook directory
58
+ # @param watermark [Integer] the ledger watermark the decision reads
59
+ # @return [Verdict]
60
+ def decide_latest(latest, bluebook:, translations:, directory:, watermark:)
61
+ decide(held: [held_for_decision(latest)], bluebook: bluebook, watermark: watermark, rows: [],
62
+ edge_source: { translations: translations, recorded: recorded_moves(bluebook.name, directory) })
63
+ end
64
+
65
+ # A held era as the decision reads it: with `declaration`, the storage shape it holds as a
66
+ # bluebook view (LineageManager::HeldEra). Its held text is not read.
67
+ #
68
+ # @param era [Hash] an era as `Lineage#eras` answers it
69
+ # @return [Hash] the era with `declaration`, a `Runtime::ProjectedBluebook`
70
+ # @raise [Runtime::WiringError] naming the era, when its shape cannot be known
71
+ def held_for_decision(era) = era.merge(declaration: LineageManager.held_bluebook(era))
72
+
73
+ # The implicit moves a domain has recorded: beside its own bluebooks, when a directory is
74
+ # given, and in the framework's record. This is the only read the decision's inputs need.
75
+ #
76
+ # @param domain [String] the bluebook name the moves are recorded under
77
+ # @param directory [String, nil] the domain's bluebook directory
78
+ # @return [Array<Array(String, String)>] each recorded move as `[from, to]`
79
+ def recorded_moves(domain, directory)
80
+ paths = [directory && File.join(directory, ShapeLedger::IMPLICIT_FILE), FRAMEWORK_MOVES].compact
81
+ paths.flat_map { |path| ShapeLedger.pairs_of(ShapeLedger.implicit_moves(path).fetch(domain, [])) }
82
+ end
83
+
84
+ # Whether the move from the held era is breaking and nothing covers it: the decision needs
85
+ # an edge, and the change is not provably additive. A move a mint would go ahead on, or a
86
+ # decision already refused for another reason, is not this. An edge from the held shape
87
+ # covers it even when the held era has not been named yet.
88
+ #
89
+ # @return [Boolean]
90
+ def breaking?(latest, bluebook, verdict, translations)
91
+ return false unless verdict.verdict == "needs_edge"
92
+ return false unless leading(translations, bluebook, held_label_of(latest)).empty?
93
+
94
+ !additive?(verdict.diff, held_for_decision(latest), bluebook)
95
+ end
96
+
97
+ # @return [String] the stored label of a held era, or the one its shape would be named
98
+ def held_label_of(era)
99
+ era[:label] || LineageManager.held_hash(era)[0, Runtime::StorageShape::LABEL_LENGTH]
100
+ end
101
+
102
+ # The shape label a storage shape of this bluebook carries.
103
+ #
104
+ # @return [String]
105
+ def label_of(bluebook) = Runtime::StorageShape.mint_hash(bluebook)[0, Runtime::StorageShape::LABEL_LENGTH]
106
+
107
+ # The edges the domain loads that lead the held era straight to the current shape. An edge
108
+ # from the held era to any other shape plays no part: the translation is from the held
109
+ # shape to the current one, so other edges neither fork the decision nor make it stale.
110
+ #
111
+ # @return [Array<Object>] the edges from `from` to the bluebook's current label
112
+ def leading(translations, bluebook, from)
113
+ to = label_of(bluebook)
114
+ translations.select { |edge| edge.domain == bluebook.name && edge.from == from && edge.to == to }
115
+ end
116
+
117
+ # The implicit empty edge: the recorded moves must reach the shape from the held label,
118
+ # and the change must qualify as additive by `Translation::ImplicitEdge.qualifies?`.
119
+ def implicit(latest, bluebook, recorded, watermark)
120
+ diff = diff_of(latest, bluebook)
121
+ to = label_of(bluebook)
122
+ return verdict_of("needs_edge", diff, watermark, reason: :unrecorded) unless reachable?(latest, to, recorded)
123
+ return verdict_of("needs_edge", diff, watermark, reason: :non_qualifying) unless additive?(diff, latest, bluebook)
124
+
125
+ edge = Translation::ImplicitEdge.new(domain: bluebook.name, from: latest[:label], to: to)
126
+ verdict_of("would_mint", diff, watermark, edge: edge, edges: [], source: "implicit")
127
+ end
128
+
129
+ # @return [Hash] the scaffold's diff of the held era against the current bluebook
130
+ def diff_of(latest, bluebook) = Translation::Scaffold.diff(latest[:declaration], bluebook)
131
+
132
+ # @return [Boolean] whether the recorded moves chain from the held label to `to`
133
+ def reachable?(latest, to, recorded) = ShapeLedger.reachable?(latest[:label], to, recorded)
134
+
135
+ # @return [Boolean] whether the change qualifies as additive by the implicit edge's rule
136
+ def additive?(diff, latest, bluebook) = Translation::ImplicitEdge.qualifies?(diff, latest[:declaration], bluebook)
137
+
138
+ # A written edge from the held shape to the current one leads on. Two files declaring that
139
+ # same pair disagree about one translation, so neither is taken.
140
+ def written(edges, latest, bluebook, watermark)
141
+ diff = diff_of(latest, bluebook)
142
+ return verdict_of("refused", diff, watermark, reason: :duplicate_edge, edges: edges) if edges.size > 1
143
+
144
+ verdict_of("would_mint", diff, watermark, edge: edges.first, edges: edges, source: "file")
145
+ end
146
+
147
+ # An audit's refusals turn a would_mint into a refusal that names the audit.
148
+ def audit_refusal(found)
149
+ return found unless found.verdict == "would_mint"
150
+
151
+ verdict_of("refused", found.diff, found.watermark, reason: :audit, edges: found.edges)
152
+ end
153
+
154
+ # @return [Verdict] a verdict of `kind`, with the fields it carries and none it does not
155
+ def verdict_of(kind, diff, watermark, **attributes)
156
+ Verdict.new(verdict: kind, reason: nil, edge: nil, edges: [], source: nil, diff: diff,
157
+ watermark: watermark, **attributes)
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,24 @@
1
+ module Hecks
2
+ module Adapters
3
+ class PostgresEra
4
+ module LineageManager
5
+ # The request a mint carries into the era check: whether the mint was confirmed, the verdict
6
+ # the rehearsal of that same era reached, and the ledger watermark the rehearsal read. Only the
7
+ # Maintenance mint path builds one; a boot has none, so a boot that would mint refuses.
8
+ MintRequest = Data.define(:confirm, :verdict, :watermark) do
9
+ # Reads the request out of a settings hash, spelled with symbol or string keys.
10
+ #
11
+ # @param settings [Hash] the settings the era check was booted with
12
+ # @return [MintRequest, nil] the request, or nil when the settings carry none
13
+ def self.from(settings)
14
+ raw = PostgresEra.setting(settings, :mint_request)
15
+ return nil if raw.nil?
16
+
17
+ raw = raw.transform_keys(&:to_sym)
18
+ new(confirm: raw[:confirm] == true, verdict: raw[:verdict].to_s, watermark: raw[:watermark].to_i)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -4,6 +4,8 @@ require_relative "../../../../ports/persistence/plugins/era/translation/audit"
4
4
  require_relative "../../../../ports/persistence/plugins/era/translation/scaffold"
5
5
  require_relative "context"
6
6
  require_relative "refusals"
7
+ require_relative "mint_decision"
8
+ require_relative "era_resolution"
7
9
 
8
10
  module Hecks
9
11
  module Adapters
@@ -19,25 +21,30 @@ module Hecks
19
21
  # @param context [Context] the era check so far; `latest` is the latest held era, named
20
22
  # here if it has no name yet
21
23
  # @return [Integer] the ordinal of the era minted
22
- # @raise [Runtime::WiringError] if the edge, its coverage or its audit refuses
24
+ # @raise [Runtime::WiringError] if a held era already holds the shape, or the edge, its
25
+ # coverage or its audit refuses
23
26
  def mint!(context)
27
+ refuse_held_shape!(context)
28
+ refuse_unrehearsed_mint!(context)
24
29
  ensure_named!(context.lineage, context.latest)
25
30
  context = context.with(latest: context.held_eras.last)
31
+ decided_at = context.watermark
26
32
  edge = verified_edge!(context)
27
33
  refuse_unpermitted_mint!(context) unless context.mint_permitted
28
34
  chain = audited_chain!(context, edge)
29
- commit_era!(context, chain)
35
+ refuse_moved_watermark!(context, decided_at)
36
+ commit_era!(context, chain, edge)
30
37
  end
31
38
 
32
- # Finds the one translation edge leaving the held era and targeting the current
33
- # shape's label; a second edge from the same source is a wiring mistake, not a
34
- # merge to resolve automatically.
39
+ # The edge a mint leaves the held era by, as `MintDecision` decides it. A refusal the
40
+ # decision names is raised by name; a change that needs a rule refuses toward the
41
+ # scaffold.
35
42
  def resolve_edge!(context)
36
- edges = edges_leaving(context)
37
- refuse_toward_the_scaffold!(context) if edges.empty?
38
- refuse_forked_eras!(context, edges) if edges.size > 1
39
- refuse_stale_edge!(context, edges.first)
40
- edges.first
43
+ verdict = decide!(context)
44
+ return verdict.edge if verdict.verdict == "would_mint"
45
+ return refuse_toward_the_scaffold!(context) if verdict.verdict == "needs_edge"
46
+
47
+ refuse_refused_verdict!(context, verdict)
41
48
  end
42
49
 
43
50
  # Diffs the held era against the current shape and writes the edge file —
@@ -46,7 +53,7 @@ module Hecks
46
53
  ensure_named!(lineage, latest)
47
54
  latest = lineage.eras.last
48
55
  label = Runtime::StorageShape.mint_hash(bluebook)[0, Runtime::StorageShape::LABEL_LENGTH]
49
- diffed = Translation::Scaffold.diff(shadow(latest[:held_text]), bluebook)
56
+ diffed = Translation::Scaffold.diff(held_bluebook(latest), bluebook)
50
57
  edge = Translation::Scaffold::Edge.new(
51
58
  domain: bluebook.name, from: latest[:label], to: label, ordinal: latest[:ordinal] + 1,
52
59
  label: label, aggregates: diffed[:aggregates], retired: diffed[:retired]
@@ -60,23 +67,40 @@ module Hecks
60
67
  def ensure_named!(lineage, era)
61
68
  return if era[:hash]
62
69
 
63
- held_bluebook = shadow(era[:held_text])
64
- hash = Runtime::StorageShape.mint_hash(held_bluebook)
70
+ hash = held_hash(era)
65
71
  lineage.mint_name!(era[:ordinal], hash, hash[0, Runtime::StorageShape::LABEL_LENGTH])
66
72
  end
67
73
 
68
74
  private
69
75
 
70
- def edges_leaving(context)
76
+ # Refuses a mint of a shape a held era already holds, by the match the boot resolves with.
77
+ def refuse_held_shape!(context)
78
+ held = EraResolution.matching_era(context.held_eras, context.bluebook) or return
79
+
80
+ raise Runtime::WiringError,
81
+ "cannot mint #{context.domain_name}: era #{held[:ordinal]} already holds the current shape"
82
+ end
83
+
84
+ # The verdict `MintDecision` reaches for the held era the mint leaves, read at the
85
+ # watermark the context holds now.
86
+ def decide!(context)
87
+ MintDecision.decide(held: [MintDecision.held_for_decision(context.latest)], bluebook: context.bluebook,
88
+ edge_source: edge_source_of(context), watermark: context.watermark, rows: [])
89
+ end
90
+
91
+ def edge_source_of(context)
71
92
  registry = context.registry
72
- registry.translations.select do |t|
73
- t.domain == context.domain_name && t.from == context.latest[:label]
74
- end
93
+ { translations: registry.translations,
94
+ recorded: MintDecision.recorded_moves(context.domain_name, context.directory) }
75
95
  end
76
96
 
97
+ # The refusal a decided edge stands for: two files declaring the one translation.
98
+ def refuse_refused_verdict!(context, verdict) = refuse_duplicate_edges!(context, verdict.edges)
99
+
77
100
  # The edge chain to the current shape, after its audit passes.
78
101
  def audited_chain!(context, edge)
79
- chain = edge_chain(context.registry, context.bluebook, context.held_eras, context.label)
102
+ chain = edge_chain(context.registry, context.bluebook, context.held_eras, context.label,
103
+ target: minted_record(edge))
80
104
  audit!(context.bluebook, context.lineage, chain, context.ordinal, edge)
81
105
  chain
82
106
  end
@@ -84,17 +108,31 @@ module Hecks
84
108
  # The edge leaving the held era, once resolved and found to cover the diff.
85
109
  def verified_edge!(context)
86
110
  edge = resolve_edge!(context)
87
- check_coverage!(context.registry, context.bluebook, shadow(context.latest[:held_text]), edge)
111
+ check_coverage!(context.registry, context.bluebook, held_bluebook(context.latest), edge)
88
112
  edge
89
113
  end
90
114
 
91
- def commit_era!(context, chain)
115
+ # The journal record of the era a mint reaches, when the edge is implicit; nil when a
116
+ # written edge file leads there.
117
+ #
118
+ # @return [Hash, nil] the era record `edge_chain` reads as its last step
119
+ def minted_record(edge)
120
+ edge.is_a?(Translation::ImplicitEdge) ? edge.record : nil
121
+ end
122
+
123
+ # @return [Hash, nil] the `edge` column of the minted era: the implicit marker, or nil
124
+ def implicit_record(edge)
125
+ edge.is_a?(Translation::ImplicitEdge) ? Translation::ImplicitEdge::RECORD : nil
126
+ end
127
+
128
+ def commit_era!(context, chain, edge)
92
129
  hash = context.shape_hash
93
130
  bluebook = context.bluebook
94
131
  context.lineage.mint_era!(
95
132
  ordinal: context.ordinal, hash: hash, label: hash[0, Runtime::StorageShape::LABEL_LENGTH],
96
133
  held_text: context.current_text, aggregates: bluebook.aggregates, edges: chain,
97
- role: context.role, projection: Runtime::StorageShape.project(context.bluebook)
134
+ role: context.role, projection: Runtime::StorageShape.project(context.bluebook),
135
+ edge: implicit_record(edge)
98
136
  )
99
137
  context.ordinal
100
138
  end
@@ -32,21 +32,34 @@ module Hecks
32
32
  "persisted_by block of its world", minting: false)
33
33
  end
34
34
 
35
- private
35
+ # Refuses a mint that the rehearsal does not back: not confirmed, not a would_mint verdict, or a
36
+ # ledger watermark that moved since the rehearsal read it.
37
+ def refuse_unrehearsed_mint!(context)
38
+ request = context.mint_request
39
+ raise era_refusal(context, "the mint was not confirmed") unless request.confirm
40
+ unless request.verdict == "would_mint"
41
+ raise era_refusal(context, "the rehearsal's verdict was #{request.verdict}, not would_mint; " \
42
+ "rehearse again")
43
+ end
36
44
 
37
- def refuse_forked_eras!(context, edges)
38
- latest = context.latest
39
- raise era_refusal(context, "#{edges.size} translation edges leave era #{latest[:ordinal]} " \
40
- "(#{latest[:label]}) — eras fork mechanically; keep one edge per source shape",
41
- minting: false)
45
+ refuse_moved_watermark!(context, request.watermark)
42
46
  end
43
47
 
44
- def refuse_stale_edge!(context, edge)
45
- return if edge.to == context.label
48
+ private
49
+
50
+ def refuse_moved_watermark!(context, watermark)
51
+ current = context.watermark
52
+ return if current == watermark
53
+
54
+ raise era_refusal(context, "the ledger watermark moved from #{watermark} to #{current} since the " \
55
+ "rehearsal; rehearse again")
56
+ end
46
57
 
47
- raise era_refusal(context, "the translation edge from #{context.latest[:label]} targets " \
48
- "#{edge.to}, but the current shape is #{context.label} — the edge is stale; " \
49
- "re-run hecks scaffold_translation", minting: false)
58
+ def refuse_duplicate_edges!(context, edges)
59
+ latest = context.latest
60
+ raise era_refusal(context, "#{edges.size} translation edges lead era #{latest[:ordinal]} " \
61
+ "(#{latest[:label]}) to the current shape #{context.label}; keep one",
62
+ minting: false)
50
63
  end
51
64
 
52
65
  # Builds the refusal; a mint's own refusals say "cannot mint era N of X", the
@@ -4,6 +4,7 @@ require_relative "lineage_manager/era_resolver"
4
4
  require_relative "lineage_manager/minter"
5
5
  require_relative "lineage_manager/merge_coordinator"
6
6
  require_relative "lineage_manager/coverage_check"
7
+ require_relative "lineage_manager/held_era"
7
8
  require_relative "../../../ports/persistence/plugins/era/era_guard"
8
9
  require_relative "../../../runtime/registry"
9
10
 
@@ -17,6 +18,7 @@ module Hecks
17
18
  extend Minter
18
19
  extend MergeCoordinator
19
20
  extend CoverageCheck
21
+ extend HeldEra
20
22
 
21
23
  module_function
22
24
 
@@ -27,25 +29,57 @@ module Hecks
27
29
  # @param bluebook [Bluebook::Declaration] the domain; only edges for its name count
28
30
  # @param eras [Array<Hash>] the ancestor eras in order, as `Lineage#eras` returns them
29
31
  # @param current_label [String] the shape label the last step must lead to
32
+ # @param target [Hash, nil] the era record the last step reaches when it is not in `eras`
33
+ # (the held era of a settled chain, or the era a mint is about to write)
30
34
  # @return [Array<Hash>] one `{ translation: edge }` per step, in mint order
31
- # @raise [Runtime::WiringError] if no loaded translation leads one label to the next
32
- def edge_chain(registry, bluebook, eras, current_label)
35
+ # @raise [Runtime::WiringError] if no loaded translation or journal record leads a label
36
+ # to the next one
37
+ def edge_chain(registry, bluebook, eras, current_label, target: nil)
33
38
  labels = eras.map { |era| era[:label] } + [current_label]
34
- labels.each_cons(2).with_index.map do |(from, to), index|
35
- step = edge_between(registry, bluebook, from, to)
39
+ labels.each_cons(2).with_index.filter_map do |(from, to), index|
40
+ next if same_shape?(from, to)
41
+
42
+ step = edge_between(registry, bluebook, from, to) ||
43
+ recorded_edge(bluebook, from, to, eras[index + 1] || target)
36
44
  refuse_broken_chain!(bluebook, index, from, to) unless step
37
45
  { translation: step }
38
46
  end
39
47
  end
40
48
 
41
- # Finds the loaded translation that leads one shape label to the next.
49
+ # Whether two shape labels name the same shape. A same-shape step is current, not a change,
50
+ # so it needs no edge and `edge_chain` skips it.
51
+ #
52
+ # @param from [String] the shape label the step leaves
53
+ # @param to [String] the shape label the step reaches
54
+ # @return [Boolean] true when both labels are the same shape
55
+ def same_shape?(from, to) = from == to
56
+
57
+ # The implicit edge a journal record names for the step that reached its era, or nil.
58
+ #
59
+ # @param bluebook [Bluebook::Declaration] the domain the edge belongs to
60
+ # @param from [String] the shape label the step leaves
61
+ # @param to [String] the shape label the step reaches
62
+ # @param record [Hash, nil] the era record the step reaches
63
+ # @return [Translation::ImplicitEdge, nil]
64
+ def recorded_edge(bluebook, from, to, record)
65
+ return unless record && record[:label] == to && record[:edge] == Translation::ImplicitEdge::RECORD
66
+
67
+ Translation::ImplicitEdge.new(domain: bluebook.name, from: from, to: to)
68
+ end
69
+
70
+ # Finds the loaded translation that leads one shape label to the next. A same-shape pair
71
+ # has no edge to find: it answers nil without searching, and `edge_chain` treats it as
72
+ # current.
42
73
  #
43
74
  # @param registry [Runtime::Registry] the registry whose `translations` are searched
44
75
  # @param bluebook [Bluebook::Declaration] the domain; only edges for its name count
45
76
  # @param from [String] the shape label the edge leaves
46
77
  # @param to [String] the shape label the edge reaches
47
- # @return [Bluebook::Translation, nil] the edge, or nil when none is loaded
78
+ # @return [Bluebook::Translation, nil] the edge, or nil when none is loaded, or the shapes
79
+ # match
48
80
  def edge_between(registry, bluebook, from, to)
81
+ return nil if same_shape?(from, to)
82
+
49
83
  registry.translations.find { |t| t.domain == bluebook.name && t.from == from && t.to == to }
50
84
  end
51
85
 
@@ -0,0 +1,32 @@
1
+ require_relative "events"
2
+ require_relative "sagas"
3
+ require_relative "../postgres/outbox"
4
+
5
+ module Hecks
6
+ module Adapters
7
+ class PostgresEra
8
+ # The event, saga and outbox tables a database shares across its domains. Only the mint path
9
+ # creates them, through `Lineage#ensure_base!`; a boot reads them and never provisions them.
10
+ class SharedTables
11
+ include Events
12
+ include Sagas
13
+ include PostgresOutbox
14
+
15
+ # @param db [PG::Connection] the owner connection the mint path holds
16
+ def initialize(db)
17
+ @db = db
18
+ end
19
+
20
+ # Creates each shared table that is missing. Every statement is idempotent.
21
+ #
22
+ # @return [void]
23
+ # @raise [PG::Error] if Postgres refuses a statement
24
+ def provision!
25
+ create_event_table!
26
+ create_saga_table!
27
+ create_outbox_table!
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -5,6 +5,9 @@ Hecks.adapter "PostgresEra" do
5
5
  field :database
6
6
  field :role
7
7
  field :schema
8
+ # The name this domain's history is held under until `era.rename_domain` moves it: `formerly "Old"`.
9
+ # A storage fact, so the world says it and the bluebook's `formerly_known_as` is the fallback.
10
+ field :formerly
8
11
  # Opt-in to boot over a superuser or BYPASSRLS role, which the era write fence cannot
9
12
  # bite. Refused by default; see `Lineage#check_fence_applies!`.
10
13
  field :allow_superuser
@@ -12,6 +15,15 @@ Hecks.adapter "PostgresEra" do
12
15
  # next era through a translation edge. `false` refuses; unset follows
13
16
  # `LineageManager::EraResolver::MINT_BY_DEFAULT`; see `Refusals#refuse_unpermitted_mint!`.
14
17
  field :mint_eras
18
+ # Declares the store a disposable tooling ledger: a shape change needs no era, edge or mint, an
19
+ # additive one is applied in place, any other archives the aggregate's rows under a dated name
20
+ # and starts it empty, and a boot never refuses as unminted or superseded. Unset or `false`
21
+ # keeps the era guard; see `LineageManager::DisposableLedger`. Never for client data.
22
+ field :disposable_ledger
23
+ # The commands whose own record an unminted boot may write: `mints_era "Maintenance.MintEra"`, one
24
+ # `Aggregate.Command` name or a list. This is where the allowance is declared; a command's own
25
+ # `mints_era true` is a fallback that must agree. See `Ports::Persistence::MintDoor`.
26
+ field :mints_era
15
27
  # Rewrites every row of an aggregate in one statement, on the same SQL path as Postgres.
16
28
  provides "set_transform"
17
29
  end
@@ -63,22 +63,22 @@ module Hecks
63
63
  def self.tenant_capable? = true
64
64
 
65
65
  # Joins the process's shared connection for the declared database and schema, so every
66
- # aggregate of a domain runs on one connection, then provisions the journal, this
67
- # aggregate's head and field caches, and the event, saga and outbox tables. Every step is
68
- # idempotent.
66
+ # aggregate of a domain runs on one connection, then resolves the era it reads and the field
67
+ # caches that era holds. Reads only: the lineage, head and cache tables are provisioned by the
68
+ # mint path, and a database no mint has provisioned refuses by name.
69
69
  #
70
70
  # @param settings [Hash{Symbol, String => Object}] world settings plus what
71
71
  # `RepositoryFactory.build` merges in: `domain`, `era` and `superseded_by`
72
- # @raise [Runtime::WiringError] if `database` is missing or the connection is refused
72
+ # @raise [Runtime::WiringError] if `database` is missing, the connection is refused, or the
73
+ # database holds no era
73
74
  def initialize(aggregate:, settings: {}, root: nil)
74
75
  @aggregate = aggregate
75
76
  @settings = settings
76
- @db = PostgresSharedConnection.for(aggregate.name, settings, connector: self.class)
77
+ @db = PostgresSharedConnection.for(aggregate.name, settings, connector: ReadConnector)
77
78
  @domain = journal_domain(aggregate, settings)
78
- @lineage = Lineage.new(@db, @domain)
79
- @lineage.ensure_base!
79
+ @lineage = Lineage.new(@db, @domain, reading: true)
80
80
  resolve_era!(settings)
81
- provision!
81
+ @field_caches = existing_field_caches
82
82
  end
83
83
 
84
84
  # Names this aggregate in storage: the journal's `aggregate` value and the stem of its
@@ -87,6 +87,16 @@ module Hecks
87
87
  # @return [String] the aggregate's snake_case storage name
88
88
  def table = @aggregate.storage_name
89
89
 
90
+ # Whether this binding's `mints_era` names the command: its own record may be journaled
91
+ # through a boot whose shape no era holds yet.
92
+ #
93
+ # @param aggregate_name [String] the aggregate the command belongs to
94
+ # @param command_name [String] the command
95
+ # @return [Boolean]
96
+ def mints_era_declared?(aggregate_name, command_name)
97
+ Ports::Persistence::MintDoor.declared?(@settings, aggregate_name, command_name)
98
+ end
99
+
90
100
  # Reads one record's current state through the head view, translated to the current shape.
91
101
  #
92
102
  # @param id [String, Object] the record's identity, compared as `id.to_s`
@@ -151,7 +161,12 @@ module Hecks
151
161
  # @yield the dispatch order; an exception rolls the transaction back
152
162
  # @return [Object] the block's own value
153
163
  # @raise [PG::ConnectionBad] if the connection dropped; it reconnects, then re-raises
154
- def with_write_lock(&) = transaction { lock_writes!; yield } # rubocop:disable Style/Semicolon
164
+ def with_write_lock(&)
165
+ transaction do
166
+ lock_writes!
167
+ yield
168
+ end
169
+ end
155
170
 
156
171
  # Builds the instance an entry describes, writing nothing; the head is derived, so
157
172
  # projecting is reading.
@@ -183,7 +198,7 @@ module Hecks
183
198
  # @param id [String, Object] the record's identity, journaled as `id.to_s`
184
199
  # @return [true] always
185
200
  # @raise [Runtime::WiringError] if this boot's era has been superseded by a mint
186
- def delete(id) # rubocop:disable Naming/PredicateMethod -- the repository port's verb, not a question
201
+ def delete(id)
187
202
  entry = Ports::Persistence::Entry.new(operation: "delete", id: id.to_s, state: nil)
188
203
  append(entry)
189
204
  true
@@ -10,7 +10,6 @@ module Hecks
10
10
  # Not frozen — a real cache, keyed by file path and mutated by
11
11
  # #tree_for below (`TREES[file] ||= ...`) and #forget/#forget_all.
12
12
  # False positive for Style/MutableConstant.
13
- # rubocop:disable-next Style/MutableConstant
14
13
  TREES = {}
15
14
 
16
15
  # The first block node starting on each line, per parsed tree (by identity), built by one
@@ -40,6 +40,7 @@ module Hecks
40
40
  # @raise [ArgumentError] if a where clause uses an operator this builder cannot compile,
41
41
  # or `contains` targets a list of a value object with more than one field
42
42
  def query(declared, args = {}, context: {})
43
+ Runtime::Value.check_query_arguments!(@aggregate, declared, args)
43
44
  return in_memory_answer(declared, args, context) if in_memory?(declared)
44
45
 
45
46
  sql = "SELECT #{select_list} FROM #{from_relation}"
@@ -17,7 +17,7 @@ module Hecks
17
17
  # @param key [String] the dispatch key a saga leg stamped on the command
18
18
  # @return [Boolean] true when the key was new and is now held; false when already held
19
19
  # @raise [SQLite3::Exception] if the insert fails
20
- def dispatch_claim(key) # rubocop:disable Naming/PredicateMethod -- the claim port's verb
20
+ def dispatch_claim(key)
21
21
  @db.execute("INSERT OR IGNORE INTO hecks_dispatch_claims (claim_key, claimed_at) VALUES (?, ?)",
22
22
  [key, Time.now.utc.iso8601])
23
23
  @db.changes.positive?
@@ -0,0 +1,25 @@
1
+ require_relative "../../../ports/persistence/stored_name_guard"
2
+
3
+ module Hecks
4
+ module Adapters
5
+ class Sqlite
6
+ # Reads how many rows a table holds before any table is created, for the stored-name guard.
7
+ module NameGuard
8
+ private
9
+
10
+ def refuse_orphaned_rows!
11
+ Ports::Persistence::StoredNameGuard.check!(@aggregate, row_count: method(:rows_under))
12
+ end
13
+
14
+ def rows_under(name)
15
+ [name, "#{name}_entries"].sum { |table| table_rows(table) }
16
+ end
17
+
18
+ def table_rows(table)
19
+ exists = @db.get_first_value("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?", [table])
20
+ exists ? @db.get_first_value("SELECT COUNT(*) FROM #{quote_ident(table)}").to_i : 0
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end