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
@@ -8,69 +8,18 @@ require_relative "instance"
8
8
 
9
9
  module Hecks
10
10
  module Runtime
11
- # **One entity element, located and mutated** — the walk-and-write half of
12
- # dispatching into a piece an aggregate holds, factored out of
13
- # `EntityInterpreter` so a second caller (`CommandInterpreter`'s own
14
- # `delegate_to_entity` step) can locate and mutate the same element the
15
- # same way, against an aggregate record it already holds in memory
16
- # rather than one freshly loaded from a repository. `EntityInterpreter`
17
- # keeps its own dispatch order and Context; this is the part underneath
18
- # that both now share, so it exists in exactly one place rather than two
19
- # that could only ever drift (the same reasoning `Runtime::Identity`'s
20
- # own header gives for the join/dig/reading trio it centralizes).
21
- #
22
- # `rules` (a `CommandRules` instance) is passed explicitly throughout
23
- # rather than closed over, since this module has no instance of its own
24
- # to hold one.
11
+ # Locates and mutates one entity element within an aggregate record — the shared
12
+ # implementation behind EntityInterpreter and CommandInterpreter's own delegation.
25
13
  module EntityElement
26
14
  module_function
27
15
 
28
- # BUG#3 — an addressing value that can never match a stored element,
29
- # returned from `element_of`'s own `wants` coercion in place of a real
30
- # `Value` (below). A unique object, never `nil`: a stored, optional
31
- # element field really can hold `nil`, and comparing that against a
32
- # bare `nil` sentinel would accidentally "match" it.
16
+ # A sentinel that never equals a stored element field, since a real field can hold nil.
33
17
  UNMATCHABLE = Object.new.freeze
34
18
  private_constant :UNMATCHABLE
35
19
 
36
- # Walks `chain`, one hop per entry, and returns the located element (or
37
- # `instance` itself, when `chain` is empty).
38
- #
39
- # **One hop per chain entry**. `container` starts as `instance` (the root
40
- # aggregate record) and becomes each just-located element in turn —
41
- # Dispatch's own element is found inside the Handler element
42
- # `locate_chain` located the step before, never inside `instance`
43
- # directly. `owner` is whichever construct's own attribute declares
44
- # the list being searched (Handler declares `dispatches` ; the root
45
- # aggregate declares `handlers`) — `root_aggregate` stays the root
46
- # the whole way through instead, passed to `element_of` separately,
47
- # because coercion (`Value.for_attribute`) resolves value objects
48
- # against the root's own namespace only ; an entity must never
49
- # answer `.value_object` (Entity's own header comment) so handing
50
- # it an intermediate owner instead would break every VO-typed
51
- # identity field a nested entity declares.
52
- #
53
- # `route`, if given, is the routing envelope's own entity chain
54
- # (`ctx.route.entities`, one entry per hop) — the routing/payload
55
- # split's own consequence: an entity's own identity may arrive via
56
- # `to:` rather than duplicated into `args`, so each hop is offered
57
- # its routed identity ahead of falling back to `args`.
58
- #
59
- # @param root_aggregate [Bluebook::Aggregate] the root aggregate record's
60
- # own construct, held constant across every hop for coercion
61
- # @param chain [Array<Bluebook::Entity>] the entity chain to walk, root-first
62
- # @param instance [Runtime::Instance] the root aggregate record to walk from
63
- # @param args [Hash{String, Symbol => Object}] the offered command arguments,
64
- # read for each hop's own identity when `route` does not supply it
65
- # @param command_name [String] the command name, quoted in a refusal
66
- # @param route [Runtime::Routing::Envelope, nil] the call's resolved routing
67
- # envelope, if any; its own `entities` supply each hop's identity first
68
- # @return [Runtime::Instance, Hash{Symbol => Object}] the located element;
69
- # `instance` itself, unchanged, when `chain` is empty
70
- # @raise [Runtime::UnknownVerb] if a hop's owner declares no list attribute
71
- # for that entity
72
- # @raise [Runtime::NotFound] if a hop's identity is absent from `args`, or no
73
- # element matches it
20
+ # Walks `chain` one hop at a time and returns the located element (or `instance`
21
+ # itself when `chain` is empty). `route`, when given, offers each hop's identity
22
+ # before falling back to `args`.
74
23
  def locate_chain(root_aggregate, chain, instance, args, command_name, route = nil)
75
24
  container = instance
76
25
  owner = root_aggregate
@@ -82,42 +31,14 @@ module Hecks
82
31
  container
83
32
  end
84
33
 
