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,38 +5,11 @@ require_relative "../../rendering"
5
5
  module Hecks
6
6
  module Runtime
7
7
  class Value
8
- # How a `list_of` attribute's own elements GET hydrated — entity-typed
9
- # and value-object-typed alike — split out of `Coercion` (this file's
10
- # sibling, extended into `Value` alongside it exactly the way
11
- # `Admission` already is) once `Coercion` itself grew past
12
- # `Metrics/ModuleLength`'s budget from two, unrelated fixes landing in
13
- # the same method the same week (BUG#32's own `hydrate_entity_identity`
14
- # and BUG#33's own `check_entity_list_identities` — see each method's
15
- # own header, and this repo's `.rubocop_todo.yml` for the merge that
16
- # made the split necessary). Cross-calls into `Coercion`'s own
17
- # `for_attribute`/`build`/`fields_for`/`value_object_for`/
18
- # `trusting_stored_state?` work unqualified here, exactly as they do
19
- # within `Coercion` itself, because both modules land on the same
20
- # `Value` singleton class once extended — `self` never has to know
21
- # which file a sibling method actually lives in.
8
+ # Hydrates a `list_of` attribute's own elements, entity-typed and
9
+ # value-object-typed alike; extended into `Value` alongside `Coercion`.
22
10
  module EntityListCoercion
23
- # S17, ADR 0026 — searches the whole entity tree, not only the
24
- # root's own direct children. `aggregate` here is always the
25
- # root aggregate — `for_attribute`'s own `aggregate` argument is
26
- # never reassigned as hydration recurses into a nested element,
27
- # because coercion has to resolve value objects, and only the
28
- # root answers `.value_object` at all (Entity's own header
29
- # comment: an entity must not answer to it, or `Value.
30
- # for_attribute` could not tell a piece from a head). So
31
- # a nested entity — Dispatch, inside Handler — is not a direct
32
- # child of the root the way Handler itself is, and a plain
33
- # `aggregate.entities.find` stops one level short of it.
34
- #
35
- # @param construct [Bluebook::Aggregate, Bluebook::Entity] the construct to
36
- # search, and every entity nested under it
37
- # @param name [String] the entity's declared `hecks_name` to find
38
- # @return [Bluebook::Entity, nil] the matching entity anywhere in the tree, or
39
- # nil if none matches
11
+ # Searches the whole entity tree, not just the root's direct
12
+ # children; `aggregate` here is always the root aggregate. (ADR 0026)
40
13
  def find_entity(construct, name)
41
14
  construct.entities.each do |candidate|
42
15
  return candidate if candidate.hecks_name == name
@@ -47,54 +20,12 @@ module Hecks
47
20
  nil
48
21
  end
49
22
 
50
- # Hydrates a `list_of` attribute's offered value — each element of a
51
- # whole-list offering, or a single remove-target value, depending on
52
- # `attribute.type` and `value`'s own shape.
53
- #
54
- # Frozen through: a list read back out of the store is an answer,
55
- # not a handle on what is stored.
23
+ # Hydrates a `list_of` attribute's offered value: each element of a
24
+ # whole-list Array, or a single remove-target value.
56
25
  #
