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
@@ -5,70 +5,73 @@ require_relative "../storage_shape"
5
5
 
6
6
  module Hecks
7
7
  module Translation
8
- # The question re-attestation must answer before anything else: did
9
- # the edit change the era's shape, or only its text? Cosmetic edits
10
- # (comments, whitespace, behavior) re-freeze safely; a shape change
11
- # would retroactively redefine what era N *meant* for data already
12
- # written under it, and refuses hard — there is no --accept past
13
- # this guard.
14
- #
15
- # This does not violate minted-once. That prohibition exists so
16
- # boot-time recognition never depends on canonicalization stability;
17
- # this is operator-initiated repair, where a false negative is a
18
- # loud refusal, never a silent misread.
8
+ # Decides whether an edited era text changed the era's shape or only its text.
9
+ # A shape change refuses hard; no --accept flag gets past it.
19
10
  module Reattest
20
11
  module_function
21
12
 
22
- # Decides whether an edited era text still projects to the shape the era was frozen
23
- # with, refusing the edit when it does not.
13
+ # Says how an edited era text stands against the shape the era was frozen with, without
14
+ # refusing anything: the facts `Era.Permit`'s givens hold, and what `shape_guard!` raises on.
15
+ #
16
+ # @param text [String] the held era's bluebook source as it now stands
17
+ # @param stored_hash [String, nil] the era's minted shape hash (SHA-256 hex); nil if unnamed
18
+ # @param stored_projection [Hash{String => Object}, nil] the stored
19
+ # `Runtime::StorageShape.project` result as parsed JSON; nil when absent
20
+ # @return [Symbol] `:cosmetic` when the shape is unchanged, `:unnamed` when neither a
21
+ # projection nor a hash is stored, `:changed` when the text projects to another shape,
22
+ # `:unloadable` when the text does not load as a bluebook
23
+ def verdict(text:, stored_hash:, stored_projection: nil)
24
+ bluebook = shadow(text)
25
+ return :unloadable unless bluebook
26
+
27
+ # The stored projection is compared first: it is version-free, so a new canonical form
28
+ # cannot make a cosmetic edit look like a shape change. The hash is the fallback.
29
+ if stored_projection
30
+ edited = JSON.parse(JSON.generate(Runtime::StorageShape.project(bluebook)))
31
+ return edited == stored_projection ? :cosmetic : :changed
32
+ end
33
+ return :unnamed unless stored_hash
34
+
35
+ Runtime::StorageShape.mint_hash(bluebook) == stored_hash ? :cosmetic : :changed
36
+ end
37
+
38
+ # Refuses an edited era text that projects to another shape than the era froze with.
24
39
  #
25
40
  # @param domain [String] the domain's name, used in refusal messages
26
41
  # @param ordinal [Integer] the era's ordinal, used in refusal messages
27
42
  # @param text [String] the held era's bluebook source as it now stands
28
- # @param stored_hash [String, nil] the era's minted shape hash (SHA-256 hex); nil for an
29
- # era that was never named
30
- # @param stored_projection [Hash{String => Object}, nil] the era's stored
31
- # `Runtime::StorageShape.project` result as parsed JSON; nil for a store without one
43
+ # @param stored_hash [String, nil] the era's minted shape hash (SHA-256 hex); nil if unnamed
44
+ # @param stored_projection [Hash{String => Object}, nil] the stored
45
+ # `Runtime::StorageShape.project` result as parsed JSON; nil when absent
32
46
  # @return [Symbol] `:cosmetic` when the shape is unchanged, `:unnamed` when neither a
33
- # projection nor a hash is stored so no comparison is possible
34
- # @raise [Runtime::WiringError] if `text` does not load as a bluebook, or it projects to
35
- # a shape other than the stored one
47
+ # projection nor a hash is stored
48
+ # @raise [Runtime::WiringError] if `text` does not load, or projects to another shape
36
49
  def shape_guard!(domain:, ordinal:, text:, stored_hash:, stored_projection: nil)
37
- bluebook = shadow(text)
38
- unless bluebook
50
+ found = verdict(text: text, stored_hash: stored_hash, stored_projection: stored_projection)
51
+ return found if %i[cosmetic unnamed].include?(found)
52
+
53
+ if found == :unloadable
39
54
  raise Runtime::WiringError,
40
55
  "cannot re-attest era #{ordinal} of #{domain}: the edited text does not load as a " \
41
56
  "bluebook — a held era text is bootable source; restore a loadable text"
42
57
  end
