hecks 2.8.0 → 3.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 (886) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +50 -7
  3. data/lib/hecks/adapters/driven/claude_code.rb +4 -104
  4. data/lib/hecks/adapters/driven/d1.rb +44 -237
  5. data/lib/hecks/adapters/driven/folder.rb +17 -76
  6. data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
  7. data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
  8. data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
  9. data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
  10. data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
  11. data/lib/hecks/adapters/driven/heki.rb +13 -42
  12. data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
  13. data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
  14. data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
  15. data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
  16. data/lib/hecks/adapters/driven/lambda.rb +10 -84
  17. data/lib/hecks/adapters/driven/local_storage.rb +5 -40
  18. data/lib/hecks/adapters/driven/memory.rb +32 -100
  19. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
  20. data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
  21. data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
  22. data/lib/hecks/adapters/driven/postgres/reconnect.rb +10 -32
  23. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
  24. data/lib/hecks/adapters/driven/postgres/shared_connection.rb +180 -0
  25. data/lib/hecks/adapters/driven/postgres.rb +149 -136
  26. data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
  27. data/lib/hecks/adapters/driven/prism.rb +48 -38
  28. data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
  29. data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
  30. data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
  31. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
  32. data/lib/hecks/adapters/driven/sqlite.rb +128 -65
  33. data/lib/hecks/adapters/driven/tenant_provisioner.rb +76 -62
  34. data/lib/hecks/adapters/driven.rb +5 -36
  35. data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
  36. data/lib/hecks/behaviors/dsl.rb +7 -25
  37. data/lib/hecks/behaviors/expectations.rb +32 -142
  38. data/lib/hecks/behaviors/ir.rb +7 -20
  39. data/lib/hecks/behaviors/rspec.rb +6 -17
  40. data/lib/hecks/behaviors/runner.rb +10 -34
  41. data/lib/hecks/behaviors.rb +4 -8
  42. data/lib/hecks/bench/cli.rb +62 -0
  43. data/lib/hecks/bench/environment.rb +71 -0
  44. data/lib/hecks/bench/postgres_probe.rb +30 -0
  45. data/lib/hecks/bench/report.rb +76 -0
  46. data/lib/hecks/bench/ruby_runner.rb +93 -0
  47. data/lib/hecks/bench/run.rb +55 -0
  48. data/lib/hecks/bench/rust_runner.rb +101 -0
  49. data/lib/hecks/bench/stats.rb +46 -0
  50. data/lib/hecks/bench/suite.rb +98 -0
  51. data/lib/hecks/bench/workload.rb +89 -0
  52. data/lib/hecks/bench.rb +17 -0
  53. data/lib/hecks/bluebook/aggregate.rb +9 -75
  54. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
  55. data/lib/hecks/bluebook/assembly/build.rb +4 -15
  56. data/lib/hecks/bluebook/assembly/contract.rb +15 -136
  57. data/lib/hecks/bluebook/assembly/contracts.rb +56 -174
  58. data/lib/hecks/bluebook/assembly/marks.rb +31 -223
  59. data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
  60. data/lib/hecks/bluebook/assembly.rb +6 -45
  61. data/lib/hecks/bluebook/attribute.rb +12 -61
  62. data/lib/hecks/bluebook/behaviour/aggregate.rb +39 -39
  63. data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
  64. data/lib/hecks/bluebook/behaviour/chapter.rb +14 -42
  65. data/lib/hecks/bluebook/behaviour/command.rb +14 -66
  66. data/lib/hecks/bluebook/behaviour/domain_port.rb +11 -20
  67. data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
  68. data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
  69. data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
  70. data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
  71. data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
  72. data/lib/hecks/bluebook/behaviour/read_model.rb +25 -31
  73. data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
  74. data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
  75. data/lib/hecks/bluebook/capabilities.rb +17 -49
  76. data/lib/hecks/bluebook/chapter.rb +16 -50
  77. data/lib/hecks/bluebook/command.rb +23 -81
  78. data/lib/hecks/bluebook/domain_port.rb +49 -67
  79. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
  80. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
  81. data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
  82. data/lib/hecks/bluebook/dsl/binding_proxy.rb +16 -69
  83. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +96 -708
  84. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +63 -169
  85. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +3 -1
  86. data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
  87. data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
  88. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +42 -89
  89. data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
  90. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
  91. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +148 -197
  92. data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
  93. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
  94. data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
  95. data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
  96. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
  97. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
  98. data/lib/hecks/bluebook/dsl/query_builder.rb +38 -43
  99. data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
  100. data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
  101. data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
  102. data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
  103. data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
  104. data/lib/hecks/bluebook/dsl/world_builder.rb +46 -111
  105. data/lib/hecks/bluebook/entity.rb +13 -71
  106. data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
  107. data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
  108. data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
  109. data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
  110. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
  111. data/lib/hecks/bluebook/expression/resolver.rb +39 -661
  112. data/lib/hecks/bluebook/hexagon.rb +18 -33
  113. data/lib/hecks/bluebook/lifecycle.rb +5 -16
  114. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
  115. data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
  116. data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
  117. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
  118. data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
  119. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +25 -176
  120. data/lib/hecks/bluebook/meta_validator/shapes.rb +53 -267
  121. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -306
  122. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
  123. data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +246 -0
  124. data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
  125. data/lib/hecks/bluebook/meta_validator.rb +87 -352
  126. data/lib/hecks/bluebook/model_check/client_profile.rb +6 -21
  127. data/lib/hecks/bluebook/model_check.rb +122 -596
  128. data/lib/hecks/bluebook/pattern_subset.rb +49 -69
  129. data/lib/hecks/bluebook/process_manager.rb +13 -83
  130. data/lib/hecks/bluebook/project_loader.rb +3 -39
  131. data/lib/hecks/bluebook/project_register.rb +12 -60
  132. data/lib/hecks/bluebook/query.rb +27 -51
  133. data/lib/hecks/bluebook/read_model.rb +57 -81
  134. data/lib/hecks/bluebook/reference.rb +7 -41
  135. data/lib/hecks/bluebook/smoke_test.rb +9 -99
  136. data/lib/hecks/bluebook/synthesizer.rb +13 -62
  137. data/lib/hecks/bluebook/translation.rb +26 -62
  138. data/lib/hecks/bluebook/value_object.rb +11 -36
  139. data/lib/hecks/bluebook.rb +5 -22
  140. data/lib/hecks/cache_dir.rb +4 -23
  141. data/lib/hecks/canonical_json.rb +30 -0
  142. data/lib/hecks/chapters.rb +102 -0
  143. data/lib/hecks/cli/behaviors.rb +61 -0
  144. data/lib/hecks/cli/canonicalise.rb +25 -0
  145. data/lib/hecks/cli/check_engine_agreement.rb +32 -0
  146. data/lib/hecks/cli/check_era.rb +88 -0
  147. data/lib/hecks/cli/console.rb +66 -0
  148. data/lib/hecks/cli/deploy_template_diff.rb +40 -0
  149. data/lib/hecks/cli/doc_coverage.rb +32 -0
  150. data/lib/hecks/cli/document.rb +5 -23
  151. data/lib/hecks/cli/expression_projection.rb +41 -0
  152. data/lib/hecks/cli/follow.rb +88 -0
  153. data/lib/hecks/cli/history.rb +44 -0
  154. data/lib/hecks/cli/ir.rb +4 -6
  155. data/lib/hecks/cli/mcp.rb +5 -6
  156. data/lib/hecks/cli/model_check.rb +24 -88
  157. data/lib/hecks/cli/pattern_cases.rb +47 -0
  158. data/lib/hecks/cli/present.rb +39 -0
  159. data/lib/hecks/cli/project_cli.rb +223 -64
  160. data/lib/hecks/cli/project_diagrams.rb +4 -10
  161. data/lib/hecks/cli/project_glossary.rb +44 -0
  162. data/lib/hecks/cli/reference.rb +46 -0
  163. data/lib/hecks/cli/refresh_projections.rb +44 -0
  164. data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +150 -0
  165. data/lib/hecks/cli/release.rb +70 -0
  166. data/lib/hecks/cli/release_gem.rb +59 -0
  167. data/lib/hecks/cli/rspec_io_parallel_files.rb +137 -0
  168. data/lib/hecks/cli/rspec_shard_files.rb +66 -0
  169. data/lib/hecks/cli/run.rb +15 -61
  170. data/lib/hecks/cli/seed_semantics_corpus.rb +71 -0
  171. data/lib/hecks/cli/serve_query_ir_mcp.rb +30 -0
  172. data/lib/hecks/cli/shape.rb +70 -0
  173. data/lib/hecks/cli/smoke_http.rb +230 -0
  174. data/lib/hecks/cli/smoke_test.rb +7 -19
  175. data/lib/hecks/cli/spec_example.rb +27 -0
  176. data/lib/hecks/cli/statements.rb +32 -0
  177. data/lib/hecks/cli/stores.rb +4 -6
  178. data/lib/hecks/cli/stress_concurrency_specs.rb +177 -0
  179. data/lib/hecks/cli.rb +216 -73
  180. data/lib/hecks/codemod.rb +324 -0
  181. data/lib/hecks/construct.rb +8 -34
  182. data/lib/hecks/corpus.rb +423 -0
  183. data/lib/hecks/deploy/bluebook/deploy.bluebook +617 -158
  184. data/lib/hecks/deploy/bluebook/deploy.hecksagon +41 -11
  185. data/lib/hecks/deploy/oidc.json +82 -2
  186. data/lib/hecks/doc/reference.rb +351 -0
  187. data/lib/hecks/doors/cli_door.rb +196 -0
  188. data/lib/hecks/doors/cli_runner.rb +297 -0
  189. data/lib/hecks/{facade → doors}/command_request.rb +14 -34
  190. data/lib/hecks/doors/handle.rb +206 -0
  191. data/lib/hecks/doors/json_door.rb +132 -0
  192. data/lib/hecks/doors/launcher_options.rb +129 -0
  193. data/lib/hecks/{cli → doors}/mcp_door.rb +25 -120
  194. data/lib/hecks/doors/mcp_door_scope.rb +97 -0
  195. data/lib/hecks/doors/ruby_door/aggregate_door.rb +162 -0
  196. data/lib/hecks/doors/ruby_door/chapter.rb +72 -0
  197. data/lib/hecks/doors/ruby_door.rb +77 -0
  198. data/lib/hecks/doors.rb +61 -0
  199. data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
  200. data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
  201. data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
  202. data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
  203. data/lib/hecks/embryonaut_bluebook.rb +5 -72
  204. data/lib/hecks/engine_agreement.rb +156 -0
  205. data/lib/hecks/facade.rb +23 -51
  206. data/lib/hecks/forms/app.rb +21 -76
  207. data/lib/hecks/forms/banking_presentation.rb +50 -0
  208. data/lib/hecks/forms/command_form_renderer.rb +10 -29
  209. data/lib/hecks/forms/field_renderer.rb +17 -156
  210. data/lib/hecks/forms/field_shape.rb +31 -222
  211. data/lib/hecks/forms/html.rb +12 -47
  212. data/lib/hecks/forms/index_renderer.rb +1 -4
  213. data/lib/hecks/forms/page.rb +3 -9
  214. data/lib/hecks/forms/params.rb +14 -60
  215. data/lib/hecks/forms/port_argument.rb +2 -19
  216. data/lib/hecks/forms/query_form_renderer.rb +4 -79
  217. data/lib/hecks/forms/record_renderer.rb +8 -75
  218. data/lib/hecks/forms/record_table.rb +7 -50
  219. data/lib/hecks/forms/reference_options.rb +3 -30
  220. data/lib/hecks/forms/value_object_shape.rb +8 -35
  221. data/lib/hecks/forms.rb +5 -33
  222. data/lib/hecks/fqn.rb +5 -12
  223. data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
  224. data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
  225. data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
  226. data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
  227. data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
  228. data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
  229. data/lib/hecks/framework.rb +11 -80
  230. data/lib/hecks/freezer.rb +5 -39
  231. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +393 -0
  232. data/lib/hecks/fuzzing/combination_miner.rb +86 -0
  233. data/lib/hecks/fuzzing/concurrent_dispatch.rb +214 -0
  234. data/lib/hecks/fuzzing/coverage_campaign.rb +143 -0
  235. data/lib/hecks/fuzzing/differential.rb +156 -0
  236. data/lib/hecks/fuzzing/domain_generator.rb +615 -0
  237. data/lib/hecks/fuzzing/era_boundary.rb +71 -0
  238. data/lib/hecks/fuzzing/form_census.rb +136 -0
  239. data/lib/hecks/fuzzing/generated_domain_check.rb +93 -0
  240. data/lib/hecks/fuzzing/invalid_value_generator.rb +64 -0
  241. data/lib/hecks/fuzzing/isolated_boot.rb +301 -0
  242. data/lib/hecks/fuzzing/nondeterministic.rb +51 -0
  243. data/lib/hecks/fuzzing/outside_world.rb +45 -0
  244. data/lib/hecks/fuzzing/persistence_parity.rb +102 -0
  245. data/lib/hecks/fuzzing/properties/corrections.rb +88 -0
  246. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +314 -0
  247. data/lib/hecks/fuzzing/properties/guards.rb +190 -0
  248. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +300 -0
  249. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +93 -0
  250. data/lib/hecks/fuzzing/properties/outbox.rb +89 -0
  251. data/lib/hecks/fuzzing/properties/querying.rb +175 -0
  252. data/lib/hecks/fuzzing/properties.rb +162 -0
  253. data/lib/hecks/fuzzing/qa_settings.rb +123 -0
  254. data/lib/hecks/fuzzing/replay.rb +505 -0
  255. data/lib/hecks/fuzzing/rotation_priority.rb +48 -0
  256. data/lib/hecks/fuzzing/rust_gap_manifest.rb +108 -0
  257. data/lib/hecks/fuzzing/self_consistency.rb +339 -0
  258. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +385 -0
  259. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +132 -0
  260. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +95 -0
  261. data/lib/hecks/fuzzing/sequence_generator/picker.rb +77 -0
  262. data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +109 -0
  263. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +237 -0
  264. data/lib/hecks/fuzzing/sequence_generator.rb +189 -0
  265. data/lib/hecks/fuzzing/shrinker.rb +166 -0
  266. data/lib/hecks/fuzzing/structural_skips.rb +33 -0
  267. data/lib/hecks/fuzzing/sweep_depth.rb +43 -0
  268. data/lib/hecks/fuzzing/target_capabilities.rb +163 -0
  269. data/lib/hecks/fuzzing/value_generator.rb +216 -0
  270. data/lib/hecks/fuzzing.rb +23 -0
  271. data/lib/hecks/grammar/evolve.rb +336 -0
  272. data/lib/hecks/grammar/expression.bluebook +15 -40
  273. data/lib/hecks/grammar/translation.bluebook +3 -6
  274. data/lib/hecks/grammar.rb +16 -41
  275. data/lib/hecks/hecks/adapters/codebase/codemods.rb +45 -0
  276. data/lib/hecks/hecks/adapters/codebase/conformance.rb +71 -0
  277. data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +202 -0
  278. data/lib/hecks/hecks/adapters/codebase/gem_registry.rb +80 -0
  279. data/lib/hecks/hecks/adapters/codebase/kernel_tables.rb +54 -0
  280. data/lib/hecks/hecks/adapters/codebase/language.rb +240 -0
  281. data/lib/hecks/hecks/adapters/codebase/npm_registry.rb +102 -0
  282. data/lib/hecks/hecks/adapters/codebase/publishing.rb +142 -0
  283. data/lib/hecks/hecks/adapters/codebase/regeneration.rb +67 -0
  284. data/lib/hecks/hecks/adapters/codebase/release_facts.rb +90 -0
  285. data/lib/hecks/hecks/adapters/codebase/ruby_child.rb +83 -0
  286. data/lib/hecks/hecks/adapters/codebase/secret_vault.rb +36 -0
  287. data/lib/hecks/hecks/adapters/codebase/source_tree.adapter +7 -0
  288. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +189 -0
  289. data/lib/hecks/hecks/adapters/codebase/sqlite_fixture.rb +71 -0
  290. data/lib/hecks/hecks/adapters/codebase/style.rb +171 -0
  291. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +55 -0
  292. data/lib/hecks/hecks/adapters/codebase/test_suite.rb +165 -0
  293. data/lib/hecks/hecks/adapters/codebase/tree.rb +111 -0
  294. data/lib/hecks/hecks/adapters/console_capture.rb +79 -0
  295. data/lib/hecks/hecks/adapters/deploy_toolchain.adapter +7 -0
  296. data/lib/hecks/hecks/adapters/deploy_toolchain.rb +108 -0
  297. data/lib/hecks/hecks/adapters/git.adapter +7 -0
  298. data/lib/hecks/hecks/adapters/git.rb +102 -0
  299. data/lib/hecks/hecks/adapters/host_http.adapter +7 -0
  300. data/lib/hecks/hecks/adapters/host_http.rb +65 -0
  301. data/lib/hecks/hecks/adapters/in_process_boot.adapter +7 -0
  302. data/lib/hecks/hecks/adapters/in_process_boot.rb +197 -0
  303. data/lib/hecks/hecks/adapters/in_process_operations.rb +202 -0
  304. data/lib/hecks/hecks/adapters/journal_store/changes.rb +143 -0
  305. data/lib/hecks/hecks/adapters/journal_store/compaction.rb +145 -0
  306. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +132 -0
  307. data/lib/hecks/hecks/adapters/journal_store/examination.rb +135 -0
  308. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +163 -0
  309. data/lib/hecks/hecks/adapters/journal_store/readings.rb +187 -0
  310. data/lib/hecks/hecks/adapters/journal_store.adapter +7 -0
  311. data/lib/hecks/hecks/adapters/journal_store.rb +64 -0
  312. data/lib/hecks/hecks/adapters/local_files.adapter +7 -0
  313. data/lib/hecks/hecks/adapters/local_files.rb +46 -0
  314. data/lib/hecks/hecks/adapters/pg_admin.adapter +7 -0
  315. data/lib/hecks/hecks/adapters/pg_admin.rb +245 -0
  316. data/lib/hecks/hecks/adapters/process_pool.adapter +7 -0
  317. data/lib/hecks/hecks/adapters/process_pool.rb +119 -0
  318. data/lib/hecks/hecks/adapters/rust_toolchain.adapter +7 -0
  319. data/lib/hecks/hecks/adapters/rust_toolchain.rb +179 -0
  320. data/lib/hecks/hecks/adapters/rust_workspace.rb +150 -0
  321. data/lib/hecks/hecks/adapters/shell.adapter +7 -0
  322. data/lib/hecks/hecks/adapters/shell.rb +49 -0
  323. data/lib/hecks/hecks/adapters/terminal.adapter +7 -0
  324. data/lib/hecks/hecks/adapters/terminal.rb +74 -0
  325. data/lib/hecks/hecks/codebase.behaviors +172 -0
  326. data/lib/hecks/hecks/codebase.bluebook +2453 -0
  327. data/lib/hecks/hecks/context_map.hecksagon +13 -0
  328. data/lib/hecks/hecks/custodian.behaviors +179 -0
  329. data/lib/hecks/hecks/custodian.bluebook +1847 -0
  330. data/lib/hecks/hecks/deploy.behaviors +74 -0
  331. data/lib/hecks/hecks/deploy.world +12 -0
  332. data/lib/hecks/hecks/environments/memory.world +10 -0
  333. data/lib/hecks/hecks/governance.world +7 -0
  334. data/lib/hecks/hecks/hecks.behaviors +62 -0
  335. data/lib/hecks/hecks/hecks.bluebook +124 -0
  336. data/lib/hecks/hecks/hecks.hecksagon +390 -0
  337. data/lib/hecks/hecks/hecks.world +42 -0
  338. data/lib/hecks/ir.rb +14 -83
  339. data/lib/hecks/kernel_capabilities.rb +194 -0
  340. data/lib/hecks/language/adapter.bluebook +2 -7
  341. data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
  342. data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
  343. data/lib/hecks/language/bluebook/bluebook.bluebook +26 -83
  344. data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
  345. data/lib/hecks/language/bluebook/command.bluebook +27 -144
  346. data/lib/hecks/language/bluebook/entity.bluebook +24 -97
  347. data/lib/hecks/language/bluebook/policy.bluebook +16 -67
  348. data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
  349. data/lib/hecks/language/bluebook/projection.bluebook +126 -60
  350. data/lib/hecks/language/bluebook/query.bluebook +19 -43
  351. data/lib/hecks/language/bluebook/shape.bluebook +23 -73
  352. data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
  353. data/lib/hecks/language/bluebook/vocabulary.bluebook +83 -198
  354. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
  355. data/lib/hecks/language/hecksagon/domain_port.bluebook +14 -19
  356. data/lib/hecks/language/hecksagon/hecksagon.bluebook +26 -25
  357. data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
  358. data/lib/hecks/language/oidc.json +35 -0
  359. data/lib/hecks/language/port.bluebook +4 -17
  360. data/lib/hecks/language/translation/translation.bluebook +3 -9
  361. data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
  362. data/lib/hecks/language/world/wiring.bluebook +1 -3
  363. data/lib/hecks/language/world/world.bluebook +5 -7
  364. data/lib/hecks/literal.rb +8 -50
  365. data/lib/hecks/mcp_stdio_guard.rb +4 -41
  366. data/lib/hecks/naming.rb +29 -137
  367. data/lib/hecks/persistence_legacy_fixture/regenerate.rb +161 -0
  368. data/lib/hecks/persistence_legacy_fixture.rb +113 -0
  369. data/lib/hecks/ports/access_control.rb +7 -23
  370. data/lib/hecks/ports/agent/answers.rb +5 -23
  371. data/lib/hecks/ports/agent.rb +47 -172
  372. data/lib/hecks/ports/authentication.rb +12 -39
  373. data/lib/hecks/ports/authorization.rb +16 -43
  374. data/lib/hecks/ports/clock.rb +5 -45
  375. data/lib/hecks/ports/extraction.rb +7 -12
  376. data/lib/hecks/ports/identity_assignment.rb +8 -29
  377. data/lib/hecks/ports/identity_generation.rb +6 -29
  378. data/lib/hecks/ports/identity_resolution.rb +2 -10
  379. data/lib/hecks/ports/key_vault.rb +9 -45
  380. data/lib/hecks/ports/persistence/append_only.rb +61 -64
  381. data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
  382. data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
  383. data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
  384. data/lib/hecks/ports/persistence/plugin.rb +13 -42
  385. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +44 -144
  386. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
  387. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +20 -85
  388. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +6 -25
  389. data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +18 -24
  390. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
  391. data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
  392. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
  393. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
  394. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
  395. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
  396. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
  397. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
  398. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +19 -76
  399. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
  400. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
  401. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
  402. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
  403. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
  404. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +43 -127
  405. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
  406. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +131 -555
  407. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
  408. data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +227 -0
  409. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
  410. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
  411. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
  412. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
  413. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
  414. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +50 -47
  415. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -124
  416. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
  417. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
  418. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
  419. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
  420. data/lib/hecks/ports/persistence/plugins/era/translation.rb +1 -0
  421. data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
  422. data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
  423. data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
  424. data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
  425. data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
  426. data/lib/hecks/ports/persistence/state_codec.rb +47 -108
  427. data/lib/hecks/ports/persistence.rb +7 -14
  428. data/lib/hecks/ports/projection.rb +42 -84
  429. data/lib/hecks/ports/query/in_memory.rb +10 -58
  430. data/lib/hecks/ports/query/ordering.rb +11 -32
  431. data/lib/hecks/ports/query.rb +14 -37
  432. data/lib/hecks/ports.rb +2 -8
  433. data/lib/hecks/projection_files.rb +285 -0
  434. data/lib/hecks/projections/bootstrap_table.rb +12 -44
  435. data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
  436. data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
  437. data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
  438. data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
  439. data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
  440. data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
  441. data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
  442. data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
  443. data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
  444. data/lib/hecks/projections/deploy/fargate.rb +40 -207
  445. data/lib/hecks/projections/deploy/lambda.rb +191 -708
  446. data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
  447. data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
  448. data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
  449. data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
  450. data/lib/hecks/projections/deploy/preview/script.rb +2 -14
  451. data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
  452. data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
  453. data/lib/hecks/projections/deploy/preview/template.rb +3 -59
  454. data/lib/hecks/projections/deploy/preview.rb +2 -67
  455. data/lib/hecks/projections/deploy/scripts/deploy-service.sh.tmpl +1 -1
  456. data/lib/hecks/projections/deploy/scripts/expected-era.header +1 -1
  457. data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +3 -3
  458. data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
  459. data/lib/hecks/projections/deploy/scripts/smoke-after-deploy.sh.tmpl +1 -1
  460. data/lib/hecks/projections/deploy/scripts.rb +4 -57
  461. data/lib/hecks/projections/deploy/shared.rb +48 -147
  462. data/lib/hecks/projections/deploy/smoke.rb +4 -61
  463. data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
  464. data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
  465. data/lib/hecks/projections/deploy/template_diff.rb +5 -57
  466. data/lib/hecks/projections/diagrams.rb +22 -584
  467. data/lib/hecks/projections/glossary/html.rb +14 -130
  468. data/lib/hecks/projections/glossary/markdown.rb +8 -69
  469. data/lib/hecks/projections/glossary/mermaid.rb +9 -66
  470. data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
  471. data/lib/hecks/projections/glossary/sentences.rb +14 -159
  472. data/lib/hecks/projections/glossary.rb +30 -222
  473. data/lib/hecks/projections/ir.rb +3 -10
  474. data/lib/hecks/projections/model/deviations.rb +16 -43
  475. data/lib/hecks/projections/model.rb +12 -51
  476. data/lib/hecks/projections/oidc.rb +12 -56
  477. data/lib/hecks/projections/parser_table.rb +13 -32
  478. data/lib/hecks/projections/reference.rb +4 -18
  479. data/lib/hecks/projections/rust_vocabulary.rb +13 -251
  480. data/lib/hecks/projections/shape.rb +3 -29
  481. data/lib/hecks/projections/statements.rb +7 -86
  482. data/lib/hecks/projections/vocabulary.rb +6 -22
  483. data/lib/hecks/projections.rb +2 -16
  484. data/lib/hecks/projector/cli_projector.rb +154 -400
  485. data/lib/hecks/projector/docs_projector.rb +10 -201
  486. data/lib/hecks/projector/exporter.rb +42 -134
  487. data/lib/hecks/projector/ir_projector.rb +2 -9
  488. data/lib/hecks/projector/narrate_projector.rb +15 -189
  489. data/lib/hecks/projector/target.rb +13 -76
  490. data/lib/hecks/projector.rb +30 -121
  491. data/lib/hecks/quality_control/adapters/agent.adapter +7 -0
  492. data/lib/hecks/quality_control/adapters/agent.rb +58 -0
  493. data/lib/hecks/quality_control/adapters/angle_tools.adapter +7 -0
  494. data/lib/hecks/quality_control/adapters/angle_tools.rb +15 -0
  495. data/lib/hecks/quality_control/adapters/clearance_recorder.rb +36 -0
  496. data/lib/hecks/quality_control/adapters/clearance_tools.adapter +7 -0
  497. data/lib/hecks/quality_control/adapters/clearance_tools.rb +17 -0
  498. data/lib/hecks/quality_control/adapters/git_pr.adapter +7 -0
  499. data/lib/hecks/quality_control/adapters/git_pr.rb +226 -0
  500. data/lib/hecks/quality_control/adapters/github_checks.adapter +9 -0
  501. data/lib/hecks/quality_control/adapters/github_checks.rb +83 -0
  502. data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +56 -0
  503. data/lib/hecks/quality_control/adapters/github_issues.adapter +7 -0
  504. data/lib/hecks/quality_control/adapters/github_issues.rb +49 -0
  505. data/lib/hecks/quality_control/adapters/qa_tool.rb +59 -0
  506. data/lib/hecks/quality_control/adapters/sweep_tools.adapter +7 -0
  507. data/lib/hecks/quality_control/adapters/sweep_tools.rb +51 -0
  508. data/lib/hecks/quality_control/adapters/target_tools.adapter +7 -0
  509. data/lib/hecks/quality_control/adapters/target_tools.rb +43 -0
  510. data/lib/hecks/quality_control/cli/child.rb +45 -0
  511. data/lib/hecks/quality_control/cli/qa_concurrency_racer.rb +45 -0
  512. data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +248 -0
  513. data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +163 -0
  514. data/lib/hecks/quality_control/cli/qa_generated_domains.rb +450 -0
  515. data/lib/hecks/quality_control/cli/qa_log_bug.rb +195 -0
  516. data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +220 -0
  517. data/lib/hecks/quality_control/cli/qa_open_pr.rb +305 -0
  518. data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +154 -0
  519. data/lib/hecks/quality_control/cli/qa_postgres_role.rb +159 -0
  520. data/lib/hecks/quality_control/cli/qa_pr_check.rb +232 -0
  521. data/lib/hecks/quality_control/cli/qa_seed_angles.rb +142 -0
  522. data/lib/hecks/quality_control/cli/qa_seed_targets.rb +69 -0
  523. data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +280 -0
  524. data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +329 -0
  525. data/lib/hecks/quality_control/cli/qa_sweep/dials.rb +92 -0
  526. data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +117 -0
  527. data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +175 -0
  528. data/lib/hecks/quality_control/cli/qa_sweep/release_mode.rb +60 -0
  529. data/lib/hecks/quality_control/cli/qa_sweep.rb +611 -0
  530. data/lib/hecks/quality_control/cli/qa_tick.rb +274 -0
  531. data/lib/hecks/quality_control/quality_control.bluebook +2224 -0
  532. data/lib/hecks/quality_control/quality_control.hecksagon +13 -0
  533. data/lib/hecks/quality_control/quality_control.ports.hecksagon +54 -0
  534. data/lib/hecks/query_ir.rb +346 -0
  535. data/lib/hecks/query_ir_mcp.rb +198 -0
  536. data/lib/hecks/query_specification/common/comparators.rb +5 -26
  537. data/lib/hecks/query_specification/common/comparison.rb +35 -143
  538. data/lib/hecks/query_specification/common/dsl.rb +8 -24
  539. data/lib/hecks/query_specification/common/null_policy.rb +20 -70
  540. data/lib/hecks/query_specification/common/options.rb +2 -6
  541. data/lib/hecks/query_specification/common/where_clause.rb +2 -10
  542. data/lib/hecks/query_specification/field_path.rb +37 -77
  543. data/lib/hecks/query_specification/hop_path.rb +12 -76
  544. data/lib/hecks/release/gem_pin.rb +2 -26
  545. data/lib/hecks/release/runner/ci_publisher.rb +5 -8
  546. data/lib/hecks/release/runner/clean_tree.rb +42 -0
  547. data/lib/hecks/release/runner/commands.rb +2 -4
  548. data/lib/hecks/release/runner/console.rb +6 -0
  549. data/lib/hecks/release/runner/gem_publisher.rb +15 -9
  550. data/lib/hecks/release/runner/npm_publisher.rb +9 -53
  551. data/lib/hecks/release/runner/preflight.rb +29 -20
  552. data/lib/hecks/release/runner/published.rb +8 -26
  553. data/lib/hecks/release/runner/tagger.rb +31 -23
  554. data/lib/hecks/release/runner.rb +60 -38
  555. data/lib/hecks/rendering.rb +4 -26
  556. data/lib/hecks/router/namespace_installer.rb +15 -39
  557. data/lib/hecks/router.rb +4 -8
  558. data/lib/hecks/runtime/adapter_lookup.rb +124 -0
  559. data/lib/hecks/runtime/aggregate_lock.rb +8 -33
  560. data/lib/hecks/runtime/boot_gates.rb +3 -18
  561. data/lib/hecks/runtime/caller.rb +19 -59
  562. data/lib/hecks/runtime/capability_graph.rb +5 -21
  563. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
  564. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +27 -160
  565. data/lib/hecks/runtime/command_interpreter.rb +124 -306
  566. data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
  567. data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
  568. data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
  569. data/lib/hecks/runtime/command_rules/emission.rb +8 -21
  570. data/lib/hecks/runtime/command_rules/references.rb +23 -202
  571. data/lib/hecks/runtime/dependency_planning.rb +50 -104
  572. data/lib/hecks/runtime/dispatcher.rb +134 -243
  573. data/lib/hecks/runtime/entity_element.rb +40 -462
  574. data/lib/hecks/runtime/entity_interpreter.rb +64 -219
  575. data/lib/hecks/runtime/errors.rb +32 -115
  576. data/lib/hecks/runtime/event.rb +3 -25
  577. data/lib/hecks/runtime/identity.rb +18 -154
  578. data/lib/hecks/runtime/instance.rb +18 -150
  579. data/lib/hecks/runtime/interpreting.rb +14 -70
  580. data/lib/hecks/runtime/invocation.rb +28 -164
  581. data/lib/hecks/runtime/loader.rb +109 -194
  582. data/lib/hecks/runtime/outbox.rb +39 -262
  583. data/lib/hecks/runtime/policy_interpreter.rb +43 -202
  584. data/lib/hecks/runtime/port_operation_interpreter.rb +28 -97
  585. data/lib/hecks/runtime/query_interpreter.rb +122 -187
  586. data/lib/hecks/runtime/reaction_invocation.rb +36 -138
  587. data/lib/hecks/runtime/reaction_outcome.rb +89 -0
  588. data/lib/hecks/runtime/read_model_interpreter.rb +117 -208
  589. data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
  590. data/lib/hecks/runtime/reference_hop.rb +8 -81
  591. data/lib/hecks/runtime/refusal_wording.rb +28 -87
  592. data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
  593. data/lib/hecks/runtime/registry/verification.rb +213 -227
  594. data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
  595. data/lib/hecks/runtime/registry.rb +156 -247
  596. data/lib/hecks/runtime/remote_dispatcher.rb +68 -154
  597. data/lib/hecks/runtime/routing.rb +4 -15
  598. data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
  599. data/lib/hecks/runtime/saga_interpreter.rb +79 -263
  600. data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
  601. data/lib/hecks/runtime/tenant_check.rb +6 -68
  602. data/lib/hecks/runtime/tenant_scope.rb +3 -28
  603. data/lib/hecks/runtime/value/admission.rb +16 -67
  604. data/lib/hecks/runtime/value/coercion.rb +162 -760
  605. data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
  606. data/lib/hecks/runtime/value/field_checks.rb +172 -0
  607. data/lib/hecks/runtime/value.rb +15 -84
  608. data/lib/hecks/runtime.rb +35 -69
  609. data/lib/hecks/rust_build/conformance.rb +158 -0
  610. data/lib/hecks/rust_build/conformance_fuzz.rb +71 -0
  611. data/lib/hecks/rust_build/coverage.rb +218 -0
  612. data/lib/hecks/rust_build/native_build.rb +124 -0
  613. data/lib/hecks/rust_build/project_rust/root_mod.rb +120 -0
  614. data/lib/hecks/rust_build/project_rust.rb +332 -0
  615. data/lib/hecks/rust_build/wasm.rb +105 -0
  616. data/lib/hecks/rust_build/wasm_browser.rb +113 -0
  617. data/lib/hecks/rust_build.rb +144 -0
  618. data/lib/hecks/storehouse.rb +155 -582
  619. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +10 -34
  620. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
  621. data/lib/hecks/three_zero/forms.yml +127 -0
  622. data/lib/hecks/three_zero.rb +12 -0
  623. data/lib/hecks/tools/argument_gate_matrix.rb +316 -0
  624. data/lib/hecks/tools/comment_style.rb +1070 -0
  625. data/lib/hecks/tools/corpus_report.rb +87 -0
  626. data/lib/hecks/tools/deploy_recipe.rb +255 -0
  627. data/lib/hecks/tools/deploy_recipe_lint.rb +282 -0
  628. data/lib/hecks/tools/drop_implicit_append_fields.rb +95 -0
  629. data/lib/hecks/tools/era_projection_backfill.rb +94 -0
  630. data/lib/hecks/tools/era_reattest.rb +146 -0
  631. data/lib/hecks/tools/evolve_run.rb +189 -0
  632. data/lib/hecks/tools/fuzz_sweep.rb +373 -0
  633. data/lib/hecks/tools/heki_compaction.rb +100 -0
  634. data/lib/hecks/tools/hoist_local_givens.rb +246 -0
  635. data/lib/hecks/tools/journal_compaction.rb +89 -0
  636. data/lib/hecks/tools/oidc_manifests.rb +70 -0
  637. data/lib/hecks/tools/query_ir_run.rb +81 -0
  638. data/lib/hecks/tools/regeneration_run.rb +166 -0
  639. data/lib/hecks/tools/rust_comment_style.rb +642 -0
  640. data/lib/hecks/tools/sequence_script.rb +62 -0
  641. data/lib/hecks/tools/tail_merge.rb +117 -0
  642. data/lib/hecks/tools/tenant_provisioning.rb +142 -0
  643. data/lib/hecks/tools/translation_audit.rb +208 -0
  644. data/lib/hecks/tools/translation_scaffold.rb +131 -0
  645. data/lib/hecks/tools.rb +86 -0
  646. data/lib/hecks/vendoring/git_environment.rb +2 -8
  647. data/lib/hecks/vendoring/git_source.rb +4 -10
  648. data/lib/hecks/vendoring.rb +7 -46
  649. data/lib/hecks/version.rb +3 -14
  650. data/lib/hecks.rb +52 -90
  651. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
  652. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
  653. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
  654. data/qa/settings.yml +66 -0
  655. data/rust/.cargo/config.toml +6 -0
  656. data/rust/.gitignore +2 -0
  657. data/rust/Cargo.lock +54 -0
  658. data/rust/Cargo.toml +61 -0
  659. data/rust/build/.cargo/config.toml +3 -0
  660. data/rust/build/.gitignore +1 -0
  661. data/rust/build/Cargo.lock +7 -0
  662. data/rust/build/Cargo.toml +19 -0
  663. data/rust/build/src/build_artifact.rs +47 -0
  664. data/rust/build/src/cargo_sync.rs +248 -0
  665. data/rust/build/src/json.rs +421 -0
  666. data/rust/build/src/lineage_pass.rs +285 -0
  667. data/rust/build/src/main.rs +51 -0
  668. data/rust/build/src/optional_pass.rs +150 -0
  669. data/rust/build/src/pipeline.rs +264 -0
  670. data/rust/build/src/reserved_names.rs +76 -0
  671. data/rust/build/src/resolve.rs +124 -0
  672. data/rust/build/src/root.rs +25 -0
  673. data/rust/build/src/sidecars.rs +73 -0
  674. data/rust/build/src/subprocess.rs +51 -0
  675. data/rust/build/src/tmp.rs +31 -0
  676. data/rust/codegen/.cargo/config.toml +3 -0
  677. data/rust/codegen/.gitignore +1 -0
  678. data/rust/codegen/Cargo.lock +7 -0
  679. data/rust/codegen/Cargo.toml +20 -0
  680. data/rust/codegen/src/attr.rs +32 -0
  681. data/rust/codegen/src/bridging.rs +481 -0
  682. data/rust/codegen/src/commands.rs +1226 -0
  683. data/rust/codegen/src/constraints.rs +109 -0
  684. data/rust/codegen/src/dependency_planning.rs +209 -0
  685. data/rust/codegen/src/domain_generator.rs +1288 -0
  686. data/rust/codegen/src/exemplar.rs +230 -0
  687. data/rust/codegen/src/expr_emitter.rs +87 -0
  688. data/rust/codegen/src/fielded.rs +192 -0
  689. data/rust/codegen/src/hecks_naming.rs +33 -0
  690. data/rust/codegen/src/json.rs +335 -0
  691. data/rust/codegen/src/json_codec.rs +697 -0
  692. data/rust/codegen/src/literal.rs +207 -0
  693. data/rust/codegen/src/main.rs +290 -0
  694. data/rust/codegen/src/manifest.rs +227 -0
  695. data/rust/codegen/src/mutations.rs +784 -0
  696. data/rust/codegen/src/naming.rs +286 -0
  697. data/rust/codegen/src/ports.rs +208 -0
  698. data/rust/codegen/src/prelude.rs +116 -0
  699. data/rust/codegen/src/queries.rs +786 -0
  700. data/rust/codegen/src/reactions.rs +532 -0
  701. data/rust/codegen/src/read_models.rs +697 -0
  702. data/rust/codegen/src/reference_specs.rs +40 -0
  703. data/rust/codegen/src/registry.rs +966 -0
  704. data/rust/codegen/src/reserved_names.rs +76 -0
  705. data/rust/codegen/src/shared.rs +93 -0
  706. data/rust/codegen/src/skip_reason.rs +25 -0
  707. data/rust/codegen/src/types.rs +362 -0
  708. data/rust/host/.cargo/config.toml +3 -0
  709. data/rust/host/.gitignore +1 -0
  710. data/rust/host/Cargo.lock +4297 -0
  711. data/rust/host/Cargo.toml +61 -0
  712. data/rust/host/HECKS_RELEASE +1 -0
  713. data/rust/host/rds-ca-bundle.pem +2736 -0
  714. data/rust/host/src/api.rs +1596 -0
  715. data/rust/host/src/approval.rs +652 -0
  716. data/rust/host/src/auth.rs +1287 -0
  717. data/rust/host/src/bin/expr_harness.rs +46 -0
  718. data/rust/host/src/bin/lineage_harness.rs +119 -0
  719. data/rust/host/src/bin/mint_harness.rs +135 -0
  720. data/rust/host/src/checkout.rs +265 -0
  721. data/rust/host/src/dispatch.rs +1443 -0
  722. data/rust/host/src/expr_json.rs +1117 -0
  723. data/rust/host/src/field_hints.rs +52 -0
  724. data/rust/host/src/ir.rs +733 -0
  725. data/rust/host/src/journal.rs +874 -0
  726. data/rust/host/src/lambda_client.rs +378 -0
  727. data/rust/host/src/log.rs +147 -0
  728. data/rust/host/src/main.rs +474 -0
  729. data/rust/host/src/mint.rs +1865 -0
  730. data/rust/host/src/payments/keystore.rs +330 -0
  731. data/rust/host/src/payments/tests.rs +1400 -0
  732. data/rust/host/src/payments.rs +767 -0
  733. data/rust/host/src/presentation.rs +698 -0
  734. data/rust/host/src/presentation_write.rs +1431 -0
  735. data/rust/host/src/query_step.rs +149 -0
  736. data/rust/host/src/rate_limit.rs +904 -0
  737. data/rust/host/src/reference_transform.rs +241 -0
  738. data/rust/host/src/reference_validate.rs +338 -0
  739. data/rust/host/src/resend.rs +296 -0
  740. data/rust/host/src/secrets.rs +106 -0
  741. data/rust/host/src/server.rs +663 -0
  742. data/rust/host/src/storage_shape.rs +175 -0
  743. data/rust/host/src/test_pg.rs +40 -0
  744. data/rust/host/src/ui_schema.rs +1351 -0
  745. data/rust/host/src/wasm_runner.rs +191 -0
  746. data/rust/host/src/web/newsletter/cooldown.rs +126 -0
  747. data/rust/host/src/web/newsletter/tests.rs +104 -0
  748. data/rust/host/src/web/newsletter.rs +310 -0
  749. data/rust/host/src/web/newsletter_send.rs +357 -0
  750. data/rust/host/src/web/registrations.rs +1505 -0
  751. data/rust/host/src/web.rs +2937 -0
  752. data/rust/lsp/.gitignore +1 -0
  753. data/rust/lsp/Cargo.lock +7 -0
  754. data/rust/lsp/Cargo.toml +16 -0
  755. data/rust/lsp/README.md +133 -0
  756. data/rust/lsp/src/diagnostics.rs +165 -0
  757. data/rust/lsp/src/json.rs +385 -0
  758. data/rust/lsp/src/main.rs +399 -0
  759. data/rust/lsp/src/outline.rs +177 -0
  760. data/rust/lsp/src/rpc.rs +67 -0
  761. data/rust/parser/.cargo/config.toml +5 -0
  762. data/rust/parser/.gitignore +1 -0
  763. data/rust/parser/Cargo.lock +7 -0
  764. data/rust/parser/Cargo.toml +21 -0
  765. data/rust/parser/src/build/closed_sets.rs +27 -0
  766. data/rust/parser/src/build/identity.rs +276 -0
  767. data/rust/parser/src/build/mod.rs +12 -0
  768. data/rust/parser/src/build/naming.rs +141 -0
  769. data/rust/parser/src/build/pattern_subset.rs +161 -0
  770. data/rust/parser/src/build/query_derive.rs +72 -0
  771. data/rust/parser/src/build/query_inference.rs +269 -0
  772. data/rust/parser/src/build/query_options.rs +100 -0
  773. data/rust/parser/src/build/read_model.rs +94 -0
  774. data/rust/parser/src/build/references.rs +32 -0
  775. data/rust/parser/src/canonical.rs +114 -0
  776. data/rust/parser/src/diag.rs +55 -0
  777. data/rust/parser/src/emit.rs +953 -0
  778. data/rust/parser/src/expr/ast_json.rs +147 -0
  779. data/rust/parser/src/expr/evaluator.rs +81 -0
  780. data/rust/parser/src/expr/mod.rs +84 -0
  781. data/rust/parser/src/expr/resolver.rs +497 -0
  782. data/rust/parser/src/ir.rs +387 -0
  783. data/rust/parser/src/keywords.rs +585 -0
  784. data/rust/parser/src/lex.rs +662 -0
  785. data/rust/parser/src/main.rs +252 -0
  786. data/rust/parser/src/parse/aggregate.rs +612 -0
  787. data/rust/parser/src/parse/chapter.rs +517 -0
  788. data/rust/parser/src/parse/command.rs +637 -0
  789. data/rust/parser/src/parse/domain_port.rs +127 -0
  790. data/rust/parser/src/parse/entity.rs +527 -0
  791. data/rust/parser/src/parse/file.rs +67 -0
  792. data/rust/parser/src/parse/hecksagon.rs +231 -0
  793. data/rust/parser/src/parse/lifecycle.rs +162 -0
  794. data/rust/parser/src/parse/mod.rs +1262 -0
  795. data/rust/parser/src/parse/policy.rs +87 -0
  796. data/rust/parser/src/parse/process_manager.rs +305 -0
  797. data/rust/parser/src/parse/query.rs +100 -0
  798. data/rust/parser/src/parse/read_model.rs +214 -0
  799. data/rust/parser/src/parse/value_object.rs +250 -0
  800. data/rust/parser/src/ruby_value.rs +422 -0
  801. data/rust/project/bridging.rb +257 -0
  802. data/rust/project/commands.rb +877 -0
  803. data/rust/project/constraints.rb +86 -0
  804. data/rust/project/dependency_planning.rb +178 -0
  805. data/rust/project/domain_generator.rb +980 -0
  806. data/rust/project/exemplar.rb +148 -0
  807. data/rust/project/expr_emitter.rb +72 -0
  808. data/rust/project/fielded.rb +141 -0
  809. data/rust/project/json_codec.rb +641 -0
  810. data/rust/project/mutations.rb +721 -0
  811. data/rust/project/naming.rb +205 -0
  812. data/rust/project/ports.rb +65 -0
  813. data/rust/project/queries.rb +493 -0
  814. data/rust/project/reactions.rb +317 -0
  815. data/rust/project/read_models.rb +690 -0
  816. data/rust/project/reference_specs.rb +27 -0
  817. data/rust/project/registry.rb +396 -0
  818. data/rust/project/skip_reason.rb +29 -0
  819. data/rust/project/types.rb +225 -0
  820. data/rust/project/write_if_changed.rb +83 -0
  821. data/rust/project.rb +30 -0
  822. data/rust/project_rust_pipeline.rb +383 -0
  823. data/rust/src/exemplar/commands.rs +279 -0
  824. data/rust/src/exemplar/constraints.rs +18 -0
  825. data/rust/src/exemplar/fielded.rs +280 -0
  826. data/rust/src/exemplar/json.rs +277 -0
  827. data/rust/src/exemplar/mod.rs +17 -0
  828. data/rust/src/exemplar/mutations.rs +80 -0
  829. data/rust/src/exemplar/queries.rs +33 -0
  830. data/rust/src/exemplar/reactions.rs +88 -0
  831. data/rust/src/exemplar/read_models.rs +48 -0
  832. data/rust/src/exemplar/registry.rs +166 -0
  833. data/rust/src/exemplar/types.rs +44 -0
  834. data/rust/src/kernel/attribute_shapes/composite.rs +88 -0
  835. data/rust/src/kernel/attribute_shapes/list.rs +18 -0
  836. data/rust/src/kernel/attribute_shapes/mod.rs +44 -0
  837. data/rust/src/kernel/attribute_shapes/optional.rs +9 -0
  838. data/rust/src/kernel/attribute_shapes/scalar.rs +39 -0
  839. data/rust/src/kernel/cli.rs +585 -0
  840. data/rust/src/kernel/dispatch.rs +1090 -0
  841. data/rust/src/kernel/expr.rs +458 -0
  842. data/rust/src/kernel/expression_operators/arithmetic.rs +128 -0
  843. data/rust/src/kernel/expression_operators/comparison.rs +48 -0
  844. data/rust/src/kernel/expression_operators/enumeration.rs +232 -0
  845. data/rust/src/kernel/expression_operators/logical.rs +13 -0
  846. data/rust/src/kernel/expression_operators/membership.rs +18 -0
  847. data/rust/src/kernel/expression_operators/mod.rs +68 -0
  848. data/rust/src/kernel/expression_operators/pattern_match.rs +73 -0
  849. data/rust/src/kernel/expression_operators/positional.rs +126 -0
  850. data/rust/src/kernel/expression_operators/presence.rs +101 -0
  851. data/rust/src/kernel/expression_operators/sign_test.rs +16 -0
  852. data/rust/src/kernel/expression_operators/sized.rs +35 -0
  853. data/rust/src/kernel/expression_operators/text.rs +79 -0
  854. data/rust/src/kernel/expression_operators/to_string.rs +18 -0
  855. data/rust/src/kernel/json.rs +779 -0
  856. data/rust/src/kernel/mod.rs +133 -0
  857. data/rust/src/kernel/named_query.rs +219 -0
  858. data/rust/src/kernel/orchestrate.rs +1810 -0
  859. data/rust/src/kernel/pattern.rs +307 -0
  860. data/rust/src/kernel/query_comparators.rs +206 -0
  861. data/rust/src/kernel/query_ordering.rs +103 -0
  862. data/rust/src/kernel/read_model.rs +914 -0
  863. data/rust/src/kernel/reference_lookup.rs +149 -0
  864. data/rust/src/kernel/repository.rs +468 -0
  865. data/rust/src/kernel/routing.rs +612 -0
  866. data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +118 -0
  867. data/rust/src/kernel/vocab/entity_dispatch_order.rs +114 -0
  868. data/rust/src/kernel/vocab/field_hint.rs +70 -0
  869. data/rust/src/kernel/vocab/mod.rs +20 -0
  870. data/rust/src/kernel/vocab/query_comparator.rs +65 -0
  871. data/rust/src/kernel/vocab/refusal_template.rs +1592 -0
  872. data/rust/src/lib.rs +8 -0
  873. data/rust/src/main.rs +16 -0
  874. data/rust/web/.gitignore +1 -0
  875. data/rust/web/Cargo.lock +119 -0
  876. data/rust/web/Cargo.toml +18 -0
  877. data/rust/web/src/lib.rs +8 -0
  878. metadata +478 -12
  879. data/lib/hecks/facade/cli_door.rb +0 -178
  880. data/lib/hecks/facade/cli_runner.rb +0 -271
  881. data/lib/hecks/facade/handle.rb +0 -293
  882. data/lib/hecks/facade/json_door.rb +0 -247
  883. data/lib/hecks/facade/surface/aggregate_door.rb +0 -222
  884. data/lib/hecks/facade/surface/chapter.rb +0 -116
  885. data/lib/hecks/facade/surface.rb +0 -61
  886. data/lib/hecks/mcp_door_scope.rb +0 -176
