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
@@ -6,23 +6,8 @@ require_relative "../../../../runtime/registry"
6
6
 
7
7
  module Hecks
8
8
  module Runtime
9
- # The shape-drift coverage primitives — ADR 0032. Not a driver: nothing
10
- # here walks a registry or reads/writes a held snapshot on its own.
11
- # `PostgresEra::LineageManager::CoverageCheck` calls `uncovered_
12
- # attributes`/`unsafe_additions`/`refuse_uncovered!`/`refuse_unsafe_
13
- # addition!`/`check_vanished_aggregates!` directly, per translation
14
- # edge, over its own DB-held shapes; `Translation::Reattest` and
15
- # `PostgresEra::LineageManager` call `shadow_parse` directly, to read
16
- # historical bluebook text under old grammar defaults. Both are real,
17
- # independent, currently-shipped consumers.
18
- #
19
- # There is deliberately no top-level `check!`/`check_bluebook!` here
20
- # walking a registry and reading/writing a held snapshot under
21
- # `data/eras/*.bluebook`: it would duplicate, on its own, the same
22
- # per-aggregate walk `CoverageCheck` already performs against
23
- # `PostgresEra`'s own DB-held shapes, and nothing in production would
24
- # call it — an unwired driver is not kept, per ADR 0032. If one is
25
- # wanted, it is built informed by `CoverageCheck`'s real orchestration.
9
+ # Shape-drift coverage primitives (ADR 0032). Not a driver: callers own
10
+ # walking a registry and reading/writing held snapshots; nothing here does either.
26
11
  module EraGuard
27
12
  extend ShapeDiff
28
13
 
@@ -30,20 +15,16 @@ module Hecks
30
15
 
31
16
  # Refuses the boot when a held aggregate is gone and no translation says where it went.
32
17
  #
33
- # An aggregate that existed in the held text and answers to no
34
- # current name — renamed silently, with nothing declaring `was:` to
35
- # explain where its data went — is exactly the disease this guards
36
- # against, and a plain per-aggregate diff would never see it: the
37
- # current aggregate simply has no held counterpart to compare to.
18
+ # A held aggregate matching no current name has no counterpart for a
19
+ # plain per-aggregate diff to compare against; only a `was:` or
20
+ # `retired` translation can explain it.
38
21
  #
39
- # @param registry [Runtime::Registry] the registry whose declared translations are
40
- # searched for a `was:` or a `retired` entry naming the held aggregate
22
+ # @param registry [Runtime::Registry] the registry searched for a `was:`/`retired` entry
41
23
  # @param bluebook [Bluebook::Chapter] the bluebook booting now
42
24
  # @param held_bluebook [Bluebook::Chapter] the bluebook parsed from the held era's text
43
25
  # @return [void]
44
- # @raise [Runtime::WiringError] if a held aggregate matches no current aggregate by
45
- # name, no current aggregate's translation declares it as `was:`, and no translation
46
- # for this domain retires it
26
+ # @raise [Runtime::WiringError] if a held aggregate matches no current aggregate, no
27
+ # `was:` declares it, and no translation retires it
47
28
  def check_vanished_aggregates!(registry, bluebook, held_bluebook)
48
29
  held_bluebook.aggregates.each do |held_aggregate|
49
30
  claimed = bluebook.aggregates.any? do |aggregate|
@@ -125,65 +106,16 @@ module Hecks
125
106
  end
126
107
  end
127
108
 
128
- # Parses held source into its own IR, in a scratch registry so a past
129
- # era's text never touches the one actually booting.
109
+ # Parses held source into its own IR, in a throwaway registry.
130
110
  #
