hecks 1.2.0 → 1.4.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 (358) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hecks/adapters/driven/claude_code.rb +7 -7
  3. data/lib/hecks/adapters/driven/d1.rb +187 -23
  4. data/lib/hecks/adapters/driven/folder.rb +10 -10
  5. data/lib/hecks/adapters/driven/google_authentication.rb +8 -8
  6. data/lib/hecks/adapters/driven/governance_authorization.rb +31 -13
  7. data/lib/hecks/adapters/driven/heki/journal.rb +60 -2
  8. data/lib/hecks/adapters/driven/heki/saga_store.rb +5 -5
  9. data/lib/hecks/adapters/driven/heki.rb +13 -7
  10. data/lib/hecks/adapters/driven/identity_registry.rb +2 -2
  11. data/lib/hecks/adapters/driven/in_memory_ordering.rb +3 -3
  12. data/lib/hecks/adapters/driven/lambda/client.rb +34 -9
  13. data/lib/hecks/adapters/driven/lambda.rb +39 -33
  14. data/lib/hecks/adapters/driven/local_storage.rb +17 -10
  15. data/lib/hecks/adapters/driven/memory.rb +205 -9
  16. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +1 -1
  17. data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
  18. data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
  19. data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
  20. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
  21. data/lib/hecks/adapters/driven/postgres.rb +175 -28
  22. data/lib/hecks/adapters/driven/postgres_era.adapter +5 -0
  23. data/lib/hecks/adapters/driven/prism.rb +4 -4
  24. data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
  25. data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
  26. data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
  27. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
  28. data/lib/hecks/adapters/driven/sqlite.rb +181 -21
  29. data/lib/hecks/adapters/driven.rb +4 -4
  30. data/lib/hecks/adapters/driving/github_webhook.rb +145 -0
  31. data/lib/hecks/behaviors/dsl.rb +2 -2
  32. data/lib/hecks/behaviors/expectations.rb +51 -23
  33. data/lib/hecks/behaviors/ir.rb +1 -1
  34. data/lib/hecks/behaviors/rspec.rb +1 -1
  35. data/lib/hecks/behaviors/runner.rb +2 -2
  36. data/lib/hecks/behaviors.rb +1 -1
  37. data/lib/hecks/bluebook/aggregate.rb +13 -13
  38. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +10 -10
  39. data/lib/hecks/bluebook/assembly/build.rb +1 -1
  40. data/lib/hecks/bluebook/assembly/contract.rb +39 -16
  41. data/lib/hecks/bluebook/assembly/contracts.rb +40 -38
  42. data/lib/hecks/bluebook/assembly/marks.rb +18 -18
  43. data/lib/hecks/bluebook/assembly/specializer.rb +19 -21
  44. data/lib/hecks/bluebook/assembly.rb +9 -9
  45. data/lib/hecks/bluebook/attribute.rb +9 -9
  46. data/lib/hecks/bluebook/behaviour/aggregate.rb +11 -11
  47. data/lib/hecks/bluebook/behaviour/attribute.rb +5 -5
  48. data/lib/hecks/bluebook/behaviour/chapter.rb +23 -5
  49. data/lib/hecks/bluebook/behaviour/command.rb +23 -23
  50. data/lib/hecks/bluebook/behaviour/domain_port.rb +27 -3
  51. data/lib/hecks/bluebook/behaviour/entity.rb +8 -8
  52. data/lib/hecks/bluebook/behaviour/hexagon.rb +4 -4
  53. data/lib/hecks/bluebook/behaviour/lifecycle.rb +5 -5
  54. data/lib/hecks/bluebook/behaviour/policy.rb +12 -12
  55. data/lib/hecks/bluebook/behaviour/process_manager.rb +7 -7
  56. data/lib/hecks/bluebook/behaviour/query.rb +1 -1
  57. data/lib/hecks/bluebook/behaviour/read_model.rb +8 -8
  58. data/lib/hecks/bluebook/behaviour/traits.rb +12 -12
  59. data/lib/hecks/bluebook/behaviour/value_object.rb +6 -6
  60. data/lib/hecks/bluebook/capabilities.rb +27 -0
  61. data/lib/hecks/bluebook/chapter.rb +28 -9
  62. data/lib/hecks/bluebook/command.rb +12 -12
  63. data/lib/hecks/bluebook/domain_port.rb +9 -9
  64. data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
  65. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
  66. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +96 -96
  67. data/lib/hecks/bluebook/dsl/attribute_collector.rb +41 -41
  68. data/lib/hecks/bluebook/dsl/binding_proxy.rb +22 -2
  69. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +111 -74
  70. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +48 -30
  71. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
  72. data/lib/hecks/bluebook/dsl/command_builder.rb +103 -103
  73. data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
  74. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
  75. data/lib/hecks/bluebook/dsl/entity_builder.rb +56 -56
  76. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
  77. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +89 -30
  78. data/lib/hecks/bluebook/dsl/identity_declaration.rb +17 -17
  79. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
  80. data/lib/hecks/bluebook/dsl/policy_builder.rb +30 -21
  81. data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
  82. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
  83. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +35 -35
  84. data/lib/hecks/bluebook/dsl/query_builder.rb +5 -5
  85. data/lib/hecks/bluebook/dsl/read_model_builder.rb +34 -34
  86. data/lib/hecks/bluebook/dsl/rule_reference.rb +41 -39
  87. data/lib/hecks/bluebook/dsl/translation_builder.rb +9 -9
  88. data/lib/hecks/bluebook/dsl/value_object_builder.rb +16 -16
  89. data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
  90. data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
  91. data/lib/hecks/bluebook/entity.rb +11 -11
  92. data/lib/hecks/bluebook/expression/ast_json.rb +20 -20
  93. data/lib/hecks/bluebook/expression/ast_reader.rb +3 -3
  94. data/lib/hecks/bluebook/expression/canonical_form.rb +9 -9
  95. data/lib/hecks/bluebook/expression/evaluator.rb +18 -18
  96. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +18 -18
  97. data/lib/hecks/bluebook/expression/resolver.rb +60 -62
  98. data/lib/hecks/bluebook/hexagon.rb +1 -1
  99. data/lib/hecks/bluebook/lifecycle.rb +1 -1
  100. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -1
  101. data/lib/hecks/bluebook/meta_validator/judge.rb +122 -86
  102. data/lib/hecks/bluebook/meta_validator/plan.rb +39 -39
  103. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -2
  104. data/lib/hecks/bluebook/meta_validator/readings.rb +43 -43
  105. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +44 -37
  106. data/lib/hecks/bluebook/meta_validator/shapes.rb +25 -21
  107. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +145 -31
  108. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +6 -6
  109. data/lib/hecks/bluebook/meta_validator/world_judge.rb +5 -5
  110. data/lib/hecks/bluebook/meta_validator.rb +70 -70
  111. data/lib/hecks/bluebook/model_check.rb +301 -84
  112. data/lib/hecks/bluebook/pattern_subset.rb +9 -9
  113. data/lib/hecks/bluebook/policy.rb +15 -13
  114. data/lib/hecks/bluebook/process_manager.rb +14 -14
  115. data/lib/hecks/bluebook/project_register.rb +6 -6
  116. data/lib/hecks/bluebook/query.rb +4 -4
  117. data/lib/hecks/bluebook/read_model.rb +14 -14
  118. data/lib/hecks/bluebook/reference.rb +8 -8
  119. data/lib/hecks/bluebook/smoke_test.rb +19 -19
  120. data/lib/hecks/bluebook/synthesizer.rb +12 -12
  121. data/lib/hecks/bluebook/translation.rb +4 -4
  122. data/lib/hecks/bluebook/value_object.rb +6 -6
  123. data/lib/hecks/bluebook.rb +2 -2
  124. data/lib/hecks/codemod/legacy_dispatch_args.rb +299 -0
  125. data/lib/hecks/codemod/legacy_dispatch_recorder.rb +186 -0
  126. data/lib/hecks/codemod.rb +36 -35
  127. data/lib/hecks/construct.rb +6 -6
  128. data/lib/hecks/corpus.rb +317 -0
  129. data/lib/hecks/deprecation.rb +95 -0
  130. data/lib/hecks/doc/reference.rb +19 -19
  131. data/lib/hecks/embryonaut_bluebook.rb +11 -11
  132. data/lib/hecks/facade/cli_door.rb +69 -10
  133. data/lib/hecks/facade/cli_runner.rb +105 -24
  134. data/lib/hecks/facade/command_request.rb +23 -0
  135. data/lib/hecks/facade/handle.rb +79 -32
  136. data/lib/hecks/facade/json_door.rb +106 -25
  137. data/lib/hecks/facade/surface/aggregate_door.rb +42 -27
  138. data/lib/hecks/facade/surface/chapter.rb +26 -17
  139. data/lib/hecks/facade/surface.rb +16 -3
  140. data/lib/hecks/facade.rb +15 -4
  141. data/lib/hecks/forms/app.rb +46 -30
  142. data/lib/hecks/forms/command_form_renderer.rb +70 -9
  143. data/lib/hecks/forms/field_renderer.rb +142 -6
  144. data/lib/hecks/forms/field_shape.rb +183 -20
  145. data/lib/hecks/forms/html.rb +51 -7
  146. data/lib/hecks/forms/index_renderer.rb +14 -2
  147. data/lib/hecks/forms/params.rb +120 -23
  148. data/lib/hecks/forms/port_argument.rb +2 -2
  149. data/lib/hecks/forms/query_form_renderer.rb +2 -2
  150. data/lib/hecks/forms/record_renderer.rb +2 -2
  151. data/lib/hecks/forms/record_table.rb +1 -1
  152. data/lib/hecks/forms/value_object_shape.rb +3 -3
  153. data/lib/hecks/forms.rb +24 -4
  154. data/lib/hecks/fqn.rb +1 -1
  155. data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
  156. data/lib/hecks/framework.rb +48 -17
  157. data/lib/hecks/freezer.rb +11 -11
  158. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +90 -90
  159. data/lib/hecks/fuzzing/combination_miner.rb +119 -0
  160. data/lib/hecks/fuzzing/concurrent_dispatch.rb +361 -0
  161. data/lib/hecks/fuzzing/coverage_campaign.rb +118 -0
  162. data/lib/hecks/fuzzing/differential.rb +158 -0
  163. data/lib/hecks/fuzzing/domain_generator.rb +694 -0
  164. data/lib/hecks/fuzzing/era_boundary.rb +124 -0
  165. data/lib/hecks/fuzzing/form_census.rb +199 -0
  166. data/lib/hecks/fuzzing/generated_domain_check.rb +95 -0
  167. data/lib/hecks/fuzzing/invalid_value_generator.rb +6 -6
  168. data/lib/hecks/fuzzing/isolated_boot.rb +226 -38
  169. data/lib/hecks/fuzzing/nondeterministic.rb +67 -0
  170. data/lib/hecks/fuzzing/persistence_parity.rb +161 -0
  171. data/lib/hecks/fuzzing/properties/corrections.rb +100 -0
  172. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +321 -41
  173. data/lib/hecks/fuzzing/properties/guards.rb +129 -26
  174. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +32 -32
  175. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +31 -11
  176. data/lib/hecks/fuzzing/properties/outbox.rb +142 -0
  177. data/lib/hecks/fuzzing/properties/querying.rb +17 -17
  178. data/lib/hecks/fuzzing/properties.rb +84 -39
  179. data/lib/hecks/fuzzing/qa_settings.rb +152 -0
  180. data/lib/hecks/fuzzing/replay.rb +224 -114
  181. data/lib/hecks/fuzzing/rotation_priority.rb +94 -0
  182. data/lib/hecks/fuzzing/rust_gap_manifest.rb +113 -0
  183. data/lib/hecks/fuzzing/self_consistency.rb +676 -0
  184. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +526 -0
  185. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +101 -30
  186. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +55 -8
  187. data/lib/hecks/fuzzing/sequence_generator/picker.rb +31 -11
  188. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +123 -32
  189. data/lib/hecks/fuzzing/sequence_generator.rb +152 -31
  190. data/lib/hecks/fuzzing/shrinker.rb +197 -0
  191. data/lib/hecks/fuzzing/structural_skips.rb +39 -0
  192. data/lib/hecks/fuzzing/sweep_depth.rb +53 -0
  193. data/lib/hecks/fuzzing/target_capabilities.rb +180 -0
  194. data/lib/hecks/fuzzing/value_generator.rb +66 -14
  195. data/lib/hecks/fuzzing.rb +11 -0
  196. data/lib/hecks/grammar/evolve.rb +10 -10
  197. data/lib/hecks/grammar.rb +7 -7
  198. data/lib/hecks/ir.rb +13 -13
  199. data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
  200. data/lib/hecks/language/bluebook/policy.bluebook +11 -1
  201. data/lib/hecks/language/bluebook/vocabulary.bluebook +365 -15
  202. data/lib/hecks/language/oidc.json +5 -0
  203. data/lib/hecks/literal.rb +9 -9
  204. data/lib/hecks/naming.rb +89 -21
  205. data/lib/hecks/ports/access_control.rb +58 -2
  206. data/lib/hecks/ports/agent/answers.rb +83 -6
  207. data/lib/hecks/ports/agent.rb +119 -35
  208. data/lib/hecks/ports/authentication.rb +44 -4
  209. data/lib/hecks/ports/authorization.rb +53 -11
  210. data/lib/hecks/ports/clock.rb +42 -23
  211. data/lib/hecks/ports/extraction.rb +16 -0
  212. data/lib/hecks/ports/identity_assignment.rb +24 -2
  213. data/lib/hecks/ports/identity_generation.rb +17 -3
  214. data/lib/hecks/ports/identity_resolution.rb +18 -1
  215. data/lib/hecks/ports/loading.rb +4 -0
  216. data/lib/hecks/ports/persistence/append_only.rb +172 -8
  217. data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
  218. data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
  219. data/lib/hecks/ports/persistence/execution.rb +4 -0
  220. data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
  221. data/lib/hecks/ports/persistence/plugin.rb +42 -4
  222. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
  223. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
  224. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
  225. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
  226. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
  227. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
  228. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
  229. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
  230. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
  231. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +160 -58
  232. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
  233. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +28 -5
  234. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
  235. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
  236. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
  237. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +44 -6
  238. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
  239. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +57 -4
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
  241. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +338 -83
  242. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
  243. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
  244. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
  245. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +42 -8
  246. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
  247. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
  248. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
  249. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -19
  250. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +5 -5
  251. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +1 -1
  252. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
  253. data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
  254. data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
  255. data/lib/hecks/ports/persistence/repository_factory.rb +29 -6
  256. data/lib/hecks/ports/persistence/state_codec.rb +319 -0
  257. data/lib/hecks/ports/persistence.rb +36 -1
  258. data/lib/hecks/ports/projection.rb +61 -7
  259. data/lib/hecks/ports/query/in_memory.rb +3 -3
  260. data/lib/hecks/ports/query/ordering.rb +6 -6
  261. data/lib/hecks/ports/query.rb +35 -0
  262. data/lib/hecks/projections/bootstrap_table.rb +112 -0
  263. data/lib/hecks/projections/diagrams.rb +75 -75
  264. data/lib/hecks/projections/glossary/html.rb +250 -0
  265. data/lib/hecks/projections/glossary/markdown.rb +105 -0
  266. data/lib/hecks/projections/glossary/mermaid.rb +110 -0
  267. data/lib/hecks/projections/glossary/page.css +271 -0
  268. data/lib/hecks/projections/glossary/page.js +72 -0
  269. data/lib/hecks/projections/glossary/sections.rb +17 -0
  270. data/lib/hecks/projections/glossary/sentences.rb +205 -0
  271. data/lib/hecks/projections/glossary.rb +214 -286
  272. data/lib/hecks/projections/ir.rb +1 -1
  273. data/lib/hecks/projections/model/deviations.rb +18 -17
  274. data/lib/hecks/projections/model.rb +25 -21
  275. data/lib/hecks/projections/oidc.rb +7 -7
  276. data/lib/hecks/projections/parser_table.rb +5 -5
  277. data/lib/hecks/projections/reference.rb +3 -3
  278. data/lib/hecks/projections/rust_vocabulary.rb +443 -0
  279. data/lib/hecks/projections/shape.rb +2 -2
  280. data/lib/hecks/projections/statements.rb +11 -11
  281. data/lib/hecks/projections/vocabulary.rb +9 -9
  282. data/lib/hecks/projections.rb +5 -3
  283. data/lib/hecks/projector/cli_projector.rb +29 -29
  284. data/lib/hecks/projector/docs_projector.rb +13 -13
  285. data/lib/hecks/projector/exporter.rb +42 -21
  286. data/lib/hecks/projector/ir_projector.rb +1 -1
  287. data/lib/hecks/projector/narrate_projector.rb +15 -22
  288. data/lib/hecks/projector/target.rb +13 -13
  289. data/lib/hecks/projector.rb +15 -15
  290. data/lib/hecks/query_ir.rb +47 -47
  291. data/lib/hecks/query_specification/common/comparators.rb +19 -3
  292. data/lib/hecks/query_specification/common/comparison.rb +132 -24
  293. data/lib/hecks/query_specification/common/dsl.rb +65 -9
  294. data/lib/hecks/query_specification/common/null_policy.rb +57 -13
  295. data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
  296. data/lib/hecks/query_specification/common/options.rb +25 -0
  297. data/lib/hecks/query_specification/field_path.rb +69 -15
  298. data/lib/hecks/query_specification/hop_path.rb +57 -20
  299. data/lib/hecks/query_specification/read_model/specification.rb +4 -0
  300. data/lib/hecks/rendering.rb +3 -3
  301. data/lib/hecks/router/namespace_installer.rb +3 -3
  302. data/lib/hecks/router.rb +1 -1
  303. data/lib/hecks/runtime/aggregate_lock.rb +11 -11
  304. data/lib/hecks/runtime/boot_gates.rb +3 -3
  305. data/lib/hecks/runtime/caller.rb +8 -8
  306. data/lib/hecks/runtime/capability_graph.rb +2 -2
  307. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +22 -25
  308. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +64 -67
  309. data/lib/hecks/runtime/command_interpreter.rb +159 -102
  310. data/lib/hecks/runtime/command_rules/admissibility.rb +69 -69
  311. data/lib/hecks/runtime/command_rules/arithmetic.rb +137 -91
  312. data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
  313. data/lib/hecks/runtime/command_rules/emission.rb +18 -1
  314. data/lib/hecks/runtime/command_rules/references.rb +94 -19
  315. data/lib/hecks/runtime/command_rules.rb +3 -0
  316. data/lib/hecks/runtime/dependency_planning.rb +11 -11
  317. data/lib/hecks/runtime/dispatcher.rb +283 -90
  318. data/lib/hecks/runtime/entity_element.rb +282 -46
  319. data/lib/hecks/runtime/entity_interpreter.rb +160 -69
  320. data/lib/hecks/runtime/errors.rb +19 -19
  321. data/lib/hecks/runtime/event.rb +6 -6
  322. data/lib/hecks/runtime/identity.rb +22 -22
  323. data/lib/hecks/runtime/instance.rb +39 -14
  324. data/lib/hecks/runtime/interpreting.rb +12 -12
  325. data/lib/hecks/runtime/invocation.rb +276 -0
  326. data/lib/hecks/runtime/loader.rb +14 -14
  327. data/lib/hecks/runtime/outbox.rb +23 -23
  328. data/lib/hecks/runtime/policy_interpreter.rb +54 -54
  329. data/lib/hecks/runtime/port_operation_interpreter.rb +22 -19
  330. data/lib/hecks/runtime/query_interpreter.rb +111 -56
  331. data/lib/hecks/runtime/reaction_invocation.rb +76 -9
  332. data/lib/hecks/runtime/read_model_interpreter.rb +40 -40
  333. data/lib/hecks/runtime/rebuild_sweep.rb +4 -4
  334. data/lib/hecks/runtime/reference_hop.rb +6 -6
  335. data/lib/hecks/runtime/refusal_wording.rb +92 -112
  336. data/lib/hecks/runtime/registry/saga_persistence.rb +21 -21
  337. data/lib/hecks/runtime/registry/verification.rb +36 -26
  338. data/lib/hecks/runtime/registry.rb +56 -27
  339. data/lib/hecks/runtime/remote_dispatcher.rb +38 -23
  340. data/lib/hecks/runtime/routing.rb +10 -88
  341. data/lib/hecks/runtime/saga_interpreter/correlation.rb +17 -17
  342. data/lib/hecks/runtime/saga_interpreter.rb +93 -56
  343. data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
  344. data/lib/hecks/runtime/tenant_check.rb +9 -9
  345. data/lib/hecks/runtime/tenant_scope.rb +5 -5
  346. data/lib/hecks/runtime/value/admission.rb +75 -30
  347. data/lib/hecks/runtime/value/coercion.rb +379 -226
  348. data/lib/hecks/runtime/value/entity_list_coercion.rb +248 -0
  349. data/lib/hecks/runtime/value.rb +28 -23
  350. data/lib/hecks/runtime.rb +7 -7
  351. data/lib/hecks/storehouse.rb +64 -64
  352. data/lib/hecks/version.rb +3 -3
  353. data/lib/hecks/vocabulary.rb +207 -5
  354. data/lib/hecks.rb +13 -11
  355. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +11 -11
  356. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +14 -12
  357. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +11 -11
  358. metadata +43 -2