@@ -1,22 +1,15 @@
1
1
  require "json"
2
2
  require_relative "commands"
3
3
  require_relative "git"
4
+ require_relative "clean_tree"
4
5
 
5
6
  module Hecks
6
7
  module Release
7
8
  class Runner
8
- # The checks that run before a release does anything: the tools are
9
- # installed, the checkout is a clean, current `main`, the gem and the
10
- # JavaScript client agree on a version, and the changelog names it.
11
- #
12
- # Every refusal says what to do about it.
9
+ # The checks that run before a release does anything: tools installed, a
10
+ # clean current `main`, matching versions, and a changelog entry.
13
11
  class Preflight
14
- # What the checks learned about the release.
15
- #
16
- # @!attribute [r] version
17
- # @return [String] the version `lib/hecks/version.rb` declares
18
- # @!attribute [r] sha
19
- # @return [String] the commit `HEAD` points at, which is also `origin/main`
12
+ # What the checks learned; `sha` is also `origin/main`, enforced by check_current.
20
13
  Facts = Struct.new(:version, :sha, keyword_init: true)
21
14
 
22
15
  INSTALL_HINTS = {
@@ -28,11 +21,8 @@ module Hecks
28
21
  }.freeze
29
22
  VERSION_LINE = /^\s*VERSION\s*=\s*"(?<version>[^"]+)"/