58
+ raise Runtime::WiringError, changed_shape_message(domain, ordinal, text, stored_hash, stored_projection)
59
+ end
43
60
 
44
- # The stored projection is the preferred comparison: structural,
45
- # version-free, and the same mechanism every boot trusts — so
46
- # this guard never depends on canonicalization stability, and a
47
- # future canonical-form version cannot make cosmetic edits to
48
- # old-form eras false-refuse as shape changes. The hash path
49
- # survives only as a fallback for stores that predate stored
50
- # projections.
61
+ # The refusal for an edit that changed the era's shape.
62
+ #
63
+ # @return [String] names the minted label when the era was compared by hash
64
+ def changed_shape_message(domain, ordinal, text, stored_hash, stored_projection)
65
+ head = "cannot re-attest era #{ordinal} of #{domain}: the edit changed the era's SHAPE, not just "
66
+ tail = "Attesting would retroactively redefine what era #{ordinal} meant for data already written " \
67
+ "under it; restore a text with the original shape"
51
68
  if stored_projection
52
- edited = JSON.parse(JSON.generate(Runtime::StorageShape.project(bluebook)))
53
- return :cosmetic if edited == stored_projection
54
-
55
- raise Runtime::WiringError,
56
- "cannot re-attest era #{ordinal} of #{domain}: the edit changed the era's SHAPE, not just " \
57
- "its text — the text no longer projects to the shape frozen for era #{ordinal}. " \
58
- "Attesting would retroactively redefine what era #{ordinal} meant for data already written " \
59
- "under it; restore a text with the original shape"
69
+ return "#{head}its text — the text no longer projects to the shape frozen for era #{ordinal}. #{tail}"
60
70
  end
61
- return :unnamed unless stored_hash
62
-
63
- computed = Runtime::StorageShape.mint_hash(bluebook)
64
- return :cosmetic if computed == stored_hash
65
71
 
66
- raise Runtime::WiringError,
67
- "cannot re-attest era #{ordinal} of #{domain}: the edit changed the era's SHAPE, not just " \
68
- "its text — its name #{stored_hash[0, Runtime::StorageShape::LABEL_LENGTH]} was minted from " \
69
- "a different shape (the text now projects to #{computed[0, Runtime::StorageShape::LABEL_LENGTH]}). " \
70
- "Attesting would retroactively redefine what era #{ordinal} meant for data already written " \
71
- "under it; restore a text with the original shape"
72
+ label = Runtime::StorageShape::LABEL_LENGTH
73
+ "#{head}its text — its name #{stored_hash[0, label]} was minted from a different shape (the text " \
74
+ "now projects to #{Runtime::StorageShape.mint_hash(shadow(text))[0, label]}). #{tail}"
72
75
  end
73
76
 
74
77
  # Parses bluebook source in a scratch registry, through a temporary file that is
@@ -2,37 +2,13 @@ require "json"
2
2
 
3
3
  module Hecks
4
4
  module Translation
5
- # The closed, pure half of Postgres's own SQL compiler
6
- # (ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb)
7
- # — the part that turns one TranslationAggregate's declared rules into
8
- # a jsonb-transforming SQL expression. No database connection, no
9
- # watermark, no era chain, no catalog lookup: those live in
10
- # head_compiler.rb's own per-mint assembly, which calls into this
11
- # module instead of defining these methods itself.
12
- #
13
- # A module of its own — not private methods on
14
- # Adapters::PostgresEra::Lineage — so a second, adapter-agnostic
15
- # caller (Exporter.translation_aggregate's build-time SQL export,
16
- # feeding rust/host's own future boot-time mint) can call the exact
17
- # same code Ruby's own mint path runs, not a hand-ported duplicate
18
- # that could silently drift the way a hand-kept
19
- # `Exporter.translation_hash` can drift from `hecks_eras`/
20
- # `hecks_approvals`' real schema (leaving out rekeys and backfills).
5
+ # Compiles one TranslationAggregate's declared rules into a jsonb-transforming SQL
6
+ # expression, shared by Ruby's own mint path and any other SQL-emitting caller.
21
7
  module RuleCompiler
22
8
  module_function
23
9
 