57
- # ADR 0047 — bailing (`return value unless entity`) the moment
58
- # `attribute.type` names a value object rather than an entity would
59
- # hand back the raw, un-hydrated argument untouched. A `sets :field`
60
- # mutation sourced from a whole-array argument (as opposed to
61
- # element-by-element `append:`) goes straight through
62
- # `for_attribute`'s `:list` branch, so `Banking::CardPayment.
63
- # Authorize`'s own `sets :tags` (`list_of(Tag)`) would store plain
64
- # Ruby Hashes as its `tags` elements forever — never a real
65
- # `Value`, never through `Tag`'s own `pattern:`/`invariant`
66
- # checks. `remove:`'s `==` comparison (a real `Value` against a
67
- # raw `Hash`) would then always fail, since `Hash#==` refuses
68
- # anything that isn't itself a compatible Hash — the bug ADR 0047
69
- # traces in full. Delegating to `hydrate_value_object_list` below
70
- # closes that gap the same way the entity branch already works:
71
- # build a real, validated `Value` per element, reusing
72
- # `for_attribute`'s own composite-construction path rather than
73
- # inventing a second one.
74
- # BUG#32 (QualityControl ledger) — without this, `remove:`'s own
75
- # single-target value would fall straight into
76
- # `Array(value).map { ... }` below unguarded, unlike this method's
77
- # own delegated `hydrate_value_object_list` sibling, whose
78
- # `value.is_a?(Array)` check exists for exactly this shape (see
79
- # that method's own comment). For an entity-typed list, `remove:`'s
80
- # scalar target (`Ledger.Void`'s `sequence: EntrySequence`) is
81
- # never a Hash, so `Array(2)` would merely wrap it as `[2]` rather
82
- # than shredding it — but the wrapping itself would still be wrong:
83
- # `MutationApplier#removed`'s `element == value` would then compare
84
- # a stored `Entry` Hash against a one-element Array, which can
85
- # never be `==` a Hash, so nothing would ever be removed and
86
- # nothing would ever refuse either. Routed to `hydrate_entity_identity`
87
- # instead, below.
88
- #
89
- # @param aggregate [Bluebook::Aggregate] the root aggregate `attribute` is
90
- # declared on
91
- # @param attribute [Bluebook::Attribute] the `list_of` attribute being hydrated
92
- # @param value [Array<Hash, Object>, Object] the offered value: a whole-list
93
- # Array (a `sets`/hydrate load) or a single remove-target value
94
- # @return [Object] a frozen Array of hydrated elements when `value` is a
95
- # whole-list Array and `attribute.type` names an entity; otherwise whatever
96
- # `hydrate_entity_identity` (a non-Array value naming an entity) or
97
- # `hydrate_value_object_list` (`attribute.type` naming no entity) returns
26
+ # Delegates non-entity types to `hydrate_value_object_list` so
27
+ # elements get the same `pattern:`/invariant checks other
28
+ # composites get. (ADR 0047)
98
29
  def hydrate_entity_list(aggregate, attribute, value)
99
30
  entity = find_entity(aggregate, attribute.type.to_s)
100
31
  return hydrate_value_object_list(aggregate, attribute, value) unless entity
@@ -110,61 +41,16 @@ module Hecks
110
41
  acc[key] = field ? for_attribute(aggregate, field, field_value) : field_value
111
42
  end
112
43
  end
113
- # BUG#33 — only a genuine whole-list offering (`value.is_a?(Array)`)
114
- # is a caller naming every element's own identity at once; the
115
- # single-target shape this same method also hydrates (a `remove:`
116
- # target, wrapped one level up by `Array()`) never reaches this
117
- # check, and never should — see `check_entity_list_identities`'s
118
- # own comment.
44
+ # Only a genuine whole-list offering names every element's own
45
+ # identity at once; a single `remove:` target never reaches this.
119
46
  check_entity_list_identities(aggregate, entity, hydrated) if value.is_a?(Array)
120
47
  Freezer.deep(hydrated)
121
48
  end
122
49
 