@@ -2,8 +2,8 @@ module Hecks
2
2
  module Bluebook
3
3
  module DSL
4
4
  class BluebookBuilder
5
- # THE self.validate_*/self.correlation_*/self.event_*/self.walk_*
6
- # CLUSTER — every whole-chapter, cross-aggregate check `#build`
5
+ # The self.validate_*/self.correlation_*/self.event_*/self.walk_*
6
+ # cluster — every whole-chapter, cross-aggregate check `#build`
7
7
  # runs once a chapter is fully assembled (reference targets, event
8
8
  # shapes, correlation keys, query hops, projected fields,
9
9
  # bidirectional-reference cycles), plus each one's own private
@@ -27,10 +27,10 @@ module Hecks
27
27
  # an instance method, matching what `def self.foo` already made
28
28
  # every one of these before the split.
29
29
  module Validation
30
- # EVERY WHOLE-CHAPTER CHECK, IN ONE PLACE — the battery `#build`
30
+ # **Every whole-chapter check, in one place** — the battery `#build`
31
31
  # used to run inline, now a pure function of an assembled
32
32
  # `Bluebook::Chapter` so `MetaValidator.judge_deferred!` can run
33
- # it too, once, on a chapter whose files have ALL loaded (see
33
+ # it too, once, on a chapter whose files have all loaded (see
34
34
  # `#build`'s own comment for why that split exists at all).