24
- # One edge's rules over one jsonb state, compiled as a nested
25
- # expression tree — hecks_tr_* helpers composed innermost-first
26
- # in the reference transform's phase order (renames, moves,
27
- # converts, drops), computes last. `retype` compiles to nothing:
28
- # stored state never carries a type name.
29
- # Compiles a declared edge's rename/move/convert/drop/compute rules into one nested SQL
30
- # expression over the `state` jsonb column.
31
- #
32
- # @param declared [Bluebook::TranslationAggregate] this edge's declared rules for one
33
- # aggregate
34
- # @return [String] a SQL expression, `"state"` unchanged when `declared` declares none
35
- # of the five rule kinds
10
+ # Compiles one edge's rename/move/convert/drop/compute/backfill rules into a nested
11
+ # SQL expression over `state`, composed innermost-first in that phase order.
36
12
  def compile_rules(declared)
37
13
  expression = "state"
38
14
  declared.renames.each do |old_name, new_name|
@@ -54,85 +30,33 @@ module Hecks
54
30
  declared.computes.each do |compute|
55
31
  expression = compile_compute(expression, compute)
56
32
  end
57
- # Backfills last, same order `Lineage#translate` already applies
58
- # in-process (that method's own comment: "only where nothing
59
- # already answered") — now compiled here too, closing the gap
60
- # this rule kind otherwise leaves: `rust/host`'s boot-time mint
61
- # audit reads this exact compiled expression, never
62
- # `Lineage#translate`, so it cannot see a backfilled value unless
63
- # backfills compile to SQL like every other rule kind here. A
64
- # real, live gap for any new required value-object member with no
65
- # source data at all — `compute` cannot fill it either, since its
66
- # own guard requires a real, already-present field to consume
67
- # (found live: a client site's Attendee redesign, commit 4326dcd,
68
- # needed exactly this and had nothing that worked).
33
+ # Backfilled last, same order as `Lineage#translate`'s in-process pass, so the
34
+ # boot-time mint audit (which reads only this compiled SQL) sees the same result.
69
35
  declared.backfills.each do |backfill|
70
36
  expression = compile_backfill(expression, backfill)
71
37
  end
72
38
  expression
73
39
  end
74
40
 
75
- # Whether this edge's declared rules for this aggregate include a
76
- # rekey — checked directly off the raw IR object, the same way
77
- # every other rule kind is already read in `compile_rules`
78
- # (`declared.computes`, `declared.moves`, ...), not through the
79
- # `Ports::Persistence::Lineage` wrapper the app-level consumers
80
- # (coverage_check.rb, minter.rb, layer_two.rb) go through — this
81
- # module builds SQL straight off the IR either way.
82
- # Reports whether an edge's declared rules for an aggregate include a rekey.
83
- #
84
- # @param declared [Bluebook::TranslationAggregate, nil] this edge's declared rules for
85
- # one aggregate; nil for an aggregate the edge declares nothing about
86
- # @return [Boolean] true when `declared` is present and its `rekeys` is non-empty
41
+ # Reports whether an edge's declared rules for an aggregate include a rekey, read
42
+ # directly off the raw IR like every other rule kind `compile_rules` checks.
87
43
  def rekeyed?(declared) = declared && !declared.rekeys.empty?
88
44
 
89
- # The only two places `aggregate_id` needs to change — guarded so
90
- # the generated SQL for the overwhelming common case (no rekey
91
- # declared) stays the bare `aggregate_id` passthrough it always
92
- # was — this case only appears in an edge that actually declares
93
- # one.
94
- #
95
- # @param guard [String] a SQL boolean expression gating when the rekey applies, such as
96
- # `"operation = 'save'"`
97
- # @param declared [Bluebook::TranslationAggregate] this edge's declared rules; must
98
- # declare a rekey (`rekeyed?(declared)` true)
99
- # @return [String] a `"CASE WHEN ... END AS aggregate_id"` SQL expression
45
+ # Builds a `CASE WHEN ... END AS aggregate_id` expression that only overrides
46
+ # `aggregate_id` when `guard` matches, leaving the common no-rekey case untouched.
100
47
  def id_case(guard, declared)
101
48
  "CASE WHEN #{guard} THEN #{compile_id_expression(declared)} ELSE aggregate_id END AS aggregate_id"
102
49
  end
103
50
 
104
- # The rekey's own SQL — reading `state` directly, not the
105
- # progressively-built `expression` chain `compile_compute` reads
106
- # from. A rekey doesn't consume or move any field the way a move
107
- # or compute does, so there is no same-edge rename/move ordering
108
- # it needs to see first — it reads the record's stored fields
109
- # exactly as they already are, the same `__s` convention
110
- # `compile_compute` exposes.
111
- #
112
- # @param declared [Bluebook::TranslationAggregate] this edge's declared rules; its
113
- # first `rekeys` entry supplies the SQL
114
- # @return [String] a SQL expression evaluating the rekey's own SQL against the record's
115
- # current `state`
51
+ # Evaluates a rekey's own SQL against the record's current `state`, read directly
52
+ # rather than through `compile_rules`'s progressively-built expression chain.
116
53
  def compile_id_expression(declared)