131
- # Normal parse first, shadow only as a fallback — never shadow-parsing
132
- # unconditionally. A handful of DSL
133
- # defaults fork on `MetaValidator.shadow_parsing?` for a reason
134
- # that has nothing to do with syntax the live grammar cannot
135
- # read at all (`identified_by { }`, `belongs_to`, `has_one`,
136
- # `has_many` — genuinely removed spellings, exactly what shadow-
137
- # parsing exists to keep readable): `reference_to`'s own default
138
- # mint name (`default_reference_name`, attribute_collector.rb)
139
- # is bare under ADR 0025 and `_id`-suffixed under shadow mode, and
140
- # that fork applies even to text using nothing but current, live
141
- # syntax. Held text minted under the current grammar — every real
142
- # era in this corpus today, since nothing has ever minted a second
143
- # one — parses fine normally; under unconditional shadow mode only
144
- # the reference-naming default differs, so it silently
145
- # reconstructs a different shape (and hash) than a fresh parse of
146
- # the identical text — the same text hashing two different ways
147
- # depending on which code path read it, breaking `ensure_named!`'s
148
- # own from/to edge lookup with a spurious "no translation edge
149
- # covers it" refusal that has nothing to do with any real
150
- # translation gap.
151
- #
152
- # A normal parse can only ever succeed on text the live grammar
153
- # fully understands — there is no way for it to silently produce a
154
- # wrong-but-plausible answer for genuinely legacy text, since every
155
- # removed spelling refuses loudly (`Malformed`) rather than
156
- # degrading. So: try normal first — if the ordinary grammar reads
157
- # this text without complaint, that is the canonical, unambiguous
158
- # interpretation, the same one `label_of`/`mint_hash` on the same
159
- # source text always computes, whoever's asking. Only on a
160
- # `Malformed` refusal — the one signal that actually means "this
161
- # spelling is not in the live grammar" — fall back to the legacy
162
- # grammar. Any other exception (a
163
- # genuine syntax error, an unrelated validation refusal) propagates
164
- # unchanged; swallowing it here to retry under shadow mode would
165
- # risk masking a real defect in the held text behind a confusing
166
- # second failure instead of the original, more specific one.
167
- #
168
- # `MetaValidator.while_shadow_parsing` (ADR 0025, docs/dsl-work-
169
- # slices.md's S0a) is what makes the fallback a legacy grammar
170
- # rather than just a second copy of today's: it stops
171
- # `BluebookBuilder.build` from judging this text against the
172
- # grammar as it stands now, which is the one thing that would make
173
- # a removed spelling refuse history the day it is removed from
174
- # live source. The scratch registry is throwaway either way —
175
- # nothing here is dispatched against or exposed to the real one —
176
- # so skipping the judge/assemble round-trip changes nothing this
177
- # method reads: `shape`, `uncovered_attributes`, and friends only
178
- # ever ask the built IR for its own structure.
111
+ # Tries the live grammar first, falling back to the shadow one only
112
+ # on `Malformed` — the one signal meaning "not in the live grammar"
113
+ # (ADR 0025); any other exception propagates unchanged.
179
114
  #
180
115
  # @param source [String] the held bluebook text to evaluate
181
- # @param path [String] the file path the text is evaluated as, which the predicate
182
- # extractor reads from disk; callers pass a tempfile holding the same text
183
- # @return [Bluebook::Chapter, nil] the first bluebook the text declares; nil when it
184
- # declares none
185
- # @raise [Bluebook::DSL::Malformed] if the text parses under neither the live grammar
186
- # nor the legacy one
116
+ # @param path [String] the file path reported as the text's origin
117
+ # @return [Bluebook::Chapter, nil] the first bluebook declared; nil when it declares none
118
+ # @raise [Bluebook::DSL::Malformed] if neither grammar accepts the text
187
119
  # @raise [SyntaxError] if the text is not valid Ruby
188
120
  def shadow_parse(source, path)
189
121
  parse_bluebook(source, path, shadow: false)
@@ -196,7 +128,7 @@ module Hecks
196
128
  # @param source [String] the bluebook text to evaluate
197
129
  # @param path [String] the file path reported to `Kernel.eval` as the text's origin
198
130
  # @param shadow [Boolean] true evaluates inside `MetaValidator.while_shadow_parsing`
199
- # (the legacy grammar); false evaluates under the live grammar
131
+ # (the shadow grammar); false evaluates under the live grammar
200
132
  # @return [Bluebook::Chapter, nil] the first bluebook the text registered in the scratch
201
133
  # registry; nil when it declares none
202
134
  # @raise [Bluebook::DSL::Malformed] if the chosen grammar refuses the text
@@ -207,7 +139,10 @@ module Hecks
207
139
  run = lambda do
208
140
  Hecks.with_registry(scratch) do
209
141
  loading.load_library
210
- Kernel.eval(source, TOPLEVEL_BINDING, path, 1)
142
+ # Held text of a chapter spread over files is several blocks in one string, each
143
+ # opening the same chapter: judge once after all of them, as a directory load does.
144
+ Hecks::Bluebook::MetaValidator.defer { Kernel.eval(source, TOPLEVEL_BINDING, path, 1) }
145
+ Hecks::Bluebook::MetaValidator.judge_deferred!(scratch)
211
146
  end
212
147
  end
213
148
  shadow ? Hecks::Bluebook::MetaValidator.while_shadow_parsing(&run) : run.call