123
- # `MutationApplier#check_entity_collision`'s own guard
124
- # (mutation_applier.rb), extended from a single caller-supplied
125
- # append (BUG#13) to a whole-list replace — `sets :entries` bare
126
- # (`Ledger.ReplaceEntries`, the corpus's first `list_of(ENTITY)`
127
- # command argument/mutation, qa/stress_domains/corrections). The
128
- # array branch above rebuilds each offered element's own declared
129
- # fields but never checked the offered list itself for either way
130
- # it can misname its own entities:
131
- #
132
- # - two elements sharing one identity — the same silent-duplicate
133
- # hazard BUG#13's own comment describes: `EntityInterpreter#
134
- # element_of`'s own `find_index` always matches the first
135
- # match, so the second becomes permanently unaddressable by any
136
- # later command.
137
- # - an element missing its identity altogether — there is no
138
- # auto-mint for a whole-list replace the way `MutationApplier#
139
- # entity_element` mints one for a single append (which element
140
- # would it mint for? every element here is the caller's own
141
- # whole state, offered at once), so an absent identity is
142
- # refused rather than guessed.
143
- #
144
- # Non-composite identities only, exactly BUG#13's own scope
145
- # (`entity.identified_by` answers a single Symbol only when
146
- # `identity_heads.size == 1`, `Behaviour::Traits#derive_identity`) —
147
- # a composite identity's own duplicate/missing question is the
148
- # same pre-existing, narrower gap BUG#13 documented and left open,
149
- # not widened here.
150
- #
151
- # Refuses a whole-list offering that misnames its own entities' identities —
152
- # a duplicate identity across two elements, or an element missing one.
153
- #
154
- # Skipped under `trusting_stored_state?`, the same guard `validate!`
155
- # already gives every value object (C6.3): a record already
156
- # written is trusted as it was, so tightening this check can never
157
- # make an old, already-persisted record unreadable.
158
- #
159
- # @param aggregate [Bluebook::Aggregate] the aggregate `entity` belongs to,
160
- # named in a refusal
161
- # @param entity [Bluebook::Entity] the entity type `elements` are shaped as
162
- # @param elements [Array<Hash, Object>] the hydrated whole-list offering; a
163
- # non-Hash element is skipped, not checked
164
- # @return [void]
165
- # @raise [Runtime::TypeMismatch] if `entity` declares a single-field identity
166
- # and an element offers no value for it
167
- # @raise [Runtime::AlreadyExists] if two elements offer the same identity value
50
+ # Refuses a whole-list offering that misnames its own entities: a
51
+ # duplicate identity across two elements, or an element missing
52
+ # one. Single-field identities only; skipped once
53
+ # `trusting_stored_state?`.
168
54
  def check_entity_list_identities(aggregate, entity, elements)
169
55
  identity = entity.identified_by
170
56
  return unless identity
@@ -194,43 +80,10 @@ module Hecks
194
80
  end
195
81
  end
196
82
 
197
- # BUG#32 — `remove:`'s own single-target value against an
198
- # entity-typed list. An entity is never offered to `remove:`
199
- # whole the way a value object is (`hydrate_value_object_list`'s
200
- # own `element == value` full-value-equality shape) — an entity
201
- # must never answer `.value_object` at all (`Entity`'s own header
202
- # comment), so there is no whole-value shape here to rebuild in
203
- # the first place, only the one field a caller would otherwise
204
- # have to name to address that element any other way
205
- # (`EntityElement#element_of`'s own `wants`). So this coerces the
206
- # offered scalar against the entity's own identity field's
207
- # declared type — not the entity's full shape — and hands back a
208
- # real, correctly-typed `Value` ready to compare against each
209
- # stored element's own identity field
210
- # (`EntityElement.list_element_match?`, the shared rule both
211
- # `MutationApplier#removed` and `EntityElement#
212
- # removed_from_element` match against).
213
- #
214
- # A composite identity (more than one head) has no single field a
215
- # bare `remove:` target could mean, so this passes the value
216
- # through uncoerced rather than guessing which head — the same
217
- # "nothing in this corpus needs it yet" boundary
218
- # `MutationApplier#check_entity_collision`'s own header already
219
- # draws for entity identity elsewhere in this runtime.
220
- # Coerces a `remove:` target against an entity's own single-field
221
- # identity type, rather than the entity's full shape.
222
- #
223
- # `list_element_match?` treats an uncoerced value the same way
224
- # it always treated the pre-fix wrapped Array: never a match, a
225
- # documented no-op rather than a crash.
226
- #
227
- # @param aggregate [Bluebook::Aggregate] the aggregate `entity` belongs to
228
- # @param entity [Bluebook::Entity] the entity type `value` addresses
229
- # @param value [Object] the offered remove-target value
230
- # @return [Runtime::Value, Object] `value` already coerced (returned unchanged);
231
- # the value coerced against the identity field's declared type when `entity`
232
- # has a single identity head and a matching attribute; `value` unchanged
233
- # otherwise (no identity head, a composite identity, or no matching attribute)
83
+ # Coerces a `remove:` target against an entity's single-field
84
+ # identity type, rather than the entity's full shape. Passed
85
+ # through unchanged for a composite identity (more than one head)
86
+ # rather than guessing which head it means.
234
87
  def hydrate_entity_identity(aggregate, entity, value)
235
88
  return value if value.is_a?(self)
236
89
 