30
23
  CLIENT_PACKAGE = "packages/hecks-client/package.json".freeze
24
+ HOST_RELEASE_FILE = "rust/host/HECKS_RELEASE".freeze
31
25
 
32
- # @param root [String] the repository root
33
- # @param commands [#capture] runs the tool probes
34
- # @param git [Git] the repository the release is cut from
35
- # @param tools [Array<String>] the executables the release needs on PATH
36
26
  def initialize(root:, commands:, git:, tools:)
37
27
  @root = root
38
28
  @commands = commands
@@ -40,10 +30,15 @@ module Hecks
40
30
  @tools = tools
41
31
  end
42
32
 
43
- # Runs every check.
33
+ # Refuses when a tool the release runs is not installed.
44
34
  #
45
- # @return [Facts] the version and commit the release is cut from
46
- # @raise [Refusal] on the first check that fails, naming the fix
35
+ # @return [void]
36
+ # @raise [Refusal] naming the tool and how to install it
37
+ def check_tools!
38
+ check_tools
39
+ end
40
+
41
+ # Runs every check; the first refusal stops it.
47
42
  def check!
48
43
  check_tools
49
44
  check_branch
@@ -51,6 +46,7 @@ module Hecks
51
46
  check_clean
52
47
  version = declared_version
53
48
  check_client_version(version)