@@ -5,26 +5,11 @@ require_relative "storage_shape"
5
5
 
6
6
  module Hecks
7
7
  module Runtime
8
- # The refusal wording for a held era whose digest does not match its
9
- # frozen text — the digest mismatch alone is what detects tampering (a
10
- # plain SHA256 comparison over raw bytes, unrelated to any of this);
11
- # this only supplies the wording once that's already fired.
8
+ # Wording for the boot refusal when a held era's frozen text was
9
+ # edited after freezing (detected elsewhere via a digest mismatch).
12
10
  #
13
- # Lives here, not under `Ports::Persistence` — `project` below directly
14
- # calls `Runtime::EraGuard.shadow_parse`/`Runtime::StorageShape.project`
15
- # (DSL-execution machinery), the "an adapter/port reaches into the
16
- # runtime instead of being handed already-computed data" shape that
17
- # has caused trouble here before. A capability this dependent on the
18
- # runtime is a runtime-owned one that the Postgres adapter calls, not
19
- # a ports-level module that happens to reach sideways into it.
20
- #
21
- # Every tamper refusal reaches the same generic wording, cosmetic edit
22
- # or real shape change alike: telling the two apart by re-parsing the
23
- # edited text is a pure quality-of-message nicety, not a safety
24
- # property, and an edit that cannot be classified has to fall to the
25
- # generic wording anyway. An operator judges "did this matter"
26
- # themselves, reading the still-archived original — an anomalous
27
- # recovery moment already, not a normal boot path.
11
+ # Lives here, not under `Ports::Persistence`, because `project` below
12
+ # calls runtime DSL-execution machinery (`EraGuard`, `StorageShape`) directly.
28
13
  module EraTamper
29
14
  module_function
30
15
 
@@ -40,12 +25,8 @@ module Hecks
40
25
 
41
26
  # Parses a bluebook text and returns its storage-shape projection.
42
27
  #
43
- # The projection is JSON-normalized for structural comparison
44
- # against a stored projection; nil when the text does not load.
45
- # Always parsed through a fresh tempfile, never the held file's own
46
- # path: the predicate extractor caches source by path, and a held
47
- # path whose content has changed (the very situation this module
48
- # exists for) would hand it stale lines.
28
+ # Always parsed from a fresh tempfile, never the held file's own path,
29
+ # since the predicate extractor caches source by path and would see stale lines there.
49
30
  #
50
31
  # @param text [String] the bluebook source to parse
51
32
  # @param _source_path [String, nil] ignored; the text is always parsed from a tempfile
@@ -5,27 +5,8 @@ require "uri"
5
5
  module Hecks
6
6
  module Runtime
7
7
  module EraCheck
8
- # The read side of the era gate, for a deploy operator rather than a boot:
9
- # asks a running host which era it reports at `GET /version` and compares
10
- # it with an allow-list file of the eras that should be running.
11
- #
12
- # `EraCheck.check!` decides at boot, against the store, whether a host may
13
- # run on an era. This answers the question after a roll, from outside:
14
- # did the host that came up report an era the operator expects? The two
15
- # never share state. The host's own `GET /version` document
16
- # (`rust/host/src/server.rs`, `version_body`) is the only input, so a
17
- # rollback to an older image, or a fork of the journal back onto an older
18
- # era, shows up here as an era missing from the list.
19
- #
20
- # ## The allow-list file
21
- #
22
- # One era id per line. Blank lines and lines starting with `#` are
23
- # ignored, and so is a trailing ` # comment`. A file that lists no era
24
- # means "only check that the host reports one", so a first roll can be
25
- # checked before any era id is known. The generated `expected-era` file
26
- # (`Deploy::Scripts`) has this shape.
27
- #
28
- # `bin/check_era` is the command-line wrapper.
8
+ # Compares a running host's reported era (`GET /version`) against an
9
+ # allow-list file of eras that should be running, for use after a roll.
29
10
  module ExpectedEra
30
11
  # The host could not be reached, or did not answer with a `200`.
31
12
  class Unreachable < StandardError; end
@@ -36,7 +17,7 @@ module Hecks
36
17
  # What a comparison concluded.
37
18
  #
38
19
  # @!attribute [r] status
39
- # @return [Symbol] `:match`, `:unlisted` (no era on the list, one reported) or `:mismatch`
20
+ # @return [Symbol] `:match`, `:unlisted` (no era listed) or `:mismatch`
40
21
  # @!attribute [r] era
41
22
  # @return [String] the era the host reported
42
23
  # @!attribute [r] allowed
