hecks 1.3.0 → 1.5.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 (373) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hecks/adapters/driven/claude_code.rb +72 -7
  3. data/lib/hecks/adapters/driven/d1.rb +187 -23
  4. data/lib/hecks/adapters/driven/folder.rb +83 -10
  5. data/lib/hecks/adapters/driven/google_authentication.rb +33 -12
  6. data/lib/hecks/adapters/driven/governance_authorization.rb +87 -18
  7. data/lib/hecks/adapters/driven/heki/journal.rb +13 -4
  8. data/lib/hecks/adapters/driven/heki/saga_store.rb +56 -10
  9. data/lib/hecks/adapters/driven/heki/snapshot.rb +1 -1
  10. data/lib/hecks/adapters/driven/heki.rb +106 -9
  11. data/lib/hecks/adapters/driven/identity_registry.rb +12 -2
  12. data/lib/hecks/adapters/driven/in_memory_ordering.rb +25 -3
  13. data/lib/hecks/adapters/driven/in_process_key_vault.adapter +3 -0
  14. data/lib/hecks/adapters/driven/in_process_key_vault.rb +53 -0
  15. data/lib/hecks/adapters/driven/lambda/client.rb +67 -14
  16. data/lib/hecks/adapters/driven/lambda.rb +82 -35
  17. data/lib/hecks/adapters/driven/local_storage.rb +83 -10
  18. data/lib/hecks/adapters/driven/memory.rb +205 -9
  19. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +21 -1
  20. data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
  21. data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
  22. data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
  23. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
  24. data/lib/hecks/adapters/driven/postgres.rb +175 -28
  25. data/lib/hecks/adapters/driven/prism.rb +50 -11
  26. data/lib/hecks/adapters/driven/secure_random_identity.rb +3 -0
  27. data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
  28. data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
  29. data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
  30. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
  31. data/lib/hecks/adapters/driven/sqlite.rb +181 -21
  32. data/lib/hecks/adapters/driven/system_clock.rb +3 -0
  33. data/lib/hecks/adapters/driven/tenant_provisioner.adapter +3 -0
  34. data/lib/hecks/adapters/driven/tenant_provisioner.rb +66 -0
  35. data/lib/hecks/adapters/driven.rb +6 -4
  36. data/lib/hecks/adapters/driving/github_webhook.rb +31 -18
  37. data/lib/hecks/behaviors/dsl.rb +60 -2
  38. data/lib/hecks/behaviors/expectations.rb +190 -29
  39. data/lib/hecks/behaviors/ir.rb +12 -1
  40. data/lib/hecks/behaviors/rspec.rb +9 -1
  41. data/lib/hecks/behaviors/runner.rb +21 -2
  42. data/lib/hecks/behaviors.rb +9 -1
  43. data/lib/hecks/bluebook/aggregate.rb +43 -13
  44. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +17 -10
  45. data/lib/hecks/bluebook/assembly/build.rb +26 -5
  46. data/lib/hecks/bluebook/assembly/contract.rb +98 -23
  47. data/lib/hecks/bluebook/assembly/contracts.rb +59 -52
  48. data/lib/hecks/bluebook/assembly/marks.rb +159 -30
  49. data/lib/hecks/bluebook/assembly/specializer.rb +38 -21
  50. data/lib/hecks/bluebook/assembly.rb +32 -14
  51. data/lib/hecks/bluebook/attribute.rb +26 -12
  52. data/lib/hecks/bluebook/behaviour/aggregate.rb +43 -11
  53. data/lib/hecks/bluebook/behaviour/attribute.rb +18 -5
  54. data/lib/hecks/bluebook/behaviour/chapter.rb +76 -5
  55. data/lib/hecks/bluebook/behaviour/command.rb +55 -25
  56. data/lib/hecks/bluebook/behaviour/domain_port.rb +27 -7
  57. data/lib/hecks/bluebook/behaviour/entity.rb +20 -8
  58. data/lib/hecks/bluebook/behaviour/hexagon.rb +30 -4
  59. data/lib/hecks/bluebook/behaviour/lifecycle.rb +27 -6
  60. data/lib/hecks/bluebook/behaviour/policy.rb +42 -17
  61. data/lib/hecks/bluebook/behaviour/process_manager.rb +39 -8
  62. data/lib/hecks/bluebook/behaviour/query.rb +6 -1
  63. data/lib/hecks/bluebook/behaviour/read_model.rb +29 -8
  64. data/lib/hecks/bluebook/behaviour/traits.rb +48 -12
  65. data/lib/hecks/bluebook/behaviour/value_object.rb +21 -9
  66. data/lib/hecks/bluebook/capabilities.rb +27 -0
  67. data/lib/hecks/bluebook/chapter.rb +51 -9
  68. data/lib/hecks/bluebook/command.rb +62 -17
  69. data/lib/hecks/bluebook/domain_port.rb +34 -9
  70. data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
  71. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
  72. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +282 -123
  73. data/lib/hecks/bluebook/dsl/attribute_collector.rb +112 -75
  74. data/lib/hecks/bluebook/dsl/binding_proxy.rb +81 -2
  75. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +486 -117
  76. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +179 -47
  77. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
  78. data/lib/hecks/bluebook/dsl/command_builder.rb +284 -122
  79. data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
  80. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
  81. data/lib/hecks/bluebook/dsl/entity_builder.rb +191 -61
  82. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
  83. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +130 -30
  84. data/lib/hecks/bluebook/dsl/identity_declaration.rb +38 -21
  85. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
  86. data/lib/hecks/bluebook/dsl/policy_builder.rb +86 -36
  87. data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
  88. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
  89. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +111 -47
  90. data/lib/hecks/bluebook/dsl/query_builder.rb +37 -8
  91. data/lib/hecks/bluebook/dsl/read_model_builder.rb +127 -52
  92. data/lib/hecks/bluebook/dsl/rule_reference.rb +97 -43
  93. data/lib/hecks/bluebook/dsl/translation_builder.rb +150 -44
  94. data/lib/hecks/bluebook/dsl/value_object_builder.rb +68 -20
  95. data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
  96. data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
  97. data/lib/hecks/bluebook/entity.rb +40 -11
  98. data/lib/hecks/bluebook/expression/ast_json.rb +128 -36
  99. data/lib/hecks/bluebook/expression/ast_reader.rb +32 -3
  100. data/lib/hecks/bluebook/expression/canonical_form.rb +55 -16
  101. data/lib/hecks/bluebook/expression/evaluator.rb +221 -43
  102. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +54 -18
  103. data/lib/hecks/bluebook/expression/resolver.rb +369 -128
  104. data/lib/hecks/bluebook/hexagon.rb +35 -1
  105. data/lib/hecks/bluebook/lifecycle.rb +12 -1
  106. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +2 -1
  107. data/lib/hecks/bluebook/meta_validator/judge.rb +126 -108
  108. data/lib/hecks/bluebook/meta_validator/plan.rb +81 -46
  109. data/lib/hecks/bluebook/meta_validator/port_judge.rb +3 -2
  110. data/lib/hecks/bluebook/meta_validator/readings.rb +200 -50
  111. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +68 -41
  112. data/lib/hecks/bluebook/meta_validator/shapes.rb +166 -21
  113. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +286 -46
  114. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +11 -10
  115. data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -5
  116. data/lib/hecks/bluebook/meta_validator.rb +235 -139
  117. data/lib/hecks/bluebook/model_check.rb +434 -104
  118. data/lib/hecks/bluebook/pattern_subset.rb +32 -10
  119. data/lib/hecks/bluebook/policy.rb +15 -13
  120. data/lib/hecks/bluebook/process_manager.rb +27 -14
  121. data/lib/hecks/bluebook/project_discovery.rb +5 -0
  122. data/lib/hecks/bluebook/project_loader.rb +40 -0
  123. data/lib/hecks/bluebook/project_register.rb +50 -6
  124. data/lib/hecks/bluebook/query.rb +31 -4
  125. data/lib/hecks/bluebook/read_model.rb +35 -15
  126. data/lib/hecks/bluebook/reference.rb +26 -13
  127. data/lib/hecks/bluebook/smoke_test.rb +46 -23
  128. data/lib/hecks/bluebook/synthesizer.rb +46 -12
  129. data/lib/hecks/bluebook/translation.rb +34 -5
  130. data/lib/hecks/bluebook/value_object.rb +29 -11
  131. data/lib/hecks/bluebook.rb +5 -6
  132. data/lib/hecks/codemod.rb +138 -50
  133. data/lib/hecks/construct.rb +21 -7
  134. data/lib/hecks/corpus.rb +438 -0
  135. data/lib/hecks/deploy/bluebook/deploy.hecksagon +19 -0
  136. data/lib/hecks/doc/reference.rb +200 -31
  137. data/lib/hecks/embryonaut_bluebook.rb +38 -15
  138. data/lib/hecks/facade/cli_door.rb +69 -10
  139. data/lib/hecks/facade/cli_runner.rb +105 -24
  140. data/lib/hecks/facade/command_request.rb +23 -0
  141. data/lib/hecks/facade/handle.rb +155 -35
  142. data/lib/hecks/facade/json_door.rb +106 -25
  143. data/lib/hecks/facade/surface/aggregate_door.rb +50 -27
  144. data/lib/hecks/facade/surface/chapter.rb +26 -17
  145. data/lib/hecks/facade/surface.rb +16 -3
  146. data/lib/hecks/facade.rb +15 -4
  147. data/lib/hecks/forms/app.rb +46 -30
  148. data/lib/hecks/forms/command_form_renderer.rb +70 -9
  149. data/lib/hecks/forms/field_renderer.rb +142 -6
  150. data/lib/hecks/forms/field_shape.rb +183 -19
  151. data/lib/hecks/forms/html.rb +51 -7
  152. data/lib/hecks/forms/index_renderer.rb +14 -2
  153. data/lib/hecks/forms/page.rb +14 -0
  154. data/lib/hecks/forms/params.rb +120 -23
  155. data/lib/hecks/forms/port_argument.rb +14 -2
  156. data/lib/hecks/forms/query_form_renderer.rb +65 -2
  157. data/lib/hecks/forms/record_renderer.rb +60 -2
  158. data/lib/hecks/forms/record_table.rb +28 -1
  159. data/lib/hecks/forms/reference_options.rb +24 -0
  160. data/lib/hecks/forms/value_object_shape.rb +13 -3
  161. data/lib/hecks/forms.rb +24 -4
  162. data/lib/hecks/fqn.rb +59 -1
  163. data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
  164. data/lib/hecks/framework/bluebook/privacy.bluebook +155 -0
  165. data/lib/hecks/framework/oidc.json +15 -0
  166. data/lib/hecks/framework.rb +79 -25
  167. data/lib/hecks/freezer.rb +27 -11
  168. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +241 -106
  169. data/lib/hecks/fuzzing/combination_miner.rb +178 -0
  170. data/lib/hecks/fuzzing/concurrent_dispatch.rb +241 -45
  171. data/lib/hecks/fuzzing/coverage_campaign.rb +161 -0
  172. data/lib/hecks/fuzzing/differential.rb +192 -0
  173. data/lib/hecks/fuzzing/domain_generator.rb +871 -0
  174. data/lib/hecks/fuzzing/era_boundary.rb +68 -19
  175. data/lib/hecks/fuzzing/form_census.rb +121 -20
  176. data/lib/hecks/fuzzing/generated_domain_check.rb +171 -0
  177. data/lib/hecks/fuzzing/invalid_value_generator.rb +45 -6
  178. data/lib/hecks/fuzzing/isolated_boot.rb +137 -80
  179. data/lib/hecks/fuzzing/nondeterministic.rb +79 -0
  180. data/lib/hecks/fuzzing/persistence_parity.rb +111 -21
  181. data/lib/hecks/fuzzing/properties/corrections.rb +34 -9
  182. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +300 -51
  183. data/lib/hecks/fuzzing/properties/guards.rb +86 -42
  184. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +80 -32
  185. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +40 -35
  186. data/lib/hecks/fuzzing/properties/outbox.rb +70 -32
  187. data/lib/hecks/fuzzing/properties/querying.rb +82 -28
  188. data/lib/hecks/fuzzing/properties.rb +84 -51
  189. data/lib/hecks/fuzzing/qa_settings.rb +164 -0
  190. data/lib/hecks/fuzzing/replay.rb +241 -133
  191. data/lib/hecks/fuzzing/rotation_priority.rb +48 -28
  192. data/lib/hecks/fuzzing/rust_gap_manifest.rb +139 -0
  193. data/lib/hecks/fuzzing/self_consistency.rb +315 -137
  194. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +46 -40
  195. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +18 -11
  196. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +13 -12
  197. data/lib/hecks/fuzzing/sequence_generator/picker.rb +21 -12
  198. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +59 -32
  199. data/lib/hecks/fuzzing/sequence_generator.rb +158 -23
  200. data/lib/hecks/fuzzing/shrinker.rb +309 -0
  201. data/lib/hecks/fuzzing/structural_skips.rb +37 -130
  202. data/lib/hecks/fuzzing/sweep_depth.rb +12 -4
  203. data/lib/hecks/fuzzing/target_capabilities.rb +107 -29
  204. data/lib/hecks/fuzzing/value_generator.rb +110 -22
  205. data/lib/hecks/fuzzing.rb +5 -0
  206. data/lib/hecks/grammar/evolve.rb +188 -12
  207. data/lib/hecks/grammar.rb +53 -7
  208. data/lib/hecks/ir.rb +51 -20
  209. data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
  210. data/lib/hecks/language/bluebook/policy.bluebook +11 -1
  211. data/lib/hecks/language/bluebook/vocabulary.bluebook +348 -13
  212. data/lib/hecks/language/hecksagon/hecksagon.bluebook +11 -0
  213. data/lib/hecks/language/oidc.json +5 -0
  214. data/lib/hecks/literal.rb +41 -9
  215. data/lib/hecks/naming.rb +112 -31
  216. data/lib/hecks/ports/access_control.rb +53 -2
  217. data/lib/hecks/ports/agent/answers.rb +83 -6
  218. data/lib/hecks/ports/agent.rb +119 -35
  219. data/lib/hecks/ports/authentication.rb +44 -4
  220. data/lib/hecks/ports/authorization.rb +50 -11
  221. data/lib/hecks/ports/clock.rb +42 -23
  222. data/lib/hecks/ports/extraction.rb +16 -0
  223. data/lib/hecks/ports/identity_assignment.rb +23 -2
  224. data/lib/hecks/ports/identity_generation.rb +17 -3
  225. data/lib/hecks/ports/identity_resolution.rb +17 -1
  226. data/lib/hecks/ports/key_vault.port +6 -0
  227. data/lib/hecks/ports/key_vault.rb +58 -0
  228. data/lib/hecks/ports/loading.rb +4 -0
  229. data/lib/hecks/ports/persistence/append_only.rb +172 -8
  230. data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
  231. data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
  232. data/lib/hecks/ports/persistence/execution.rb +4 -0
  233. data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
  234. data/lib/hecks/ports/persistence/plugin.rb +42 -4
  235. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
  236. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
  237. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
  238. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
  239. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
  241. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
  242. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
  243. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
  244. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +118 -66
  245. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
  246. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +34 -5
  247. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
  248. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
  249. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
  250. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +33 -9
  251. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
  252. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +95 -6
  253. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
  254. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +314 -90
  255. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
  256. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
  257. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
  258. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +48 -8
  259. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
  260. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
  261. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
  262. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +58 -19
  263. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +96 -5
  264. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +15 -0
  265. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +9 -1
  266. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
  267. data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
  268. data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
  269. data/lib/hecks/ports/persistence/repository_factory.rb +23 -3
  270. data/lib/hecks/ports/persistence/state_codec.rb +319 -0
  271. data/lib/hecks/ports/persistence.rb +36 -1
  272. data/lib/hecks/ports/projection.rb +61 -7
  273. data/lib/hecks/ports/query/in_memory.rb +41 -8
  274. data/lib/hecks/ports/query/ordering.rb +21 -6
  275. data/lib/hecks/ports/query.rb +35 -0
  276. data/lib/hecks/ports.rb +1 -0
  277. data/lib/hecks/projections/bootstrap_table.rb +147 -0
  278. data/lib/hecks/projections/diagrams.rb +315 -79
  279. data/lib/hecks/projections/glossary/html.rb +91 -3
  280. data/lib/hecks/projections/glossary/markdown.rb +50 -3
  281. data/lib/hecks/projections/glossary/mermaid.rb +49 -1
  282. data/lib/hecks/projections/glossary/sections.rb +1 -1
  283. data/lib/hecks/projections/glossary/sentences.rb +110 -5
  284. data/lib/hecks/projections/glossary.rb +173 -31
  285. data/lib/hecks/projections/ir.rb +1 -1
  286. data/lib/hecks/projections/model/deviations.rb +62 -17
  287. data/lib/hecks/projections/model.rb +75 -21
  288. data/lib/hecks/projections/oidc.rb +45 -8
  289. data/lib/hecks/projections/parser_table.rb +53 -12
  290. data/lib/hecks/projections/reference.rb +15 -3
  291. data/lib/hecks/projections/rust_vocabulary.rb +646 -0
  292. data/lib/hecks/projections/shape.rb +10 -2
  293. data/lib/hecks/projections/statements.rb +69 -22
  294. data/lib/hecks/projections/vocabulary.rb +26 -9
  295. data/lib/hecks/projections.rb +5 -3
  296. data/lib/hecks/projector/cli_projector.rb +245 -37
  297. data/lib/hecks/projector/docs_projector.rb +154 -28
  298. data/lib/hecks/projector/exporter.rb +104 -29
  299. data/lib/hecks/projector/ir_projector.rb +7 -1
  300. data/lib/hecks/projector/narrate_projector.rb +144 -23
  301. data/lib/hecks/projector/target.rb +42 -18
  302. data/lib/hecks/projector.rb +86 -18
  303. data/lib/hecks/query_ir.rb +94 -47
  304. data/lib/hecks/query_specification/common/comparators.rb +19 -3
  305. data/lib/hecks/query_specification/common/comparison.rb +109 -27
  306. data/lib/hecks/query_specification/common/dsl.rb +65 -9
  307. data/lib/hecks/query_specification/common/null_policy.rb +61 -15
  308. data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
  309. data/lib/hecks/query_specification/common/options.rb +25 -0
  310. data/lib/hecks/query_specification/field_path.rb +69 -15
  311. data/lib/hecks/query_specification/hop_path.rb +57 -20
  312. data/lib/hecks/query_specification/read_model/specification.rb +4 -0
  313. data/lib/hecks/rendering.rb +9 -3
  314. data/lib/hecks/router/namespace_installer.rb +16 -3
  315. data/lib/hecks/router.rb +56 -1
  316. data/lib/hecks/runtime/aggregate_lock.rb +20 -11
  317. data/lib/hecks/runtime/boot_gates.rb +21 -3
  318. data/lib/hecks/runtime/caller.rb +40 -8
  319. data/lib/hecks/runtime/capability_graph.rb +13 -2
  320. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +40 -41
  321. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +45 -67
  322. data/lib/hecks/runtime/command_interpreter.rb +195 -113
  323. data/lib/hecks/runtime/command_rules/admissibility.rb +231 -80
  324. data/lib/hecks/runtime/command_rules/arithmetic.rb +154 -96
  325. data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
  326. data/lib/hecks/runtime/command_rules/emission.rb +18 -1
  327. data/lib/hecks/runtime/command_rules/references.rb +145 -55
  328. data/lib/hecks/runtime/command_rules.rb +3 -0
  329. data/lib/hecks/runtime/dependency_planning.rb +56 -11
  330. data/lib/hecks/runtime/dispatcher.rb +263 -92
  331. data/lib/hecks/runtime/entity_element.rb +304 -67
  332. data/lib/hecks/runtime/entity_interpreter.rb +149 -88
  333. data/lib/hecks/runtime/errors.rb +37 -23
  334. data/lib/hecks/runtime/event.rb +15 -10
  335. data/lib/hecks/runtime/identity.rb +91 -23
  336. data/lib/hecks/runtime/instance.rb +103 -18
  337. data/lib/hecks/runtime/interpreting.rb +24 -16
  338. data/lib/hecks/runtime/invocation.rb +358 -0
  339. data/lib/hecks/runtime/loader.rb +105 -19
  340. data/lib/hecks/runtime/outbox.rb +164 -26
  341. data/lib/hecks/runtime/policy_interpreter.rb +73 -60
  342. data/lib/hecks/runtime/port_operation_interpreter.rb +42 -19
  343. data/lib/hecks/runtime/query_interpreter.rb +93 -74
  344. data/lib/hecks/runtime/reaction_invocation.rb +73 -28
  345. data/lib/hecks/runtime/read_model_interpreter.rb +60 -44
  346. data/lib/hecks/runtime/rebuild_sweep.rb +32 -4
  347. data/lib/hecks/runtime/reference_hop.rb +48 -6
  348. data/lib/hecks/runtime/refusal_wording.rb +142 -115
  349. data/lib/hecks/runtime/registry/saga_persistence.rb +32 -21
  350. data/lib/hecks/runtime/registry/verification.rb +153 -28
  351. data/lib/hecks/runtime/registry.rb +202 -32
  352. data/lib/hecks/runtime/remote_dispatcher.rb +125 -24
  353. data/lib/hecks/runtime/routing.rb +36 -154
  354. data/lib/hecks/runtime/saga_interpreter/correlation.rb +25 -27
  355. data/lib/hecks/runtime/saga_interpreter.rb +90 -76
  356. data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
  357. data/lib/hecks/runtime/tenant_check.rb +33 -13
  358. data/lib/hecks/runtime/tenant_scope.rb +23 -5
  359. data/lib/hecks/runtime/value/admission.rb +75 -30
  360. data/lib/hecks/runtime/value/coercion.rb +555 -142
  361. data/lib/hecks/runtime/value/entity_list_coercion.rb +132 -60
  362. data/lib/hecks/runtime/value.rb +71 -21
  363. data/lib/hecks/runtime.rb +39 -7
  364. data/lib/hecks/storehouse.rb +368 -72
  365. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +130 -0
  366. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +32 -0
  367. data/lib/hecks/version.rb +3 -3
  368. data/lib/hecks/vocabulary.rb +205 -4
  369. data/lib/hecks.rb +91 -11
  370. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +19 -11
  371. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +24 -12
  372. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +38 -14
  373. metadata +28 -2