@@ -243,47 +96,12 @@ module Hecks
243
96
  for_attribute(aggregate, field, value)
244
97
  end
245
98
 
246
- # Hydrates a `list_of` attribute's offered value when `attribute.type`
247
- # names a value object rather than an entity.
99
+ # Hydrates a `list_of` attribute's offered value when
100
+ # `attribute.type` names a value object rather than an entity.
248
101
  #
249
- # The value-object sibling of the entity branch above: an element
250
- # already shaped like the target `Value` (or a `Hash`/scalar that
251
- # `fields_for` can still open) is rebuilt through the same `build`
252
- # a scalar composite attribute already uses (`for_attribute`'s own
253
- # `coerced = ... build(value_object, fields_for(...), aggregate)`
254
- # line) — same defaults, same `pattern:`/`admits:`/invariant
255
- # checks, same `trusting_stored_state?` bypass on a trusted load.
256
- # `attribute.type` naming neither an entity nor a value object
257
- # (a `list_of(String)`, say) has no shape to rebuild into, so the
258
- # element passes through unchanged, exactly as the entity branch's
259
- # own non-Hash elements do.
260
- #
261
- # Not `Array(value).map` (unlike the entity branch above) — `value`
262
- # here is not always genuinely list-shaped. `MutationApplier#
263
- # removed`'s own `Value.for_attribute(aggregate, attribute, value)`
264
- # call (`attribute` = the list attribute, `mutation.target`; `value`
265
- # = the single remove-target argument, already a real `Value` by
266
- # the time it gets here) reuses this exact branch — for `remove:`,
267
- # not for a whole-list `sets`. `Array(a_real_Value)` alone would be
268
- # harmless (`Value` defines neither `to_a` nor `to_ary`, so Kernel
269
- # wraps it `[value]`), but `Array(a_Hash)` is not harmless: Ruby's
270
- # `Array()` opens a bare Hash into its own `[[k, v], ...]` pairs,
271
- # not `[hash]` — silently shredding a single-element Hash-shaped
272
- # target into garbage instead of hydrating it. Branching on
273
- # `value.is_a?(Array)` up front (true only for a genuine whole-list
274
- # `sets`/hydrate load) keeps the single-target shape a single
275
- # target, hydrated the same way, never listified.
276
- #
277
- # @param aggregate [Bluebook::Aggregate] the aggregate `attribute` is declared
278
- # on, or a construct that does not respond to `value_object` (an entity), in
279
- # which case `value` passes through unchanged
280
- # @param attribute [Bluebook::Attribute] the `list_of` attribute being hydrated
281
- # @param value [Array<Hash, Object>, Object] the offered value: a whole-list
282
- # Array, or a single remove-target value
283
- # @return [Object] `value` unchanged when `aggregate` does not respond to
284
- # `value_object`, or `attribute.type` names no value object; otherwise a
285
- # frozen Array of built `Value`s for a whole-list Array, or a single built
286
- # `Value` (via `hydrate_value_object_element`) otherwise
102
+ # Branches on `value.is_a?(Array)` rather than `Array(value)`: a
103
+ # bare Hash-shaped single target would otherwise be shredded into
104
+ # its own `[[k, v], ...]` pairs instead of hydrated whole.
287
105
  def hydrate_value_object_list(aggregate, attribute, value)
288
106
  return value unless aggregate.respond_to?(:value_object)
289
107
 
@@ -296,19 +114,8 @@ module Hecks
296
114
  Freezer.deep(hydrated)
297
115
  end
298
116
 
299
- # Rebuilds one `list_of` element into a real, validated `Value`, unless it
300
- # already is one of `value_object`'s own type.
301
- #
302
- # @param aggregate [Bluebook::Aggregate] the aggregate `value_object` is
303
- # resolved against
304
- # @param attribute [Bluebook::Attribute] the `list_of` attribute `element`
305
- # belongs to
306
- # @param value_object [Class] the `Bluebook::ValueObject` subclass `element`
307
- # is built as
308
- # @param element [Object] the raw element to build: a Hash of fields, a scalar
309
- # `fields_for` can still open, or an already-built `Value`
310
- # @return [Runtime::Value] `element` unchanged if it is already a `Value` of
311
- # `value_object`'s own type; otherwise a freshly built one
117
+ # Rebuilds one `list_of` element into a real, validated `Value`,
118
+ # unless it already is one of `value_object`'s own type.
312
119
  def hydrate_value_object_element(aggregate, attribute, value_object, element)
