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,64 @@
1
+ require_relative "sql_templates"
2
+
3
+ module Hecks
4
+ module Adapters
5
+ class PostgresEra
6
+ class Lineage
7
+ # The shortcut that builds an era from the matview of the era before it, rather than from
8
+ # the whole journal. A chain that cannot take it falls back to `ChainSql#chain_sql`.
9
+ module LayeredSql
10
+ include SqlTemplates
11
+
12
+ # Builds era N by layering its own last edge onto era N-1's existing
13
+ # matview, instead of re-deriving from raw history; returns nil
14
+ # (falling back to chain_sql) whenever that shortcut can't honestly
15
+ # apply. `edges.size != era - 1` guards names_by_era's own
16
+ # assumption that `edges` is the full chain reaching `era` — a
17
+ # shorter chain here would index names[:storage] out of bounds
18
+ # rather than safely falling back.
19
+ def layered_chain_sql(aggregate, era, edges)
20
+ return nil unless layerable?(era, edges)
21
+
22
+ held = eras
23
+ prior_view = existing_prior_view(aggregate, era, held)
24
+ return nil unless prior_view
25
+
26
+ layered_sql(aggregate, era, edges, held, prior_view)
27
+ end
28
+
29
+ private
30
+
31
+ def layerable?(era, edges) = era >= 3 && edges.size >= 2 && edges.size == era - 1
32
+
33
+ # The previous era's matview, when it is labelled and already built.
34
+ def existing_prior_view(aggregate, era, held)
35
+ prior = held.find { |candidate| candidate[:ordinal] == era - 1 }
36
+ return nil unless prior && prior[:label]
37
+
38
+ view = matview(aggregate.storage_name, era - 1, prior[:label])
39
+ view if view_exists?(view)
40
+ end
41
+
42
+ def layered_sql(aggregate, era, edges, held, prior_view)
43
+ names = names_by_era(aggregate, edges)
44
+ declared = edges.last[:translation].for_aggregate(names[:current][edges.size])
45
+ tokens = layered_tokens(prior_view, names, era, declared)
46
+ format(LAYERED_SQL, tokens.merge(cut: cut_clause(held, era)))
47
+ end
48
+
49
+ def layered_tokens(prior_view, names, era, declared)
50
+ { prior_view: quote(prior_view), journal: quoted_journal, prior_era: era - 1,
51
+ aggregate: text_literal(names[:storage][era - 2]),
52
+ id_column: id_column_for(declared, "operation = 'save'"), expression: rules_expression(declared) }
53
+ end
54
+
55
+ # Cuts the previous era's rows at the watermark recorded when this era was minted.
56
+ def cut_clause(held, era)
57
+ cut = held.find { |candidate| candidate[:ordinal] == era }&.dig(:watermark)
58
+ " AND ordinal <= #{cut}" if cut
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,150 @@
1
+ require "json"
2
+ require "digest"
3
+
4
+ module Hecks
5
+ module Adapters
6
+ class PostgresEra
7
+ class Lineage
8
+ # The writes a disposable ledger's boot makes in place of a mint: it re-holds the latest era
9
+ # at the booting shape, gives an aggregate a head that reads only its latest era, and moves
10
+ # an aggregate's rows into a dated archive table so it starts empty. Nothing is dropped:
11
+ # archived rows stay in their table, and each archive is listed in `hecks_ledger_archives`.
12
+ module LedgerReset
13
+ # The list of every archive a disposable ledger's boot made.
14
+ ARCHIVES_SQL = <<~SQL.freeze
15
+ CREATE TABLE IF NOT EXISTS hecks_ledger_archives (
16
+ domain text NOT NULL,
17
+ aggregate text NOT NULL,
18
+ archive text NOT NULL PRIMARY KEY,
19
+ row_count bigint NOT NULL,
20
+ archived_at timestamptz NOT NULL DEFAULT now()
21
+ )
22
+ SQL
23
+
24
+ # The update that re-holds an era at a new shape.
25
+ REHOLD_SQL = "UPDATE hecks_eras SET held_text = $3, held_digest = $4, held_projection = $5::text::jsonb, " \
26
+ "hash = $6, label = $7, canon_form = $8 WHERE domain = $1 AND ordinal = $2".freeze
27
+
28
+ # Moves every journal row of one aggregate, from every era, into a new table named for it
29
+ # and the time, then empties the aggregate's head snapshots, all in one transaction.
30
+ # The journal is locked against writers for the whole move, so no row can commit between
31
+ # the copy and the delete, and the delete must remove exactly the rows the copy holds or
32
+ # the transaction rolls back. A name already taken gets `_2`, `_3`, and so on; an archive
33
+ # is never overwritten.
34
+ #
35
+ # @param storage_name [String] the aggregate's snake-cased storage name
36
+ # @param stamp [String] the time the archive is named for, as `YYYYMMDDHHMMSS`
37
+ # @return [Array(String, Integer)] the archive table's name and how many rows it holds
38
+ # @raise [PG::Error] if Postgres refuses a statement; nothing is moved then
39
+ # @raise [Runtime::WiringError] if the delete removed other rows than the copy holds
40
+ def archive_aggregate!(storage_name, stamp)
41
+ archive = nil
42
+ nested_transaction("hecks_ledger_archive") do
43
+ lock_journal!
44
+ archive = unused_archive_name(storage_name, stamp)
45
+ move_rows!(storage_name, archive)
46
+ end
47
+ [archive, archived_count(archive)]
48
+ end
49
+
50
+ # Points an aggregate's head view at its snapshot in `era` alone, with no ancestor tail,
51
+ # creating the snapshot when it is missing. Used for an aggregate whose rows are all in
52
+ # that era: one just added, or one just archived.
53
+ #
54
+ # @param storage_name [String] the aggregate's snake-cased storage name
55
+ # @param era [Integer] the ordinal of the latest held era
56
+ # @return [void]
57
+ # @raise [PG::Error] if Postgres refuses a statement
58
+ def fresh_head!(storage_name, era)
59
+ ensure_head_snapshot!(storage_name, era)
60
+ tokens = { head_view: quote(head_view(storage_name)), snapshot: quote(head_snapshot(storage_name, era)) }
61
+ nested_transaction("hecks_fresh_head") do
62
+ @db.exec("DROP VIEW IF EXISTS #{quote(head_view(storage_name))}")
63
+ @db.exec(format(SqlTemplates::FIRST_HEAD_VIEW_SQL, tokens))
64
+ end
65
+ end
66
+
67
+ # Replaces the latest era's held text, digest, projection and name with the booting
68
+ # shape's, recording the old and new digests in `hecks_attestations`.
69
+ #
70
+ # @param ordinal [Integer] the latest held era
71
+ # @param text [String] the booting bluebook's source text
72
+ # @param projection [Hash] the booting bluebook's storage shape
73
+ # @param hash [String] the booting shape's mint hash
74
+ # @return [void]
75
+ # @raise [PG::Error] if Postgres refuses a statement
76
+ def rehold!(ordinal, text, projection, hash)
77
+ fresh = Digest::SHA256.hexdigest(text)
78
+ @db.exec(EraIntegrity::CREATE_ATTESTATIONS_SQL)
79
+ record_attestation!(ordinal, raw_era(ordinal)&.fetch(:held_digest), fresh)
80
+ @db.exec_params(REHOLD_SQL, [@domain, ordinal, text, fresh, JSON.generate(projection), hash,
81
+ hash[0, Runtime::StorageShape::LABEL_LENGTH],
82
+ Runtime::StorageShape::FORM_VERSION])
83
+ archive_text!(ordinal, text)
84
+ end
85
+
86
+ private
87
+
88
+ # Blocks every concurrent insert, update and delete on the journal until the transaction
89
+ # ends; reads go on. A writer that waits here lands its row in the journal after the move.
90
+ def lock_journal! = @db.exec("LOCK TABLE #{quoted_journal} IN SHARE ROW EXCLUSIVE MODE")
91
+
92
+ def move_rows!(storage_name, archive)
93
+ @db.exec("CREATE TABLE #{quote(archive)} AS SELECT * FROM #{quoted_journal} " \
94
+ "WHERE aggregate = #{text_literal(storage_name)}")
95
+ record_archive!(storage_name, archive)
96
+ verify_moved!(archive, delete_journal_rows!(storage_name))
97
+ empty_head_snapshots!(storage_name)
98
+ end
99
+
100
+ # A delete of a row the archive does not hold would lose it; refuse and roll back.
101
+ def verify_moved!(archive, deleted)
102
+ return if deleted == archived_count(archive)
103
+
104
+ raise Runtime::WiringError, "the ledger archive #{archive} holds #{archived_count(archive)} rows but " \
105
+ "#{deleted} were deleted from the journal; nothing was moved"
106
+ end
107
+
108
+ def archived_count(archive) = @db.exec("SELECT count(*) FROM #{quote(archive)}")[0]["count"].to_i
109
+
110
+ # The archive's name, suffixed `_2`, `_3` and on while a table or listed archive has it.
111
+ def unused_archive_name(storage_name, stamp)
112
+ @db.exec(ARCHIVES_SQL)
113
+ base = "#{storage_name}_archived_#{stamp}"
114
+ (1..).lazy.map { |n| qualified_name(n == 1 ? base : "#{base}_#{n}") }.find { |name| archive_name_free?(name) }
115
+ end
116
+
117
+ def archive_name_free?(name)
118
+ return false if table_exists?(quote(name))
119
+
120
+ @db.exec_params("SELECT 1 FROM hecks_ledger_archives WHERE archive = $1", [name]).ntuples.zero?
121
+ end
122
+
123
+ def record_archive!(storage_name, archive)
124
+ @db.exec(ARCHIVES_SQL)
125
+ @db.exec_params("INSERT INTO hecks_ledger_archives (domain, aggregate, archive, row_count) " \
126
+ "SELECT $1, $2, $3, count(*) FROM #{quote(archive)}", [@domain, storage_name, archive])
127
+ end
128
+
129
+ # The journal forces row-level security with no DELETE policy, so even its owner deletes
130
+ # nothing; a policy that admits this one aggregate's rows stands for the one statement.
131
+ def delete_journal_rows!(storage_name)
132
+ aggregate = text_literal(storage_name)
133
+ @db.exec("CREATE POLICY hecks_ledger_archive ON #{quoted_journal} FOR DELETE TO PUBLIC " \
134
+ "USING (aggregate = #{aggregate})")
135
+ deleted = @db.exec("DELETE FROM #{quoted_journal} WHERE aggregate = #{aggregate}").cmd_tuples
136
+ @db.exec("DROP POLICY hecks_ledger_archive ON #{quoted_journal}")
137
+ deleted
138
+ end
139
+
140
+ def empty_head_snapshots!(storage_name)
141
+ eras.each do |era|
142
+ snapshot = head_snapshot(storage_name, era[:ordinal])
143
+ @db.exec("TRUNCATE #{quote(snapshot)}") if table_exists?(snapshot)
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,85 @@
1
+ require_relative "../field_cache_provisioner"
2
+
3
+ module Hecks
4
+ module Adapters
5
+ class PostgresEra
6
+ class Lineage
7
+ # The read side of an era that the mint path provisions: each aggregate's head view and the
8
+ # field caches its queries narrow by. The mint that compiles an era and the first-era hold
9
+ # call these; nothing a boot reads does.
10
+ module MintProvisioning
11
+ # Creates and backfills one aggregate's field caches for an era, on this lineage's
12
+ # connection, so the caches commit with the era that owns them.
13
+ #
14
+ # @param aggregate [Bluebook::Aggregate] the aggregate whose where-fields are cached
15
+ # @param era [Integer] the ordinal of the era the caches belong to
16
+ # @return [Hash{String => String}] each cached field mapped to its cache table
17
+ # @raise [PG::Error] if Postgres refuses the DDL, a source read or an upsert
18
+ def provision_read_side!(aggregate, era)
19
+ FieldCacheProvisioner.new(self, aggregate, era).provision!
20
+ end
21
+
22
+ # Holds the read side of the first era: each aggregate's head view over the snapshot the
23
+ # first era holds, then its field caches, then the app role's privileges on them, as a
24
+ # mint grants them for a later era.
25
+ #
26
+ # @param aggregates [Array<Bluebook::Aggregate>] the domain's aggregates
27
+ # @param role [String, nil] the app role to grant; none when blank
28
+ # @return [void]
29
+ # @raise [PG::Error] if Postgres refuses a statement
30
+ def provision_first_era!(aggregates, role: nil)
31
+ aggregates.each do |aggregate|
32
+ ensure_first_head!(aggregate.storage_name)
33
+ provision_read_side!(aggregate, 1)
34
+ end
35
+ grant_role!(role, aggregates: aggregates, era: 1)
36
+ end
37
+
38
+ # Holds era 1 and provisions its read side in one transaction under the domain's era lock,
39
+ # so a crash leaves either all of it or none. A run that finds era 1 already held from the
40
+ # same text with some head view missing (a half-done run of an older version) completes
41
+ # it; any other held era is refused.
42
+ #
43
+ # @param text [String] the bluebook source the first era freezes
44
+ # @param projection [Hash, nil] the storage-shape projection of the text
45
+ # @param aggregates [Array<Bluebook::Aggregate>] the domain's aggregates
46
+ # @param role [String, nil] the app role to grant; nil or empty grants nothing
47
+ # @return [void]
48
+ # @raise [Runtime::WiringError] if another era is held, the lock is not granted in 10s,
49
+ # or Postgres refuses a statement; the transaction rolls back first
50
+ def hold_first_era!(text, projection:, aggregates:, role: nil)
51
+ lock_era_table!
52
+ refuse_second_hold!(text, aggregates)
53
+ hold_first!(text, projection: projection)
54
+ provision_first_era!(aggregates, role: role)
55
+ @db.exec("COMMIT")
56
+ rescue StandardError
57
+ rollback_quietly
58
+ raise
59
+ end
60
+
61
+ private
62
+
63
+ def lock_era_table!
64
+ @db.exec("BEGIN")
65
+ @db.exec("SET LOCAL lock_timeout = '10s'")
66
+ @db.exec("SELECT pg_advisory_xact_lock(hashtext('hecks_eras:' || #{text_literal(@domain)}))")
67
+ end
68
+
69
+ # Refuses unless no era is held, or only era 1, from `text`, is held and unfinished.
70
+ def refuse_second_hold!(text, aggregates)
71
+ held = eras
72
+ return if held.empty?
73
+ return if held.size == 1 && held.first[:held_text] == text && unfinished?(aggregates)
74
+
75
+ raise Runtime::WiringError, "#{@domain} already holds an era"
76
+ end
77
+
78
+ def unfinished?(aggregates)
79
+ aggregates.any? { |aggregate| !table_exists?(head_view(aggregate.storage_name)) }
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -10,8 +10,9 @@ module Hecks
10
10
  module MintTransaction