@@ -3,34 +3,35 @@ module Hecks
3
3
  module MetaValidator
4
4
  # Offers every declaration in a built bluebook to the meta-domain.
5
5
  #
6
- # This used to be one hand-written branch per category, and the cost of that
7
- # shape was fourteen verbs the language declared and the judge never offered
8
- # — among them `Command.Argument` and `ValueObject.Field`, so a command's own
9
- # arguments and a value object's own fields were NEVER judged. Every rule
10
- # hanging off them was decoration. Nothing went red, because a branch that
11
- # does not exist cannot fail.
6
+ # There are no hand-written branches, one per category: that shape's
7
+ # real cost is any verb the language declares that the judge never
8
+ # offers — a branch nobody wrote for it — going undetected, since a
9
+ # branch that does not exist cannot fail. `Command.Argument` and
10
+ # `ValueObject.Field` were both admitted that way once, undetected;
11
+ # every rule hanging off them was decoration until offered for real.
12
12
  #
13
- # So there are no branches. The judge WALKS: it reads the plan the language
14
- # makes of itself (Plan), and for each node offers the creating command, then
15
- # each list through the command that appends to it, then each child. A verb
16
- # in the plan with no offer is now impossible — there is no branch left in
17
- # which to forget one, and spec/judge_coverage_spec holds it to that.
13
+ # So instead the judge walks: it reads the plan the language makes of
14
+ # itself (Plan), and for each node offers the creating command, then
15
+ # each list through the command that appends to it, then each child. A
16
+ # verb in the plan with no offer is now impossible — there is no
17
+ # branch left in which to forget one, and spec/judge_coverage_spec
18
+ # holds it to that.
18
19
  #