35
35
  # Public, not `private_class_method`'d, for exactly that second
36
36
  # caller — `MetaValidator` needs to reach this with no builder
@@ -49,12 +49,12 @@ module Hecks
49
49
 
50
50
  # Every hop AggregateBuilder#seal_query_field recognised and
51
51
  # deferred gets checked for real here — the earliest point a
52
- # hop CAN be checked, for exactly the reason
52
+ # hop can be checked, for exactly the reason
53
53
  # validate_no_bidirectional_references! above already gives:
54
54
  # `Bluebook.new` just stamped `hecks_owner` on every
55
55
  # aggregate, so `Reference#resolve` finally has a chapter to
56
56
  # walk. Before this line every target in the file (including
57
- # ones declared ABOVE the aggregate doing the asking) would
57
+ # ones declared above the aggregate doing the asking) would
58
58
  # have resolved to nil.
59
59
  infer_hop_query_arguments!(bluebook)
60
60
  validate_query_hops!(bluebook)
@@ -63,27 +63,64 @@ module Hecks
63
63
  # own reference cannot resolve until every aggregate in the
64
64
  # chapter is real and owner-stamped (S12, ADR 0025).
65
65
  validate_projected_fields!(bluebook)
66
+
67
+ validate_provisions!(bluebook)
68
+ end
69
+
70
+ # **What a declared capability must name**. A `provides` row is only
71
+ # worth trusting in place of a name check if it is checked: an
72
+ # unknown capability, a missing or extra key, or a verb that is
73
+ # not this chapter's own command/query of the right kind would
74
+ # otherwise wire a role check to nothing, in silence.
75
+ def validate_provisions!(bluebook)
76
+ bluebook.provides.group_by(&:capability).each do |capability, rows|
77
+ contract = Capabilities::CONTRACTS.fetch(capability) do
78
+ raise Malformed, "#{bluebook.name} provides #{capability.inspect}, which is no capability the " \
79
+ "language knows — known: #{Capabilities::CONTRACTS.keys.sort.join(', ')}"
80
+ end
81
+
82
+ keys = rows.map { |row| row.key.to_sym }
83
+ unless keys.sort == contract.keys.sort
84
+ raise Malformed, "#{bluebook.name} provides #{capability.inspect} with #{keys.join(', ')}, but " \
85
+ "#{capability} needs exactly #{contract.keys.join(', ')}"
86
+ end
87
+
88
+ rows.each { |row| validate_provided_verb!(bluebook, capability, row, contract.fetch(row.key.to_sym)) }
89
+ end
90
+ end
91
+
92
+ def validate_provided_verb!(bluebook, capability, row, kind)
93
+ aggregate_name, member = row.verb.split(".", 2)
94
+ aggregate = bluebook.aggregate(aggregate_name)
95
+ return if aggregate && member && provided_member_names(aggregate, kind).include?(member)
96
+
97
+ raise Malformed, "#{bluebook.name} provides #{capability.inspect} #{row.key}: #{row.verb.inspect}, " \
98
+ "which names no #{kind} this chapter declares (spelled \"Aggregate.#{kind.capitalize}\")"
99
+ end
100
+
101
+ def provided_member_names(aggregate, kind)
102
+ kind == :command ? aggregate.commands.map(&:hecks_name) : aggregate.queries.map(&:name)
66
103
  end