49
+ check_host_release(version)
54
50
  check_changelog(version)
55
51
  Facts.new(version: version, sha: git("rev-parse", "HEAD").strip)
56
52
  end
@@ -85,9 +81,11 @@ module Hecks
85
81
  end
86
82
 
87
83
  def check_clean
88
- return if git("status", "--porcelain").strip.empty?
84
+ unless git("status", "--porcelain").strip.empty?
85
+ raise Refusal, "the working tree has uncommitted changes; commit or discard them before releasing"
86
+ end
89
87
 
90
- raise Refusal, "the working tree has uncommitted changes; commit or discard them before releasing"
88
+ CleanTree.new(git: @git).check!
91
89
  end
92
90
 
93
91
  def declared_version
@@ -104,6 +102,17 @@ module Hecks
104
102
  raise Refusal, "packages/hecks-client is at #{client} but Hecks::VERSION is #{version}; bump the package first."
105
103
  end
106
104
 
105
+ # The Rust host reports the Hecks release it was built for from this file, and the
106
+ # committed-approval gate compares rehearsals against it.
107
+ def check_host_release(version)
108
+ path = File.join(@root, HOST_RELEASE_FILE)
109
+ host = File.exist?(path) ? File.read(path).strip : nil
110
+ return if host == version
111
+
112
+ raise Refusal, "#{HOST_RELEASE_FILE} says #{host.inspect} but Hecks::VERSION is #{version}; " \
113
+ "write #{version} into it in the release PR."
114
+ end
115
+
107
116
  def check_changelog(version)