313
120
  return element if element.is_a?(self) && element.type_name == value_object.hecks_name
314
121
 
@@ -0,0 +1,172 @@
1
+ require_relative "../errors"
2
+ require_relative "../refusal_wording"
3
+ require_relative "../../rendering"
4
+
5
+ module Hecks
6
+ module Runtime
7
+ class Value
8
+ # Boundary checks that refuse a mistyped, unknown, missing or malformed field before an
9
+ # invariant reads it; extended into `Value` alongside `Coercion`, which calls them.
10
+ module FieldChecks
11
+ # C3.8 boundary check — refuses a mistyped argument before it breaks a predicate.
12
+ private def check_bare_primitive(owner, attribute, value)
13
+ type = attribute.type.to_s
14
+ expected = NUMERIC[type]
15
+ mistyped = if expected
16
+ !value.is_a?(expected)
17
+ elsif NON_NUMERIC_SCALARS.include?(type)
18
+ COMPOSITE_SHAPES.any? { |shape| value.is_a?(shape) }
19
+ else
20
+ false
21
+ end
22
+ if mistyped
23
+ raise TypeMismatch,
24
+ RefusalWording.render_site("TypeMismatch", "numeric_field",
25
+ type: owner.hecks_name, field: attribute.name,
26
+ expected: type, offered: Rendering.describe(value))
27
+ end
28
+
29
+ check_numeric_bounds(owner.hecks_name, attribute.name, value)
30
+ end
31
+
32
+ # C3.3/C3.4 — value bounds enforced at every boundary: an Integer must fit
33
+ # signed 64 bits, a Float must be finite.
34
+ INT64_RANGE = (-(2**63))..((2**63) - 1)
35
+
36
+ private def check_numeric_bounds(type_name, field_name, given)
37
+ if given.is_a?(Integer) && !INT64_RANGE.cover?(given)
38
+ raise TypeMismatch,
39
+ RefusalWording.render_site("TypeMismatch", "integer_range",
40
+ type: type_name, field: field_name, offered: Rendering.describe(given))
41
+ end
42
+ return unless given.is_a?(Float) && !given.finite?
43
+
44
+ raise TypeMismatch,
45
+ RefusalWording.render_site("TypeMismatch", "non_finite_field",
46
+ type: type_name, field: field_name, offered: Rendering.describe(given))
47
+ end
48
+
49
+ # A value object refuses an undeclared key the same way a command's own
50
+ # payload does, checked before any other field-content check.
51
+ private def check_unknown_fields(value_object, fields)
52
+ known = value_object.attributes.map { |attribute| attribute.name.to_sym }
53
+ unknown = (fields.keys.map(&:to_sym) - known).sort
54
+ return if unknown.empty?
55
+
56
+ declared = value_object.attributes.map(&:name)
57
+ raise UnknownArgument,
58
+ RefusalWording.render_site("UnknownArgument", "unknown_args",
59
+ command: value_object.hecks_name, unknown: unknown,
60
+ declared: declared)
61
+ end
62
+
63
+ # C3.7 — every non-optional, non-list field must arrive (or construction
64
+ # refuses); a `default:` has already been filled in by `apply_defaults`.
65
+ private def check_required_fields(value_object, fields)
66
+ value_object.attributes.each do |attribute|
67
+ next if attribute.optional? || attribute.list?
68
+ next unless fields[attribute.name].nil?
69
+
70
+ raise TypeMismatch,
71
+ RefusalWording.render_site("TypeMismatch", "numeric_field",
72
+ type: value_object.hecks_name, field: attribute.name,
73
+ expected: attribute.type, offered: "nil")
74
+ end
75
+ end
76
+
77
+ # Checked before invariants, because an invariant reading a mistyped field
78
+ # is exactly the thing that would otherwise explode.
79
+ NUMERIC = { "Integer" => Integer, "Float" => Numeric }.freeze
80
+ private def check_numeric_fields(value_object, fields)
81
+ value_object.attributes.each do |attribute|
82
+ expected = NUMERIC[attribute.type.to_s]
83
+ next unless expected
84
+
85
+ given = fields[attribute.name]
86
+ next if given.nil?
87
+
88
+ offered_items(attribute, given).each do |item|
89
+ unless item.is_a?(expected)
90
+ raise TypeMismatch,
91
+ RefusalWording.render_site("TypeMismatch", "numeric_field",
92
+ type: value_object.hecks_name, field: attribute.name,
93
+ expected: attribute.type, offered: Rendering.describe(item))
94
+ end
95
+
96
+ # `is_a?(expected)` alone waves NaN/Infinity through — both are real
97
+ # Floats. `-0.0` is deliberately left unchecked: finite and legitimate.
98
+ check_numeric_bounds(value_object.hecks_name, attribute.name, item)
99
+ end
100
+ end
101
+ end
102
+
103
+ # A `list_of` field holds an Array whatever its element type, so a lone scalar
104
+ # offered for it is refused; nil stays legitimate, as it is for any optional field.
105
+ private def check_list_shapes(value_object, fields)
106
+ value_object.attributes.each do |attribute|
107
+ given = fields[attribute.name]
108
+ next unless attribute.list? && !given.nil? && !given.is_a?(Array)
109
+
110
+ raise TypeMismatch, RefusalWording.render_site(
111
+ "TypeMismatch", "numeric_field", type: value_object.hecks_name, field: attribute.name,
112
+ expected: "list_of(#{attribute.type})", offered: Rendering.describe(given)
113
+ )
114
+ end
115
+ end
116
+
117
+ # The values a field's element-level checks apply to: each element of a list, or the
118
+ # one value of a scalar field.
119
+ private def offered_items(attribute, given) = attribute.list? && given.is_a?(Array) ? given : [given]
120
+
121
+ # A scalar field (String, or a boolean) must not arrive as a composite
122
+ # (Array/Hash) standing in for a leaf value. A String field additionally
123
+ # must not arrive as any other scalar, except inside `judge_bootstrapping?`.
124
+ COMPOSITE_SHAPES = [Array, ::Hash].freeze
125
+ NON_NUMERIC_SCALARS = %w[String TrueClass FalseClass].freeze
126
+ private def check_scalar_shapes(value_object, fields)
127
+ value_object.attributes.each do |attribute|
128
+ type = attribute.type.to_s
129
+ next unless NON_NUMERIC_SCALARS.include?(type)
130
+
131
+ given = fields[attribute.name]
132
+ next if given.nil?
133
+
134
+ offered_items(attribute, given).each do |item|
135
+ composite = COMPOSITE_SHAPES.any? { |shape| item.is_a?(shape) }
136
+ non_string_scalar = type == "String" && !composite && !item.is_a?(String) && !judge_bootstrapping?
137
+ next unless composite || non_string_scalar
138
+
139
+ raise TypeMismatch,
140
+ RefusalWording.render_site("TypeMismatch", "numeric_field",
141
+ type: value_object.hecks_name, field: attribute.name,
142
+ expected: attribute.type, offered: Rendering.describe(item))
143
+ end
144
+ end
145
+ end
146
+
147
+ # A field declared with a pattern must match it, refused as a TypeMismatch
148
+ # rather than surfacing later as a broken predicate. The pattern itself is
149
+ # already vetted by PatternSubset when the bluebook is declared. `^` and `$` match the
150
+ # whole value, as in Rust, so a newline cannot smuggle text past an anchored pattern.
151
+ private def check_patterns(value_object, fields)
152
+ value_object.attributes.each do |attribute|
153
+ pattern = attribute.pattern
154
+ next unless pattern
155
+
156
+ given = fields[attribute.name]
157
+ next if given.nil?
158
+
159
+ offered_items(attribute, given).each do |item|
160
+ next if item.is_a?(String) && Regexp.new(Hecks::Bluebook::PatternSubset.whole_string(pattern)).match?(item)
161
+
162
+ raise TypeMismatch,
163
+ RefusalWording.render_site("TypeMismatch", "pattern_mismatch",
164
+ type: value_object.hecks_name, field: attribute.name,
165
+ pattern: pattern, offered: Rendering.describe(item))
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
@@ -1,41 +1,25 @@
1
1
  require "json"