19
- # What is NOT uniform lives in Readings, and only where the IR's SHAPE
20
+ # What is not uniform lives in Readings, and only where the IR's shape
20
21
  # differs from the language's. Naming differences do not appear at all: the
21
22
  # language spells its fields as the IR spells them.
22
23
  #
23
- # Only the DISPATCH half of the round trip lives here. Reconstruction is the
24
+ # Only the dispatch half of the round trip lives here. Reconstruction is the
24
25
  # experiment's business ; judging does not need it.
25
26
  class Judge
26
27
  include Readings
27
28
 
28
- # Children offered BEFORE the parent's own lists, IN THIS ORDER. An
29
+ # Children offered before the parent's own lists, in this order. An
29
30
  # attribute's type is offered as the id of the thing it names, so the
30
31
  # value objects have to exist before anything that can name one — an
31
- # aggregate's own attributes, AND an entity's own (M13: an entity is its
32
+ # aggregate's own attributes, and an entity's own (M13: an entity is its
32
33
  # own root, repeating the aggregate's whole shape one level down, so its
33
- # attributes resolve against the SAME value-object pool). ValueObject
34
+ # attributes resolve against the same value-object pool). ValueObject
34
35
  # first, Entity second, so an entity's own attributes are never offered
35
36
  # before the value objects they may reference exist — a self-hosting