117
54
  rekey = declared.rekeys.first
118
55
  "(SELECT (#{rekey.sql}) FROM (SELECT (state) AS __s) __outer)"
119
56
  end
120
57
 
121
- # A compute is the one rule whose SQL is its only implementation
122
- # — evaluated exclusively inside the compiled head, never
123
- # in-process. The source is read as a path through
124
- # `hecks_tr_extract`, bare or a dotted value-object member alike,
125
- # the same way the destination goes through `path_literal`. The
126
- # source's value is exposed to the author's SQL as text under a
127
- # column named by the source exactly as declared (`price_cents`,
128
- # or `"price.cents"` for a dotted member), and the whole record
129
- # stays readable as `__s`.
130
- #
131
- # @param expression [String] the SQL expression built so far by `compile_rules`, read as
132
- # `__s` inside the compute's own SQL
133
- # @param compute [Bluebook::TranslationCompute] the declared compute rule
134
- # @return [String] `expression` wrapped so the compute's field lands at its declared
135
- # destination when the source path is present, unchanged otherwise
58
+ # Wraps `expression` so a compute's SQL result lands at its declared destination
59
+ # when the source path is present; the whole record stays readable as `__s`.
136
60
  def compile_compute(expression, compute)
137
61
  from = compute.from.to_s
138
62
  to = compute.to.to_s
@@ -145,23 +69,8 @@ module Hecks
145
69
  "LATERAL (SELECT (__s #>> #{path_literal(from)}) AS #{quote(from)}) __fields)"
146
70
  end
147
71
 
148
- # A newly added, required attribute with no source at all — the
149
- # addition-side sibling of `compile_compute`'s own header, but with
150
- # no field to consume: `hecks_tr_extract`'s own `.present` flag
151
- # (already installed for `hecks_tr_drop`/`hecks_tr_move`/
152
- # `hecks_tr_convert` — no new database function needed) answers
153
- # "is this path — bare or a dotted value-object member alike —
154
- # already there," and `hecks_tr_insert` (already merge-safe: it
155
- # creates a missing intermediate container without disturbing any
156
- # sibling member already in it) fills it only when it is not, the
157
- # exact "never overwrites a value already there" rule `Lineage#
158
- # translate`'s own in-process backfill already holds itself to.
159
- #
160
- # @param expression [String] the SQL expression built so far by `compile_rules`, read as
161
- # `__s` inside this backfill's own check
162
- # @param backfill [Bluebook::TranslationBackfill] the declared backfill rule
163
- # @return [String] `expression` wrapped so the backfill's default lands at its declared
164
- # path when nothing is there yet, unchanged otherwise
72
+ # Wraps `expression` so a backfill's default lands at its declared path only when
73
+ # nothing is already there, the same rule `Lineage#translate`'s own pass holds to.
165
74
  def compile_backfill(expression, backfill)
166
75
  name = backfill.name.to_s
167
76
  default_json = JSON.generate(backfill.default)
@@ -171,32 +80,17 @@ module Hecks
171
80
  "FROM (SELECT (#{expression}) AS __s) __outer)"
172
81
  end
173
82
 
174
- # `PG::Connection.quote_ident` needs the `pg` gem loaded, not
175
- # connected — required here, lazily, the same "a domain that
176
- # never wires PostgresEra should never need the gem" reasoning
177
- # `PostgresEra.connect_for`'s own `require "pg"` already holds
178
- # itself to, so a build tool that exports translations for a
179
- # non-Postgres-bound domain (there are none today, but nothing
180
- # here should assume there never will be) doesn't gain a hard
181
- # dependency on `pg` just by loading this file.
182
- #
183
- # @param name [String, Symbol] the identifier to quote
184
- # @return [String] `name` as a double-quoted Postgres identifier
83
+ # Quotes a Postgres identifier; requires "pg" lazily so a non-Postgres-bound
84
+ # domain never gains a hard dependency on the gem just by loading this file.
185
85
  def quote(name)
186
86
  require "pg"
187
87
  PG::Connection.quote_ident(name.to_s)
188
88
  end
189
89
 
190
90
  # Renders a Ruby value as a single-quoted SQL text literal, escaping embedded quotes.
191
- #
192
- # @param text [String, Symbol, Object] the value to render; converted with `to_s`
193
- # @return [String] a single-quoted SQL literal
194
91
  def text_literal(text) = "'#{text.to_s.gsub("'", "''")}'"