85
- # One element, matched on every part of its identity — not just the first.
86
- # A piece's identity may be several paths, the same shape a head's can be,
87
- # so a dispatch that names the element has to supply every part and every
88
- # part has to agree with the stored one. `routed_identity`, when given,
89
- # matches by the element's own minted identity string directly instead
90
- # (`element_identity`, below) — the routing envelope already resolved
91
- # which element it means, so re-deriving `wants` from `args` would be
92
- # redundant at best and wrong if `args` does not carry that identity
93
- # at all.
94
- # Locate, then copy-before-mutate, in that order — see the "one
95
- # level deeper" comment below on why the copy has to happen exactly
96
- # where it does (aliasing the adapter's own record otherwise).
97
- # Splitting resolution from the copy/write-back would separate two
98
- # halves of one aliasing-safety invariant across method boundaries.
34
+ # Locates one element, matching every part of its declared identity, and copies
35
+ # the owning list and the element before any write so nothing aliases the caller's
36
+ # record. `routed_identity`, when given, matches directly by the element's own
37
+ # identity string instead of re-deriving `wants` from `args`.
99
38
  # rubocop:disable-next Metrics/AbcSize
100
39
  # rubocop:disable-next Metrics/CyclomaticComplexity
101
40
  # rubocop:disable-next Metrics/PerceivedComplexity
102
41
  # rubocop:disable-next Metrics/MethodLength
103
- #
104
- # @param root_aggregate [Bluebook::Aggregate] the root aggregate record's own
105
- # construct, used for value-object coercion
106
- # @param owner [Bluebook::Aggregate, Bluebook::Entity] the construct whose own
107
- # attribute declares the list `entity` is searched in
108
- # @param entity [Bluebook::Entity] the entity type being located
109
- # @param command_name [String] the command name, quoted in a refusal
110
- # @param container [Runtime::Instance, Hash{Symbol => Object}] the record or
111
- # element holding the list to search
112
- # @param args [Hash{String, Symbol => Object}] the offered command arguments,
113
- # read for the element's own identity when `routed_identity` is nil
114
- # @param routed_identity [String, nil] the routing envelope's own identity
115
- # string for this hop, matched directly instead of deriving one from `args`
116
- # @return [Hash{Symbol => Object}] a fresh copy of the located element; the
117
- # owning list inside `container` is replaced with a fresh copy too
118
- # @raise [Runtime::UnknownVerb] if `owner` declares no list attribute for `entity`
119
- # @raise [Runtime::NotFound] if an identity part is absent from `args`
120
- # (`routed_identity` nil only), or no element matches
121
42
  def element_of(root_aggregate, owner, entity, command_name, container, args, routed_identity = nil)
122
43
  entity_name = entity.hecks_name
123
44
  list_attr = owner.attributes.find { |a| a.list? && a.type.to_s == entity_name } ||
@@ -132,28 +53,9 @@ module Hecks
132
53
  command: command_name, entity: entity_name,
133
54
  identity: Identity.reading(entity)))
134
55
 
135
- # An identity offered for addressing, not for storage
136
- # (BUG#3, found live by `bin/qa_sweep` — banking fuzz seed
137
- # 23, `LedgerEntry.Amend sequence: { value: 0 }` against an
138
- # entry-less ledger). Coercing it all the way to a typed
139
- # `Value` here ran that type's own invariant before this
140
- # method ever checks whether any element matches — a
141
- # `sequence: 0` against `LedgerSequence`'s own "a ledger
142
- # sequence is positive" invariant raised InvariantViolation,
143
- # not NotFound, even when (as here) nothing was ever posted
144
- # at all. Every element actually in the list already
145
- # satisfied its own type's invariant the moment it was
146
- # created, so a value that fails it can never equal one —
147
- # degrading to `UNMATCHABLE` here, instead of propagating,
148
- # is exactly as safe as the ordinary "no match found" case
149
- # below, and lines this addressing path up with the two
150
- # conventions it already disagreed with: Rust's own
151
- # `extract_id`/`extract_wants` (a raw scalar read, never a
152
- # typed rebuild — rust/src/generated/*/*.rs) and
153
- # `Identity.from`'s own raw-comparison convention for a
154
- # root aggregate's identity (this file's sibling,
155
- # `identity.rb`). `raw` rides alongside `want` so the
156
- # eventual NotFound below can still quote what was offered.
56
+ # A value that fails its own type's invariant can never match a stored
57
+ # element (every stored one already satisfies it) — degrade to
58
+ # `UNMATCHABLE` here rather than letting InvariantViolation propagate.
157
59
  want = begin