11
11
  # The era a mint writes: its name, frozen text, the aggregates to recompile and the
12
12
  # edge chain that derives their heads.
13
- Mint = Data.define(:ordinal, :shape_hash, :label, :held_text, :aggregates, :edges, :role, :projection) do
14
- def initialize(role: nil, projection: nil, **rest) = super
13
+ Mint = Data.define(:ordinal, :shape_hash, :label, :held_text, :aggregates, :edges, :role, :projection,
14
+ :edge) do
15
+ def initialize(role: nil, projection: nil, edge: nil, **rest) = super
15
16
  end
16
17
 
17
18
  # Makes a new era real in one locked transaction, or reports a concurrent minter won.
@@ -53,7 +54,7 @@ module Hecks
53
54
  # @return [void]
54
55
  # @raise [PG::Error] if Postgres refuses a grant
55
56
  def grant_role!(role, aggregates: [], era: nil)
56
- return unless provisioner?
57
+ return if role.to_s.empty? || !provisioner?
57
58
 
58
59
  quoted_role = quote(role)
59
60
  @db.exec("GRANT INSERT, SELECT ON #{quoted_journal} TO #{quoted_role}")
@@ -112,11 +113,11 @@ module Hecks
112
113
  def insert_era!(mint)
113
114
  @db.exec_params(
114
115
  "INSERT INTO hecks_eras (domain, ordinal, hash, label, held_text, watermark, held_digest, " \
115
- "held_projection, canon_form) " \
116
- "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
116
+ "held_projection, canon_form, edge) " \
117
+ "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
117
118
  [@domain, mint.ordinal, mint.shape_hash, mint.label, mint.held_text, last_ordinal,
118
119
  Digest::SHA256.hexdigest(mint.held_text), mint.projection && JSON.generate(mint.projection),
119
- Runtime::StorageShape::FORM_VERSION]
120
+ Runtime::StorageShape::FORM_VERSION, mint.edge && JSON.generate(mint.edge)]
120
121
  )