36
37
  # casualty found live: the meta-grammar's own Handler/Dispatch/Member/
@@ -43,7 +44,7 @@ module Hecks
43
44
  # see `detail_node`'s own use of this constant, below.
44
45
  EAGER_CHILDREN = { "Aggregate" => %w[ValueObject Entity] }.freeze
45
46
 
46
- # Categories an ENTITY declares as well as an aggregate. The IR reuses
47
+ # Categories an entity declares as well as an aggregate. The IR reuses
47
48
  # Command and Query for a piece's own commands and queries, so the
48
49
  # language reuses Command and Query — and the plan cannot express a second
49
50
  # parent, because a category's parent is derived from the one `*_id` argument
@@ -52,15 +53,17 @@ module Hecks
52
53
 
53
54
  attr_reader :refusals
54
55
 
55
- # THE RECORDS SURVIVE THE VERDICT.
56
+ # **The records survive the verdict**.
56
57
  #
57
- # Judging a bluebook and HOLDING one differ by exactly this: whether anyone
58
+ # Judging a bluebook and holding one differ by exactly this: whether anyone
58
59
  # keeps the runtime the declarations were dispatched into. Nobody did, so
59
60
  # `spec/round_trip_spec` reached the records by `Judge.allocate` and four
60
61
  # `instance_variable_set` calls. Reading the chapter back is the point now,
61
62
  # not a curiosity, so the runtime is simply readable.
62
63
  attr_reader :runtime
63
64
 
65
+ # @param bluebook [Object] a built bluebook chapter graph, as
66
+ # `MetaValidator.call` receives it
64
67
  def initialize(bluebook)
65
68
  @bluebook = bluebook
66
69
  @refusals = []
@@ -71,7 +74,7 @@ module Hecks
71
74
 
72
75
  private
73
76
 
74
- # ABSENT is not EMPTY. The rules read "if you declare it, declare
77
+ # Absent is not empty. The rules read "if you declare it, declare
75
78
  # something" — a description never given is legal. Passing "" for a nil
76
79
  # turns every one of them into "you must declare it".
77
80
  #
@@ -85,7 +88,7 @@ module Hecks
85
88
  { value: text.to_s }
86
89
  end
87
90
 
88
- # A REFERENCE IS AN ID, AND AN ID IS A SCALAR.
91
+ # A reference is an ID, and an ID is a scalar.
89
92
  #
90
93
  # Every other field goes to the meta-domain as a one-field value object,