158
60
  Value.for_attribute(root_aggregate, entity.attribute(head), raw)
159
61
  rescue InvariantViolation
@@ -182,19 +84,9 @@ module Hecks
182
84
  )
183
85
  end
184
86
 
185
- # One level deeper than Instance#dup, for the same reason: a list
186
- # attribute holds Hashes, and `apply_to_element` mutates the found
187
- # one in place — the update mechanism for an entity, not a bug. But
188
- # in place means aliased with the adapter's own record until this
189
- # copies the array and the target element before handing either
190
- # back, and writes the fresh array into `container` so the copy is
191
- # what persists on success and nothing aliased survives a refusal.
192
- # `container[list_attr.name] = copied` reaches `instance` itself
193
- # when this is the first hop, and reaches the (already copied)
194
- # parent element when it is a later one — either way it is the
195
- # same already-fresh object `locate_chain` is about to hand back
196
- # as `container` for the next hop, so nothing further has to
197
- # propagate a write back up the chain by hand.
87
+ # Copies the list and the found element before handing either back — the list
88
+ # attribute holds Hashes, and the caller mutates the returned element in place,
89
+ # so this keeps that mutation off the adapter's own record until it commits.
198
90
  copied = original.dup
199
91
  element = copied[position].dup
200
92
  copied[position] = element
@@ -202,20 +94,8 @@ module Hecks
202
94
  element
203
95
  end
204
96
 
205
- # The element's own identity, joined from its parts — the entity-level
206
- # twin of `Identity.of`, reading off the stored element (a Hash) rather
207
- # than a dispatch payload. An id is a scalar, and the path is how it is
208
- # reached — never by opening a value object and taking whatever single
209
- # field is inside. That unwrapping is gone from the language: a piece
210
- # that does not name its fields is refused when the bluebook loads ("an
211
- # entity says what it is known by", "an identity part names something"),
212
- # so by the time a dispatch arrives here there is always a path to dig.
213
- #
214
- # @param entity [Bluebook::Entity] the entity type whose identity paths
215
- # are read
216
- # @param element [Hash{Symbol => Object}] the stored element to read an
217
- # identity off
218
- # @return [String] the element's identity, joined from its declared parts
97
+ # An element's identity, joined from its declared identity paths (read off the
98
+ # stored Hash, not a dispatch payload).
219
99
  def element_identity(entity, element)
220
100
  parts = entity.identity_paths.map do |path|
221
101
  head = path.to_s.split(".").first.to_sym
@@ -225,65 +105,10 @@ module Hecks
225
105
  Naming.identity(parts)
226
106
  end
227
107
 
228
- # S17, ADR 0026 — `:append`/`:remove`/`:multiply`/`:clamp`, an
229
- # entity-scoped mirror of `CommandInterpreter::MutationApplier
230
- # #apply`'s own four (that module's own header names each one's
231
- # origin). Missing until now — an entity-owned command declaring
232
- # `sets :some_list, append: {...}` matched no `when` here and
233
- # silently no-opped, the one place this language otherwise
234
- # refuses what it cannot check applying nothing instead. `Member`/
235
- # `Dispatch` (S17) are the first real callers: both need to
236
- # append a value-object-typed element (`Pair`/`Binding`) onto a
237
- # list attribute they own, once they become entities of
238
- # `ValueObject`/`ProcessManager` rather than separate aggregates.
239
- #
240
- # `:increment`/`:decrement`/`:multiply` also fixed here, found
241
- # while proving this method against a real fixture: they wrapped
242
- # `amount` unconditionally whenever `attribute` existed, the same
243
- # asymmetric-wrapping shape `MutationApplier#rewrap_arithmetic_
244
- # result`'s own comment documents fixing at the aggregate level
245
- # (migration plan task 9) — a phantom-created VO-typed field's
246
- # `current` reads back a raw, unwrapped default, `amount` was
247
- # wrapped anyway, and the two sides of one arithmetic call
248
- # disagreed on Value-ness. Confirmed live, not theoretical: this
249
- # method's own fixture (TaggedList.Bump, a VO-typed `count` with
250
- # `default: 0`) raised exactly this TypeMismatch on its first
251
- # real run.
252
- # A case dispatching over a closed, declared set of mutation ops —
253
- # deliberately kept byte-for-byte parallel to its aggregate-level
254
- # twin, MutationApplier#apply (see this method's own comment
255
- # above and each branch's "own entity-scoped twin" cross-reference):
256
- # extracting the near-duplicate increment/decrement/multiply
257
- # shape here without doing the same there would break that
258
- # intentional mirroring, which is what lets the two be diffed
259
- # against each other when one gets a fix the other needs too.
108
+ # Applies one declared mutation to an entity element, in place. `pre` is the
109
+ # element as it stood before this command: every read goes through it, every
110
+ # write lands on `element`.
260
111
  # rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity
261
- # Applies one declared mutation to an entity element, in place.
262
- #
263
- # `pre` — the element as it was before this command (C4.2): every
264
- # read below goes through it, every write lands on `element`.
265
- #
266
- # @param rules [Runtime::CommandRules] the shared rules engine `resolve_source`/
267
- # `arithmetic`/`multiply`/`clamp`/`sign_of` are read through
268
- # @param aggregate [Bluebook::Aggregate] the root aggregate, for value-object
269
- # coercion
270
- # @param entity [Bluebook::Entity] the entity type `element` is an instance of
271
- # @param element [Hash{Symbol => Object}] the element to mutate; written in place
272
- # @param mutation [Bluebook::Mutation] the declared mutation to apply
273
- # @param args [Hash{String, Symbol => Object}] the offered command arguments,
274
- # a mutation's source may read from
275
- # @param pre [Hash{Symbol => Object}] the element as it stood before this
276
- # command; every read goes through this, every write lands on `element`
277
- # @return [void]
278
- # @raise [Runtime::TypeMismatch] if a mutation's own value cannot be coerced,
279
- # or an arithmetic op's operands are not numeric or compatible value objects
280
- # @raise [Runtime::InvariantViolation] if a coerced or arithmetic-derived value
281
- # object breaks one of its own invariants
282
- # @raise [Runtime::AlreadyExists] if an `:append` mints a nested entity whose
283
- # identity collides with an existing element
284
- # @raise [Bluebook::Expression::EvaluationError] if an arithmetic op's product
285
- # does not fit a signed 64-bit Integer, or is a non-finite Float
286
- # @raise [Runtime::WiringError] if `mutation.op` names no handled mutation kind
287
112
  def apply_to_element(rules, aggregate, entity, element, mutation, args, pre = element)
288
113
  case mutation.op
289
114
  when :set
@@ -310,73 +135,26 @@ module Hecks
310
135
  element[mutation.target] = rewrap_arithmetic_result(aggregate, attribute, current, result)
311
136
  when :clamp
312
137
  element[mutation.target] = rules.clamp(pre[mutation.target], mutation.source, mutation.target)
313
- # `corrects` — BUG#30. `MutationApplier#apply`'s own aggregate-
314
- # level `:corrects` branch's own comment gives the full reasoning;
315
- # the same one applies here unchanged: this mutation targets no
316
- # field on this element at all — its own event name, and whether
317
- # the owning record has actually emitted it, was already checked
318
- # once, up front, by `EntityInterpreter#step_enforce_givens`
319
- # (`CommandRules::Admissibility#enforce_correction_target`, called
320
- # there against the parent record/root aggregate — see that
321
- # step's own comment for exactly why). Whatever field a correction
322
- # actually changes is an ordinary declared `sets`/`increment`/etc.
323
- # mutation of its own, applied by one of the branches above like
324
- # any other — `qa/stress_domains/corrections`' own `Entry.Amend`
325
- # pairs `corrects "EntryRecorded", ...` with a separate `sets
326
- # :amount`, exactly this shape.
138
+ # `corrects`: a no-op here; the target event was already checked by
139
+ # EntityInterpreter#step_enforce_givens.
327
140
  when :corrects
328
141
  nil
329
142
  else
330
- # The aggregate-level twin's own backstop
331
- # (MutationApplier#apply), for the same reason: applying
332
- # nothing and refusing nothing would be the one silent
333
- # no-op in a language that otherwise refuses what it cannot
334
- # check.
143
+ # Backstop: an unhandled op must refuse, not silently apply nothing.
335
144
  raise WiringError, "no entity mutation applier handles :#{mutation.op} — add one before declaring it"
336
145
  end
337
146
  end
338
147
 