67
104
 
68
- # AN ENTITY COMMAND MAY NOT NAME ITSELF AS ITS ROOT.
105
+ # An entity command may not name itself as its root.
69
106
  #
70
107
  # That is the whole of what is left here, and it needs saying plainly
71
108
  # because the sentence this used to raise — "references must target
72
109
  # aggregate heads" — was never what it checked.
73
110
  #
74
- # `CommandBuilder#reference_to` sets `references` ONLY when the target's
111
+ # `CommandBuilder#reference_to` sets `references` only when the target's
75
112
  # bare name equals the owner's ; anything else becomes a reference
76
- # ATTRIBUTE. So on an aggregate command `references` is always a copy of
113
+ # attribute. So on an aggregate command `references` is always a copy of
77
114
  # that aggregate's own name, and looking it up in an index of aggregates
78
- # is a TAUTOLOGY — that branch never refused anything and structurally
115
+ # is a tautology — that branch never refused anything and structurally
79
116
  # could not. Verified across all eight golden chapters before deleting it.
80
117
  #
81
- # On a PIECE's command the owner is the entity, and an entity is not a
118
+ # On a piece's command the owner is the entity, and an entity is not a
82
119
  # head, so what this actually refuses is `reference_to <its own name>`
83
- # written inside `entity do … end`. A piece is reached THROUGH its
120
+ # written inside `entity do … end`. A piece is reached through its
84
121
  # aggregate ; a command on one addresses the aggregate, never the piece.