@@ -78,13 +59,26 @@ module Hecks
78
59
  # @raise [Unreachable] if the request fails or the status is not `200`
79
60
  # @raise [BadResponse] if the body is not JSON or its `era` is not a non-empty string
80
61
  def fetch_era(url, timeout: 10)
62
+ fetch_version(url, timeout: timeout).fetch("era")
63
+ end
64
+
65
+ # Asks a host for its `/version` document.
66
+ #
67
+ # @param url [String] the host's base URL, or its `/version` URL
68
+ # @param timeout [Numeric] seconds allowed for connecting and for reading
69
+ # @return [Hash{String => String}] `"era"` (never empty) and `"version"` (empty when the
70
+ # host reports none)
71
+ # @raise [Unreachable] if the request fails or the status is not `200`
72
+ # @raise [BadResponse] if the body is not JSON or its `era` is not a non-empty string
73
+ def fetch_version(url, timeout: 10)
81
74
  response = get(version_url(url), timeout)
82
75
  raise Unreachable, "#{version_url(url)} answered #{response.code}" unless response.code == "200"
83
76
 
84
- era = JSON.parse(response.body)["era"]
77
+ document = JSON.parse(response.body)
78
+ era = document["era"]
85
79
  raise BadResponse, "#{version_url(url)} carries no era" unless era.is_a?(String) && !era.empty?
86
80
 
87
- era
81
+ { "era" => era, "version" => document["version"].to_s }
88
82
  rescue JSON::ParserError, TypeError
89
83
  raise BadResponse, "#{version_url(url)} did not answer a JSON version document"
90
84
  end
@@ -6,11 +6,7 @@ module Hecks
6
6
  module Ports
7
7
  module Persistence
8
8
  # Translates a journal entry written under an old shape into the one
9
- # the current bluebook declares — a renamed attribute, a renamed
10
- # aggregate, or a field crossing a value-object boundary. Applied
11
- # wherever entries are read, so replay derives the current head from
12
- # history that was never rewritten — the port owns the meaning,
13
- # adapters stay oblivious.
9
+ # the current bluebook declares; replay derives the head from unrewritten history.
14
10
  class Lineage
15
11
  # `ancestor_name` is the declared name a rename came from (matches
16
12
  # the held bluebook's own aggregate names); `ancestor_storage_name`
@@ -24,8 +20,8 @@ module Hecks
24
20
  # searched, in declaration order
25
21
  # @param domain [String, Symbol] name of the domain the aggregate belongs to
26
22
  # @param aggregate [Bluebook::Aggregate] the aggregate as currently declared
27
- # @return [Ports::Persistence::Lineage, nil] the rules of the first translation for `domain`
28
- # that names the aggregate; nil when none does
23
+ # @return [Ports::Persistence::Lineage, nil] the first translation for `domain` naming
24
+ # the aggregate; nil when none does
29
25
  def self.for(registry, domain, aggregate)
30
26
  translation = registry.translations.find do |candidate|
31
27
  candidate.domain == domain.to_s && candidate.for_aggregate(aggregate.name)
@@ -37,9 +33,8 @@ module Hecks
37
33
 
38
34
  # Builds the rules one declared translation edge carries for one aggregate.
39
35
  #
40
- # One specific edge's rules for one aggregate — what the mint
41
- # path uses, where `for` would happily answer with whichever
42
- # edge in the registry mentioned the aggregate first.
36
+ # Unlike `for`, this uses one specific edge, not whichever edge in
37
+ # the registry mentions the aggregate first — what the mint path needs.
43
38
  #
44
39
  # @param declared [Bluebook::TranslationAggregate, nil] the edge's entry for the
45
40
  # aggregate, as `Bluebook::Translation#for_aggregate` returns it; nil when the edge
@@ -60,24 +55,16 @@ module Hecks
60
55
  ancestor_name: ancestor_name, ancestor_storage_name: ancestor_storage_name)
61
56
  end
62
57
 