339
- # Rewraps a plain-Numeric arithmetic result into `attribute`'s own declared
340
- # value-object type, when the arithmetic itself ran unwrapped.
341
- #
342
- # `MutationApplier#rewrap_arithmetic_result`'s own entity-scoped
343
- # twin, byte-for-byte the same fix — see that method's own
344
- # comment for the full "phantom-field asymmetric wrapping" story.
345
- # A no-op whenever `current` was already a Value (the arithmetic
346
- # call already returned one) or the mutation targets no declared
347
- # attribute at all.
348
- #
349
- # @param aggregate [Bluebook::Aggregate] the root aggregate, for value-object
350
- # coercion
351
- # @param attribute [Bluebook::Attribute, nil] the mutated field's own declared
352
- # attribute; a no-op when nil (targets no declared attribute)
353
- # @param current [Object] the field's pre-mutation value, as read off `pre`
354
- # @param result [Object] the arithmetic op's own result
355
- # @return [Runtime::Value, Object] `result` unchanged when already a `Value`,
356
- # `current` is a `Value`, or `attribute` is nil; otherwise `result` coerced
357
- # into `attribute`'s own declared type
148
+ # Rewraps a plain-Numeric arithmetic result into the attribute's own Value type.
149
+ # A no-op when `current` was already a Value, or the mutation targets no attribute.
358
150
  def rewrap_arithmetic_result(aggregate, attribute, current, result)
359
151
  return result if current.is_a?(Value) || attribute.nil? || result.is_a?(Value)
360
152
 
361
153
  Value.for_attribute(aggregate, attribute, result)
362
154
  end
363
155
 
364
- # Resolves an `:append` mutation's own field source against the offered
365
- # arguments, falling back to the element's own current field.
366
- #
367
- # `MutationApplier#resolve_append_source`'s own entity-scoped
368
- # twin — a caller-supplied arg first, falling back to the
369
- # element's own current field (never the parent instance's) when
370
- # it isn't one.
371
- #
372
- # @param source [Symbol, Object] the mutation's own field source: a Symbol
373
- # names a command argument or, failing that, an element field; anything
374
- # else is returned as is
375
- # @param element [Hash{Symbol => Object}] the element to fall back to reading
376
- # from
377
- # @param args [Hash{String, Symbol => Object}] the offered command arguments
378
- # @return [Object, nil] the named argument's value; failing that, the named
379
- # element field's value; `source` itself when it is not a Symbol
156
+ # A caller-supplied arg wins; otherwise the field falls back to the element's own
157
+ # value. `args.key?` so an explicit nil still counts as supplied.
380
158
  def resolve_element_append_source(source, element, args)
381
159
  return source unless source.is_a?(Symbol)
382
160
  return args[source] if args.key?(source)
@@ -384,42 +162,6 @@ module Hecks
384
162
  element[source]
385
163
  end
386
164
 
387
- # `MutationApplier#appended`'s own entity-scoped twin. Usually a
388
- # value object element — an entity's own list, appended to by an
389
- # entity-owned command, holds a value object (`Member.pairs`'
390
- # own `Pair`, `Dispatch.with_spec`'s own `Binding`) the same way
391
- # most real corpus appends do — but entity-in-entity nesting (a
392
- # list of another entity, owned by this one) is real now too:
393
- # `qa/stress_domains/nested_pieces` (`Board.AddCard`, appending a
394
- # `Card` onto `Board`'s own `cards`) is the first corpus member to
395
- # do it, the comment this replaces having been written before that
396
- # domain existed. `element_type` naming an entity rather than a
397
- # value object falls through to `fields` unchanged, same as
398
- # before — `MutationApplier#entity_element`'s own identity-minting
399
- # fallback still isn't mirrored here (nothing in this corpus needs
400
- # auto-minting at this depth — Card supplies its own identity in
401
- # the append mapping) — but its collision-checking fallback now is
402
- # (BUG#145, `check_entity_collision`, below — see its own call
403
- # site's comment for why "collision-checking a nested entity is its
404
- # own separate, unfixed question," this comment's own prior wording,
405
- # stopped being true). BUG#12's fix (below) is likewise shared:
406
- # every declared attribute the append mapping doesn't name gets its
407
- # own default the same way a fresh aggregate's own attributes
408
- # already do (`Instance.defaults`), whichever branch built `fields`.
409
- #
410
- # @param aggregate [Bluebook::Aggregate] the root aggregate, for value-object
411
- # coercion
412
- # @param entity [Bluebook::Entity] the entity type `element`'s mutated list
413
- # attribute belongs to
414
- # @param element [Hash{Symbol => Object}] the element being appended to, read
415
- # as the source for a field the mutation's own map does not supply directly
416
- # @param mutation [Bluebook::Mutation] the declared `:append` mutation
417
- # @param args [Hash{String, Symbol => Object}] the offered command arguments
418
- # @return [Array] `element[mutation.target]`'s existing elements, frozen deep,
419
- # with the newly built element (a `Runtime::Value`, or a Hash for an entity
420
- # or untyped element) appended last
421
- # @raise [Runtime::AlreadyExists] if the appended element is a nested entity
422
- # whose identity collides with an existing one
423
165
  def appended_to_element(aggregate, entity, element, mutation, args)