85
122
  #
86
- # Reference ATTRIBUTES are the language's business now — offered as the
123
+ # Reference attributes are the language's business now — offered as the
87
124
  # head's own id and resolved as references, so `Aggregate.Reference` and
88
125
  # `Command.Reference` refuse an undeclared head with no predicate at all.
89
126
  def validate_reference_value_objects!(aggregates)
@@ -106,19 +143,19 @@ module Hecks
106
143
  "an entity command is addressed through its aggregate; #{violations.uniq.join('; ')}"
107
144
  end
108
145
 
109
- # EVENTS ARE FIRST-CLASS BY CONVENTION, NOT BY DECLARATION (ADR
146
+ # Events are first-class by convention, not by declaration (ADR
110
147
  # 0025, "events and reactions" — "a domain event is a value
111
148
  # object with its own attributes, not a label"). No new `event
112
149
  # do ... end` construct exists to hand-author and keep in step
113
150
  # with every emitting command by hand — an event's own known
114
- # shape IS whichever command(s) declare `emits` for its name, and
115
- # this is the ONE thing that has to hold for that convention to
151
+ # shape is whichever command(s) declare `emits` for its name, and
152
+ # this is the one thing that has to hold for that convention to
116
153
  # mean anything: every command that emits a given name has to
117
154
  # agree on what it carries. An event is one fact; a fact does not
118
155
  # carry two different truths depending on who is telling it.
119
156
  #
120
- # STRUCTURAL fields only (name/type/list/optional) — `pattern:`/
121
- # `admits:`/`default:` are refinements ON a field, not a second
157
+ # Structural fields only (name/type/list/optional) — `pattern:`/
158
+ # `admits:`/`default:` are refinements on a field, not a second
122
159
  # claim about what the payload holds, so two emitting commands
123
160
  # are free to differ there without actually disagreeing about
124
161
  # the event's own shape.
@@ -136,26 +173,26 @@ module Hecks
136
173
  end
137
174
  end
138
175
 
139
- # THE "EXPENSIVE HALF" the ADR names: "with: { account: :account }
176
+ # The "expensive half" the ADR names: "with: { account: :account }
140
177
  # projecting into a reaction that has no declared contract ...
141
178
  # breaks at dispatch rather than at load." Checked here, now that
142
179
  # `validate_event_shapes!` (above) guarantees at most one real
143
180
  # shape per event name, and command references being first-class
144
- # (`Naming.command_ref`) means the TARGET side is a real
181
+ # (`Naming.command_ref`) means the target side is a real
145
182
  # resolvable command, not a string that might be a typo.
146
183
  #
147
- # SAME-CHAPTER ONLY, ON PURPOSE — a `with:` whose source event or
184
+ # **Same-chapter only, on purpose** — a `with:` whose source event or
148
185
  # target command lives outside this chapter (an `across` policy
149
186
  # reacting to another domain's event entirely) is silently left
150
187
  # unchecked rather than refused: there is nothing here yet to
151
188
  # check it against, and "unresolvable" is not the same claim as
152
189
  # "wrong."