121
122
  end
122
123
 
@@ -136,7 +137,10 @@ module Hecks
136
137
  # grant_role! must follow compile_head!, which creates the per-era snapshot
137
138
  # tables that it grants on.
138
139
  def compile_and_grant!(mint)
139
- mint.aggregates.each { |aggregate| compile_head!(aggregate, mint.ordinal, mint.label, mint.edges) }
140
+ mint.aggregates.each do |aggregate|
141
+ compile_head!(aggregate, mint.ordinal, mint.label, mint.edges)
142
+ provision_read_side!(aggregate, mint.ordinal)
143
+ end
140
144
  grant_role!(mint.role, aggregates: mint.aggregates, era: mint.ordinal) if mint.role
141
145
  end
142
146
 
@@ -1,5 +1,6 @@
1
1
  require_relative "base_sql"
2
2
  require_relative "domain_rename"
3
+ require_relative "../shared_tables"
3
4
 
4
5
  module Hecks
5
6
  module Adapters
@@ -12,16 +13,17 @@ module Hecks
12
13
  include DomainRename
13
14
 
14
15
  # Builds or tops up this domain's lineage schema when the connected role owns the
15
- # journal (or none exists yet); any other role only attempts the rename bridge.
16
+ # journal (or none exists yet); any other role skips it. Also
17
+ # creates the event, saga and outbox tables the database shares.
16
18
  #