2
2
  require_relative "../rendering"
3
3
  require_relative "value/invariant_violation"
4
+ require_relative "value/field_checks"
4
5
  require_relative "value/coercion"
5
6
  require_relative "value/entity_list_coercion"
6
7
  require_relative "value/admission"
7
8
 
8
9
  module Hecks
9
10
  module Runtime
10
- # A typed value object in hand: frozen fields, read by name. How one is
11
- # made — coerced from a raw argument, checked against its declared
12
- # numeric types, patterns and closed sets — is the class-side engine in
13
- # value/coercion.rb, value/entity_list_coercion.rb (a `list_of`
14
- # attribute's own elements — split out once growing Coercion tripped
15
- # Metrics/ModuleLength, see that file's own header), and
16
- # value/admission.rb, extended here so the door stays where it always
17
- # was: `Value.for`, `Value.build`.
11
+ # A typed value object: frozen fields, read by name.
12
+ # Construction lives in value/coercion.rb, field_checks.rb, entity_list_coercion.rb and
13
+ # admission.rb.
18
14
  class Value
15
+ extend FieldChecks
19
16
  extend Coercion
20
17
  extend EntityListCoercion
21
18
  extend Admission
22
19
 
23
20
  attr_reader :value_object
24
21
 
25
- # Frozen through, not just on top.
26
- #
27
- # `@fields.freeze` alone stops a key being added or removed and
28
- # nothing else: the String, Array or Hash a field holds stays
29
- # mutable, so `vo[:value] << "!"` edits a value object in place —
30
- # demonstrated on a real dispatch before this was written, not
31
- # supposed. Same shape as the three freezing bugs already fixed
32
- # (list attributes, the event log, query rows), where the container
33
- # was frozen and the contents were not.
34
- #
35
- # A value object is the one thing in the domain that has no
36
- # identity to change over — `with` already answers a new one rather
37
- # than mutating — so freezing it through is what it always claimed
38
- # to be.
22
+ # Deep-freezes the fields so a held String, Array or Hash cannot be mutated in place.
39
23
  #