153
190
  #
154
- # A FOR_EACH POLICY'S SOURCE ISN'T THE EVENT AT ALL — a fan-out
155
- # `with:`'s symbols read the QUERY ROW `for_each` answers
191
+ # A FOR_EACH policy's source isn't the event at all — a fan-out
192
+ # `with:`'s symbols read the query row `for_each` answers
156
193
  # (FreezeAccountsOnSuspension's own comment: "`account` is the
157
194
  # key the fan-out merges for each row"), which this has no shape
158
- # for; the SOURCE half is skipped for those, the TARGET half
195
+ # for; the source half is skipped for those, the target half
159
196
  # (does the dispatched command actually declare the field) still
160
197
  # runs, since that half is true regardless of where the value
161
198
  # came from.
@@ -184,11 +221,11 @@ module Hecks
184
221
  end
185
222
 
186
223
  # `process_manager:` is present only for a process manager's own dispatch — a
187
- # saga leg's source symbol resolves against the CURRENT triggering
224
+ # saga leg's source symbol resolves against the current triggering
188
225
  # event first, same as a policy, but falls all the way back to the
189
- # saga's own MEMORY when the current event does not carry it
226
+ # saga's own memory when the current event does not carry it
190
227
  # (`SagaInterpreter#dispatch_args`, its own last `else`) — and
191
- # memory starts as the OPENING event's payload
228
+ # memory starts as the opening event's payload
192
229
  # (`SagaInterpreter#instance = { ..., memory: event.payload }`,
193
230
  # never updated after), never the leg's own. Settlement's own
194
231
  # comment names exactly this: "the credit leg reads a destination
@@ -211,7 +248,7 @@ module Hecks
211
248
  source_shape = event_name && event_shape_for(event_name, aggregates)
212
249
  memory_shape = process_manager && event_shape_for(process_manager.starts_on, aggregates)
213
250
  correlation = process_manager&.correlates_by && process_manager.correlation_head
214
- # A POLICY'S SOURCE ALSO CARRIES THE EMITTER'S OWN IDENTITY
251
+ # A policy's source also carries the emitter's own identity
215
252
  # `PolicyInterpreter#emitter_identity`, the runtime half of this.
216
253
  # An entity command's event never declares its aggregate's
217
254
  # identity (it arrives through `reference_to`, not an
@@ -243,15 +280,15 @@ module Hecks
243
280
  end
244
281
  end
245
282
 
246
- # A command's OWN `reference_to` (bare, no `as:`) never lands in
283
+ # A command's own `reference_to` (bare, no `as:`) never lands in
247
284
  # `attributes` — `CommandBuilder#reference_to`'s self-reference
248
285
  # branch sets `command.references` instead (S2), and mints no new
249
- # field at all. What addresses it is not one name but the SAME
250
- # SET `CommandInterpreter::ArgumentGate#refuse_unknown_arguments`
286
+ # field at all. What addresses it is not one name but the same
287
+ # set `CommandInterpreter::ArgumentGate#refuse_unknown_arguments`
251
288
  # already accepts at dispatch time — `:id`, the owning aggregate's
252
289
  # own `identity_heads` (real corpus proof — `Account.Debit`
253
290
  # dispatched everywhere as `number: ...`, `Account`'s own
254
- # `identified_by`), AND `Naming.reference_key(command.references)`
291
+ # `identified_by`), and `Naming.reference_key(command.references)`
255
292
  # (real corpus proof — `FreezeAccountsOnSuspension`'s `for_each`
256
293
  # fan-out, whose own comment reads "`account` is the key the
257
294
  # fan-out merges for each row it answers"). Both are simultaneously
@@ -271,9 +308,9 @@ module Hecks
271
308
  referenced.identity_heads.include?(field) || Naming.reference_key(command.references) == field
272
309
  end
273
310
 
274
- # THE FOURTH addressing key `ArgumentGate#refuse_unknown_arguments`
311
+ # The fourth addressing key `ArgumentGate#refuse_unknown_arguments`
275
312
  # accepts, alongside `:id`/`identity_heads`/`reference_key` — every
276
- # saga in THIS domain's own `correlates_by` head, carried through
313
+ # saga in this domain's own `correlates_by` head, carried through
277
314
  # every dispatch as pure passthrough (Settlement's own comment:
278
315
  # "`reference:` carries the correlation forward... this is pure
279
316
  # passthrough, not an addressing key"). A command declaring none of
@@ -283,7 +320,7 @@ module Hecks
283
320
  process_managers.filter_map { |pm| pm.correlates_by && pm.correlation_head }
284
321
  end
285
322
 
286
- # Every command this chapter declares, an aggregate's own AND
323
+ # Every command this chapter declares, an aggregate's own and
287
324
  # every entity nested inside one, paired with a name for what
288
325
  # declares it — shared by `validate_event_shapes!` and
289
326
  # `validate_with_projections!`'s own command lookup, the same
@@ -299,9 +336,9 @@ module Hecks
299
336
  end
300
337
  end
301
338
 
302
- # NOT MEMOISED — this used to be `@event_emitters ||=` on the
339
+ # **Not memoised** — this used to be `@event_emitters ||=` on the
303
340
  # builder instance, which is safe for a one-file chapter but
304
- # wrong for one split across several: the FIRST file's build()
341
+ # wrong for one split across several: the first file's build()
305
342
  # call would compute and cache it from whatever `@aggregates`
306
343
  # held at that moment, and every later file's own validation
307
344
  # would keep reading that same stale snapshot, silently missing
@@ -314,26 +351,26 @@ module Hecks
314
351
  end
315
352
  end
316
353
 
317
- # STRUCTURAL, NOT NOMINAL. Two commands on two different
354
+ # **Structural, not nominal**. Two commands on two different
318
355
  # aggregates that both `emits "SameEvent"` are free to type a
319
- # field through two DIFFERENT, locally-scoped wrapper value
356
+ # field through two different, locally-scoped wrapper value
320
357
  # objects (e.g. one aggregate's own `value: SomeText` vs
321
358
  # another's `value: OtherText`, exactly the per-aggregate "own
322
359
  # text VO" convention every aggregate in this grammar already
323
360
  # follows for everything from `RuleText` to `FieldRef`) without