17
- # ALTER TABLE and REVOKE are owner-only, so a non-owner app role must skip them to boot.
19
+ # Only the mint path and the owner-only tools call it; a boot never does. ALTER TABLE and
20
+ # REVOKE are owner-only, so a non-owner app role must skip them.
18
21
  #
19
22
  # @return [void]
20
- # @raise [Runtime::WiringError] if the `formerly_known_as` rename cannot take
21
- # its locks within 10s or Postgres refuses one of its statements
23
+ # @raise [Runtime::WiringError] if the domain's `formerly_known_as` rename is still pending
22
24
  # @raise [PG::Error] if Postgres refuses a provisioning statement
23
25
  def ensure_base!
24
- rename_domain! if @formerly_known_as
26
+ refuse_pending_rename!
25
27
  return unless provisioner?
26
28
 
27
29
  create_lineage_tables!
@@ -30,6 +32,7 @@ module Hecks
30
32
  revoke_journal_mutation!
31
33
  force_row_security!
32
34
  install_transforms!
35
+ SharedTables.new(@db).provision!
33
36
  end
34
37
 
35
38
  # Refuses to boot on a connection whose role Postgres exempts from row-level security
@@ -117,6 +120,9 @@ module Hecks
117
120
  # Canonical-form version that minted the name (Runtime::StorageShape::FORM_VERSION);