91
94
  # because that is what it is. A reference is not: it carries the id of a
@@ -105,31 +108,45 @@ module Hecks
105
108
  yield
106
109
  rescue Runtime::GivenNotMet, Runtime::InvariantViolation,
107
110
  Runtime::TypeMismatch, Runtime::NotFound => e
108
- # NotFound is a VERDICT, not noise. An attribute's type is a reference to
109
- # its value object, so "no ValueObject with id …" IS the rule `attributes
111
+ # NotFound is a verdict, not noise. An attribute's type is a reference to
112
+ # its value object, so "no ValueObject with id …" is the rule `attributes
110
113
  # must use value-object types` refusing.
111
114
  @refusals << "#{label}: #{e.message}"
112
115
  rescue Runtime::UnknownVerb
113
116
  nil
114
117
  end
115
118
 
119
+ # QualityControl BUG#125 — every dispatch the judge makes into the
120
+ # meta-domain goes through here, and only here, so this is the one
121
+ # place `Runtime::Value.judge_bootstrapping` needs to wrap: it tells
122
+ # `Value::Coercion#check_scalar_shapes` this construction is the
123
+ # language's own self-hosted grammar walk, not a real domain's
124
+ # command, so a String-typed meta-grammar field (`Normalise`'s
125
+ # `position`, a `RuleText` — `appends`' generic walk-index handling
126
+ # collides with that field's own name, see the flag's own comment
127
+ # in coercion.rb) may still arrive as the raw Integer `appends`
128
+ # hands it. Scoped to exactly this method: nothing outside a judge's
129
+ # own dispatch ever runs inside it, so an ordinary domain command
130
+ # (a real caller's own PieceId, Money, …) is never affected.
116
131
  def send_to(verb, label, to: nil, **payload)
117
- offer(label) { @runtime.dispatch(verb, to: to, with: args(payload)) }
132
+ Runtime::Value.judge_bootstrapping do
133
+ offer(label) { @runtime.dispatch(verb, to: to, with: args(payload)) }
134
+ end
118
135
  end
119
136
 
120
- # THE RECEIVER, SPELLED THE WAY A REAL CALLER ADDRESSES IT.
137
+ # The receiver, spelled the way a real caller addresses it.
121
138
  #
122
139
  # `receiver` is an internal accumulator — it tracks the aggregate this
123
- # walk is inside AND, once it crosses into a real entity-owned category
140
+ # walk is inside and, once it crosses into a real entity-owned category
124
141
  # (Member/Handler/Dispatch — S17, ADR 0026), every entity hop on top of
125
142
  # it. But `Routing.envelope`/`parse_envelope_hash` do not want that
126
143
  # shape restated when there is no entity to route to: a plain aggregate
127
144
  # command is addressed by its bare id (`Facade::Handle#dispatch` — "to:
128
145
  # @id" — and `CommandRequest`'s own header: "aggregate command: { to:
129
146
  # "record-id", ... }"), never `{aggregate:, entities: []}` — that hash
130
- # is the ENTITY route's own shape, degenerate with nothing in it.
147
+ # is the entity route's own shape, degenerate with nothing in it.
131
148
  #
132
- # So THIS is the one place `receiver` turns into a `to:` value: bare
149
+ # So this is the one place `receiver` turns into a `to:` value: bare
133
150
  # when there is no entity hop (the overwhelming common case — every
134
151
  # category but those three), the full envelope only when there
135
152
  # genuinely is one.
@@ -144,19 +161,19 @@ module Hecks
144
161
  detail_node("Bluebook", @bluebook, nil, 0)
145
162
  end
146
163
 
147
- # DECLARED BEFORE DETAILED, for every set of siblings.
164
+ # Declared before detailed, for every set of siblings.
148
165
  #
149
- # A node used to be offered whole — declared, then its lists, then its
150
- # children — one sibling at a time. Which means an aggregate's attributes
151
- # were offered before its later siblings existed, and an attribute that
152
- # POINTS AT another aggregate could only resolve if that aggregate happened
153
- # to be declared earlier in the file. Banking survives on luck: Customer is
154
- # written above Account.
166
+ # Offering a node whole — declared, then its lists, then its children
167
+ # — one sibling at a time would mean an aggregate's attributes are
168
+ # offered before its later siblings exist, so an attribute that
169
+ # points at another aggregate could only resolve if that aggregate
170
+ # happens to be declared earlier in the file: banking would survive
171
+ # on luck, Customer written above Account.
155
172
  #
156
173
  # So siblings are declared in one pass and detailed in a second. It is the
157
174
  # same ordering the walk already used one level down — value objects before
158
175
  # the attributes that name them — lifted to the level above, and it is what
159
- # lets a reference be a REFERENCE rather than a string nobody can check.
176
+ # lets a reference be a reference rather than a string nobody can check.
160
177
  def declare_node(category, node, parent_id, index, extra = {}, receiver: nil)
161
178
  plan = @plan.category(category)
162
179
  return unless plan
@@ -169,34 +186,34 @@ module Hecks
169
186
  return unless plan
170
187
 
171
188
  id = identify(category, parent_id, node, index)
172
- # `extra` is the CUMULATIVE identity of every entity-owned
173
- # ancestor above this node (Handler's own `event_type` AND
189
+ # `extra` is the cumulative identity of every entity-owned
190
+ # ancestor above this node (Handler's own `event_type` and
174
191
  # ProcessManager's own `bluebook`/`name`, by the time Dispatch
175
192
  # is reached — S17, ADR 0026's two-level chain). `identity`
176
- # adds THIS node's own on top — computed for EVERY category,
193
+ # adds this node's own on top — computed for every category,
177
194
  # entity-owned or not, because a node need not be entity-owned
178
- # itself to OWN one (ValueObject isn't, and Member still needs
179
- # its `aggregate:`/`name:`) — it is simply what THIS node's own
195
+ # itself to own one (ValueObject isn't, and Member still needs
196
+ # its `aggregate:`/`name:`) — it is simply what this node's own
180
197
  # `identified_by` resolves to, the same fields `identify` two
181
- # lines up already derives the joined id FROM.
198
+ # lines up already derives the joined id from.
182
199
  #
183
- # `own` is the SUBSET actually spent on a dispatch payload —
184
- # only when THIS category is itself entity-owned, since an
200
+ # `own` is the subset actually spent on a dispatch payload —
201
+ # only when this category is itself entity-owned, since an
185
202
  # ordinary category (Command's own "Rule"/"Argument", offered
186
- # through the SAME `extra` SLOT for a DIFFERENT reason, see
203
+ # through the same `extra` slot for a different reason, see
187
204
  # `within_entity` below) locates the record it attaches to
188
205
  # through the parent id `id:` already carries, and merging
189
- # unrecognized `aggregate:`/`entity_id:` into THEIR payload
206
+ # unrecognized `aggregate:`/`entity_id:` into their payload
190
207
  # would have the runtime refuse them for an argument they
191
208
  # never declared.
192
209
  identity = extra.merge(node_identity(plan, category, node, index, parent_id))