424
166
  fields = mutation.source.transform_values { |source| resolve_element_append_source(source, element, args) }
425
167
  element_type = entity.attribute(mutation.target)&.type
@@ -431,41 +173,10 @@ module Hecks
431
173
  if value_object
432
174
  Value.build(value_object, fields, aggregate)
433
175
  else
434
- # `entity.entities`, not `aggregate.entities` — a piece
435
- # nested inside a piece is a child of the owning entity
436
- # (`Card` is `Board.entities`, never `Workspace.entities`;
437
- # `Behaviour::Entity#entities` answers direct children only,
438
- # by design — see its own comment), the same lexical-nesting
439
- # rule `EntityBuilder#entity_impl` builds the tree with in
440
- # the first place.
176
+ # `entity.entities`, not `aggregate.entities` — a nested piece is a child of
177
+ # the owning entity, not of the root aggregate.
441
178
  nested_entity = entity.entities.find { |piece| piece.hecks_name == element_type.to_s }
442
179
  if nested_entity
443
- # BUG#145 — `MutationApplier#entity_element`'s own
444
- # `check_entity_collision` call (one hop up, an aggregate's
445
- # own entity list) never had a twin here: a nested entity's
446
- # own identity is always caller-supplied at this depth
447
- # (`Card.sequence` rides the append mapping directly — no
448
- # nested-entity auto-mint exists anywhere in this corpus,
449
- # see this method's own header), so this is unconditional,
450
- # unlike `#entity_element`'s own auto-mint/collision `if`/
451
- # `else` split — there is no auto-mint branch here to skip.
452
- # Found live: `qa/stress_domains/nested_pieces`'s own
453
- # differential sweep, `Board.AddCard` dispatched twice under
454
- # the same `sequence` — Ruby silently appended a second
455
- # `Card`, Rust's generated code (`rust/project/mutations.rb`'s
456
- # `emit_mutation_line_body`, which never splits an
457
- # aggregate-owned append from an entity-owned one the way
458
- # this runtime's two separate methods do) already refused
459
- # `AlreadyExists` for both depths.
460
- # `entity` (the owner — `Board`), not `aggregate` (the root
461
- # — `Workspace`), is what the refusal names as "on {…}" —
462
- # `check_entity_collision`'s first argument is only ever
463
- # used for that one naming purpose (`owner.hecks_name`,
464
- # below), matching Rust's own generated wording exactly
465
- # (`rust/project/mutations.rb`'s own `collision_guard`
466
- # passes the entity's declaring construct's name the same
467
- # way — "a Card already exists on Board", never "…on
468
- # Workspace").
469
180
  check_entity_collision(entity, nested_entity, element[mutation.target], fields)
470
181
  fill_declared_defaults(aggregate, nested_entity, fields)
471
182
  else
@@ -475,35 +186,9 @@ module Hecks
475
186
  Freezer.deep(Array(element[mutation.target]) + [appended])
476
187
  end
477
188
 
478
- # BUG#12 — an entity created via `sets :list, append: {...}` used
479
- # to leave any of its own declared attributes the append mapping
480
- # simply didn't name (an optional field a later, separate command
481
- # sets — `Board.label`, `Card.note`) absent from the stored hash
482
- # entirely, not even a `nil` placeholder, until that later command
483
- # actually ran. `rust/project/json_codec.rb#emit_to_json_flat`'s
484
- # own header comment documents the opposite as the intended
485
- # contract for a persisted record: every declared field present,
486
- # `null` when unset, "because Ruby's own `JSON.generate(state)`
487
- # round-trip this mirrors does the same" — true for a freshly
488
- # created aggregate (`Instance.defaults` already fills one key per
489
- # declared attribute, `default_for` per attribute), never true for
490
- # an entity minted by an append. This closes that gap the same
491
- # way: `Instance.default_for` is the same per-attribute default
492
- # rule (nil with no declared `default:`, a fully-defaulted value
493
- # object when every one of its own fields has one), reused rather
494
- # than reimplemented so the two creation paths can never drift on
495
- # what "the default" means. Additive only — a key `fields` already
496
- # holds (the append mapping, an auto-minted identity, a lifecycle
497
- # default) is never overwritten.
498
- #
499
- # @param aggregate [Bluebook::Aggregate] the root aggregate, for value-object
500
- # coercion
501
- # @param entity [Bluebook::Entity] the entity type whose declared attributes
502
- # are defaulted
503
- # @param fields [Hash{Symbol => Object}] the element fields already resolved;
504
- # written in place
505
- # @return [Hash{Symbol => Object}] `fields`, with every declared attribute it
506
- # did not already hold filled with its own default
189
+ # Fills every declared attribute `fields` does not already hold with its own
190
+ # default (Instance.default_for), matching a freshly created aggregate's own
191
+ # per-attribute defaults. Additive only: an existing key in `fields` is kept.
507
192
  def fill_declared_defaults(aggregate, entity, fields)