108
117
  return if File.read(File.join(@root, "CHANGELOG.md")).match?(/^## \[#{Regexp.escape(version)}\]/)
109
118
 
@@ -1,5 +1,6 @@
1
- require "json"
2
1
  require_relative "commands"
2
+ require "hecks/hecks/adapters/codebase/gem_registry"
3
+ require "hecks/hecks/adapters/codebase/npm_registry"
3
4
 
4
5
  module Hecks
5
6
  module Release
@@ -7,16 +8,14 @@ module Hecks
7
8
  # Asks the registries whether a version is already out, so a re-run of the
8
9
  # release skips what an earlier run finished.
9
10
  #
10
- # Neither question needs credentials.
11
+ # Neither question needs credentials. The registries themselves are the GemRegistry and
12
+ # NpmRegistry adapters.
11
13
  class Published
12
- GEM_VERSIONS_URL = "https://rubygems.org/api/v1/versions/hecks.json".freeze
13
- NPM_PACKAGE = "@hecks/client".freeze
14
-
15
14
  # @param root [String] the repository root
16
15
  # @param commands [#capture] runs curl and npm
17
16
  def initialize(root:, commands:)
18
- @root = root
19
- @commands = commands
17
+ @gems = Hecks::Adapters::Codebase::GemRegistry.new(root: root, commands: commands)
18
+ @npm = Hecks::Adapters::Codebase::NpmRegistry.new(root: root, commands: commands)
20
19
  end
21
20
 
22
21
  # Says whether RubyGems lists the hecks gem at a version.
@@ -24,31 +23,14 @@ module Hecks
24
23
  # @param version [String] the version to look for
25
24
  # @return [Boolean] true when it is published
26
25
  # @raise [Refusal] if RubyGems cannot be reached or answers with something unreadable
27
- def gem?(version)
28
- result = @commands.capture("curl", "-fsS", GEM_VERSIONS_URL, chdir: @root)
29
- unless result.success?
30
- raise Refusal, "could not list published hecks versions (#{result.stderr.strip}); " \
31
- "check the network and re-run"
32
- end
33
-
34
- JSON.parse(result.stdout).any? { |entry| entry["number"] == version }
35
- rescue JSON::ParserError
36
- raise Refusal, "RubyGems answered with something other than a version list; re-run in a minute"
37
- end
26
+ def gem?(version) = @gems.published?(version)
38
27
 
39
28
  # Says whether npm lists @hecks/client at a version.
40
29
  #
41
30
  # @param version [String] the version to look for
42
31
  # @return [Boolean] true when it is published
43
32
  # @raise [Refusal] if npm fails for any reason other than the version not existing
44
- def npm?(version)
45
- result = @commands.capture("npm", "view", "#{NPM_PACKAGE}@#{version}", "version", chdir: @root)
46
- return result.stdout.strip == version if result.success?
47
- return false if result.stderr.include?("E404")
48
-
49
- raise Refusal, "could not check npm for #{NPM_PACKAGE}@#{version} (#{result.stderr.strip.lines.first}); " \
50
- "check the network and re-run"
51
- end
33
+ def npm?(version) = @npm.published?(version)
52
34
  end
53
35
  end
54
36
  end
@@ -7,35 +7,54 @@ module Hecks
7
7
  # Makes sure the release tag `vX.Y.Z` is an annotated tag on the release
8
8
  # commit and is on origin, creating and pushing it only when it is missing.
9
9
  class Tagger
10
- # @param git [Git] the repository the release is cut from
11
- # @param console [Console] asks before the tag is created or pushed
12
- # @param dry_run [Boolean] report what would happen and change nothing
13
10
  def initialize(git:, console:, dry_run:)
14
11
  @git = git
15
12
  @console = console
16
13
  @dry_run = dry_run
14
+ @changed = false
17
15
  end
18
16
 
19
- # Brings the tag to the state described above, saying what it did.
17
+ # @return [Boolean] whether this run created or pushed the tag, for real
18
+ def changed?
19
+ @changed
20
+ end
21
+
22
+ # Brings the tag to the state described above, saying what it did; returns
23
+ # false only when the person declined the confirmation.
20
24
  #
21
- # @param facts [Preflight::Facts] the version and commit being released
22
- # @return [Boolean] false when the person declined the question, true otherwise
23
- # @raise [Refusal] if the tag already points at another commit, locally or on origin
24
- # @raise [CommandFailed] if creating or pushing the tag fails
25
- def ensure!(facts)
25
+ # @param facts [#version, #sha] the release
26
+ # @param note [String, nil] what pushing the tag sets off, worded into the question
27
+ def ensure!(facts, note: nil)
26
28
  tag = "v#{facts.version}"
27
29
  local = local_commit(tag)
28
30
  remote = remote_commit(tag)
29
31
  refuse_elsewhere(tag, facts.sha, local: local, remote: remote)
30
32
  return true.tap { already_there(tag) } if remote
31
33
  return true.tap { preview(tag, facts.sha, local) } if @dry_run
32
- return false unless @console.confirm?(question(tag, facts.sha, local))
34
+ return false unless @console.confirm?(question(tag, facts.sha, local, note))
33
35
 
34
36
  create(tag, facts.sha) unless local
35
37
  push(tag)
38
+ @changed = true
36
39
  true
37
40
  end
38
41
 
42
+ # @param tag [String] the tag, such as `v3.0.0`
43
+ # @return [String, nil] the commit the tag points at in this checkout, or nil when absent
44
+ def local_commit(tag)
45
+ result = @git.capture("rev-parse", "-q", "--verify", "refs/tags/#{tag}^{commit}")
46
+ result.success? ? result.stdout.strip : nil
47
+ end
48
+
49
+ # @param tag [String] the tag, such as `v3.0.0`
50
+ # @return [String, nil] the commit the tag points at on origin, or nil when it is not there
51
+ # @raise [Refusal] when the remote's tags cannot be listed
52
+ def remote_commit(tag)
53
+ listing = @git.read("ls-remote", "--tags", "origin", "refs/tags/#{tag}", "refs/tags/#{tag}^{}")
54
+ shas = listing.lines.to_h { |line| line.split.then { |sha, ref| [ref, sha] } }
55
+ shas.fetch("refs/tags/#{tag}^{}") { shas["refs/tags/#{tag}"] }
56
+ end
57
+
39
58
  private
40
59
 
41
60
  def already_there(tag)
@@ -47,9 +66,9 @@ module Hecks
47
66
  @console.say("Would push #{tag} to origin.")
48
67
  end
49
68
 
50
- def question(tag, sha, local)
69
+ def question(tag, sha, local, note)
51
70
  verb = local ? "Push" : "Create and push"
52
- "#{verb} annotated tag #{tag} at #{sha[0, 7]} to origin?"
71
+ "#{verb} annotated tag #{tag} at #{sha[0, 7]} to origin#{" (#{note})" if note}?"
53
72
  end
54
73
 
55
74
  def create(tag, sha)
@@ -70,17 +89,6 @@ module Hecks
70
89
  "and the missing package must be published from a checkout of #{tag}"
71
90
  end
72
91
  end
73
-
74
- def local_commit(tag)
75
- result = @git.capture("rev-parse", "-q", "--verify", "refs/tags/#{tag}^{commit}")
76
- result.success? ? result.stdout.strip : nil
77
- end
78
-
79
- def remote_commit(tag)
80
- listing = @git.read("ls-remote", "--tags", "origin", "refs/tags/#{tag}", "refs/tags/#{tag}^{}")
81
- shas = listing.lines.to_h { |line| line.split.then { |sha, ref| [ref, sha] } }
82
- shas.fetch("refs/tags/#{tag}^{}") { shas["refs/tags/#{tag}"] }
83
- end
84
92
  end
85
93
  end
86
94
  end
@@ -11,39 +11,10 @@ require_relative "runner/ci_publisher"
11
11
  module Hecks
12
12
  module Release
13
13
  # Performs the release once the release PR has merged: tags the merge
14
- # commit, publishes the gem to rubygems.org and gets the JavaScript client
15
- # published to npm.
14
+ # commit, publishes the gem, and gets the JS client published to npm.
16
15
  #
17
- # ## Why it exists
18
- #
19
- # A release is four steps that have to happen in one order, and only
20
- # the contributing guide remembered it. This runs them in that order, refuses to
21
- # start from a checkout that is not the merged `main`, and can be run again:
22
- # it asks the registries what is already published and skips it, so a run
23
- # that died between the gem and the package resumes at the package.
24
- #
25
- # ## Steps
26
- #
27
- # 1. Preflight: tools installed, on a clean `main` equal to `origin/main`,
28
- # the gem and the client at one version, the changelog naming it.
29
- # 2. Published state: which of the gem and the package are already out.
30
- # 3. Tag: an annotated `vX.Y.Z` on the release commit, pushed to origin.
31
- # 4. Gem: `bin/release_gem`, unchanged.
32
- # 5. npm, one of two ways:
33
- # - by default CI publishes: the tag triggers `publish-client.yml`, which
34
- # uses npm trusted publishing, and this waits for the version to appear
35
- # (`--no-wait` skips the wait);
36
- # - with `--npm-local` this publishes from the machine, with a
37
- # bypass-two-factor token 1Password holds: the way to make the first
38
- # publish, before trusted publishing can be configured, and the fallback
39
- # when CI is down.
40
- #
41
- # ## Injectable commands and time
42
- #
43
- # Every process is started through `commands`, any object answering
44
- # `capture(*argv, env:, chdir:)` and `run!(*argv, env:, chdir:)` like
45
- # {Commands}, so a spec drives the whole release with a recorder. The wait for
46
- # CI takes its clock and its pause as callables for the same reason.
16
+ # Idempotent: it asks the registries what is already published and skips
17
+ # it, so a run that died between the gem and the package resumes at the package.
47
18
  class Runner
48
19
  # Which steps to run and how.
49
20
  class Options
@@ -123,9 +94,16 @@ module Hecks
123
94
  # @param err [IO] where refusals and failures are written
124
95
  # @param pause [#call] sleeps for a number of seconds while waiting for CI
125
96
  # @param now [#call] answers the current time in seconds, monotonically, while waiting for CI
97
+ # @param facts [Preflight::Facts, nil] what a caller already checked and cleared (a branch, a
98
+ # clean tree, matching versions, a changelog entry); the release then checks only that its
99
+ # tools are installed, and every rule stays with the caller
126
100
  def initialize(root:, options: Options.new, commands: Commands.new, input: $stdin, out: $stdout, err: $stderr,
127
- pause: ->(seconds) { sleep(seconds) }, now: -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) })
101
+ pause: ->(seconds) { sleep(seconds) }, now: -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) },
102
+ facts: nil)
128
103
  @root = root