193
210
  receiver ||= { aggregate: id, entities: [] }
194
211
  eager, later = children_of(category).partition { |child| eager?(category, child) }
195
- # ORDERED AS `EAGER_CHILDREN` DECLARES, not as `children_of` happens to
212
+ # Ordered as `EAGER_CHILDREN` declares, not as `children_of` happens to
196
213
  # list them — `children_of` reads `@plan.names`, whose own order is an
197
214
  # accident of which .bluebook file registered which category first,
198
215
  # never a promise about which of two eager children exists before the
199
- # other. `EAGER_CHILDREN`'s own array IS that promise (ValueObject
216
+ # other. `EAGER_CHILDREN`'s own array is that promise (ValueObject
200
217
  # before Entity), so the walk keeps only what this parent actually
201
218
  # has, in the order the constant states — see that constant's own
202
219
  # comment for the bug this exact reordering fixes.
@@ -204,12 +221,12 @@ module Hecks
204
221
 
205
222
  eager.each { |child| walk_all(child, node, id, entity_child_extra(child, identity), receiver: receiver) }
206
223
  setters(plan, category, node, receiver)
207
- # BEFORE `appends`, not after — the same reason `EAGER_CHILDREN`
208
- # walks an aggregate's OWN entities before its OWN attributes
224
+ # Before `appends`, not after — the same reason `EAGER_CHILDREN`
225
+ # walks an aggregate's own entities before its own attributes
209
226
  # (M13): a piece nested inside a piece (Handler's own
210
227
  # `dispatches, list_of(Dispatch)` — S17, ADR 0026) must exist
211
228
  # before this piece's own attribute list can reference it as a
212
- # HELD entity, the same way `Account#ledger` needs Account's own
229
+ # held entity, the same way `Account#ledger` needs Account's own
213
230
  # entities walked eagerly. `nest_entities` is a no-op for every
214
231
  # category but "Entity" (its own early return), so reordering it
215
232
  # ahead of `appends` costs nothing for anything else that walks
@@ -221,11 +238,11 @@ module Hecks
221
238
  sealers(plan, category, receiver)
222
239
  end
223
240
 
224
- # WHAT A CHILD'S OWN `extra` STARTS FROM. An entity-owned child's
225
- # own dotted dispatch needs every ANCESTOR's identity, which is
241
+ # What a child's own `extra` starts from. An entity-owned child's
242
+ # own dotted dispatch needs every ancestor's identity, which is
226
243
  # exactly `identity` — already accumulated one level at a time by
227
244
  # `detail_node` itself (regardless of whether each ancestor is
228
- # ITSELF entity-owned — ValueObject contributes its own `aggregate:
245
+ # itself entity-owned — ValueObject contributes its own `aggregate:
229
246
  # `/`name:` to Member's payload despite being an ordinary top-
230
247
  # level category), so there is nothing left to re-derive here. An
231
248
  # ordinary child (one with a real top-level aggregate of its own
@@ -234,15 +251,15 @@ module Hecks
234
251
  @plan.category(child)&.entity_owned ? identity : {}
235
252
  end
236
253
 
237
- # ONE NODE'S OWN IDENTITY, read off its own declaration — S17,
254
+ # One node's own identity, read off its own declaration — S17,
238
255
  # ADR 0026. Three cases, the same three `identify`/`identity_part`
239
256
  # already resolve one level up, unified here because a chain now
240
257
  # walks more than one level (Handler -> Dispatch) and each level
241
- # needs the SAME three answered about itself, not just the first:
258
+ # needs the same three answered about itself, not just the first:
242
259
  #
243
260
  # the parent link (plan.parent_key) -> `parent_id`, the id
244
261
  # the walk already carries in from one level up
245
- # a walk-minted one (POSITION) -> the walk INDEX itself ;
262
+ # a walk-minted one (`POSITION`) -> the walk index itself ;
246
263
  # never a stored field (Member's own header:
247
264
  # "position is not a mint — it is read straight
248
265
  # out of the source file")
@@ -251,12 +268,12 @@ module Hecks
251
268
  # (Handler's own `event_type`, Dispatch's own
252
269
  # `command_name`)
253
270
  #
254
- # `carried` still decides bare-vs-wrapped the normal way ; POSITION
271
+ # `carried` still decides bare-vs-wrapped the normal way ; `POSITION`
255
272
  # is the one case with no verb to ask `carried` about (`plan.
256
273
  # declare` is always nil for an entity-owned category — Plan#read's
257
274
  # own comment says why), so it is minted straight as a value object,
258
275
  # matching exactly what `declare`'s own field loop already mints a
259
- # POSITION field as.
276
+ # `POSITION` field as.
260
277
  def node_identity(plan, category, node, index, parent_id)
261
278
  plan.identity_paths.each_with_object({}) do |path, fields|
262
279
  head = path.to_s.split(".").first
@@ -271,9 +288,9 @@ module Hecks
271
288
  end
272
289
  end
273
290
 
274
- # THE FULL DOTTED PREFIX a category's own verbs hang off — the
291
+ # The full dotted prefix a category's own verbs hang off — the
275
292
  # plain name for an ordinary category (its own top-level
276
- # aggregate reaches every verb bare), or its PARENT's own prefix
293
+ # aggregate reaches every verb bare), or its parent's own prefix
277
294
  # with this category's name appended, for an entity-owned one.
278
295
  # Dispatch's own parent, Handler, is itself entity-owned (S17,
279
296
  # ADR 0026's two-level chain — `ProcessManager.Handler.Dispatch`),
@@ -284,9 +301,9 @@ module Hecks
284
301
  "#{dotted_prefix(@plan.category(plan.parent))}.#{plan.name}"
285
302
  end
286
303
 
287
- # ENTITY-OWNED categories have no top-level aggregate for the runtime
304
+ # Entity-owned categories have no top-level aggregate for the runtime
288
305
  # to route a bare verb into any more — `Member`'s own "Pair" reaches
289
- # the runtime as `ValueObject.Member.Pair`, and a NESTED one
306
+ # the runtime as `ValueObject.Member.Pair`, and a nested one
290
307
  # (`Dispatch`, inside `Handler`) reaches it as `ProcessManager.
291
308
  # Handler.Dispatch.Bind` — the dotted shape `EntityInterpreter#call`
292
309
  # already splits any real entity's own verb into, one hop per
@@ -312,12 +329,12 @@ module Hecks
312
329
  end
313
330
  end
314
331
 
315
- # A piece's commands and queries, addressed under the PIECE so two commands
332
+ # A piece's commands and queries, addressed under the piece so two commands
316
333
  # of the same name on an aggregate and on one of its entities cannot collide,
317
334
  # while `aggregate` still names the aggregate the reference resolves
318
335
  # against and `entity_id` says which piece declared it. `entity_id`
319
- # keeps its own `_id` — an EXPLICIT `as:` on `reference_to Entity`,
320
- # never touched by ADR 0025's rename (only the DEFAULT, un-aliased
336
+ # keeps its own `_id` — an explicit `as:` on `reference_to Entity`,
337
+ # never touched by ADR 0025's rename (only the default, un-aliased
321
338
  # mint dropped the suffix; `aggregate` did precisely because