324
361
  # actually disagreeing about the event's shape — comparing
325
- # `a.type` by NAME would flag that as a violation for no real
362
+ # `a.type` by name would flag that as a violation for no real
326
363
  # reason: an event is one fact, and two isomorphic wrapper types
327
364
  # tell an identical one. So a value-object type is unwrapped to
328
- # its OWN attribute shape (recursively — a wrapper could itself
365
+ # its own attribute shape (recursively — a wrapper could itself
329
366
  # wrap another) before comparing, and only a primitive type
330
367
  # (nothing left to unwrap) or two VOs that truly differ once
331
368
  # unwrapped still counts as a real mismatch. `owner` carries the
332
369
  # type's `value_object` lookup — a command's own attributes only
333
- # know their type's NAME, never the aggregate that declared it,
370
+ # know their type's name, never the aggregate that declared it,
334
371
  # and two sibling aggregates in one chapter each keep a
335
372
  # same-named VO private to themselves, so the unwrap has to ask
336
- # the SAME aggregate the field's own command belongs to, never a
373
+ # the same aggregate the field's own command belongs to, never a
337
374
  # neighbor's.
338
375
  def event_shape(command, owner)
339
376
  command.attributes.map { |a| [a.name, unwrap_shape(owner, a.type.to_s), a.list?, a.optional?] }.sort
@@ -351,10 +388,10 @@ module Hecks
351
388
  shape.attributes.map { |a| [a.name, unwrap_shape(owner, a.type.to_s, seen + [type_name]), a.list?, a.optional?] }.sort
352
389
  end
353
390
 
354
- # `owner` (from `each_command`) is a plain STRING — the aggregate's
391
+ # `owner` (from `each_command`) is a plain string — the aggregate's
355
392
  # `hecks_name` alone, or `"Aggregate.Entity"` for an entity's own
356
- # command. Either way the VALUE OBJECTS a command's fields can be
357
- # typed with are the AGGREGATE's own (`Entity` carries no
393
+ # command. Either way the value objects a command's fields can be
394
+ # typed with are the aggregate's own (`Entity` carries no
358
395
  # `value_object` lookup of its own — the whole rest of this file
359
396
  # already resolves hop/type lookups only at the aggregate level,
360
397
  # e.g. `validate_hop_tail!`'s `target.value_object(type)`), so only
@@ -372,7 +409,7 @@ module Hecks
372
409
  end
373
410
 
374
411
  # The identity heads of the aggregate that emits `event_name` — an
375
- # entity's event is stamped with its OWNING aggregate's identity
412
+ # entity's event is stamped with its owning aggregate's identity
376
413
  # (`Event#id` is the parent's), so an owner spelled "Game.Knight"
377
414
  # answers Game's heads.
378
415
  def event_identity_heads_for(event_name, aggregates)
@@ -384,7 +421,7 @@ module Hecks
384
421
  return [] unless aggregate
385
422
 
386
423
  heads = aggregate.identity_heads.map(&:to_sym)
387
- # AN ENTITY'S EVENT ALSO CARRIES THE PIECE'S OWN IDENTITY — the
424
+ # An entity's event also carries the piece's own identity — the
388
425
  # args a piece was addressed by are the args its event announces
389
426
  # (`Emission#emit`: `payload: args`), so `id`-shaped heads are
390
427
  # genuinely there at runtime even though no `attribute` line on
@@ -400,9 +437,9 @@ module Hecks
400
437
  end
401
438
  end
402
439
 
403
- # A REFERENCE RING IS NOT A MODELLING CHOICE, IT IS A MISSING ONE
440
+ # A reference ring is not a modelling choice, it is a missing one
404
441
  # — a DDD aggregate is a consistency boundary precisely because
405
- # something outside it can only ever point IN, by id, never the
442
+ # something outside it can only ever point in, by id, never the
406
443
  # other way. A caller must be able to reason about one aggregate
407
444
  # alone ; a ring back to where it started means no aggregate in
408
445
  # it is a boundary anyone can reason about without the rest of
@@ -414,11 +451,11 @@ module Hecks
414
451
  # aggregate finishes building long before it can know whether
415
452
  # some later aggregate in the same file points back at it.
416
453
  #
417
- # ACYCLIC WITHIN A CHAPTER (ADR 0025, "References") — widened
454
+ # Acyclic within a chapter (ADR 0025, "References") — widened
418
455
  # from the direct pair (A -> B -> A) this used to catch alone to
419
456
  # any ring, however long (A -> B -> C -> A), the same DFS
420
457
  # coloring a reference graph needs for any cycle. A cross-chapter
421
- # reference is UNREACHABLE here rather than unchecked:
458
+ # reference is unreachable here rather than unchecked:
422
459
  # `Reference#resolve` is scoped to its own chapter by
423
460
  # construction, so a target this chapter never declares is a
424
461
  # dangling name, not an edge — `edges.key?` below is what keeps
@@ -443,7 +480,7 @@ module Hecks
443
480
  end
444
481
 
445
482
  # Plain DFS with a visiting/done coloring, over the reference
446
- # graph THIS chapter's own aggregates declare. Returns the ring
483
+ # graph this chapter's own aggregates declare. Returns the ring
447
484
  # itself (in the order it closes), or nil.
448
485
  def find_reference_cycle(edges)
449
486
  state = {}
@@ -475,10 +512,10 @@ module Hecks
475
512
  nil
476
513
  end
477
514
 
478
- # THE OTHER HALF OF A HOP — AggregateBuilder#seal_query_field
479
- # recognised the HEAD of a dotted where-field that names one of
515
+ # **The other half of a hop** — AggregateBuilder#seal_query_field
516
+ # recognised the head of a dotted where-field that names one of
480
517
  # its own references and deferred it here, unable to check
481
- # further: it cannot yet resolve what the reference points AT.
518
+ # further: it cannot yet resolve what the reference points at.
482
519
  # This runs once every aggregate exists in one chapter, so it
483
520
  # can.
484
521
  #
@@ -486,11 +523,11 @@ module Hecks
486
523
  # refused outright, immediately, back in seal_query_field
487
524
  # itself (that answer never needed the target's shape).
488
525
  #