104
+ @facts = facts
105
+ @steps = []
106
+ @verified = false
129
107
  @options = options
130
108
  @commands = commands
131
109
  @console = Console.new(input: input, out: out, err: err, assume_yes: options.yes?)
@@ -134,16 +112,28 @@ module Hecks
134
112
  @ci = CiPublisher.new(root: root, published: @published, console: @console, pause: pause, now: now)
135
113
  end
136
114
 
115
+ # @return [Array<Symbol>] the steps this run carried out for real: `:tagged`, `:gem`, `:npm`
116
+ attr_reader :steps
117
+
118
+ # @return [Boolean] whether, after a real run, every registry in scope lists the version
119
+ attr_reader :verified
120
+
137
121
  # Runs the release.
138
122
  #
139
123
  # @return [Integer] 0 when the release finished or had nothing to do, 1 when a check refused,
140
124
  # a step failed, CI's publish did not arrive in time or a confirmation was declined
141
125
  def call
142
- facts = Preflight.new(root: @root, commands: @commands, git: @git, tools: tools).check!
126
+ facts = preflight
143
127
  pending = pending_steps(facts.version)
144
128
  require_workflow(pending)
145
- return declined unless Tagger.new(git: @git, console: @console, dry_run: @options.dry_run).ensure!(facts)
129
+ # Nothing is tagged or pushed until the person has agreed to the publish: the tag push
130
+ # is what starts CI's npm publish.
131
+ return declined unless @options.dry_run || pending.empty? || publish_confirmed?(facts.version, pending)
132
+
133
+ tagger = Tagger.new(git: @git, console: @console, dry_run: @options.dry_run)
134
+ return declined unless tagger.ensure!(facts, note: tag_note(facts.version, pending))
146
135
 