322
339
  # `Command#reference_to Aggregate`/`Query#reference_to Aggregate`
323
340
  # carry no `as:` of their own).
@@ -333,26 +350,26 @@ module Hecks
333
350
  end
334
351
  end
335
352
 
336
- # AN ENTITY MAY NEST FURTHER ENTITIES — S17, ADR 0026's own words:
353
+ # An entity may nest further entities — S17, ADR 0026's own words:
337
354
  # "That is what `entity` is for, and `entity` is declared by the
338
355
  # language and used zero times in it." `Dispatch`, inside
339
- # `Handler`, is the first real use. The GENERIC "Entity" category
356
+ # `Handler`, is the first real use. The generic "Entity" category
340
357
  # cannot express this through `children_of`/`EAGER_CHILDREN` the
341
358
  # way Aggregate's own entities/value_objects can — there is only
342
- # ONE "Entity" Plan category, describing what ANY entity looks
359
+ # one "Entity" Plan category, describing what any entity looks
343
360
  # like, not one per nesting level — so this recurses by hand,
344
361
  # the same special case `within_entity` (above) already is for
345
362
  # Command/Query.
346
363
  #
347
364
  # `owner` is the field this repurposes — `entity.bluebook`
348
365
  # declares it (`attribute :owner, EntityText`) and it has held
349
- # exactly one value since ADR 0025's rename: the SAME id
350
- # `aggregate` already carries, kept as a wrapped-text COPY,
366
+ # exactly one value since ADR 0025's rename: the same id
367
+ # `aggregate` already carries, kept as a wrapped-text copy,
351
368
  # never read back anywhere else in this codebase (grep finds no
352
- # second reference). For a NESTED entity, the two finally
353
- # diverge — `aggregate` stays the ROOT (Dispatch resolves
369
+ # second reference). For a nested entity, the two finally
370
+ # diverge — `aggregate` stays the root (Dispatch resolves
354
371
  # exactly the way any other Entity record does, by its root
355
- # aggregate), and `owner` becomes THIS entity's own DIRECT
372
+ # aggregate), and `owner` becomes this entity's own direct
356
373
  # parent (Handler, not ProcessManager) — which is exactly the
357
374
  # fact `Reconstruction#direct_entities` needs to tell a
358
375
  # root-level entity apart from a nested one sharing the same
@@ -367,13 +384,14 @@ module Hecks
367
384
  })
368
385
  end
369
386
 
370
- # WHERE IT SITS AMONG ITS SIBLINGS IS A FACT ABOUT THE WALK, not about the
387
+ # Where it sits among its siblings is a fact about the walk, not about the
371
388
  # node : a command does not know it is the third command on its aggregate.
372
389
  # The walk knows, so the walk supplies it, and every other field still
373
- # comes from the node. Declaration order used to survive only because the
374
- # meta store happened to iterate in insertion order — an accident that an
375
- # ask ordered any other way would have taken away, and Reconstruction is
376
- # the one reader that must have the SOURCE'S order rather than a stable one.
390
+ # comes from the node. Without this, declaration order would survive only
391
+ # because the meta store happens to iterate in insertion order — an
392
+ # accident that an ask ordered any other way would take away, and
393
+ # Reconstruction is the one reader that must have the source's order
394
+ # rather than a stable one.
377
395
  # `private` above has no effect on a constant; kept here anyway,
378
396
  # beside the method that reads it, for the narrative.
379
397
  # rubocop:disable-next Lint/UselessConstantScoping
@@ -416,7 +434,7 @@ module Hecks
416
434
  plan.appends.each do |list_name, append|
417
435
  rows_for(category, list_name, node).each_with_index do |row, index|
418
436
  chosen = append_for(category, list_name, append, row, node)
419
- # `position` IS THE WALK INDEX here exactly as it is in `declare` —
437
+ # `position` is the walk index here exactly as it is in `declare` —
420
438
  # an appended element that names its position (ValueObject.Member,
421
439
  # S17) is ordered by where the walk found it, never by a field the
422
440
  # row happens to hold.
@@ -436,15 +454,15 @@ module Hecks
436
454
  end
437
455
  end
438
456
 
439
- # WHICH AGGREGATE OWNS THE VALUE OBJECTS an attribute's TYPE may
457
+ # Which aggregate owns the value objects an attribute's type may
440
458
  # resolve against. An aggregate owns its own — `id` already names
441
459
  # it. An entity never has value objects of its own (Entity
442
460
  # deliberately never answers `value_object` — see entity.rb's own
443
- # comment on why); its attributes read the SAME pool its
461
+ # comment on why); its attributes read the same pool its
444
462
  # enclosing aggregate declares, one level up the construct tree
445
463
  # no matter how many entities deep this attribute is nested —
446
464
  # `parent_id` names it because `detail_node`/`nest_entities`
447
- # thread the ROOT aggregate's id down as `parent_id` at every
465
+ # thread the root aggregate's id down as `parent_id` at every
448
466
  # entity level, never the direct (possibly entity) parent.
449
467
  def owning_aggregate_ref(category, id, parent_id)
450
468
  category == "Entity" ? parent_id : id
@@ -455,30 +473,30 @@ module Hecks
455
473
  plan.sealers.each { |verb| send_to("Bluebook::#{verb_for(plan, verb)}", id, to: address(receiver)) }
456
474
  end
457
475
 
458
- # An aggregate's or an entity's attribute names its value object by TYPE,
476
+ # An aggregate's or an entity's attribute names its value object by type,
459
477
  # and the language models that as a reference — so the type is offered as
460
478
  # the value object's own id. This is the rule "attributes must use
461
479
  # value-object types", enforced by reference resolution rather than by a
462
- # predicate — for a HEAD's own attributes, aggregate or entity alike: an
480
+ # predicate — for a head's own attributes, aggregate or entity alike: an
463
481
  # entity is its own root, repeating the aggregate's whole shape one level
464
482
  # down (entity.rb's own words), and an undeclared type on an entity's
465
483
  # attribute must fail the same reference resolution an aggregate's own
466
484
  # does, not go unchecked because only "Aggregate.attributes" was ever
467
485
  # asked.
468
- # An attribute's type is offered as the ID OF THE THING IT NAMES, so the
486
+ # An attribute's type is offered as the ID of the thing it names, so the
469
487
  # language resolves it as a reference and "the type is declared" costs no
470
488
  # predicate. Three kinds, three ids: a value object and an entity both hang
471
489
  # off this aggregate, so they share its prefix; another aggregate's head
472
490
  # hangs off the chapter.
473
491
  def cell(category, list_name, row, field, id, append, aggregate_id)
474
492
  value = row_value(row, field)
475
- # A default keeps its TYPE by being written as a literal — 0.0 rather than
493
+ # A default keeps its type by being written as a literal — 0.0 rather than
476
494
  # "0.0" — because the language holds it as text and text alone forgets.
477
495
  return encode_literal(value) if field == :default
478
496
  return value unless field == :type