63
- # @param renames [Hash{Symbol => Symbol}] old top-level attribute name to new name
64
- # @param moves [Array<Bluebook::TranslationMove>] fields crossing a value-object
65
- # boundary, each a `from`/`to` pair of bare or dotted paths
66
- # @param converts [Array<Bluebook::TranslationConvert>] moves whose value is replaced
67
- # through an exhaustive `values` lookup table
68
- # @param drops [Array<Symbol>] bare or dotted paths whose data is deliberately discarded
69
- # @param retypes [Array<Bluebook::TranslationRetype>] value-object or entity type names
70
- # declared to mean the same shape
71
- # @param computes [Array<Bluebook::TranslationCompute>] SQL-only rules, never applied
72
- # in process
73
- # @param rekeys [Array<Bluebook::TranslationRekey>] SQL-only identity rewrites; only
74
- # the first is read
75
- # @param backfills [Array<Bluebook::TranslationBackfill>] defaults for new top-level
76
- # attributes an old entry lacks
77
- # @param ancestor_name [String, nil] the aggregate's declared name before the edge;
78
- # nil unless the edge renames the aggregate itself
79
- # @param ancestor_storage_name [String, nil] snake_case storage name of
80
- # `ancestor_name`; nil unless the edge renames the aggregate itself
58
+ # @param renames [Hash{Symbol => Symbol}] old attribute name to new name
59
+ # @param moves [Array<Bluebook::TranslationMove>] from/to paths across a value object
60
+ # @param converts [Array<Bluebook::TranslationConvert>] moves mapped through a values table
61
+ # @param drops [Array<Symbol>] bare or dotted paths whose data is discarded
62
+ # @param retypes [Array<Bluebook::TranslationRetype>] type names meaning the same shape
63
+ # @param computes [Array<Bluebook::TranslationCompute>] SQL-only rules, never applied here
64
+ # @param rekeys [Array<Bluebook::TranslationRekey>] SQL rewrites; only the first is read
65
+ # @param backfills [Array<Bluebook::TranslationBackfill>] defaults for a new attribute
66
+ # @param ancestor_name [String, nil] the aggregate's name before the edge, if renamed
67
+ # @param ancestor_storage_name [String, nil] snake_case storage name of ancestor_name
81
68
  def initialize(renames, moves = [], converts = [], drops = [], retypes: [], computes: [], rekeys: [],
82
69
  backfills: [], ancestor_name: nil, ancestor_storage_name: nil)
83
70
  @renames = renames
@@ -94,54 +81,39 @@ module Hecks
94
81
 
95
82
  # Reports whether any rule in this edge is a compute.
96
83
  #
97
- # Compute is the one rule kind with no in-process implementation at
98
- # all. An aggregate carrying one refuses to boot anywhere but
99
- # Postgres, per-rule and by name, before the general drift
100
- # machinery says anything vaguer.
84
+ # Compute has no in-process implementation; an aggregate carrying
85
+ # one refuses to boot anywhere but Postgres.
101
86
  #
102
87
  # @return [Boolean] true when the edge declares at least one compute rule
103
88
  def computes? = !@computes.empty?
104
89
 
105
90
  # Reports whether this edge rewrites the aggregate's identity.
106
91
  #
107
- # The single source of truth for "does this edge rekey this
108
- # aggregate" — every consumer (coverage_check.rb's identity gate,
109
- # minter.rb's approval gate, layer_two.rb's audit, head_compiler.rb's
110
- # SQL compilation) asks this, never re-derives it from `declared`
111
- # independently. One accessor to change if what a rekey rule means
112
- # ever needs to change, not four call sites in four files.
92
+ # The single source of truth for this; other call sites ask here
93
+ # rather than re-deriving it from `declared` themselves.
113
94
  #
114
95
  # @return [Boolean] true when the edge declares at least one rekey rule
115
96
  def rekey? = !@rekeys.empty?
116
97
 
117
98
  # Returns the SQL expression the edge's first rekey rule declares.
118
99
  #
119
- # The rekey's own SQL — first-and-only rule, same one-per-aggregate
120
- # assumption `compute` makes about its own list where it matters
121
- # (an edge with more than one is a DSL-level decision, not
122
- # something this reader arbitrates).
100
+ # Only the first rule is read, the same one-per-aggregate assumption
101
+ # `compute` makes; more than one is a DSL-level decision to arbitrate elsewhere.
123
102
  #
124
103
  # @return [String, nil] the first rekey rule's SQL; nil when the edge declares no rekey
125
104
  def rekey_sql = @rekeys.first&.sql
126
105
 
127
106
  # Rewrites one journal entry's state from the held shape into the current one.
128
107
  #
129
- # The reference semantics for the five portable rule kinds —
130
- # rename, move, convert, drop, and the aggregate-level `was:`.
131
- # `retype` moves nothing (stored state never carries a type name)
132
- # and `compute` is deliberately not applied here: its SQL is its
133
- # only implementation, so this transform neither imitates nor
134
- # checks it — the source field passes through untouched, and the
135
- # audit verifies compute output against the matview alone.
108
+ # The reference semantics for rename, move, convert, drop, and the aggregate-level `was:`.
109
+ # `compute` is not applied here — its SQL is the only implementation, audited separately.
136
110
  #