136
+ @steps << :tagged if tagger.changed?
147
137
  publish(facts, pending)
148
138
  rescue Refusal, CommandFailed => e
149
139
  @console.warn(e.message)
@@ -152,6 +142,14 @@ module Hecks
152
142
 
153
143
  private
154
144
 
145
+ def preflight
146
+ check = Preflight.new(root: @root, commands: @commands, git: @git, tools: tools)
147
+ return check.check! unless @facts
148
+
149
+ check.check_tools!
150
+ @facts
151
+ end
152
+
155
153
  def tools
156
154
  list = %w[git curl]
157
155
  list << "gem" if @options.gem?
@@ -172,6 +170,11 @@ module Hecks
172
170
  published
173
171
  end
174
172
 
173
+ # The steps this run's flags put in scope, whether or not a registry already lists them.
174
+ def in_scope
175
+ [(:gem if @options.gem?), (:npm if @options.npm?)].compact
176
+ end
177
+
175
178
  def ci_publishes?(pending)
176
179
  pending.include?(:npm) && !@options.npm_local?
177
180
  end
@@ -186,13 +189,19 @@ module Hecks
186
189
  def publish(facts, pending)
187
190
  if pending.empty?
188
191
  @console.say("Nothing to publish for #{facts.version}.")
192
+ @verified = registries_list?(facts.version, in_scope) unless @options.dry_run
189
193
  return 0
190
194
  end
191
- return declined unless @options.dry_run || publish_confirmed?(facts.version, pending)
192
-
193
195
  run_steps(facts.version, pending)
194
196
  end
195
197
 
198
+ # What pushing the tag sets off, for the tag question; nothing when CI publishes nothing.
199
+ def tag_note(version, pending)
200
+ return unless ci_publishes?(pending)
201
+
202
+ "CI then publishes @hecks/client #{version} to npm from the tag, which cannot be undone"
203
+ end
204
+
196
205
  def publish_confirmed?(version, pending)
197
206
  targets = []
198
207
  targets << "hecks #{version} to rubygems.org" if pending.include?(:gem)
@@ -208,29 +217,42 @@ module Hecks
208
217
  publish_gem(version, dry_run) if pending.include?(:gem)
209
218
  return 1 if pending.include?(:npm) && !publish_npm!(version, dry_run, ci_publishes?(pending))
210
219
 
220
+ @verified = registries_list?(version, pending) unless dry_run
221
+
211
222
  @console.say(dry_run ? "Dry run complete; nothing was tagged, pushed or published." : "Released hecks #{version}.")
212
223
  0
213
224
  end
214
225
 
215
226
  def publish_gem(version, dry_run)
216
227
  GemPublisher.new(root: @root, commands: @commands, console: @console).publish!(version, dry_run: dry_run)
228
+ @steps << :gem unless dry_run
229
+ end
230
+
231
+ # Asks each registry a step published to whether it now lists the version.
232
+ def registries_list?(version, pending)
233
+ (!pending.include?(:gem) || @published.gem?(version)) && (!pending.include?(:npm) || @published.npm?(version))
234
+ rescue Refusal
235
+ false
217
236
  end
218
237
 
219
238
  def publish_npm!(version, dry_run, via_ci)
220
239
  return wait_for_ci!(version, dry_run) if via_ci
221
240
 
222
241
  NpmPublisher.new(root: @root, commands: @commands, console: @console).publish!(version, dry_run: dry_run)
242
+ @steps << :npm unless dry_run
223
243
  true
224
244
  rescue CommandFailed => e
225
245
  @console.warn("npm publish failed: #{e.message}")
226
246
  unless dry_run
227
- @console.warn("Finish the release with: bin/release --npm-only --npm-local (published steps are not repeated)")
247
+ @console.warn("Finish the release with: hecks publish --npm-only --npm-local --confirm " \
248
+ "(published steps are not repeated)")
228
249
  end
229
250
  raise
230
251
  end
231
252
 
232
253
  def wait_for_ci!(version, dry_run)
233
254
  arrived = @ci.wait!(version, dry_run: dry_run, wait: @options.wait?)
255
+ @steps << :npm if arrived && !dry_run
234
256
  @console.warn(CiPublisher.timeout_hint(version)) unless arrived
235
257
  arrived
236
258
  end
@@ -1,19 +1,9 @@
1
1
  require "json"
2
2
 
3
3
  module Hecks
4
- # How a value reads inside a refusal, in one place, because a refusal is an
5
- # answer and its wording is contract — pinned byte-for-byte by the corpus.
4
+ # How a value reads inside a refusal; the wording is contract, pinned by the corpus.
6
5
  #