508
193
  entity.attributes.each do |attribute|
509
194
  next if fields.key?(attribute.name)
@@ -513,24 +198,7 @@ module Hecks
513
198
  fields
514
199
  end
515
200
 
516
- # `MutationApplier#removed`'s own entity-scoped twin — matches by
517
- # value equality, element-wise, the same "so a concurrent Add can
518
- # never be lost" reasoning that method's own comment gives, unless
519
- # the list this targets is itself entity-typed — see
520
- # `list_element_match?`, below, which both this and
521
- # `MutationApplier#removed` now share.
522
- #
523
- # @param rules [Runtime::CommandRules] the shared rules engine `resolve_source`
524
- # is read through
525
- # @param aggregate [Bluebook::Aggregate] the root aggregate, for value-object
526
- # coercion
527
- # @param entity [Bluebook::Entity] the entity type `element`'s mutated list
528
- # attribute belongs to
529
- # @param element [Hash{Symbol => Object}] the element being removed from
530
- # @param mutation [Bluebook::Mutation] the declared `:remove` mutation
531
- # @param args [Hash{String, Symbol => Object}] the offered command arguments
532
- # @return [Array] `element[mutation.target]`'s existing elements, with any
533
- # matching the resolved remove target left out
201
+ # Removes the element matching by value, or by identity for entity-typed lists.
534
202
  def removed_from_element(rules, aggregate, entity, element, mutation, args)
535
203
  value = rules.resolve_source(mutation.source, args)
536
204
  attribute = entity.attribute(mutation.target)
@@ -538,49 +206,9 @@ module Hecks
538
206
  Array(element[mutation.target]).reject { |candidate| list_element_match?(aggregate, attribute, candidate, value) }
539
207
  end
540
208
 
541
- # BUG#32 (QualityControl ledger) — the match rule `remove:` uses
542
- # against one stored list element. Value equality for a
543
- # value-object-typed list stays exactly what it always was — an
544
- # element and `value` are both real `Value`s there, so `==` already
545
- # compares every field, the "concurrent Add can never be lost"
546
- # shape `removed`/`removed_from_element`'s own headers describe.
547
- # An entity-typed list is different in kind, not just in type: a
548
- # stored element is a plain Hash, never a `Value` (`Entity`'s own
549
- # header — "an entity must never answer .value_object"), so there
550
- # is no whole-value shape to compare against at all — only the
551
- # entity's own identity field, the same field a caller already has
552
- # to name to address that element any other way
553
- # (`element_of`'s own `wants`, above). `value` arrives here already
554
- # coerced against that identity field's declared type
555
- # (`Coercion#hydrate_entity_identity`, run underneath
556
- # `Value.for_attribute` before either caller above ever sees it),
557
- # so this only has to know which field to read off the stored
558
- # element — `entity.identity_heads`'s own single head, when there
559
- # is exactly one. A composite identity (more than one head, or
560
- # none) has no single field a bare `remove:` target could mean —
561
- # this returns `false` (never a match, the same documented no-op
562
- # `hydrate_entity_identity`'s own header already commits to) rather
563
- # than guessing which head, matching the narrow, honest boundary
564
- # `MutationApplier#check_entity_collision`'s own header draws for
565
- # entity identity elsewhere in this runtime.
566
- #
567
- # Shared by `MutationApplier#removed` (an aggregate's own list) and
568
- # `#removed_from_element` (a list an entity owns), so the two
569
- # `remove:` call sites can never quietly disagree on what
570
- # "matches" means — the same reasoning this file's own header
571
- # gives for centralizing `locate_chain`/`element_of` once rather
572
- # than twice.
573
- #
574
- # @param aggregate [Bluebook::Aggregate] the root aggregate, to resolve
575
- # whether `attribute`'s own type is an entity
576
- # @param attribute [Bluebook::Attribute, nil] the list attribute `element`
577
- # belongs to
578
- # @param element [Object] the stored list element to check: a Hash for an
579
- # entity-typed list, a `Runtime::Value` otherwise
580
- # @param value [Object] the `remove:` target to match `element` against
581
- # @return [Boolean] whole-value equality for a non-entity-typed list;
582
- # identity-field equality for an entity-typed one with a single identity
583
- # head; false for a composite or absent identity
209
+ # The match rule `remove:` uses against one stored list element. Whole-value
210
+ # equality for a non-entity-typed list; for an entity-typed one, matches by its
211
+ # single identity head (a composite or absent identity never matches).
584
212
  def list_element_match?(aggregate, attribute, element, value)