137
- # @param entry [Ports::Persistence::Entry] the entry as stored: `state` has Symbol
138
- # top-level keys and String keys inside a nested value-object Hash
139
- # @return [Ports::Persistence::Entry] a new entry with a deep-copied, translated state
140
- # and the same `operation`, `id` and `mirrors`; `entry` itself, untouched, when it
141
- # is not a save or carries no state
142
- # @raise [Runtime::WiringError] if a convert meets a value missing from its `values`
143
- # table, or a move or convert would nest under a destination already holding a
144
- # non-Hash value
111
+ # @param entry [Ports::Persistence::Entry] the entry as stored, with Symbol
112
+ # top-level keys and String keys nested in a value-object Hash
113
+ # @return [Ports::Persistence::Entry] a new entry with translated state and the same
114
+ # `operation`, `id` and `mirrors`; `entry` itself when it is not a save or has no state
115
+ # @raise [Runtime::WiringError] if a convert value is missing from its `values` table, or a
116
+ # move/convert would nest under a destination already holding a non-Hash value
145
117
  def translate(entry)
146
118
  return entry unless entry.save? && entry.state
147
119
 
@@ -153,45 +125,18 @@ module Hecks
153
125
  @moves.each { |move| apply_move(state, move) }
154
126
  @converts.each { |convert| apply_convert(state, convert) }
155
127
  @drops.each { |name| apply_drop(state, name) }
156
- # Last, and only where nothing already answered — a backfill
157
- # fills the gap a rename/move/convert left untouched, never
158
- # overwrites a value that already made it across. Dotted-path
159
- # aware, same as `apply_drop` above (`apply_backfill`'s own
160
- # header) — a bare name was the only shape this ever needed
161
- # until a value object gained new required members with zero
162
- # source data of their own (found live: a client site's Attendee
163
- # redesign, commit 4326dcd).
128
+ # Only fills a gap nothing else already filled; dotted-path aware, like apply_drop.
164
129
  @backfills.each { |backfill| apply_backfill(state, backfill) }
165
130
  Entry.new(operation: entry.operation, id: entry.id, state: state, mirrors: entry.mirrors)
166
131
  end
167
132
 
168
133
  # Reports whether some rule accounts for a held path that vanished or changed type.
169
134
  #
170
- # Whether this translation names `path` as an old key it accounts
171
- # for — the rename, move, or convert it came from, or an explicit
172
- # drop. `path` is a bare name ("cost") or a dotted value-object
173
- # member ("price.currency"); a rule covering the whole top-level
174
- # attribute (a rename, a top-level move/convert/drop) also covers
175
- # anything nested under it, since the whole value travels or goes
176
- # away together. This is what catches a field — or a value object's
177
- # own member — that vanished (or silently changed type) without
178
- # anything explaining it, even when some other field is covered.
135
+ # A rule covering a whole top-level attribute also covers anything nested
136
+ # under it; `backfills` only matches a whole name, since a backfill adds an
137
+ # attribute that is new outright, never a path that existed and moved.
179
138
  #
180
- # `backfills` matches on the whole name only, never a dotted
181
- # prefix — a backfill names a top-level attribute that is new
182
- # outright (nothing to be a prefix of on the held side), unlike
183
- # every rule above it, which explains a path that existed and
184
- # moved, converted, or vanished.
185
- #
186
- # One `||` chain over a closed, fixed set of rule kinds (renames,
187
- # moves, converts, drops, computes, backfills) — the same six this
188
- # file's other methods enumerate. Splitting each disjunct into its
189
- # own predicate would scatter one question ("does any rule explain
190
- # this path") across six same-shaped methods with nothing else to
191
- # do.
192
- #
193
- # @param path [String, Symbol] a bare attribute name or a dotted value-object member
194
- # path on the held side
139
+ # @param path [String, Symbol] a bare attribute name or a dotted value-object member path
195
140
  # @return [Boolean] true when a rename, move, convert, drop or compute names the path or
196
141
  # its top-level attribute as its source, or a backfill names the top-level attribute
197
142
  # rubocop:disable-next Metrics/CyclomaticComplexity
@@ -210,32 +155,11 @@ module Hecks
210
155
 
211
156
  # Reports whether some rule gives an existing record a value at a new attribute.
212
157
  #