7
- # `inspect` and JSON agree on scalars and disagree on everything composite :
8
- # a hash is `{"cents"=>100}` against `{"cents":100}`, an array is `["a", "b"]`
9
- # against `["a","b"]`. Each such spelling is invisible until a composite
10
- # actually reaches a message, which is why both known cases were found by
11
- # something deliberately passing the wrong shape rather than by review — the
12
- # first by hand in spec/corpus/banking.json, the second by bin/fuzz, at a
13
- # different site, after the first was patched where it was found.
14
- #
15
- # So it lives here rather than in whichever file noticed it, and the house style
16
- # is JSON because that is what every other refusal in the corpus already prints.
6
+ # `inspect` and JSON disagree on composites, so refusals use JSON throughout.
17
7
  module Rendering
18
8
  module_function
19
9
 
@@ -28,20 +18,8 @@ module Hecks
28
18
  when nil then "nil"
29
19
  when Hash, Array then JSON.generate(value)
30
20
  else
31
- # A Hecks::Runtime::Value reaching a refusal message (an
32
- # arithmetic op's own `amount`/`current`, an Admissibility
33
- # `current`, ...) had no case here, falling straight through to
34
- # Ruby's own #inspect and leaking a raw object pointer
35
- # ("#<Hecks::Runtime::Value:0x...>") into an otherwise
36
- # correct domain refusal. Duck-typed on `respond_to?(:to_h)`
37
- # rather than naming `Runtime::Value` directly — `Runtime::Value`
38
- # itself requires this file (`runtime/value.rb`'s own
39
- # `require_relative "../rendering"`), so naming it here would be
40
- # circular. A single-field wrapper (the overwhelming common case
41
- # — an amount, an id, a lifecycle field) unwraps to its bare
42
- # scalar, described recursively; a genuinely multi-field value
43
- # renders as its fields' JSON, same as a bare Hash already does
44
- # two lines up.
21
+ # Duck-typed on `to_h`: naming Runtime::Value here would be circular, since
22
+ # it requires this file. A one-field wrapper unwraps to its bare scalar.
45
23
  if value.respond_to?(:to_h) && !value.is_a?(Hash) && !value.is_a?(Array)
46
24
  fields = value.to_h
47
25
  fields.size == 1 ? describe(fields.values.first) : JSON.generate(fields)
@@ -1,24 +1,15 @@
1
1
  require_relative "../fqn"
2
- require_relative "../facade/handle"
2
+ require_relative "../doors/handle"
3
3
 
4
4
  module Hecks
5
5
  class Router
6
- # Installs optional Ruby syntax over an already-loaded router. FQN
7
- # resolution stays in Router; this object only adapts it to constants and
8
- # method calls.
6
+ # Installs optional Ruby syntax over an already-loaded router; FQN
7
+ # resolution stays in Router, this only adapts it to constants and methods.
9
8
  class NamespaceInstaller
10
- # Returned by the `.options(version:)` method installed on each
11
- # namespace module — forwards any command/query verb called on it
12
- # to the router, pinned to this specific FQN version rather than
13
- # the router's default resolution.
9
+ # Returned by `.options(version:)`; forwards command/query verbs to the
10
+ # router, pinned to this FQN version rather than the router's default.
14
11
  class OptionsProxy
15
- # @param router [Router] router to dispatch resolved calls through
16
- # @param realm [String, nil] realm segment of the FQN this proxy pins
17
- # @param domain [String] domain segment of the FQN this proxy pins
18
- # @param aggregate [String, nil] aggregate segment, or nil for a domain-level query
19
- # @param options [Hash{Symbol => Object}] the `.options(...)` call's keywords; only
20
- # `:version` is accepted
21
- # @raise [ArgumentError] if `options` has a key other than `:version`
12
+ # Only the `:version` keyword is accepted; any other key raises `ArgumentError`.
22
13
  def initialize(router:, realm:, domain:, aggregate:, options:)
23
14
  unknown = options.keys - [:version]
24
15
  raise ArgumentError, "unknown router options: #{unknown.join(', ')}" unless unknown.empty?
@@ -52,16 +43,12 @@ module Hecks
52
43
  end
53
44
  end
54
45
 
55
- # @param router [Router] router whose current routes get Ruby constants and methods
56
46
  def initialize(router)
57
47
  @router = router
58
48
  end
59
49
 
60
- # Installs every current-version route as a namespace constant/method,
61
- # plus the aggregate `find`/`all`/`count`/`events`/`repository` door and
62
- # short `Aggregate.verb` shortcuts.
63
- #
64
- # @return [self]
50
+ # Installs every current-version route as a namespace constant/method, plus
51
+ # the aggregate CRUD door and short `Aggregate.verb` shortcuts.
65
52
  def install!
66
53
  current_entries.each { |entry| install_namespace_entry(entry) }
67
54
  install_shortcuts!
@@ -90,18 +77,8 @@ module Hecks
90
77
  end
91
78
  end
92
79
 
93
- # `.find`/`.all`/`.count`/`.events`/`.repository` — the same read/CRUD
94
- # surface `Facade::Surface::AggregateDoor` gives a plain `Hecks
95
- # .boot`, missing here until now: `install_namespace_entry` above
96
- # installs one method per declared verb, so an aggregate with no
97
- # commands or queries of its own shape (or simply never asked for
98
- # a `find`-shaped query) had no way to look up one record by id
99
- # through the router surface at all — real gap, hit live building
100
- # a `List` aggregate meant to be read this way. Grouped by
101
- # (realm, domain, aggregate) rather than installed per-verb,
102
- # because unlike a command or query this is the same five methods
103
- # regardless of which verb happened to trigger this aggregate's
104
- # own namespace module into existing.
80
+ # `.find`/`.all`/`.count`/`.events`/`.repository`, matching `Hecks.boot`'s
81
+ # door; grouped by (realm, domain, aggregate) since the five don't vary by verb.
105
82
  def install_aggregate_doors!
106
83
  current_entries.reject { |entry| entry.fqn.aggregate.nil? }
107
84
  .group_by { |entry| [entry.fqn.realm, entry.fqn.domain, entry.fqn.aggregate] }
@@ -123,12 +100,12 @@ module Hecks
123
100
 
124
101
  target.define_singleton_method(:find) do |id|
125
102
  found = dispatcher.registry.repository(domain, ir).find(id)
126
- found && Facade::Handle.new(dispatcher: dispatcher, domain: domain, aggregate: ir, instance: found)
103
+ found && Doors::Handle.new(dispatcher: dispatcher, domain: domain, aggregate: ir, instance: found)
127
104
  end
128
105
 
129
106
  target.define_singleton_method(:all) do
130
107
  dispatcher.registry.repository(domain, ir).all.map do |instance|
131
- Facade::Handle.new(dispatcher: dispatcher, domain: domain, aggregate: ir, instance: instance)
108
+ Doors::Handle.new(dispatcher: dispatcher, domain: domain, aggregate: ir, instance: instance)
132
109
  end
133
110
  end
134
111
  end
@@ -138,10 +115,9 @@ module Hecks
138
115
  current_entries.reject { |entry| entry.fqn.aggregate.nil? }
139
116
  .group_by { |entry| [entry.fqn.aggregate, entry.fqn.verb] }
140
117
  .each do |(aggregate, verb), candidates|
141
- # Bounded chapters wrap in their own module (`Domain::Aggregate`)
142
- # so two BCs can both declare `Person` without colliding on
143
- # Object::Person. Folder-spread files of the same chapter still
144
- # get the shortcut — they are not BCs.
118
+ # Bounded chapters wrap in their own module (`Domain::Aggregate`) so two
119
+ # BCs can both declare `Person` without colliding on `Object::Person`.
120
+ # Folder-spread files of the same chapter aren't BCs, so they still get it.
145
121
  next if bounded_chapter?(candidates)
146
122
 
147
123
  shortcut_target(aggregate).define_singleton_method(verb) do |**args|
data/lib/hecks/router.rb CHANGED
@@ -16,8 +16,7 @@ module Hecks
16
16
  # @return [Router] the built router
17
17
  def self.load(root) = new(Bluebook::ProjectLoader.load(root))
18
18
 
19
- # Install one project router for ordinary application calls. The explicit
20
- # `Router.load` API remains useful for tests and embedded hosts.
19
+ # Installs one project router as `.default` for ordinary application calls.
21
20
  #
22
21
  # @param root [String] project root to discover bluebooks under
23
22
  # @return [Router] the booted router, also stored as `.default`
@@ -75,14 +74,12 @@ module Hecks
75
74
  # Dispatches a command to its resolved aggregate.
76
75
  #
77
76
  # @param address [String] a fully-qualified command address, realm included
78
- # @param args [Hash] command facts, plus the dispatcher's optional `:to`, `:with`,
79
- # and `:saga_correlation` keys
77
+ # @param args [Hash] command facts, plus optional `:to`, `:with`, `:saga_correlation`
80
78
  # @return [Runtime::Dispatcher::Result] the dispatch result
81
79
  # @raise [UnknownAddress] if `address` has no realm, or names no known route
82
80
  # @raise [WrongVerbKind] if `address` names a query
83
81
  # @raise [Runtime::UnknownVerb] if the resolved verb names something undeclared
84
- # @raise [StandardError] any class in `Runtime::DOMAIN_REFUSALS` when the domain refuses
85
- # the call
82
+ # @raise [StandardError] any `Runtime::DOMAIN_REFUSALS` class when the domain refuses
86
83
  # @raise [Runtime::StaleWrite] if concurrent writers beat this one through every retry
87
84
  # @raise [Runtime::WiringError] if the aggregate's repository cannot be resolved
88
85
  def dispatch(address, **args)
@@ -97,13 +94,12 @@ module Hecks
97
94
  # @param address [String] a fully-qualified query address, realm included
98
95
  # @param args [Hash{Symbol => Object}] the query's declared arguments
99
96
  # @return [Array<Hash>] one row Hash per match; see `Runtime::Dispatcher#query`
100
- # for the exact shape per address kind
101
97
  # @raise [UnknownAddress] if `address` has no realm, or names no known route
102
98
  # @raise [WrongVerbKind] if `address` names a command
103
99
  # @raise [Runtime::UnknownVerb] if the resolved verb names something undeclared
104
100
  # @raise [Runtime::NotFound] if a read model's root reference names no record
105
101
  # @raise [Runtime::TypeMismatch] if an argument cannot be coerced to its declared type
106
- # @raise [KeyError] if a rooted read model is asked without its reference argument
102
+ # @raise [KeyError] if a rooted read model lacks its reference argument
107
103
  # @raise [Runtime::WiringError] if the aggregate's repository cannot be resolved
108
104
  def query(address, **args)
109
105
  entry = resolve(address)