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,7 +5,7 @@ require "uri"
5
5
  require_relative "sql_query_builder"
6
6
  require_relative "sqlite/schema_builder"
7
7
  require_relative "sqlite/codec"
8
- require_relative "sqlite" # for Sqlite::SchemaBuilder/Sqlite::Codec — see the reuse note below
8
+ require_relative "sqlite"
9
9
  require_relative "../../ports/persistence/append_only"
10
10
  require_relative "../../query_specification/common/null_policy"
11
11
  require_relative "../../query_specification/common/order_by"
@@ -15,59 +15,23 @@ require_relative "../../runtime/instance"
15
15
 
16
16
  module Hecks
17
17
  module Adapters
18
- # Cloudflare D1 — SQLite, managed, reached over its REST API rather
19
- # than a local file. D1 is SQLite, dialect and all, so this file
20
- # reuses Sqlite::SchemaBuilder and Sqlite::Codec unchanged (the DDL
21
- # and the column encode/decode) and SqlQueryBuilder's dialect hooks
22
- # are copied near-verbatim from sqlite.rb — the only real difference
23
- # is the transport (D1::Connection, an HTTP call per query, vs a
24
- # persistent local sqlite3 handle). See sqlite.rb's own header
25
- # comment: "this file supplies only SQLite's dialect" — true here too.
18
+ # Cloudflare D1 (managed SQLite over REST): reuses Sqlite's schema and codec unchanged.
19
+ # Only the transport differs, one HTTP call per query.
26
20
  class D1
27
- # **The transport** — mirrors just the slice of SQLite3::Database's own
28
- # interface (execute/get_first_row/get_first_value, rows as
29
- # column-name-keyed hashes) that Sqlite::SchemaBuilder, Sqlite::Codec,
30
- # and this file's own methods already assume. One stateless HTTP call
31
- # per execute, not a persistent connection — D1 has no connection to
32
- # hold open.
21
+ # HTTP transport exposing the slice of `SQLite3::Database` the shared SQLite code uses.
33
22
  class Connection
34
23
  ENDPOINT = "https://api.cloudflare.com/client/v4".freeze
35
24
 
36
- # @param account_id [String] the Cloudflare account that owns the database
37
- # @param database_id [String] the D1 database's id
38
- # @param api_token [String] a Cloudflare API token, sent as a bearer token on every
39
- # request
40
25
  def initialize(account_id:, database_id:, api_token:)
41
26
  @uri = URI("#{ENDPOINT}/accounts/#{account_id}/d1/database/#{database_id}/query")
42
27
  @api_token = api_token
43
28
  end
44
29
 
45
- # Runs one statement in its own HTTP request and returns its rows.
46
- #
47
- # @param sql [String] the statement, with `?` placeholders
48
- # @param binds [Array<Object>] one value per placeholder, in order
49
- # @return [Array<Hash{String => Object}>] the result rows keyed by column name; `[]`
50
- # for a statement that returns none
51
- # @raise [Runtime::WiringError] if D1 reports the query failed or answers with a body
52
- # that is not JSON
53
30
  def execute(sql, binds = [])
54
31
  response_results({ sql: sql, params: binds }).first.fetch("results", [])
55
32
  end
56
33
 
57
- # Runs several statements as one transaction in a single HTTP request.
58
- #
59
- # D1 batches are SQL transactions: statements execute in order and a
60
- # failure rolls the entire sequence back. Keep the tuple-shaped local
61
- # seam small so adapter code and focused fakes do not need to know the
62
- # REST request envelope.
63
- # https://developers.cloudflare.com/d1/worker-api/d1-database/#batch
64
- #
65
- # @param statements [Array<Array(String, Array)>] `[sql, binds]` pairs in execution
66
- # order; nil binds mean none
67
- # @return [Array<Array<Hash{String => Object}>>] each statement's result rows, in
68
- # the order given
69
- # @raise [Runtime::WiringError] if D1 reports the request or any one statement failed,
70
- # or answers with a body that is not JSON
34
+ # D1 batches are transactions: statements run in order and a failure rolls all back.
71
35
  def batch(statements)