213
- # The destination-side twin of `explains?` above, which only ever
214
- # asks about a rule's source. `unsafe_additions` asks a different
215
- # question — not "was this vanished path accounted for" but "does
216
- # an existing record end up with a value here" — and a move or
217
- # convert whose `to:` lands a old field inside a brand-new
218
- # top-level attribute (`weight` becoming `contents.weight` when
219
- # `Contents` did not exist before) fills that attribute for an
220
- # existing record exactly as a `backfill` would, even though
221
- # nothing named `contents` explains any vanished path. `compute`
222
- # counts on the same terms `explains?` already grants it
223
- # elsewhere in this file — Postgres-only and audited, not
224
- # actually applied by this method, the same gap the vanish side
225
- # already lives with.
158
+ # The destination-side twin of `explains?`, which checks a rule's source; this checks
159
+ # `@renames.value?` too, since a bare rename fills the destination unconditionally,
160
+ # the same way a backfill would.
226
161
  #
227
- # `@renames.value?` belongs here too: a bare
228
- # `rename :cost, to: :amount` is the plainest possible covering
229
- # rule there is (`translate` above applies it unconditionally, no
230
- # lookup table, no per-record ambiguity — simpler than a move or
231
- # convert), and without it `unsafe_additions` reports the new name
232
- # as an unexplained required addition on every rename-only edge,
233
- # the single most common translation shape there is. `explains?`
234
- # checks the source side (`@renames.key?`); this is the symmetric
235
- # destination-side check.
236
- #
237
- # @param path [String, Symbol] the name of a top-level attribute new in the current
238
- # shape
162
+ # @param path [String, Symbol] the name of a top-level attribute new in the current shape
239
163
  # @return [Boolean] true when a rename, move, convert or compute lands a value in that
240
164
  # attribute, or a backfill names it
241
165
  def fills?(path)
@@ -250,15 +174,11 @@ module Hecks
250
174
 
251
175
  # Reports whether a declared retype pairs two type names as the same shape.
252
176
  #
253
- # A retype covers a value object or entity whose own name changed
254
- # with its members intact. Nothing in the stored data carries the
255
- # type name, so this never moves a value; it only satisfies the
256
- # era diff's literal type-name comparison.
177
+ # Nothing in the stored data carries a type name, so this never moves a value;
178
+ # it only satisfies the era diff's literal type-name comparison.
257
179
  #
258
- # @param held_type [String, Bluebook::Reference] the type the held era declares,
259
- # compared by its `to_s`
260
- # @param current_type [String, Bluebook::Reference] the type declared now, compared by
261
- # its `to_s`
180
+ # @param held_type [String, Bluebook::Reference] the type the held era declares
181
+ # @param current_type [String, Bluebook::Reference] the type declared now
262
182
  # @return [Boolean] true when some retype rule runs from `held_type` to `current_type`
263
183
  def retype?(held_type, current_type)
264
184
  @retypes.any? { |retype| retype.from == held_type.to_s && retype.to == current_type.to_s }
@@ -274,30 +194,14 @@ module Hecks
274
194
  end
275
195
  end
276
196
 
277
- # M27 (docs/audits/2026-08-10-main-bug-audit.md,
278
- # docs/audits/2026-08-11-bug-triage.md) — simultaneous, not
279
- # sequential: `state[new] = state.delete(old)` per rename, run
280
- # one rule at a time against the same hash it was reading from,
281
- # loses data the instant one rule's destination is another
282
- # rule's source. Applied sequentially, a swap (`rename :a, to: :b`
283
- # alongside `rename :b, to: :a`) on `{a: 1, b: 2}` produces
284
- # `{a: 1}` — the first rule writes `b: 1` over the real `b: 2`
285
- # before the second rule ever gets a chance to read it, and the
286
- # value the whole edge is supposed to preserve (2, moved to
287
- # `:a`) is gone. The standard fix: snapshot every rule's old
288
- # key and value from `state` first, then remove every old key
289
- # and only then write every new key — a rename never reads a
290
- # key this same pass has already written to, so a swap or a
291
- # longer chain applies as one permutation, not a sequence of
292
- # edits each stepping on the last.
197
+ # Snapshots every rename's old key/value before writing any new key, so a
198
+ # swap (:a<->:b) applies as one permutation instead of losing data when one
199
+ # rule's destination is another's source.
293
200
  def apply_renames(state, renames)
294
201
  snapshot = renames.filter_map { |old_name, new_name| [old_name, new_name, state[old_name]] if state.key?(old_name) }
295
202
  snapshot.each { |old_name, _new_name, _value| state.delete(old_name) }