118
121
  # NULL reads as 1.
119
122
  @db.exec("ALTER TABLE hecks_eras ADD COLUMN IF NOT EXISTS canon_form int")
123
+ # The edge an era was minted under when no edge file wrote it, as `Translation::ImplicitEdge::RECORD`;
124
+ # NULL for every era a written edge reached.
125
+ @db.exec("ALTER TABLE hecks_eras ADD COLUMN IF NOT EXISTS edge jsonb")
120
126
  @db.exec(ERA_TEXTS_SQL)
121
127
  end
122
128
 
@@ -0,0 +1,76 @@
1
+ module Hecks
2
+ module Adapters
3
+ class PostgresEra
4
+ class Lineage
5
+ # ADR 0166: a `split` writes rows into another aggregate from one aggregate's rows. The target's
6
+ # head is not stored: its tail is the source's held-era state, fanned out one row per target key,
7
+ # and read through the same chain every head reads.
8
+ module SplitSql
9
+ # The source's rows as they are in the era the split edge starts from, latest per id, with the
10
+ # era kept so later edges' guards still hold.
11
+ SPLIT_SOURCE_SQL = <<~SQL.freeze
12
+ WITH tail AS MATERIALIZED (%<tail>s),
13
+ %<chain>s
14
+ SELECT ordinal, era, aggregate_id, operation, state FROM edge_%<last>s
15
+ SQL
16
+
17
+ # The split edge that creates `names[:current][n]`, with the source aggregate and the split, or nil.
18
+ def split_into(names, edges)
19
+ edges.each_with_index do |edge, index|
20
+ target = names[:current][index + 1]
21
+ edge[:translation].aggregates.each do |source|
22
+ split = source.splits.find { |candidate| candidate.into == target }
23
+ return { index: index, source: source, split: split } if split
24
+ end
25
+ end
26
+ nil
27
+ end
28
+
29
+ # The target's tail from its source's held-era rows: the source is chained through the edges
30
+ # before the split edge, so the split reads the shape it declares its fields in.
31
+ def split_tail_sql(names, edges)
32
+ found = split_into(names, edges)
33
+ return nil unless found
34
+
35
+ source_sql = split_source_sql(found[:source], edges, found[:index])
36
+ split_fanout_sql(source_sql, found[:split], names[:storage][found[:index] + 1])
37
+ end
38
+
39
+ # A split target's records as its split fans them out of the source, latest per id, or nil when
40
+ # the aggregate is not a split target: the "before" side of the audit of a split edge.
41
+ def split_latest(aggregate, edges)
42
+ tail = split_tail_sql(names_by_era(aggregate, edges), edges)
43
+ tail && latest_of("SELECT ordinal, era, aggregate_id, operation, state FROM (#{tail}) split_rows")
44
+ end
45
+
46
+ private
47
+
48
+ def split_source_sql(source, edges, index)
49
+ through = edges.first(index + 1)
50
+ names = names_by_era(Struct.new(:name).new(source.name), through)
51
+ tail = latest_per_id(ancestor_tail_sql(names, index + 2))
52
+ index.zero? ? tail : split_chain_sql(tail, through.first(index), names)
53
+ end
54
+
55
+ def split_chain_sql(tail, edges, names)
56
+ chain = edges.each_with_index.map { |edge, i| edge_step_sql(edge, i, names) }
57
+ format(SPLIT_SOURCE_SQL, tail: tail, chain: chain.join(",\n"), last: edges.size)
58
+ end
59
+
60
+ # One row per source row that carries the key: the key becomes the target's id, and the named
61
+ # fields are copied under their own names. Deletes are kept, so a deleted source deletes its
62
+ # target row too.
63
+ def split_fanout_sql(source_sql, split, target_storage)
64
+ key = text_literal(split.keyed_by.to_s)
65
+ # A keyed_by field is often a value object, whose identity is its `value` member.
66
+ key_value = "COALESCE(state -> #{key} ->> 'value', state ->> #{key})"
67
+ fields = split.fields.map { |field| "#{text_literal(field.to_s)}, state -> #{text_literal(field.to_s)}" }
68
+ "SELECT ordinal, era, #{text_literal(target_storage)} AS aggregate, #{key_value} AS aggregate_id, " \
69
+ "operation, jsonb_build_object(#{fields.join(", ")}) AS state " \
70
+ "FROM (#{source_sql}) split_source WHERE state ? #{key}"
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -77,6 +77,15 @@ module Hecks
77
77
  SELECT ordinal, aggregate_id, operation, state FROM edge_%<last>s