195
92
 
196
93
  # Renders a dotted path as a SQL `text[]` array literal, one element per segment.
197
- #
198
- # @param path [String, Symbol] a bare or dotted path, such as `"price.cents"`
199
- # @return [String] a SQL `ARRAY[...]::text[]` expression
200
94
  def path_literal(path)
201
95
  segments = path.to_s.split(".").map { |segment| text_literal(segment) }
202
96
  "ARRAY[#{segments.join(', ')}]::text[]"
@@ -3,18 +3,16 @@ require_relative "../../storage_shape"
3
3
  module Hecks
4
4
  module Translation
5
5
  module Scaffold
6
- # Diff two eras' storage-shape projections into the edge's
7
- # declarations — confident rules by unique signature pairing,
8
- # everything ambiguous left unresolved for a human.
6
+ # Diffs two eras' storage shapes into the edge's declarations; rules are written only
7
+ # for unique signature pairs, everything else is left unresolved.
9
8
  module Differ
10
- # Diff two bluebook IRs into the edge's declarations.
9
+ # Diffs two bluebook IRs into the edge's declarations.
11
10
  #
12
11
  # @param held_bluebook [Bluebook::Chapter] the era being translated from
13
12
  # @param current_bluebook [Bluebook::Chapter] the era being translated to
14
- # @return [Hash{Symbol => Object}] `:aggregates` (Array<Scaffold::ScaffoldedAggregate>,
15
- # one per matched aggregate carrying a rename or a rule), `:retired` (Array<String>,
16
- # vanished aggregate names with no successor), `:unclaimed` (Array<String>, vanished
17
- # aggregate names left ambiguous)
13
+ # @return [Hash{Symbol => Object}] `:aggregates` (Array<Scaffold::ScaffoldedAggregate>),
14
+ # `:retired` (Array<String>, vanished names with no successor), `:unclaimed`
15
+ # (Array<String>, vanished names left ambiguous)
18
16
  def diff(held_bluebook, current_bluebook)
19
17
  held_shapes = projections(held_bluebook)
20
18
  current_shapes = projections(current_bluebook)
@@ -34,31 +32,19 @@ module Hecks
34
32
  { aggregates: aggregates, retired: matched[:retired], unclaimed: matched[:unclaimed] }
35
33
  end
36
34
 
37
- # Projects a bluebook's storage shape and indexes its aggregates by name.
38
- #
39
- # @param bluebook [Bluebook::Chapter] the bluebook to project
40
- # @return [Hash{String => Hash}] the bluebook's storage-shape aggregates (see
41
- # `Runtime::StorageShape.project`), keyed by aggregate name
35
+ # Projects a bluebook's storage shape, indexing its aggregates by name.
42
36
  def projections(bluebook)
43
37
  Runtime::StorageShape.project(bluebook)["aggregates"].to_h { |shape| [shape["name"], shape] }
44
38
  end
45
39
 
46
- # A vanished aggregate whose full shape reappears under exactly one
47
- # new name counts as a rename. `retired` is only confident when nothing
48
- # remains it could plausibly have become — a vanished aggregate
49
- # beside an unmatched new one might be a rename-plus-reshape, and
50
- # writing `retired` there would be a guess that strands data.
51
- # Anything ambiguous stays unclaimed, and the coverage gate names
52
- # it until a human decides.
40
+ # Pairs vanished aggregates with new ones whose full shape reappears under exactly one
41
+ # name. A vanished aggregate is `retired` only when no unmatched new one remains, since
42
+ # it could be a rename-plus-reshape and guessing would strand data.
53
43
  #
54
- # @param held_shapes [Hash{String => Hash}] the held era's aggregate shapes, keyed by
55
- # name (see `projections`)
56
- # @param current_shapes [Hash{String => Hash}] the current era's aggregate shapes,
57
- # keyed by name
58
- # @return [Hash{Symbol => Object}] `:pairs` (Hash{String => String, nil}, each current
59
- # name to its matched held name, or nil when unmatched), `:retired` (Array<String>,
60
- # vanished names with no successor), `:unclaimed` (Array<String>, vanished names
61
- # left ambiguous)
44
+ # @param held_shapes [Hash{String => Hash}] held aggregate shapes, keyed by name
45
+ # @param current_shapes [Hash{String => Hash}] current aggregate shapes, keyed by name
46
+ # @return [Hash{Symbol => Object}] `:pairs` (current name to held name, or nil),
47
+ # `:retired` (Array<String>), `:unclaimed` (Array<String>)
62
48
  def match_aggregates(held_shapes, current_shapes)