296
- # Not combinable (Style/CombinableLoops is disabled repo-wide, see
297
- # .rubocop.yml, for exactly this reason): a swap (:a<->:b) needs
298
- # every delete done before any write, or the first rename's write
299
- # becomes the second rename's delete target — see this method's
300
- # own comment above.
203
+ # Not combinable: every delete must finish before any write, or a swap's
204
+ # first write becomes its second delete target.
301
205
  snapshot.each { |_old_name, new_name, value| state[new_name] = value }
302
206
  end
303
207
 
@@ -317,18 +221,7 @@ module Hecks
317
221
  end
318
222
  end
319
223
 
320
- # Applies one backfill, dotted-path aware — `apply_drop`'s own
321
- # mirror on the addition side. A bare name sets a plain top-level
322
- # key, unchanged from before; a dotted name (`"attendee.
323
- # first_name"`) reaches into an existing value-object member the
324
- # same way `apply_drop`/`hecks_tr_insert` (rule_compiler.rb's own
325
- # SQL-compiled twin, kept in step with this) already do — creating
326
- # the container Hash if an old record somehow lacks it entirely,
327
- # never overwriting a value already there at either level.
328
- #
329
- # @param state [Hash] the entry's own state Hash, mutated in place
330
- # @param backfill [Bluebook::TranslationBackfill] the backfill rule to apply
331
- # @return [void]
224
+ # Dotted-path aware; must stay in step with `hecks_tr_insert` in rule_compiler.rb.
332
225
  def apply_backfill(state, backfill)
333
226
  name = backfill.name.to_s
334
227
  top, member = name.split(".", 2)
@@ -342,17 +235,8 @@ module Hecks
342
235
  end
343
236
  end
344
237
 
345
- # A dotted path's first segment is a top-level (symbol) key; a
346
- # second segment reaches into a value-object member by its string
347
- # key — the spelling a raw stored row carries. Translation runs on
348
- # raw rows, before the state codec decodes anything (PR A3): its
349
- # only caller (`Translation::Audit::LayerTwo`) feeds it
350
- # head-snapshot rows straight out of `JSON.parse`, and the
351
- # PostgresEra head applies the same rules in SQL before
352
- # `PostgresEra#decode` ever sees the jsonb. Decode is always the
353
- # last step, so an undeclared (retired) member this rule has to
354
- # read is still exactly as it was written, and never something an
355
- # adapter's `entries` — decoded, deep-symbol — would be fed here.
238
+ # Runs on raw rows, before the state codec decodes anything — decode is
239
+ # always the last step, so this never sees an adapter's deep-symbolized entry.
356
240
  def apply_move(state, move)
357
241
  old_top, old_member = move.from.split(".", 2)
358
242
  new_top, new_member = move.to.split(".", 2)
@@ -364,9 +248,8 @@ module Hecks
364
248
  insert(state, new_top.to_sym, new_member, value, rule: "move #{move.from} to: #{move.to}")
365
249
  end
366
250
 
367
- # A convert is a move whose value has nothing in common with its
368
- # replacement — the same path machinery, plus a lookup. A value
369
- # with no entry in the table refuses loudly rather than carry an
251
+ # A convert is a move whose value has nothing in common with its replacement.
252
+ # A value missing from the lookup table refuses loudly rather than carry an
370
253
  # unrecognized value silently into the new era.
371
254
  def apply_convert(state, convert)
372
255
  old_top, old_member = convert.from.split(".", 2)
@@ -397,18 +280,9 @@ module Hecks
397
280
  [value, true]
398
281
  end
399
282
 
400
- # Adversarial finding, not a hypothetical: a destination whose
401
- # top segment already holds a value — most commonly a reference,
402
- # stored as a bare scalar id — must not be nested under when a
403
- # dotted destination needs it (`state[top] ||= {}` alone only
404
- # guards nil/false, so a truthy non-Hash sails straight through
405
- # to `state[top][member] =`, i.e. `"team-1"["detail"] =`, which
406
- # is String#[]= and raises an unrelated-looking IndexError).
407
- # Whether it crashes or silently replaces the value, that is a
408
- # `drop` that never declared itself — the one thing this language
409
- # exists to make explicit (see apply_convert's own refusal above,
410
- # the same shape). Refuse by name instead, on both sides: the SQL
411
- # half (hecks_tr_insert) raises the identical wording.
283
+ # A destination already holding a non-Hash value (e.g. a bare reference id)
284
+ # must not be silently nested under — that would be an undeclared drop. The
285
+ # SQL half (`hecks_tr_insert`) refuses with identical wording.
412
286
  def insert(state, top, member, value, rule:)
413
287
  return state[top] = value unless member
414
288