78
78
  SQL
79
79
 
80
+ # The chain in one step: each held era's rows take the one composed translation from
81
+ # that era to the current shape.
82
+ DIRECT_SQL = <<~SQL.freeze
83
+ WITH tail AS MATERIALIZED (%<tail>s),
84
+ direct AS MATERIALIZED (SELECT ordinal, era, aggregate_id, operation,
85
+ %<state>s AS state FROM tail)
86
+ SELECT ordinal, aggregate_id, operation, state FROM direct
87
+ SQL
88
+
80
89
  # Reduces to newest entry per aggregate id, dropping any id whose newest entry is a
81
90
  # delete.
82
91
  LATEST_SQL = <<~SQL.freeze
@@ -10,6 +10,8 @@ require_relative "lineage/resumable_backfill"
10
10
  require_relative "lineage/head_compiler"
11
11
  require_relative "lineage/field_cache"
12
12
  require_relative "lineage/transform_installer"
13
+ require_relative "lineage/mint_provisioning"
14
+ require_relative "lineage/ledger_reset"
13
15
  require_relative "../../../naming"
14
16
 
15
17
  module Hecks
@@ -27,6 +29,8 @@ module Hecks
27
29
  include HeadCompiler
28
30
  include FieldCache
29
31
  include TransformInstaller
32
+ include MintProvisioning
33
+ include LedgerReset
30
34
 
31
35
  # Longer identifiers are silently truncated by Postgres, so `qualified_name` hashes them.
32
36
  POSTGRES_IDENTIFIER_LIMIT = 63