489
- # AN ENTITY'S OWN QUERIES DID reach `EntityBuilder#reference_to`
526
+ # An entity's own queries did reach `EntityBuilder#reference_to`
490
527
  # (added after this comment first claimed otherwise — S9, ADR
491
- # 0025) without ever reaching HERE: tier-1 sealing
528
+ # 0025) without ever reaching here: tier-1 sealing
492
529
  # (`AggregateBuilder#query_surfaces`) already recognises a hop
493
- # on an entity's own field and DEFERS it exactly like an
530
+ # on an entity's own field and defers it exactly like an
494
531
  # aggregate's, but nothing ever walked entity queries at tier 2
495
532
  # to check the deferral — a bad hop, or even a well-formed one,
496
533
  # built silently and then matched nothing at runtime
@@ -540,7 +577,7 @@ module Hecks
540
577
  end
541
578
  end
542
579
 
543
- # THE LEAF `infer_hop_query_arguments!` INFERS for one resolved
580
+ # The leaf `infer_hop_query_arguments!` infers for one resolved
544
581
  # hop plan — a pure function of `plan` and the symbolic `name`
545
582
  # it is naming, pulled out because it is a self-contained
546
583
  # computation with no dependency on the enclosing loop's own
@@ -602,10 +639,10 @@ module Hecks
602
639
  validate_hop_tail!(aggregate, query, clause, target, plan.tail)
603
640
  end
604
641
 
605
- # The same three-way answer seal_query_field gives for its OWN
642
+ # The same three-way answer seal_query_field gives for its own
606
643
  # aggregate's fields — landing on a real scalar (fine), landing
607
644
  # on a value object (refused by name), or naming nothing at all
608
- # (refused by name) — asked instead of the hop's TARGET aggregate,
645
+ # (refused by name) — asked instead of the hop's target aggregate,
609
646
  # since that is whose shape the tail actually has to answer for.
610
647
  def validate_hop_tail!(aggregate, query, clause, target, tail)
611
648
  name, *nested = tail.to_s.split(".")
@@ -632,11 +669,11 @@ module Hecks
632
669
  "not exist matches nothing and refuses nothing"
633
670
  end
634
671
 
635
- # A WHERE hop with an ordered comparator is legitimate ("client
672
+ # A where hop with an ordered comparator is legitimate ("client
636
673
  # whose balance > 500") — AggregateBuilder#seal_ordered_comparator
637
674
  # already deferred this exact check for the same reason every
638
675
  # other hop check is deferred, and this is where it gets asked,
639
- # against the hop's TARGET instead of the querying aggregate.
676
+ # against the hop's target instead of the querying aggregate.
640
677
  def validate_hop_comparator!(aggregate, query, clause, target, attribute, nested)
641
678
  return unless AggregateBuilder::ORDERED_COMPARATORS.include?(clause.op.to_s.to_sym)
642
679
  return if attribute &&
@@ -650,10 +687,10 @@ module Hecks
650
687
  "anything else the adapters answer differently or not at all"
651
688
  end
652
689
 
653
- # THE TARGET HALF of `projects` validation (S12, ADR 0025) —
690
+ # The target half of `projects` validation (S12, ADR 0025) —
654
691
  # `AggregateBuilder#seal_projected_fields` already checked the
655
- # LOCAL half at declare time (the reference names a real
656
- # `reference_to` on THIS aggregate); this checks the reference
692
+ # local half at declare time (the reference names a real
693
+ # `reference_to` on this aggregate); this checks the reference
657
694
  # actually resolves to a real aggregate in this chapter, and
658
695
  # that aggregate really declares `remote_field` as a scalar.
659
696
  #
@@ -671,7 +708,7 @@ module Hecks
671
708
  end
672
709
  end
673
710
 
674
- # A linear decision tree of validation rules over ONE resolved
711
+ # A linear decision tree of validation rules over one resolved
675
712
  # hop plan, each already explained by its own comment above
676
713
  # (the lifecycle fallback, the chained-projection fallback, the
677
714
  # final scalar check) — a fixed, closed sequence "resolve, then
@@ -693,17 +730,17 @@ module Hecks
693
730
  target = plan.hops.last.target
694
731
  remote_attribute = target.attributes.find { |candidate| candidate.name.to_s == plan.tail }
695
732
 
696
- # THE WORKED EXAMPLE ITSELF (ADR 0025) reads through a
697
- # LIFECYCLE field — banking's Customer.status is `lifecycle
733
+ # The worked example itself (ADR 0025) reads through a
734
+ # lifecycle field — banking's Customer.status is `lifecycle
698
735
  # :status`, never a plain `attribute` — the same fallback
699
736
  # validate_hop_tail! already gives a query's own hop tail. A
700
737
  # lifecycle field is always a plain string by construction ;
701
738
  # nothing further to check once it matches by name.
702
739
  return if remote_attribute.nil? && target.lifecycle&.field.to_s == plan.tail
703
740
 
704
- # A PROJECTION MAY CHAIN THROUGH ANOTHER PROJECTION (S12, ADR
741
+ # A projection may chain through another projection (S12, ADR
705
742
  # 0025's own boundary rule, followed through) — `target`'s
706
- # OWN projected fields live in `projected_fields`, a
743
+ # own projected fields live in `projected_fields`, a
707
744
  # separate list from `attributes`, so a match there is
708
745
  # invisible to the check above even though it names a real,
709
746
  # always-current, stored field. `Transfer.projects
@@ -737,10 +774,10 @@ module Hecks
737
774
  !attribute.list? && !attribute.reference? && target.value_object(attribute.type).nil?
738
775
  end
739
776
 
740
- # `correlates_by` NAMES A SCALAR, NOW CHECKED RATHER THAN TRUSTED.
777
+ # `correlates_by` names a scalar, now checked rather than trusted.
741
778
  #
742
779
  # ProcessManagerBuilder#validate! already refuses a bare, undotted
743
- # spelling — a SYNTACTIC guarantee that the declaration cannot leave
780
+ # spelling — a syntactic guarantee that the declaration cannot leave
744
781
  # the question open. It cannot go further: a process manager is built
745
782
  # in isolation, before this chapter's aggregates exist to check
746
783
  # against. Here, with the whole document assembled, the dotted path