63
49
  pairs = {}
64
50
  current_shapes.each_key { |name| pairs[name] = held_shapes.key?(name) ? name : nil }
@@ -81,20 +67,14 @@ module Hecks
81
67
  { pairs: pairs, retired: retired, unclaimed: retired.empty? ? unclaimed : [] }
82
68
  end
83
69
 
84
- # Every changed path in one aggregate, resolved into rules by
85
- # signature matching over the full path set — top-level names and
86
- # dotted members alike. Unique signature pair: a rename (both
87
- # top-level) or a move (any dotted end). Same path, same members,
88
- # new type name: a retype. Anything else: unresolved, carrying its
89
- # type-compatible candidates (an empty list is the arrow toward
90
- # compute, or drop).
70
+ # Resolves every changed path in one aggregate into rules by signature matching:
71
+ # a unique pair is a rename (both top-level) or a move (any dotted end), same members
72
+ # under a new type name is a retype, anything else is unresolved with its candidates.
91
73
  #
92
- # @param held_shape [Hash{String => Object}] the held era's aggregate shape (see
93
- # `projections`)
74
+ # @param held_shape [Hash{String => Object}] the held era's aggregate shape
94
75
  # @param current_shape [Hash{String => Object}] the current era's aggregate shape
95
- # @return [Array<Hash{Symbol => Object}>] one rule Hash per changed path — `:kind`
96
- # plus `:from`/`:to` for `:rename`/`:move`/`:retype`, or `:from`/`:candidates` for
97
- # `:unresolved` (see `Renderer#render_rule`); `[]` when nothing changed
76
+ # @return [Array<Hash{Symbol => Object}>] one rule per changed path (see
77
+ # `Renderer#render_rule`); `[]` when nothing changed
98
78
  def attribute_rules(held_shape, current_shape)
99
79
  rules = []
100
80
  rules << identity_hint(held_shape, current_shape)
@@ -108,26 +88,13 @@ module Hecks
108
88
  vanished = vanished_paths(held_attrs, current_attrs, retyped)
109
89
  appeared = appeared_paths(held_attrs, current_attrs, retyped)
110
90
 
111
- # Mutates `rules` in place (not build-and-concat, like the two
112
- # passes above) because it must read its own earlier writes:
113
- # `taken`, below, is recomputed from `rules` at the top of every
114
- # iteration, so a target this same loop already claimed for an
115
- # earlier vanished path is excluded from a later one. Passing a
116
- # snapshot instead of the live array would let two vanished
117
- # paths both match the same appeared target.
91
+ # Mutates `rules` in place: each iteration must see targets claimed by earlier ones,
92
+ # or two vanished paths could match the same appeared target.
118
93
  resolve_vanished_rules!(rules, vanished, appeared)
119
94
  rules
120
95
  end
121
96
 
122
- # retype pass: same attribute name, same member structure, the
123
- # type's own name changed
124
- #
125
- # @param held_attrs [Hash{String => Hash}] the held era's attributes, keyed by name
126
- # @param current_attrs [Hash{String => Hash}] the current era's attributes, keyed by
127
- # name
128
- # @return [Array<Hash{Symbol => String}>] one `{kind: :retype, from:, to:}` rule per
129
- # attribute whose members are unchanged but whose type name changed; `[]` when none
130
- # match
97
+ # Retype rules for attributes whose members are unchanged but whose type name changed.
131
98
  def retype_rules(held_attrs, current_attrs)
132
99
  (held_attrs.keys & current_attrs.keys).filter_map do |name|
133
100
  held = held_attrs[name]
@@ -140,16 +107,7 @@ module Hecks
140
107
  end
141
108
  end
142
109
 
143
- # Resolves each vanished path into a rename, move or unresolved rule, appended to
144
- # `rules` in place.
145
- #
146
- # @param rules [Array<Hash{Symbol => Object}>] the rule list to append to; also read
147
- # for `:rename`/`:move` targets an earlier iteration already claimed
148
- # @param vanished [Hash{String => Object}] vanished paths to type signature (see
149
- # `vanished_paths`)
150
- # @param appeared [Hash{String => Object}] appeared paths to type signature (see
151
- # `appeared_paths`)
152
- # @return [void]
110
+ # Resolves each vanished path into a rename, move or unresolved rule appended to `rules`.
153
111
  def resolve_vanished_rules!(rules, vanished, appeared)
154
112
  vanished.each do |path, signature|