585
213
  entity = attribute&.list? ? Value.find_entity(aggregate, attribute.type.to_s) : nil
586
214
  return element == value unless entity
@@ -591,59 +219,9 @@ module Hecks
591
219
  element.is_a?(Hash) && element[head] == value
592
220
  end
593
221
 
594
- # Refuses a caller-supplied or composite identity that already names an
595
- # element on `current`.
596
- #
597
- # BUG#13 — the same check #hydrate gives every creating
598
- # aggregate command (`repository.find(id)`,
599
- # `command_interpreter.rb`), one level down. Shared with
600
- # `MutationApplier` (mutation_applier.rb), called from
601
- # `#entity_element` — an aggregate's own entity list (`Workspace.
602
- # boards`, `Ledger.entries`) — and, moved here (BUG#145), from `#appended_
603
- # to_element`, above — an entity's own nested entity list one hop
604
- # further in (`Board.cards`) — so neither call site reimplements
605
- # it a second time, the same way `#list_element_
606
- # match?` already avoids that split for `remove:`.
607
- #
608
- # Reached, at the aggregate-owned call site, only on the two
609
- # branches that do not auto-mint: a caller-supplied identity (the
610
- # field is already in the append's own field map) or a composite
611
- # one (`entity.identified_by` is nil for those — Runtime::
612
- # Identified#derive_identity). Without this, neither checks the sibling
613
- # list at all: a second LogVisit with the same date+sequence, or a
614
- # second IssueKey with the same serial, would append a silent
615
- # duplicate — worse than an ordinary duplicate row, because
616
- # `EntityElement#element_of`'s own `find_index` always matches the
617
- # first match, so the second becomes permanently unaddressable by
618
- # any later command. At the entity-owned call site (`#appended_to_
619
- # element`), there is no auto-mint branch at all — every caller
620
- # reaches this unconditionally, since a nested entity's own
621
- # identity is always caller-supplied in this corpus.
622
- #
623
- # Auto-minted (aggregate-owned) entities never reach here —
624
- # `identity_heads` for them is still checked at mint time by
625
- # construction (`current.size + 1` can only repeat if something
626
- # `remove:`s from the list between mints, which no real domain does
627
- # today), so they can't be flagged by mistake.
628
- # `owner` — the declaring construct named in the "…already exists on
629
- # {owner}" wording: the root aggregate at the aggregate-owned call
630
- # site (`Workspace`, `Ledger`), the immediately-enclosing entity at
631
- # the entity-owned one (`Board` — never the root `Workspace` two
632
- # hops up). Used for that naming purpose only (`owner.hecks_name`) —
633
- # never for `Value`/namespace resolution, which is why an `Entity`
634
- # (not just an `Aggregate`) is a valid thing to pass here.
635
- #
636
- # @param owner [Bluebook::Aggregate, Bluebook::Entity] the construct named
637
- # in a refusal as what the duplicate "already exists on"
638
- # @param entity [Bluebook::Entity] the entity type being checked for a
639
- # colliding identity
640
- # @param current [Array<Hash>, Object] the entity's own existing elements;
641
- # coerced through `Array()`, so a single element or nil is also accepted
642
- # @param fields [Hash{Symbol => Object}] the new element's own fields, whose
643
- # identity heads are checked against every element in `current`
644
- # @return [void]
645
- # @raise [Runtime::AlreadyExists] if `current` already holds an element
646
- # whose identity heads match `fields`'s own
222
+ # Refuses a caller-supplied or composite identity that already names an element
223
+ # in `current`. Shared by the aggregate-owned and entity-owned append paths so
224
+ # neither reimplements the check. `owner` is named in the refusal only.
647
225
  def check_entity_collision(owner, entity, current, fields)
648
226
  heads = entity.identity_heads
649
227
  return if heads.empty?