479
- # A REFERENCE names another head WHEREVER it is written — on a head, on
497
+ # A reference names another head wherever it is written — on a head, on
480
498
  # a command, on a piece, on an ask — so it is offered as that head's
481
- # id in all four. Only a HEAD's own attributes additionally qualify
499
+ # id in all four. Only a head's own attributes additionally qualify
482
500
  # an ordinary type into a value object's id ; a command argument's
483
501
  # type is text and stays text.
484
502
  return points_at(row, id) if append.verb == "Reference"
@@ -487,7 +505,7 @@ module Hecks
487
505
  Naming.identity([owning_aggregate_id(aggregate_id, value), value])
488
506
  end
489
507
 
490
- # A HEAD'S OWN ATTRIBUTES — an aggregate's, or an entity's (its own root,
508
+ # A head's own attributes — an aggregate's, or an entity's (its own root,
491
509
  # one level down). Every other "attributes" list belongs to something that
492
510
  # is not a head at all (a command's arguments, a value object's own
493
511
  # fields), and a type written there is a name, not a reference — the same
@@ -496,27 +514,27 @@ module Hecks
496
514
  list_name.to_s == "attributes" && %w[Aggregate Entity].include?(category)
497
515
  end
498
516
 
499
- # `id` NAMES THE ATTRIBUTE'S OWN AGGREGATE, not necessarily the
517
+ # `id` names the attribute's own aggregate, not necessarily the
500
518
  # value object's — Wave 7's own translation.bluebook/translation_
501
519
  # aggregate.bluebook split proved the difference live:
502
520
  # TranslationAggregate's own `was`/every rename-rule's own `from`/
503
- # `to`/... all deliberately reuse the SIBLING "Translation"
521
+ # `to`/... all deliberately reuse the sibling "Translation"
504
522
  # aggregate's own `TranslationName` (that file's own header:
505
523
  # "the shared TranslationName every non-identity field below
506
524
  # uses"), a real, intentional cross-aggregate reuse — not the
507
- # local-only ownership every OTHER real domain in this corpus
525
+ # local-only ownership every other real domain in this corpus
508
526
  # happens to have used until now.
509
527
  #
510
528
  # `id` (already `Naming.identity([chapter, aggregate])`-joined)
511
- # only ever composes with the LOCAL aggregate for real, non-
529
+ # only ever composes with the local aggregate for real, non-
512
530
  # entity-owned attributes — an entity's own `id` never matches
513
- # any TOP-LEVEL aggregate here, so `local` stays nil and this
531
+ # any top-level aggregate here, so `local` stays nil and this
514
532
  # returns `id` unchanged, exactly the prior behavior. Same for
515
- # every attribute whose type IS locally declared (the overwhelming
533
+ # every attribute whose type is locally declared (the overwhelming
516
534
  # common case, Banking's own Customer/Account included) — this
517
- # only ever changes the answer when the local aggregate does NOT
535
+ # only ever changes the answer when the local aggregate does not
518
536
  # declare `value` itself, falling back to the first (declaration-
519
- # order) OTHER aggregate in the SAME chapter that does.
537
+ # order) other aggregate in the same chapter that does.
520
538
  def owning_aggregate_id(id, value)
521
539
  local = @bluebook.aggregates.find { |aggregate| Naming.identity([@bluebook.name, aggregate.name]) == id }
522
540
  return id unless local
@@ -549,13 +567,13 @@ module Hecks
549
567
  # Reference its type is Reference<X>, another aggregate's head
550
568
  # Holds its type names an entity this aggregate declares
551
569
  #
552
- # NOTHING IS SKIPPED any more. Reference and Holds did not exist, so the
570
+ # Nothing is skipped any more. Reference and Holds did not exist, so the
553
571
  # walk dropped both kinds and the meta-domain silently did not contain
554
572
  # Account#customer_id or Account#ledger.
555
- # Each alternate carries its OWN map, read from the language. Borrowing the
573
+ # Each alternate carries its own map, read from the language. Borrowing the
556
574
  # primary's map dispatched `type:` where Reference declares `points_at:`,
557
575
  # and the payload gate caught it — which is the gate paying for itself.
558
- # `reference_to` can be written in FOUR places — on a head, a command, a
576
+ # `reference_to` can be written in four places — on a head, a command, a
559
577
  # piece, an ask — and each keeps its own list of attributes, so each
560
578
  # needs the Reference alternate. Only a head can hold a piece, so Holds
561
579
  # stays where it was.
@@ -573,7 +591,7 @@ module Hecks
573
591
 
574
592
  def reference_row?(row) = row.respond_to?(:reference?) && row.reference?
575
593
 
576
- # Only a HEAD declares pieces, and now that every attribute list reaches
594
+ # Only a head declares pieces, and now that every attribute list reaches
577
595
  # this, the node may be a command, a piece or an ask — none of which
578
596
  # answer `entities` at all.
579
597
  def entity_row?(row, node)
@@ -582,7 +600,7 @@ module Hecks
582
600
  Array(node.entities).any? { |entity| entity.hecks_name == row.type.to_s }
583
601
  end
584
602
 
585
- # A RECORD'S ID IS ITS DECLARED IDENTITY, JOINED — the same join the runtime
603
+ # A record's ID is its declared identity, joined — the same join the runtime
586
604
  # does, off the same declaration, because there is only one way to name a
587
605
  # thing and it should be written once.
588
606
  #
@@ -602,14 +620,14 @@ module Hecks
602
620
  Naming.identity(plan.identity_paths.map { |path| identity_part(plan, path, parent_id, node, index, category) })
603
621
  end
604
622
 
605
- # "owner_id" is a SECOND reserved head, beside `position` : it names
606
- # whichever record is walking THIS one right now, aggregate or entity
623
+ # "owner_id" is a second reserved head, beside `position` : it names
624
+ # whichever record is walking this one right now, aggregate or entity
607
625
  # alike, without saying which — Command and Query read it so an
608
626
  # entity's verbs are the entity's own. It is never a declared
609
627
  # attribute (declaring one for a field that names two different types
610
628
  # would be a lie about which), so it cannot be read through
611
629
  # `field_value` ; it is read the same way `plan.parent_key` already is,
612
- # because it IS that fact, spelled for the walk's immediate parent
630
+ # because it is that fact, spelled for the walk's immediate parent
613
631
  # rather than for one specific kind of one.
614
632
  # `private` above has no effect on a constant; kept here anyway,
615
633
  # beside the method that reads it, for the narrative.
@@ -640,8 +658,8 @@ module Hecks
640
658
 
641
659
  # Command -> commands, ValueObject -> value_objects, Query -> queries.
642
660
  # Convention, not a table : the IR names a collection after what it holds.
643
- # The pluraliser lives in Naming because there used to be two of them and
644
- # one was wrong — see Naming.plural.
661
+ # The pluraliser lives in Naming, kept to exactly one implementation — a
662
+ # second one risks disagreeing with it — see Naming.plural.
645
663
  def collection_reader(category) = Naming.plural(Naming.snake(category))
646
664
  end
647
665
  end