155
113
  matches = appeared.select { |_, candidate| candidate == signature }.keys
@@ -166,18 +124,9 @@ module Hecks
166
124
  end
167
125
  end
168
126
 
169
- # Held paths that need explaining: whole attributes that vanished,
170
- # and members that vanished (or changed type) inside a kept
171
- # attribute — mirroring exactly what EraGuard will demand coverage
172
- # for.
173
- #
174
- # @param held_attrs [Hash{String => Hash}] the held era's attributes, keyed by name
175
- # @param current_attrs [Hash{String => Hash}] the current era's attributes, keyed by
176
- # name
177
- # @param retyped [Array<String>] type names already claimed by a `:retype` rule,
178
- # excluded here
179
- # @return [Hash{String => Object}] each vanished or changed path, dotted for a member,
180
- # valued by that path's type signature
127
+ # Held paths that need explaining: vanished attributes, and members that vanished or
128
+ # changed type inside a kept attribute — the set EraGuard demands coverage for.
129
+ # Returns each path (dotted for a member) valued by its type signature.
181
130
  def vanished_paths(held_attrs, current_attrs, retyped)
182
131
  paths = {}
183
132
  held_attrs.each do |name, held|
@@ -199,17 +148,7 @@ module Hecks
199
148
  paths
200
149
  end
201
150
 
202
- # Current paths that need explaining: whole attributes that appeared, and members
203
- # that appeared (or changed type) inside a kept attribute — the mirror of
204
- # `vanished_paths`.
205
- #
206
- # @param held_attrs [Hash{String => Hash}] the held era's attributes, keyed by name
207
- # @param current_attrs [Hash{String => Hash}] the current era's attributes, keyed by
208
- # name
209
- # @param retyped [Array<String>] type names already claimed by a `:retype` rule,
210
- # excluded here
211
- # @return [Hash{String => Object}] each appeared or changed path, dotted for a
212
- # member, valued by that path's type signature
151
+ # Current paths that need explaining; the mirror of `vanished_paths`.
213
152
  def appeared_paths(held_attrs, current_attrs, retyped)
214
153
  paths = {}
215
154
  current_attrs.each do |name, current|
@@ -230,58 +169,30 @@ module Hecks
230
169
  paths
231
170
  end
232
171
 
233
- # The one thing `attribute_rules` could not see before — the shape
234
- # projection already carries `"identity"` (`StorageShape
235
- # .project_aggregate`), it was simply never read here. An
236
- # unresolved placeholder, not a guess: `coverage_check.rb`'s own
237
- # `check_identity_unchanged!` is the real gate this only hints
238
- # toward, the same "tool proactively guides you" pattern the
239
- # generic unresolved message already gives unfed fields.
240
- #
241
- # @param held_shape [Hash{String => Object}] the held era's aggregate shape
242
- # @param current_shape [Hash{String => Object}] the current era's aggregate shape
243
- # @return [Hash{Symbol => Object}, nil] `{kind: :unresolved, from: :identity,
244
- # candidates: []}` when the identity paths differ; nil when they match
172
+ # An unresolved placeholder when the identity paths differ; nil when they match.
173
+ # It only hints: `check_identity_unchanged!` in `coverage_check.rb` is the real gate.
245
174
  def identity_hint(held_shape, current_shape)
246
175
  return if held_shape["identity"] == current_shape["identity"]
247
176
 
248
177
  { kind: :unresolved, from: :identity, candidates: [] }
249
178
  end
250
179
 
251
- # Finds appeared paths type-compatible with a vanished path's own signature.
252
- #
253
- # @param appeared [Hash{String => Object}] appeared paths to type signature (see
254
- # `appeared_paths`)
255
- # @param signature [Object] the vanished path's own type signature to match against
256
- # @return [Array<String>] appeared paths whose scalar signature (see `scalar_of`)
257
- # matches `signature`'s
180
+ # Appeared paths type-compatible with a vanished path's signature.
258
181
  def compatible_candidates(appeared, signature)
259
182
  appeared.select { |_, candidate| scalar_of(candidate) == scalar_of(signature) }.keys
260
183
  end
261
184
 
262
- # Reduces a type signature to the shape `compatible_candidates` compares by.
263
- #
264
- # @param signature [Object, Hash] a path's type signature
265
- # @return [Object] `signature["members"]` for a container Hash, else `signature`
266
- # unchanged
185
+ # Reduces a type signature to what `compatible_candidates` compares: members or the scalar.
267
186
  def scalar_of(signature) = signature.is_a?(Hash) ? signature["members"] : signature