40
24
  # @param value_object [Bluebook::ValueObject] the declared type this instance is one of
41
25
  # @param fields [Hash] the type's fields, keyed by name (String or Symbol); deep-frozen
@@ -103,18 +87,8 @@ module Hecks
103
87
  end
104
88
  end
105
89
 
106
- # `materialize`, but a single-attribute value object (`sole_attribute`
107
- # — [[feedback_name_the_scalar_field]]) recurses into its own bare
108
- # field instead of building `{field: ...}` — a Board's own `label`
109
- # unwraps to `"Kanban"`, not `{value: "Kanban"}`. Not a replacement
110
- # for `materialize` itself: every existing report/query/command
111
- # caller keeps the wrapped shape it already depends on (Banking's
112
- # own `CustomerPortfolio` reads `payment[:amount][:cents]`, and
113
- # changing that out from under it would be a real breaking change,
114
- # not a bug fix). This is read_model_interpreter.rb's own opt-in,
115
- # used only for a `group_by`-declared head's own rows — grouping
116
- # needs a real scalar to key by regardless, so a report already
117
- # asking for that gets the unwrap for free.
90
+ # `materialize`, but a single-attribute value object unwraps to its bare field.
91
+ # Opt-in for `group_by` rows; `materialize` keeps the wrapped shape callers depend on.
118
92
  #
119
93
  # @param value [Object] the value to materialize; anything that is not a `Runtime::Value`,
120
94
  # Array or Hash passes through unchanged
@@ -127,12 +101,7 @@ module Hecks
127
101
  sole = value.value_object.sole_attribute
128
102
  return materialize_unwrapped(value[sole.name]) if sole
129
103
 
130
- # Not `value.to_h` — `Value#to_h` materializes each field through
131
- # plain `materialize`, so a VO nested inside a multi-attribute VO
132
- # would already be a plain Hash by the time this method ever saw
133
- # it, and never reach the `when self` branch above. Read each
134
- # field straight off `value` instead, so recursion actually
135
- # happens through this method the whole way down.
104
+ # Not `value.to_h`: it materializes nested values to Hashes, ending the recursion.
136
105
  value.value_object.attributes.to_h { |attr| [attr.name, materialize_unwrapped(value[attr.name])] }