@@ -37,11 +41,15 @@ module Hecks
37
41
  # @param domain [String, Symbol] the domain's declared name; every relation name and
38
42
  # advisory-lock key derives from it
39
43
  # @param formerly_known_as [String, Symbol, nil] the domain's prior name, which makes
40
- # `ensure_base!` rename its relations and rows first; nil when there is no prior name
41
- def initialize(db, domain, formerly_known_as: nil)
44
+ # `ensure_base!` and a read refuse while the history sits under it; `rename_domain!` moves
45
+ # the history; nil when there is no prior name
46
+ # @param reading [Boolean] true for a read: the held eras are verified in memory and never
47
+ # archived or backfilled, so the connection needs only SELECT
48
+ def initialize(db, domain, formerly_known_as: nil, reading: false)
42
49
  @db = db
43
50
  @domain = domain.to_s
44
51
  @formerly_known_as = formerly_known_as&.to_s
52
+ @reading = reading
45
53
  end
46
54
 
47
55
  # Names the domain's one journal table, the partitioned parent of every era's rows.
@@ -4,10 +4,11 @@ module Hecks
4
4
  module LineageManager
5
5
  # Everything one era check carries from connecting to minting: the booting registry and
6
6
  # bluebook, its source text, the open lineage, the role to grant, the bluebook directory,
7
- # whether this copy may mint, and the latest held era once the held eras were read.
7
+ # whether this copy may mint, the mint request the Maintenance mint command made (nil on
8
+ # a boot), and the latest held era once the held eras were read.
8
9
  Context = Data.define(:registry, :bluebook, :current_text, :lineage, :role, :directory, :latest,
9
- :mint_permitted) do
10
- def initialize(latest: nil, mint_permitted: false, **rest) = super
10
+ :mint_permitted, :mint_request) do
11
+ def initialize(latest: nil, mint_permitted: false, mint_request: nil, **rest) = super
11
12
 
12
13
  # @return [String] the name of the domain being checked
13
14
  def domain_name = bluebook.name
@@ -15,9 +16,15 @@ module Hecks
15
16
  # @return [Array<Bluebook::Aggregate>] the aggregates of the bluebook being checked
16
17
  def aggregates = bluebook.aggregates
17
18
 
19
+ # @return [Array<Object>] the translation edges the registry loaded
20
+ def translations = registry.translations
21
+
18
22
  # @return [Array<Hash>] the eras the open lineage holds, oldest first
19
23
  def held_eras = lineage.eras
20
24
 
25
+ # @return [Integer] the ledger watermark now: the journal's highest ordinal
26
+ def watermark = lineage.last_ordinal
27
+
21
28
  # @return [Integer] the ordinal of the era a mint would create
22
29
  def ordinal = latest[:ordinal] + 1
23
30
 
@@ -41,6 +48,19 @@ module Hecks
41
48
  # @param ordinal [Integer] the superseding era
42
49
  # @return [Integer] `ordinal`
43
50
  def record_superseded(ordinal) = registry.superseded_eras[domain_name] = ordinal
51
+
52
+ # Records that this boot's shape is held by no era, with the latest held era it reads.
53
+ #
54
+ # @param ordinal [Integer] the latest held era
55
+ # @return [Integer] `ordinal`
56
+ def record_unminted(ordinal) = registry.unminted_eras[domain_name] = ordinal
57
+
58
+ # Records that this boot's shape is one recorded move or edge ahead of the latest
59
+ # held era.
60
+ #
61
+ # @param ordinal [Integer] the latest held era the move leaves
62
+ # @return [Integer] `ordinal`
63
+ def record_behind(ordinal) = registry.behind_eras[domain_name] = ordinal
44
64
  end
45
65
  end
46
66
  end
@@ -111,9 +111,11 @@ module Hecks
111
111
 
112
112
  # The aggregate's head as the chain's last step receives it.
113
113
  def translated_before(lineage, aggregate, ordinal, chain)
114
+ split = lineage.split_latest(aggregate, chain)
115
+ return split if split
114
116
  return lineage.ancestor_latest(aggregate, ordinal, chain) unless chain.size > 1
115
117
 
116
- lineage.translated_latest(aggregate, ordinal, chain[0..-2])
118
+ lineage.received_latest(aggregate, ordinal, chain)
117
119
  end
118
120
  end
119
121
  end