72
36
  payload = {
73
37
  batch: statements.map do |sql, binds|
@@ -104,11 +68,7 @@ module Hecks
104
68
  raise Runtime::WiringError, "D1 query failed: non-JSON response (HTTP #{response.code}): #{response.body}"
105
69
  end
106
70
 
107
- # `messages` is the whole-response :errors fallback, tried last —
108
- # a per-statement `failed["error"]`/`failed["message"]` (checked
109
- # by key presence, not truthiness, so an explicit `nil` still
110
- # counts as "the key was there") is always more specific to which
111
- # statement failed, when either is present.
71
+ # Prefers the statement's own error/message (by key presence) over the whole-response one.
112
72
  def failed_statement_detail(failed, messages)
113
73
  detail =
114
74
  if failed.key?("error")
@@ -123,26 +83,10 @@ module Hecks
123
83
 
124
84
  public
125
85
 
126
- # Runs one statement and keeps only its first row, as `SQLite3::Database` does.
127
- #
128
- # @param sql [String] the statement, with `?` placeholders
129
- # @param binds [Array<Object>] one value per placeholder, in order
130
- # @return [Hash{String => Object}, nil] the first row keyed by column name, or nil when
131
- # the statement returned none
132
- # @raise [Runtime::WiringError] if D1 reports the query failed or answers with a body
133
- # that is not JSON
134
86
  def get_first_row(sql, binds = [])
135
87
  execute(sql, binds).first
136
88
  end
137
89
 
138
- # Runs one statement and keeps only the first column of its first row.
139
- #
140
- # @param sql [String] the statement, with `?` placeholders
141
- # @param binds [Array<Object>] one value per placeholder, in order
142
- # @return [Object, nil] the value as D1's JSON carries it, or nil when the statement
143
- # returned no row
144
- # @raise [Runtime::WiringError] if D1 reports the query failed or answers with a body
145
- # that is not JSON
146
90
  def get_first_value(sql, binds = [])
147
91
  get_first_row(sql, binds)&.values&.first
148
92
  end
@@ -156,22 +100,11 @@ module Hecks
156
100
 
157
101
  attr_reader :aggregate
158
102
 
159
- # Names the optional persistence capabilities `Ports::Persistence::AppendOnly` may rely on.
160
- #
161
- # @return [Array<Symbol>] `[:atomic_put]`
162
103
  def persistence_capabilities = [:atomic_put]
163
104
 
164
- # Checks the credentials are declared and creates the aggregate, journal, event and
165
- # saga tables if absent, one HTTP request per statement.
166
- #
167
- # @param aggregate [Bluebook::Aggregate] the aggregate whose table this adapter owns
168
- # @param settings [Hash{Symbol, String => Object}] world settings for the binding:
169
- # `account_id`, `database_id` and `api_token` (all required) and `domain` (scopes saga
170
- # rows, default the aggregate's name), each read under a Symbol or a String key
171
- # @param root [String, nil] project root directory; accepted for the shared adapter
172
- # constructor shape and ignored
173
- # @raise [Runtime::WiringError] if a required setting is missing or empty, or D1 rejects
174
- # a table-creation statement
105
+ # Creates the aggregate, journal, event and saga tables if absent.
106
+ # Settings: `account_id`, `database_id`, `api_token` (required) and `domain` (saga scope).
107
+ # @raise [Runtime::WiringError] if a required setting is missing or empty
175
108
  def initialize(aggregate:, settings: {}, root: nil)
176
109
  @aggregate = aggregate
177
110
 
@@ -183,12 +116,7 @@ module Hecks
183
116
  end
184
117
 
185
118
  @db = Connection.new(account_id: account_id, database_id: database_id, api_token: api_token)
186
- # The optional saga-persistence capability's own scoping column
187
- # (§2/§4) — D1's domain isolation is by whole-database identity
188
- # (one D1 database per domain in practice), so unlike Sqlite's
189
- # own per-aggregate-file default, there's no "which file does
190
- # this end up in" ambiguity here: every aggregate on D1 within a
191
- # domain already shares one database.
119
+ # Saga rows are scoped by domain; one D1 database per domain, so aggregates share it.
192
120
  @domain = (
193
121
  if settings.key?(:domain)
194
122
  settings[:domain]
@@ -199,9 +127,7 @@ module Hecks
199
127
  end
200
128
  ).to_s
201
129
 
202
- # No PRAGMA synchronous here, unlike Sqlite — D1 is a managed
203
- # durable service; there is no local fsync policy for a caller to
204
- # tune, and the query endpoint has no PRAGMA write-access to it.
130
+ # No PRAGMA synchronous: D1 is managed and its query endpoint disallows PRAGMA writes.
205
131
  create_aggregate_table!
206
132
  create_entry_table!
207
133
  ensure_entry_operation_column!
@@ -210,16 +136,8 @@ module Hecks
210
136
  create_saga_table!
211
137
  end
212
138
 
213
- # Names the aggregate's table; the journal table is keyed off it.
214
- #
215
- # @return [String] the aggregate's snake_case storage name, unquoted
216
139
  def table = @aggregate.storage_name
217
140
 
218
- # Reads the current row for one aggregate identity.
219
- #
220
- # @param id [String, Object] the aggregate identity, bound as `id.to_s`
221
- # @return [Runtime::Instance, nil] the decoded record, or nil when no row has that id
222
- # @raise [Runtime::WiringError] if D1 rejects the statement
223
141
  def find(id)
224
142
  row = @db.get_first_row("SELECT * FROM #{quoted_table} WHERE id = ?", [id.to_s])
225
143
  return nil unless row
@@ -227,19 +145,8 @@ module Hecks
227
145
  Runtime::Instance.new(aggregate: @aggregate, id: row["id"], state: decode(row))
228
146
  end
229
147
 
230
- # Lists every stored record, ordered by id unless an ordering attribute is given.
231
- #
232
- # order_by is a runtime value — see postgres.rb's own all for the
233
- # full reasoning; whitelisted the identical way, same order_clause
234
- # Sqlite's own all reuses (D1 speaks the identical dialect).
235
- #
236
- # @param order_by [String, Symbol, nil] attribute (or dotted value-object path) to sort
237
- # by, with id as the tie-break; nil orders by id alone
238
- # @param direction [Symbol, String] `:asc` or `:desc`, case-insensitive; anything else
239
- # sorts ascending
240
- # @return [Array<Runtime::Instance>] the decoded records, `[]` when the table is empty
241
- # @raise [Runtime::WiringError] if `order_by` names no attribute of the aggregate, or D1
242
- # rejects the statement
148
+ # Lists every record, ordered by id or by `order_by` when it names an attribute.
149
+ # @raise [Runtime::WiringError] if `order_by` names no attribute of the aggregate
243
150
  def all(order_by: nil, direction: :asc)
244
151
  order_sql = "ORDER BY id"
245
152
  if order_by
@@ -258,37 +165,17 @@ module Hecks
258
165
  end
259
166
  end
260
167
 
261
- # Counts the rows in the aggregate's table, deleted records excluded.
262
- #
263
- # @return [Integer] number of current records
264
- # @raise [Runtime::WiringError] if D1 rejects the statement
265
168
  def count = @db.get_first_value("SELECT COUNT(*) FROM #{quoted_table}").to_i
266
169
 
267
- # Inserts one journal row in its own HTTP request.
268
- #
269
- # @param entry [Ports::Persistence::Entry] the save or delete to journal; `state` is
270
- # encoded through the state codec and `mirrors` stored as JSON, or NULL when nil
271
- # @return [Ports::Persistence::Entry] the same `entry`
272
- # @raise [Runtime::WiringError] if D1 rejects the insert
273
170
  def append(entry)
274
171
  @db.execute(
275
172
  "INSERT INTO #{quoted_entry_table} (aggregate_id, operation, state, mirrors) VALUES (?, ?, ?, ?)",
276
- # `mirrors` (unlike `state`) is a nullable column — an absent
277
- # mirrors hash must bind a real SQL NULL, not the four-character
278
- # JSON text `"null"` (`JSON.generate(nil)`), or a future `IS NULL`
279
- # check against it would never match. Same guard `postgres_era.rb`
280
- # already uses for its own journal's `mirrors` column.
173
+ # Absent mirrors bind SQL NULL, not the JSON text "null" (the column is nullable).
281
174
  [entry.id, entry.operation, state_json(entry.state), entry.mirrors && JSON.generate(entry.mirrors)]
282
175
  )
283
176
  entry
284
177
  end
285
178
 
286
- # Replaces or deletes the aggregate's row for one journal entry.
287
- #
288
- # @param entry [Ports::Persistence::Entry] the save or delete to materialize
289
- # @return [Runtime::Instance, Array] for a save, a new instance over the entry's state;
290
- # for a delete, the `DELETE` statement's empty result rows
291
- # @raise [Runtime::WiringError] if D1 rejects the statement
292
179
  def project(entry)
293
180
  return @db.execute("DELETE FROM #{quoted_table} WHERE id = ?", [entry.id]) if entry.delete?
294
181
 
@@ -304,13 +191,7 @@ module Hecks
304
191
  instance
305
192
  end
306
193
 
307
- # Reads the whole journal back in append order, for `AppendOnly#recover!` to replay.
308
- #
309
- # @return [Array<Ports::Persistence::Entry>] every journalled entry, state decoded
310
- # through the state codec and `mirrors` parsed with String keys (nil when none were
311
- # stored); a NULL `operation` reads as `"save"`; `[]` when nothing has been appended
312
- # @raise [Runtime::WiringError] if D1 rejects the statement
313
- # @raise [JSON::ParserError] if a stored `state` or `mirrors` value is not valid JSON
194
+ # The whole journal in append order, for `AppendOnly#recover!` to replay.
314
195
  def entries
315
196
  @db.execute("SELECT aggregate_id, operation, state, mirrors FROM #{quoted_entry_table} ORDER BY sequence").map do |row|
316
197
  state = JSON.parse(row["state"])
@@ -323,70 +204,25 @@ module Hecks
323
204
  end
324
205
  end
325
206
 
326
- # Deletes every row of the aggregate's table and its journal; events and saga rows
327
- # are left in place.
328
- #
329
- # @return [Adapters::D1] self
330
- # @raise [Runtime::WiringError] if D1 rejects a statement
207
+ # Clears the aggregate table and its journal; events and saga rows stay.
331
208
  def reset!
332
209
  @db.execute("DELETE FROM #{quoted_table}")
333
210
  @db.execute("DELETE FROM #{quoted_entry_table}")
334
211
  self
335
212
  end
336
213
 
337
- # Journals and then replaces an instance's current state, as two separate HTTP
338
- # requests rather than one batch.
339
- #
340
- # @param instance [Runtime::Instance] the instance to store
341
- # @return [Runtime::Instance] a new instance over a shallow copy of the saved state
342
- # @raise [Runtime::WiringError] if D1 rejects either statement; a journal row already
343
- # inserted stays
214
+ # Journals then projects as two HTTP requests; the journal row stays if projecting fails.
344
215
  def save(instance)
345
216
  entry = Ports::Persistence::Entry.new(operation: "save", id: instance.id.to_s, state: instance.state.dup)
346
217
  append(entry)
347
218
  project(entry)
348
219
  end
349
220
 
350
- # Stores an entry and reports whether it inserted, replaced or conflicted, all in one
351
- # batched HTTP request.
352
- #
353
- # Classification, durable journal append and current-state projection
354
- # are one D1 batch transaction and therefore one HTTP request. The first
355
- # statement supplies the outcome from database state inside that same
356
- # transaction; the runtime performs no preliminary find.
221
+ # Stores an entry in one D1 batch; returns `:inserted`, `:replaced` or `:conflicted`.
357
222
  #
358
- # Under `insert_only:`, spending a separate, earlier round trip finding
359
- # out whether the row exists before building the batch would be a real
360
- # TOCTOU gap (two concurrent creates at the same identity could both
361
- # pass that check before either wrote). D1's batch has no conditional
362
- # branch of its own, true, but it does not need one: a batch's own
363
- # statements already execute in order, atomically, as one transaction
364
- # (Connection#batch's own comment) — the exact guarantee the single-
365
- # connection adapters' own `@db.transaction do ... end` gets locally.
366
- # So the existence check sits inside the batch as its own first
367
- # statement, and the two writes are individually gated with `WHERE NOT
368
- # EXISTS (...)` against that same table, evaluated in the same
369
- # transaction — a row that already existed makes both writes into
370
- # real, zero-row no-ops rather than skipping them from the Ruby side,
371
- # matching Sqlite#atomic_put's `next` (skip append and project both,
372
- # together) with no second HTTP call and no gap for another writer to
373
- # land in between the check and the write.
374
- #
375
- # Three SQL statements, built here and batched together as one
376
- # transaction below — see the paragraph above on the real TOCTOU gap
377
- # this exact shape closes (the existence check inside the
378
- # batch, not run as a separate earlier round trip). Splitting the
379
- # per-statement builders out would still need columns/values/slots/
380
- # not_exists/quoted_table threaded into each, and would separate
381
- # three pieces of one atomic batch across methods with no single
382
- # place left to see that they are, together, the fix.
383
- #
384
- # @param entry [Ports::Persistence::Entry] the save to store
385
- # @param insert_only [Boolean] when true, an existing row turns both writes into
386
- # zero-row no-ops
387
- # @return [Symbol] `:inserted`, `:replaced`, or `:conflicted` when `insert_only` met an
388
- # existing row and nothing was written
389
- # @raise [Runtime::WiringError] if D1 rejects the batch; the whole batch is rolled back
223
+ # The existence check is the batch's first statement and both writes are gated by
224
+ # WHERE NOT EXISTS, so `insert_only` has no gap between check and write.
225
+ # @return [Symbol] `:conflicted` only when `insert_only` met an existing row
390
226
  # rubocop:disable-next Metrics/AbcSize
391
227
  # rubocop:disable-next Metrics/MethodLength
392
228
  def atomic_put(entry, insert_only: false)
@@ -405,7 +241,7 @@ module Hecks
405
241
  "THEN 'replaced' ELSE 'inserted' END AS status"
406
242
  end
407
243
 
408
- # `mirrors` is nullable (unlike `state`) — see `append`'s own comment.
244
+ # `mirrors` is nullable; see `append`.
409
245
  encoded_mirrors = entry.mirrors && JSON.generate(entry.mirrors)
410
246
 
411
247
  entry_sql, entry_binds =
@@ -444,12 +280,6 @@ module Hecks
444
280
  results.fetch(0).fetch(0).fetch("status").to_sym
445
281
  end
446
282
 
447
- # Journals a delete and then removes the row, whether or not a row exists, as two
448
- # separate HTTP requests.
449
- #
450
- # @param id [String, Object] the aggregate identity, journalled as `id.to_s`
451
- # @return [Boolean] always true
452
- # @raise [Runtime::WiringError] if D1 rejects either statement
453
283
  def delete(id)
454
284
  entry = Ports::Persistence::Entry.new(operation: "delete", id: id.to_s, state: nil)
455
285
  append(entry)
@@ -457,11 +287,6 @@ module Hecks
457
287
  true
458
288
  end
459
289
 
460
- # Inserts an emitted event into the database's shared `events` table.
461
- #
462
- # @param event [Runtime::Event] the emitted event; `payload` is stored as JSON
463
- # @return [Array] the insert's empty result rows; callers ignore it
464
- # @raise [Runtime::WiringError] if D1 rejects the insert
465
290
  def record_event(event)
466
291
  @db.execute(
467
292
  "INSERT INTO events (name, aggregate, aggregate_id, payload, occurred_at) VALUES (?, ?, ?, ?, ?)",
@@ -469,12 +294,7 @@ module Hecks
469
294
  )
470
295
  end
471
296
 
472
- # Reads back every recorded event in insertion order — the database's whole `events`
473
- # table, not only this aggregate's rows.
474
- #
475
- # @return [Array<Runtime::Event>] the stored events, `payload` parsed with Symbol keys
476
- # and `occurred_at` as stored; `[]` when none are recorded
477
- # @raise [Runtime::WiringError] if D1 rejects the statement
297
+ # Every recorded event in the shared `events` table, not only this aggregate's.
478
298
  def events
479
299
  @db.execute("SELECT * FROM events ORDER BY id").map do |row|
480
300
  Runtime::Event.new(
@@ -487,13 +307,24 @@ module Hecks
487
307
  end
488
308
  end
489
309
 
490
- # Replaces one saga instance's checkpoint, keyed by domain, process manager and
491
- # correlation.
492
- #
493
- # ── the optional saga-persistence capability (§2) — reuses the DDL
494
- # `Sqlite::SchemaBuilder` already shares with Sqlite (`d1.rb`'s own
495
- # file header). Same `?`-placeholder shape every other write here
496
- # already uses through `Connection#execute`.
310
+ # One record's recorded events, oldest first — pushed down as a `WHERE` clause
311
+ # (`hecks_events_aggregate_id_idx`) instead of filtering `#events`'s whole-table read.
312
+ def events_for(aggregate:, id:)
313
+ @db.execute(
314
+ "SELECT * FROM events WHERE aggregate = ? AND aggregate_id = ? ORDER BY id",
315
+ [aggregate, id.to_s]
316
+ ).map do |row|
317
+ Runtime::Event.new(
318
+ name: row["name"],
319
+ aggregate: row["aggregate"],
320
+ id: row["aggregate_id"],
321
+ payload: JSON.parse(row["payload"], symbolize_names: true),
322
+ occurred_at: row["occurred_at"]
323
+ )
324
+ end
325
+ end
326
+
327
+ # Persists a saga's checkpointed state as one D1 statement.
497
328
  #
498
329
  # @param process_manager [String, Symbol] the process manager's name
499
330
  # @param correlation [String, Object] the instance's correlation value, stored as
@@ -513,13 +344,6 @@ module Hecks
513
344
  )
514
345
  end
515
346
 
516
- # Removes a finished saga instance's checkpoint; a missing row is not an error.
517
- #
518
- # @param process_manager [String, Symbol] the process manager's name
519
- # @param correlation [String, Object] the instance's correlation value, matched as
520
- # `correlation.to_s`
521
- # @return [Array] the statement's empty result rows; callers ignore it
522
- # @raise [Runtime::WiringError] if D1 rejects the statement
523
347
  def delete_saga(process_manager:, correlation:)
524
348
  @db.execute(
525
349
  "DELETE FROM hecks_saga_instances WHERE domain = ? AND process_manager = ? AND correlation = ?",
@@ -527,18 +351,7 @@ module Hecks
527
351
  )
528
352
  end
529
353
 
530
- # Yields every checkpointed saga instance of this adapter's domain, for
531
- # `Registry#rehydrate_sagas!` to restore at boot.
532
- #
533
- # @yieldparam process_manager [String] the process manager's name
534
- # @yieldparam correlation [String] the instance's correlation value
535
- # @yieldparam state [String] the saga's state name
536
- # @yieldparam memory [Hash{Symbol => Object}] the saga's memory, Symbol keys at every depth
537
- # @yieldparam completed_compensations [Array] the completed-compensation ledger, `[]`
538
- # when the column is NULL
539
- # @return [Enumerator, Array<Hash>] an enumerator over the same five values when no
540
- # block is given; otherwise the raw result rows
541
- # @raise [Runtime::WiringError] if D1 rejects the statement
354
+ # Yields each checkpointed saga of this domain, for `Registry#rehydrate_sagas!`.
542
355
  def each_saga
543
356
  return enum_for(:each_saga) unless block_given?
544
357
 
@@ -555,10 +368,7 @@ module Hecks
555
368
 
556
369
  private
557
370
 
558
- # ── SqlQueryBuilder's dialect hooks — identical to Sqlite's, since
559
- # D1 speaks the same dialect (copied, not shared by module include,
560
- # because Sqlite's own copies are private instance methods on a
561
- # different class — see the file header) ───────────────────────
371
+ # SqlQueryBuilder dialect hooks, copied from Sqlite's private methods.
562
372
  def select_list = "*"
563
373
  def from_relation = quoted_table
564
374
  def dialect_name = "D1"
@@ -585,8 +395,7 @@ module Hecks
585
395
  "json_extract(#{quote_ident(name)}, '#{json_path}')"
586
396
  end
587
397
 
588
- # SQLite (and D1, the same engine) has no bare OFFSET — LIMIT -1 is
589
- # its own documented unbounded spelling, exactly for this case.
398
+ # SQLite has no bare OFFSET; LIMIT -1 is its unbounded spelling.
590
399
  def unbounded_limit = " LIMIT -1"
591
400
 
592
401
  def order_clause(order_by, policy)
@@ -597,8 +406,6 @@ module Hecks
597
406
  @db.execute(sql, binds).map { |row| Runtime::Instance.new(aggregate: @aggregate, id: row["id"], state: decode(row)) }
598
407
  end
599
408
 
600
- # ── the rest of the dialect ─────────────────────────────────────
601
-
602
409
  def quote_ident(name)
603
410
  %("#{name.to_s.gsub('"', '""')}")
604
411
  end
@@ -2,13 +2,8 @@ require_relative "../../vocabulary"
2
2
 
3
3
  module Hecks
4
4
  module Adapters
5
- # The filesystem-backed loader — glob-and-`Kernel.load` a domain's own
6
- # `.port`/`.adapter`/`.bluebook`/`.hecksagon`/`.world`/environment-overlay
7
- # files off disk, in the order `Vocabulary.fetch("LoadOrder")` requires,
8
- # and locate a domain's own root directory by walking up from any file
9
- # inside it looking for a `.hecksagon`. What `Hecks.boot(path)` uses when
10
- # a caller names a directory rather than an explicit file list (see
11
- # `Loader.boot_files` for that other path).
5
+ # Loads a domain's files off disk in `Vocabulary.fetch("LoadOrder")` order and finds
6
+ # a domain's root directory. Used by `Hecks.boot(path)` when given a directory.
12
7
  class Folder
13
8
  DOMAIN_ORDER = Hecks::Vocabulary.fetch("LoadOrder")
14
9
  PORTS = "ports".freeze
@@ -41,34 +36,12 @@ module Hecks
41
36
  load_each(File.join(root, ADAPTERS), %w[*.adapter */*.adapter */*/*.adapter])
42
37
  end
43
38
 
44
- # Chapters first, judged once, then everything that reads them.
45
- # A chapter may be split across files (the language's own grammar is
46
- # nine), and judging file one before files two-through-nine exist
47
- # refuses references that are perfectly well declared a file later —
48
- # see MetaValidator.defer for the whole reasoning. DOMAIN_ORDER
49
- # already places every `*.bluebook` ahead of hecksagons and worlds,
50
- # so the window ends at the last chapter pattern rather than at a
51
- # hand-written list this would otherwise have to keep in step.
39
+ # Loads bluebook chapters first, judged once as a deferred group, then everything
40
+ # else in `DOMAIN_ORDER`. Deferring keeps a chapter split across files from being
41
+ # judged before its later files exist (see MetaValidator.defer).
52
42
  #
53
- # `environment:` — one more pair of files, loaded last, not a glob.
54
- # Recovered, not new — see Runtime::Loader.boot's own comment for
55
- # the provenance. A caller passing `Hecks.boot(path, environment:
56
- # "production")` gets exactly `environments/production.hecksagon`
57
- # and `environments/production.world` loaded, whichever exist (a
58
- # missing one is a silent no-op — not every environment overrides
59
- # both; see docs/implemented/guides/wiring.md's "Swapping wiring per
60
- # environment" for the motivating case: swapping a driven adapter
61
- # — e.g. a real payment gateway for a mock one, or a hosting
62
- # layer's tenancy settings — without an `if`/`else` anywhere in
63
- # the domain's own wiring). Never matched by `DOMAIN_ORDER`'s own
64
- # globs (all non-recursive, none named `environments/*`), so this
65
- # is the only thing that ever reaches them. Loaded as genuine
66
- # `Hecks.hecksagon "SameDomain" do ... end` / `Hecks.world
67
- # "SameDomain" do ... end` blocks — merged into the base file's
68
- # own hecksagon/world (Registry#add_hecksagon / #add_world,
69
- # concatenate/override rather than replace), so an overlay can
70
- # rebind or add settings for anything the base file declared
71
- # without needing to know what else the base file said.
43
+ # An `environment:` overlay (`environments/<name>.hecksagon` and `.world`) loads
44
+ # last and merges into the base hecksagon/world; a missing overlay file is skipped.
72
45
  #
73
46
  # @param directory [String] the domain's bluebook directory to load, as
74
47
  # `bluebook_directory` resolves it
@@ -90,12 +63,8 @@ module Hecks
90
63
  load_each(directory, [File.join("environments", "#{environment}.world")])
91
64
  end
92
65
 
93
- # Every bluebook in a folder is one declaration set. Individual files
94
- # remain organized in the domain expert's language; the folder is the
95
- # unit callers load. Builders group declarations by the chapter name in
96
- # each file, so a folder may hold more than one chapter without a catalog.
97
- # Sorting makes source order deterministic while the deferred window keeps
98
- # cross-file references from being judged against a partial chapter.
66
+ # Loads every bluebook in a folder as one declaration set, judged after all are loaded
67
+ # so cross-file references never meet a partial chapter.
99
68
  #
100
69
  # @param directory [String] the directory to glob for bluebook chapter files
101
70
  # @param patterns [Array<String>] glob patterns, relative to `directory`, selecting the
@@ -106,23 +75,11 @@ module Hecks
106
75
  Bluebook::MetaValidator.judge_deferred!(Hecks.current_registry)
107
76
  end
108
77
 
109
- # The explicit-file sibling of `load_domain` — for a caller that names
110
- # its own exact files rather than a directory to glob (`Loader.boot_files`,
111
- # behind `Hecks.boot_files`). No `Dir.glob`, no copying: every path here
112
- # is a real file on disk, wherever it actually lives, loaded in place —
113
- # a `.behaviors` file's `loads` scopes a boot this way specifically so a
114
- # per-test boot never has to fake isolation by staging bluebooks into a
115
- # tmpdir (see Loader.boot_files's own header for why that pattern is a
116
- # hazard, not a convenience).
78
+ # Loads exactly the named files in place, without globbing (see `Loader.boot_files`).
79
+ #
80
+ # Files load by category, not in the caller's order: bluebooks (judged as one deferred
81
+ # group), then hecksagons, then worlds, since a hecksagon may reference bluebook constants.
117
82
  #
118
- # Ordered by category, not by the caller's own list order — same four
119
- # groups `Vocabulary.fetch("LoadOrder")` walks a directory in
120
- # (bluebook chapters, translations, hecksagons, worlds), because a
121
- # hecksagon can reference a bluebook's own constants and must not load
122
- # first regardless of which order a caller happened to write `loads
123
- # "x.hecksagon", "x.bluebook"` in. Bluebook chapters are judged as one
124
- # deferred group exactly like `load_domain` does, for the identical
125
- # forward-reference reason (MetaValidator.defer's own header).
126
83
  # @param files [Array<String>] file paths to load, relative to `bluebook_directory`
127
84
  # @param environment [String, nil] the environment name whose overlay, if present,
128
85
  # loads after the selected files
@@ -181,27 +138,11 @@ module Hecks
181
138
 
182
139
  # Finds the nearest domain directory at or above `from`, or nil if there is not one.
183
140
  #
184
- # **The domain you are standing in**. Walks up from `from` — the way git
185
- # finds `.git` — and answers the nearest directory a boot would accept,
186
- # or nil if there is not one above you.
187
- #
188
- # Marked by a `.hecksagon`, not by a `.bluebook`. Chapters are
189
- # everywhere: era translations, the language's own self-hosted grammar,
190
- # and `spec/fixtures`, which holds a dozen unrelated ones in a single
191
- # directory. A `.hecksagon` is the file that says "this is a domain, and
192
- # here is how its aggregates are stored", which is exactly the claim a
193
- # caller is relying on when they omit the path.
141
+ # Walks up from `from`, like git finding `.git`. A domain is marked by a `.hecksagon`,
142
+ # not a `.bluebook`, since chapters also appear in translations and fixtures.
194
143
  #
195
- # Both layouts, because `bluebook_directory` above accepts both: a
196
- # domain directory holding a `bluebook/` subdirectory (every example in
197
- # this corpus), or one holding the files directly.
198
- # Normalised to the outer directory. Standing in `examples/banking/bluebook`,
199
- # the `.hecksagon` is right there, so a plain walk stops on the
200
- # `bluebook/` directory itself. Both boot identically — `bluebook_directory`
201
- # accepts either and `Loader.boot` takes `File.dirname` of what it gets,
202
- # so the registry root comes out the same — but `examples/banking` is the
203
- # directory a person names, and the one a `.world`'s `dir "data"` reads
204
- # as relative to.
144
+ # A `bluebook/` subdirectory result is normalised to its parent, the directory
145
+ # a `.world`'s `dir "data"` is relative to.
205
146
  #
206
147
  # @param from [String] the directory to walk up from; defaults to the process's current
207
148
  # working directory