137
106
  when Array then value.map { |item| materialize_unwrapped(item) }
138
107
  when Hash then value.transform_values { |item| materialize_unwrapped(item) }
@@ -140,22 +109,8 @@ module Hecks
140
109
  end
141
110
  end
142
111
 
143
- # Reduces an append-only sub-log to its current state — the same
144
- # "a later fact supersedes an earlier one" reduction this runtime
145
- # already performs replaying an aggregate's own command history
146
- # into its current attributes, applied here to a single `list_of`
147
- # field acting as its own miniature append-only log (a placement
148
- # history, a tombstone-style soft-delete list, a versioned
149
- # setting). `rows` is what a `list_of` attribute hands back — an
150
- # Array of `Value`, in append order — and `key` names the field
151
- # that identifies "the same logical thing" across entries.
152
- #
153
- # **Grouping only, never interpretation**. What counts as "removed,"
154
- # how to order what survives — that meaning belongs to whichever
155
- # domain declared the field, never here: a generic reduction that
156
- # started guessing domain semantics would need to keep guessing
157
- # forever, once per shape of "gone" any caller ever invents. The
158
- # caller filters and sorts the result; this only groups it.
112
+ # Reduces an append-only `list_of` sub-log to its current state: the latest row per `key`.
113
+ # Grouping only; what counts as removed, and the ordering, belong to the caller.
159
114
  #
160
115
  # @param rows [Array<Runtime::Value>] a `list_of` attribute's own elements, in append order
161
116
  # @param key [Symbol] the method to call on each row to find "the same logical thing"
@@ -169,21 +124,8 @@ module Hecks
169
124
  def method_missing(name, *args)
170
125
  return @fields[name] if @fields.key?(name)
171
126
 
172
- # The language rule, not a convenience: any value object with
173
- # exactly one declared attribute answers `.value`, whatever that
174
- # attribute is actually named — a single-attribute value object
175
- # is a name for a scalar, not a genuine group
176
- # ([[feedback_name_the_scalar_field]], `Behaviour::ValueObject#
177
- # sole_attribute`), so `money.value` reads `Money`'s own `amount`
178
- # exactly as `label.value` reads a shorthand-declared `value`.
179
- # After the real-field lookup above, on purpose: a field
180
- # literally named `value` is already answered there (and is the
181
- # sole attribute whenever the count is one), so this branch only
182
- # ever aliases, never shadows. A multi-attribute value object
183
- # keeps its NoMethodError — `sole_attribute` answers nil for it,
184
- # and falling through to `super` is exactly the refusal it
185
- # always gave: with two or more fields there is no single value
186
- # `.value` could honestly mean.
127
+ # `.value` aliases the sole field of a single-attribute value object; after the real-field
128
+ # lookup so a field literally named `value` is never shadowed.
187
129
  if name == :value
188
130
  sole = @value_object.sole_attribute
189
131
  return @fields[sole.name] if sole
@@ -201,19 +143,8 @@ module Hecks
201
143
 
202
144
  private
203
145
 
204
- # **The `.value` alias for indexed access** — the same language rule
205
- # `method_missing` above enforces for method reads, applied to
206
- # `[]`/`key?`/`with`: `:value` names a single-attribute value
207
- # object's sole field whatever that field is actually called. A
208
- # real key always wins first (a field literally named `value` is
209
- # its own answer, and is the sole attribute anyway whenever the
210
- # count is one), so this only ever resolves a `:value` that would
211
- # otherwise miss — it can never redirect a genuine field read.
212
- # `with(:value, x)` in particular needs this: merging a literal
213
- # `:value` key beside a sole field named `amount` would build a
214
- # two-key hash for a one-field shape and be refused (or worse,
215
- # stored) downstream — aliasing at the merge is what keeps the
216
- # write half of the rule as true as the read half.
146
+ # Resolves `:value` to the sole field's name so `[]`, `key?`, `with` match `method_missing`.
147
+ # A real key always wins.
217
148
  def resolve_field(field)
218
149
  sym = field.to_sym
219
150
  return sym if @fields.key?(sym)