268
187
 
269
- # Reads a container attribute's own members, keyed by name.
270
- #
271
- # @param attribute [Hash{String => Object}] one path's type signature
272
- # @return [Hash{String => Object}] each member's name to its type; `{}` when
273
- # `attribute` is not a container
188
+ # A container attribute's members keyed by name; `{}` for a scalar.
274
189
  def members_of(attribute)
275
190
  return {} unless container?(attribute)
276
191
 
277
192
  attribute["type"]["members"].to_h { |member| [member["name"], member["type"]] }
278
193
  end
279
194
 
280
- # Reports whether a type signature is a container (value object or entity), not a
281
- # scalar.
282
- #
283
- # @param attribute [Hash{String => Object}] one path's type signature
284
- # @return [Boolean] true if `attribute["type"]` is a Hash, false for a scalar
195
+ # Whether the attribute's type is a container (value object or entity), not a scalar.
285
196
  def container?(attribute) = attribute["type"].is_a?(Hash)
286
197
  end
287
198
  end
@@ -1,14 +1,13 @@
1
1
  module Hecks
2
2
  module Translation
3
3
  module Scaffold
4
- # Render an edge into .bluebook text — confident rules inline,
5
- # ambiguities as parse-refusing `unresolved` constructs, never
4
+ # Renders an edge as .bluebook text. Ambiguities become `unresolved` constructs, not
6
5
  # comments, so an unresolved file can only boot into a refusal.
7
6
  module Renderer
8
7
  # Renders a scaffolded edge as loadable `.bluebook` translation source.
9
8
  #
10
9
  # @param edge [Scaffold::Edge] the edge to render
11
- # @return [String] the edge's `.bluebook` text, ending in a newline
10
+ # @return [String] the `.bluebook` text, ending in a newline
12
11
  def render(edge)
13
12
  lines = ["Hecks.data_translation #{edge.domain.inspect}, from: #{edge.from.inspect}, to: #{edge.to.inspect} do"]
14
13
  edge.aggregates.each do |aggregate|
@@ -25,10 +24,8 @@ module Hecks
25
24
 
26
25
  # Renders one scaffolded rule as a line of `.bluebook` source.
27
26
  #
28
- # @param rule [Hash{Symbol => Object}] a rule Hash as `Differ#attribute_rules` builds
29
- # it: `:kind` plus `:from`/`:to`, or `:from`/`:candidates` for `:unresolved`
30
- # @return [String, nil] the rendered line; nil if `rule[:kind]` is none of `:rename`,
31
- # `:move`, `:retype` or `:unresolved`
27
+ # @param rule [Hash{Symbol => Object}] a rule as `Differ#attribute_rules` builds it
28
+ # @return [String, nil] the rendered line; nil for an unknown `rule[:kind]`
32
29
  def render_rule(rule)
33
30
  case rule[:kind]
34
31
  when :rename then "rename :#{rule[:from]}, to: :#{rule[:to]}"
@@ -40,11 +37,7 @@ module Hecks
40
37
  end
41
38
  end
42
39
 
43
- # Renders a path as bluebook source: a Symbol literal when bare, a String literal
44
- # when dotted.
45
- #
46
- # @param path [String, Symbol] a bare or dotted path
47
- # @return [String] `":name"` for a bare path, `path.inspect` for a dotted one
40
+ # Renders a bare path as a Symbol literal and a dotted path as a String literal.
48
41
  def render_path(path) = path.to_s.include?(".") ? path.to_s.inspect : ":#{path}"
49
42
  end
50
43
  end
@@ -3,16 +3,10 @@ require "fileutils"
3
3
  module Hecks
4
4
  module Translation
5
5
  module Scaffold
6
- # Put the rendered edge on disk, regenerating in place when a file
7
- # for the same shape pair already exists.
6
+ # Writes the rendered edge to disk, reusing the file for the same shape pair if present.
8
7
  module Writer
9
- # Renders an edge and writes it under `directory/translations`, regenerating in
10
- # place when a file for the same shape pair already exists.
11
- #
12
- # The edge file, regenerated in place when one for the same shape
13
- # pair already exists (matched textually — an unresolved file
14
- # cannot be loaded to ask, that being the whole point of
15
- # unresolved).
8
+ # Renders an edge and writes it under `directory/translations`.
9
+ # An existing file is matched textually because an unresolved file cannot be loaded.
16
10
  #
17
11
  # @param directory [String] the domain's root directory
18
12
  # @param edge [Scaffold::Edge] the edge to render and write