hecks 1.3.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 (355) 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 +5 -4
  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/prism.rb +4 -4
  23. data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
  24. data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
  25. data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
  26. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
  27. data/lib/hecks/adapters/driven/sqlite.rb +181 -21
  28. data/lib/hecks/adapters/driven.rb +4 -4
  29. data/lib/hecks/adapters/driving/github_webhook.rb +18 -18
  30. data/lib/hecks/behaviors/dsl.rb +2 -2
  31. data/lib/hecks/behaviors/expectations.rb +23 -23
  32. data/lib/hecks/behaviors/ir.rb +1 -1
  33. data/lib/hecks/behaviors/rspec.rb +1 -1
  34. data/lib/hecks/behaviors/runner.rb +2 -2
  35. data/lib/hecks/behaviors.rb +1 -1
  36. data/lib/hecks/bluebook/aggregate.rb +13 -13
  37. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +10 -10
  38. data/lib/hecks/bluebook/assembly/build.rb +1 -1
  39. data/lib/hecks/bluebook/assembly/contract.rb +39 -16
  40. data/lib/hecks/bluebook/assembly/contracts.rb +40 -38
  41. data/lib/hecks/bluebook/assembly/marks.rb +18 -18
  42. data/lib/hecks/bluebook/assembly/specializer.rb +19 -21
  43. data/lib/hecks/bluebook/assembly.rb +9 -9
  44. data/lib/hecks/bluebook/attribute.rb +9 -9
  45. data/lib/hecks/bluebook/behaviour/aggregate.rb +11 -11
  46. data/lib/hecks/bluebook/behaviour/attribute.rb +5 -5
  47. data/lib/hecks/bluebook/behaviour/chapter.rb +23 -5
  48. data/lib/hecks/bluebook/behaviour/command.rb +23 -23
  49. data/lib/hecks/bluebook/behaviour/domain_port.rb +7 -7
  50. data/lib/hecks/bluebook/behaviour/entity.rb +8 -8
  51. data/lib/hecks/bluebook/behaviour/hexagon.rb +4 -4
  52. data/lib/hecks/bluebook/behaviour/lifecycle.rb +5 -5
  53. data/lib/hecks/bluebook/behaviour/policy.rb +12 -12
  54. data/lib/hecks/bluebook/behaviour/process_manager.rb +7 -7
  55. data/lib/hecks/bluebook/behaviour/query.rb +1 -1
  56. data/lib/hecks/bluebook/behaviour/read_model.rb +8 -8
  57. data/lib/hecks/bluebook/behaviour/traits.rb +12 -12
  58. data/lib/hecks/bluebook/behaviour/value_object.rb +6 -6
  59. data/lib/hecks/bluebook/capabilities.rb +27 -0
  60. data/lib/hecks/bluebook/chapter.rb +28 -9
  61. data/lib/hecks/bluebook/command.rb +12 -12
  62. data/lib/hecks/bluebook/domain_port.rb +9 -9
  63. data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
  64. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
  65. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +96 -96
  66. data/lib/hecks/bluebook/dsl/attribute_collector.rb +41 -41
  67. data/lib/hecks/bluebook/dsl/binding_proxy.rb +22 -2
  68. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +111 -74
  69. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +48 -30
  70. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
  71. data/lib/hecks/bluebook/dsl/command_builder.rb +103 -103
  72. data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
  73. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
  74. data/lib/hecks/bluebook/dsl/entity_builder.rb +56 -56
  75. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
  76. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +89 -30
  77. data/lib/hecks/bluebook/dsl/identity_declaration.rb +17 -17
  78. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
  79. data/lib/hecks/bluebook/dsl/policy_builder.rb +30 -21
  80. data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
  81. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
  82. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +35 -35
  83. data/lib/hecks/bluebook/dsl/query_builder.rb +5 -5
  84. data/lib/hecks/bluebook/dsl/read_model_builder.rb +34 -34
  85. data/lib/hecks/bluebook/dsl/rule_reference.rb +41 -39
  86. data/lib/hecks/bluebook/dsl/translation_builder.rb +9 -9
  87. data/lib/hecks/bluebook/dsl/value_object_builder.rb +16 -16
  88. data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
  89. data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
  90. data/lib/hecks/bluebook/entity.rb +11 -11
  91. data/lib/hecks/bluebook/expression/ast_json.rb +20 -20
  92. data/lib/hecks/bluebook/expression/ast_reader.rb +3 -3
  93. data/lib/hecks/bluebook/expression/canonical_form.rb +9 -9
  94. data/lib/hecks/bluebook/expression/evaluator.rb +18 -18
  95. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +18 -18
  96. data/lib/hecks/bluebook/expression/resolver.rb +60 -62
  97. data/lib/hecks/bluebook/hexagon.rb +1 -1
  98. data/lib/hecks/bluebook/lifecycle.rb +1 -1
  99. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -1
  100. data/lib/hecks/bluebook/meta_validator/judge.rb +101 -87
  101. data/lib/hecks/bluebook/meta_validator/plan.rb +39 -39
  102. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -2
  103. data/lib/hecks/bluebook/meta_validator/readings.rb +43 -43
  104. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +44 -37
  105. data/lib/hecks/bluebook/meta_validator/shapes.rb +25 -21
  106. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +145 -31
  107. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +6 -6
  108. data/lib/hecks/bluebook/meta_validator/world_judge.rb +5 -5
  109. data/lib/hecks/bluebook/meta_validator.rb +70 -70
  110. data/lib/hecks/bluebook/model_check.rb +170 -84
  111. data/lib/hecks/bluebook/pattern_subset.rb +9 -9
  112. data/lib/hecks/bluebook/policy.rb +15 -13
  113. data/lib/hecks/bluebook/process_manager.rb +14 -14
  114. data/lib/hecks/bluebook/project_register.rb +6 -6
  115. data/lib/hecks/bluebook/query.rb +4 -4
  116. data/lib/hecks/bluebook/read_model.rb +14 -14
  117. data/lib/hecks/bluebook/reference.rb +8 -8
  118. data/lib/hecks/bluebook/smoke_test.rb +19 -19
  119. data/lib/hecks/bluebook/synthesizer.rb +12 -12
  120. data/lib/hecks/bluebook/translation.rb +4 -4
  121. data/lib/hecks/bluebook/value_object.rb +6 -6
  122. data/lib/hecks/bluebook.rb +2 -2
  123. data/lib/hecks/codemod/legacy_dispatch_args.rb +299 -0
  124. data/lib/hecks/codemod/legacy_dispatch_recorder.rb +186 -0
  125. data/lib/hecks/codemod.rb +36 -35
  126. data/lib/hecks/construct.rb +6 -6
  127. data/lib/hecks/corpus.rb +317 -0
  128. data/lib/hecks/deprecation.rb +95 -0
  129. data/lib/hecks/doc/reference.rb +19 -19
  130. data/lib/hecks/embryonaut_bluebook.rb +11 -11
  131. data/lib/hecks/facade/cli_door.rb +69 -10
  132. data/lib/hecks/facade/cli_runner.rb +105 -24
  133. data/lib/hecks/facade/command_request.rb +23 -0
  134. data/lib/hecks/facade/handle.rb +79 -32
  135. data/lib/hecks/facade/json_door.rb +106 -25
  136. data/lib/hecks/facade/surface/aggregate_door.rb +42 -27
  137. data/lib/hecks/facade/surface/chapter.rb +26 -17
  138. data/lib/hecks/facade/surface.rb +16 -3
  139. data/lib/hecks/facade.rb +15 -4
  140. data/lib/hecks/forms/app.rb +46 -30
  141. data/lib/hecks/forms/command_form_renderer.rb +70 -9
  142. data/lib/hecks/forms/field_renderer.rb +142 -6
  143. data/lib/hecks/forms/field_shape.rb +180 -19
  144. data/lib/hecks/forms/html.rb +51 -7
  145. data/lib/hecks/forms/index_renderer.rb +14 -2
  146. data/lib/hecks/forms/params.rb +120 -23
  147. data/lib/hecks/forms/port_argument.rb +2 -2
  148. data/lib/hecks/forms/query_form_renderer.rb +2 -2
  149. data/lib/hecks/forms/record_renderer.rb +2 -2
  150. data/lib/hecks/forms/record_table.rb +1 -1
  151. data/lib/hecks/forms/value_object_shape.rb +3 -3
  152. data/lib/hecks/forms.rb +24 -4
  153. data/lib/hecks/fqn.rb +1 -1
  154. data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
  155. data/lib/hecks/framework.rb +48 -17
  156. data/lib/hecks/freezer.rb +11 -11
  157. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +90 -90
  158. data/lib/hecks/fuzzing/combination_miner.rb +119 -0
  159. data/lib/hecks/fuzzing/concurrent_dispatch.rb +140 -45
  160. data/lib/hecks/fuzzing/coverage_campaign.rb +118 -0
  161. data/lib/hecks/fuzzing/differential.rb +158 -0
  162. data/lib/hecks/fuzzing/domain_generator.rb +694 -0
  163. data/lib/hecks/fuzzing/era_boundary.rb +37 -18
  164. data/lib/hecks/fuzzing/form_census.rb +35 -20
  165. data/lib/hecks/fuzzing/generated_domain_check.rb +95 -0
  166. data/lib/hecks/fuzzing/invalid_value_generator.rb +6 -6
  167. data/lib/hecks/fuzzing/isolated_boot.rb +62 -62
  168. data/lib/hecks/fuzzing/nondeterministic.rb +67 -0
  169. data/lib/hecks/fuzzing/persistence_parity.rb +19 -21
  170. data/lib/hecks/fuzzing/properties/corrections.rb +9 -9
  171. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +154 -49
  172. data/lib/hecks/fuzzing/properties/guards.rb +42 -42
  173. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +32 -32
  174. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +22 -35
  175. data/lib/hecks/fuzzing/properties/outbox.rb +24 -24
  176. data/lib/hecks/fuzzing/properties/querying.rb +17 -17
  177. data/lib/hecks/fuzzing/properties.rb +64 -40
  178. data/lib/hecks/fuzzing/qa_settings.rb +152 -0
  179. data/lib/hecks/fuzzing/replay.rb +114 -114
  180. data/lib/hecks/fuzzing/rotation_priority.rb +10 -10
  181. data/lib/hecks/fuzzing/rust_gap_manifest.rb +113 -0
  182. data/lib/hecks/fuzzing/self_consistency.rb +141 -112
  183. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +35 -35
  184. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +18 -11
  185. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +13 -12
  186. data/lib/hecks/fuzzing/sequence_generator/picker.rb +21 -12
  187. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +58 -31
  188. data/lib/hecks/fuzzing/sequence_generator.rb +111 -23
  189. data/lib/hecks/fuzzing/shrinker.rb +197 -0
  190. data/lib/hecks/fuzzing/structural_skips.rb +23 -130
  191. data/lib/hecks/fuzzing/sweep_depth.rb +4 -4
  192. data/lib/hecks/fuzzing/target_capabilities.rb +49 -18
  193. data/lib/hecks/fuzzing/value_generator.rb +14 -14
  194. data/lib/hecks/fuzzing.rb +5 -0
  195. data/lib/hecks/grammar/evolve.rb +10 -10
  196. data/lib/hecks/grammar.rb +7 -7
  197. data/lib/hecks/ir.rb +13 -13
  198. data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
  199. data/lib/hecks/language/bluebook/policy.bluebook +11 -1
  200. data/lib/hecks/language/bluebook/vocabulary.bluebook +348 -13
  201. data/lib/hecks/language/oidc.json +5 -0
  202. data/lib/hecks/literal.rb +9 -9
  203. data/lib/hecks/naming.rb +25 -25
  204. data/lib/hecks/ports/access_control.rb +58 -2
  205. data/lib/hecks/ports/agent/answers.rb +83 -6
  206. data/lib/hecks/ports/agent.rb +119 -35
  207. data/lib/hecks/ports/authentication.rb +44 -4
  208. data/lib/hecks/ports/authorization.rb +53 -11
  209. data/lib/hecks/ports/clock.rb +42 -23
  210. data/lib/hecks/ports/extraction.rb +16 -0
  211. data/lib/hecks/ports/identity_assignment.rb +24 -2
  212. data/lib/hecks/ports/identity_generation.rb +17 -3
  213. data/lib/hecks/ports/identity_resolution.rb +18 -1
  214. data/lib/hecks/ports/loading.rb +4 -0
  215. data/lib/hecks/ports/persistence/append_only.rb +172 -8
  216. data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
  217. data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
  218. data/lib/hecks/ports/persistence/execution.rb +4 -0
  219. data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
  220. data/lib/hecks/ports/persistence/plugin.rb +42 -4
  221. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
  222. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
  223. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
  224. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
  225. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
  226. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
  227. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
  228. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
  229. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
  230. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +118 -66
  231. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
  232. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +28 -5
  233. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
  234. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
  235. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
  236. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +33 -9
  237. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
  238. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +57 -4
  239. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +314 -90
  241. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
  242. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
  243. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
  244. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +42 -8
  245. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
  246. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
  247. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
  248. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -19
  249. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +5 -5
  250. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +1 -1
  251. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
  252. data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
  253. data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
  254. data/lib/hecks/ports/persistence/repository_factory.rb +23 -3
  255. data/lib/hecks/ports/persistence/state_codec.rb +319 -0
  256. data/lib/hecks/ports/persistence.rb +36 -1
  257. data/lib/hecks/ports/projection.rb +61 -7
  258. data/lib/hecks/ports/query/in_memory.rb +3 -3
  259. data/lib/hecks/ports/query/ordering.rb +6 -6
  260. data/lib/hecks/ports/query.rb +35 -0
  261. data/lib/hecks/projections/bootstrap_table.rb +112 -0
  262. data/lib/hecks/projections/diagrams.rb +75 -75
  263. data/lib/hecks/projections/glossary/html.rb +3 -3
  264. data/lib/hecks/projections/glossary/markdown.rb +3 -3
  265. data/lib/hecks/projections/glossary/mermaid.rb +1 -1
  266. data/lib/hecks/projections/glossary/sections.rb +1 -1
  267. data/lib/hecks/projections/glossary/sentences.rb +5 -5
  268. data/lib/hecks/projections/glossary.rb +15 -15
  269. data/lib/hecks/projections/ir.rb +1 -1
  270. data/lib/hecks/projections/model/deviations.rb +18 -17
  271. data/lib/hecks/projections/model.rb +25 -21
  272. data/lib/hecks/projections/oidc.rb +7 -7
  273. data/lib/hecks/projections/parser_table.rb +5 -5
  274. data/lib/hecks/projections/reference.rb +3 -3
  275. data/lib/hecks/projections/rust_vocabulary.rb +443 -0
  276. data/lib/hecks/projections/shape.rb +2 -2
  277. data/lib/hecks/projections/statements.rb +11 -11
  278. data/lib/hecks/projections/vocabulary.rb +9 -9
  279. data/lib/hecks/projections.rb +5 -3
  280. data/lib/hecks/projector/cli_projector.rb +29 -29
  281. data/lib/hecks/projector/docs_projector.rb +13 -13
  282. data/lib/hecks/projector/exporter.rb +42 -21
  283. data/lib/hecks/projector/ir_projector.rb +1 -1
  284. data/lib/hecks/projector/narrate_projector.rb +11 -11
  285. data/lib/hecks/projector/target.rb +13 -13
  286. data/lib/hecks/projector.rb +15 -15
  287. data/lib/hecks/query_ir.rb +47 -47
  288. data/lib/hecks/query_specification/common/comparators.rb +19 -3
  289. data/lib/hecks/query_specification/common/comparison.rb +109 -27
  290. data/lib/hecks/query_specification/common/dsl.rb +65 -9
  291. data/lib/hecks/query_specification/common/null_policy.rb +57 -13
  292. data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
  293. data/lib/hecks/query_specification/common/options.rb +25 -0
  294. data/lib/hecks/query_specification/field_path.rb +69 -15
  295. data/lib/hecks/query_specification/hop_path.rb +57 -20
  296. data/lib/hecks/query_specification/read_model/specification.rb +4 -0
  297. data/lib/hecks/rendering.rb +3 -3
  298. data/lib/hecks/router/namespace_installer.rb +3 -3
  299. data/lib/hecks/router.rb +1 -1
  300. data/lib/hecks/runtime/aggregate_lock.rb +11 -11
  301. data/lib/hecks/runtime/boot_gates.rb +3 -3
  302. data/lib/hecks/runtime/caller.rb +8 -8
  303. data/lib/hecks/runtime/capability_graph.rb +2 -2
  304. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +22 -25
  305. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +42 -63
  306. data/lib/hecks/runtime/command_interpreter.rb +159 -102
  307. data/lib/hecks/runtime/command_rules/admissibility.rb +69 -69
  308. data/lib/hecks/runtime/command_rules/arithmetic.rb +137 -91
  309. data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
  310. data/lib/hecks/runtime/command_rules/emission.rb +18 -1
  311. data/lib/hecks/runtime/command_rules/references.rb +35 -35
  312. data/lib/hecks/runtime/command_rules.rb +3 -0
  313. data/lib/hecks/runtime/dependency_planning.rb +11 -11
  314. data/lib/hecks/runtime/dispatcher.rb +283 -90
  315. data/lib/hecks/runtime/entity_element.rb +151 -67
  316. data/lib/hecks/runtime/entity_interpreter.rb +108 -82
  317. data/lib/hecks/runtime/errors.rb +19 -19
  318. data/lib/hecks/runtime/event.rb +6 -6
  319. data/lib/hecks/runtime/identity.rb +22 -22
  320. data/lib/hecks/runtime/instance.rb +39 -14
  321. data/lib/hecks/runtime/interpreting.rb +12 -12
  322. data/lib/hecks/runtime/invocation.rb +276 -0
  323. data/lib/hecks/runtime/loader.rb +14 -14
  324. data/lib/hecks/runtime/outbox.rb +23 -23
  325. data/lib/hecks/runtime/policy_interpreter.rb +54 -54
  326. data/lib/hecks/runtime/port_operation_interpreter.rb +22 -19
  327. data/lib/hecks/runtime/query_interpreter.rb +55 -64
  328. data/lib/hecks/runtime/reaction_invocation.rb +20 -20
  329. data/lib/hecks/runtime/read_model_interpreter.rb +40 -40
  330. data/lib/hecks/runtime/rebuild_sweep.rb +4 -4
  331. data/lib/hecks/runtime/reference_hop.rb +6 -6
  332. data/lib/hecks/runtime/refusal_wording.rb +92 -115
  333. data/lib/hecks/runtime/registry/saga_persistence.rb +21 -21
  334. data/lib/hecks/runtime/registry/verification.rb +36 -26
  335. data/lib/hecks/runtime/registry.rb +45 -28
  336. data/lib/hecks/runtime/remote_dispatcher.rb +38 -23
  337. data/lib/hecks/runtime/routing.rb +10 -153
  338. data/lib/hecks/runtime/saga_interpreter/correlation.rb +17 -17
  339. data/lib/hecks/runtime/saga_interpreter.rb +64 -64
  340. data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
  341. data/lib/hecks/runtime/tenant_check.rb +9 -9
  342. data/lib/hecks/runtime/tenant_scope.rb +5 -5
  343. data/lib/hecks/runtime/value/admission.rb +75 -30
  344. data/lib/hecks/runtime/value/coercion.rb +318 -127
  345. data/lib/hecks/runtime/value/entity_list_coercion.rb +34 -34
  346. data/lib/hecks/runtime/value.rb +21 -21
  347. data/lib/hecks/runtime.rb +7 -7
  348. data/lib/hecks/storehouse.rb +64 -64
  349. data/lib/hecks/version.rb +3 -3
  350. data/lib/hecks/vocabulary.rb +205 -4
  351. data/lib/hecks.rb +13 -11
  352. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +11 -11
  353. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +14 -12
  354. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +11 -11
  355. metadata +22 -2
@@ -1,32 +1,32 @@
1
1
  module Hecks
2
2
  module Bluebook
3
3
  module MetaValidator
4
- # A bluebook rebuilt FROM the meta-domain, in the shape the builder produces.
4
+ # A bluebook rebuilt from the meta-domain, in the shape the builder produces.
5
5
  #
6
6
  # This is the second half of the claim at the top of bluebook.bluebook —
7
7
  # "loading a domain becomes dispatching commands into this meta-domain ; the
8
8
  # IR it stores must equal the IR the DSL builder produces". The judge is the
9
9
  # first half. This reads the records back and assembles `to_h`.
10
10
  #
11
- # It is the INVERSE OF THE WALK and shares its plan: the walk reads a node's
11
+ # It is the inverse of the walk and shares its plan: the walk reads a node's
12
12
  # lists through the command that appends to each, and this reads them back out
13
13
  # of the rows those commands wrote. The retired `experiment/replay.rb` needed
14
14
  # 420 hand-written lines because the dispatch half was hand-written too; there
15
15
  # is nothing to hand-write when both directions are one table.
16
16
  #
17
- # This file is the TRAVERSAL. The hashes at its tips, and the encodings they
17
+ # This file is the traversal. The hashes at its tips, and the encodings they
18
18
  # undo, are in Shapes.
19
19
  #
20
- # IT READS LEVEL BY LEVEL, THROUGH `DeclaredIn`, AND NOT THROUGH THE READ
21
- # MODEL — which is the difference between a reconstruction that can be the
22
- # SOURCE and one that can only be a check.
20
+ # It reads level by level, through `DeclaredIn`, and not through the read
21
+ # model — which is the difference between a reconstruction that can be the
22
+ # source and one that can only be a check.
23
23
  #
24
24
  # `Meta.whole_bluebook` gathers a chapter in a single read, and it sorts:
25
25
  # `ReadModelInterpreter#matching` ends `.sort_by(&:id)` deliberately, because
26
26
  # a store's iteration order is an accident, and a read model returning store
27
27
  # order would let that accident leak into an answer.
28
28
  # Right for a read model, fatal here — the order a bluebook declares its
29
- # commands in is a FACT ABOUT THE SOURCE, and the IR is a contract field for
29
+ # commands in is a fact about the source, and the IR is a contract field for
30
30
  # field and index for index ; the export carries that order verbatim.
31
31
  # `DeclaredIn` preserves it (spec/executes_spec says so), so this asks each
32
32
  # level for its own children rather than filtering one sorted gather.
@@ -35,7 +35,7 @@ module Hecks
35
35
  # Plan the walk dispatches from — so the two directions really are one table,
36
36
  # which is what the header above has always claimed.
37
37
  #
38
- # WHAT IT CANNOT REBUILD matters as much as what it can, and
38
+ # What it cannot rebuild matters as much as what it can, and
39
39
  # spec/round_trip_spec pins the difference as an exact set: a field the language
40
40
  # does not hold appears there as a named gap, and a field it stops holding
41
41
  # appears as a failure.
@@ -60,6 +60,7 @@ module Hecks
60
60
  classification: text(@chapter[:classification]),
61
61
  formerly_known_as: text(@chapter[:formerly_known_as]),
62
62
  attaches_to: attached_contexts(@chapter),
63
+ provides: provisions(@chapter),
63
64
  aggregates: declared("Aggregate", chapter_id).map { |row| aggregate(row) },
64
65
  read_models: declared("ReadModel", chapter_id).map { |row| read_model(row) },
65
66
  policies: declared("Policy", chapter_id).map { |row| policy(row) },
@@ -71,14 +72,14 @@ module Hecks
71
72
 
72
73
  def chapter_id = @chapter[:id].to_s
73
74
 
74
- # Everything DECLARED IN one parent, in the order it was declared. The key
75
+ # Everything declared in one parent, in the order it was declared. The key
75
76
  # is the one the language's own creating command carries, read from Plan.
76
77
  def declared(category, parent_id)
77
78
  key = @plan.category(category).parent_key
78
79
  @runtime.query("Bluebook::#{category}.DeclaredIn", key.to_sym => { value: parent_id.to_s })
79
80
  end
80
81
 
81
- # ONE DECLARATION, BUILT FROM THE CONTRACT.
82
+ # One declaration, built from the contract.
82
83
  #
83
84
  # There were eleven methods here, one per category, each spelling out the same
84
85
  # keys `Assembly::Contracts` already names — which is the shape the judge used
@@ -126,14 +127,20 @@ module Hecks
126
127
 
127
128
  def pairs(with) = Array(with).map { |binding| [text(binding[:key]), text(binding[:value])] }
128
129
 
129
- # THE PARTS, IN THE ORDER THEY WENT IN, because the identity is their join
130
+ # The parts, in the order they went in, because the identity is their join
130
131
  # and a join read out of order names a different record.
131
132
  def identity_paths(row) = Array(row[:identified_by]).map { |part| text(part[:value]).to_s }
132
133
 
133
- # THE CONTEXTS ONE CHAPTER NAMES ITSELF ONTO, in the order they were
134
+ # The contexts one chapter names itself onto, in the order they were
134
135
  # attached — same shape identity_paths reads back, one level up.
135
136
  def attached_contexts(row) = Array(row[:attaches_to]).map { |part| text(part[:value]).to_s }
136
137
 
138
+ def provisions(row)
139
+ Array(row[:provides]).map do |part|
140
+ { capability: text(part[:capability]).to_s, key: text(part[:key]).to_s, verb: text(part[:verb]).to_s }
141
+ end
142
+ end
143
+
137
144
  # Every cell of the meta-domain is a single-field value object, so a row
138
145
  # arrives holding Values rather than Strings.
139
146
  def text(cell)
@@ -143,19 +150,19 @@ module Hecks
143
150
  cell
144
151
  end
145
152
 
146
- # An aggregate's OWN verbs and asks — the ones no entity declared. Both carry
153
+ # An aggregate's own verbs and asks — the ones no entity declared. Both carry
147
154
  # the parent link either way, because that is the head the reference resolves
148
155
  # against, so the entity ones have to be told apart by `entity_id`. Rejecting
149
- # from an ORDERED read keeps the order.
156
+ # from an ordered read keeps the order.
150
157
  def own(category, aggregate_id)
151
158
  declared(category, aggregate_id).select { |row| text(row[:entity_id]).to_s == "" }
152
159
  end
153
160
 
154
161
  # A piece's own verbs and asks. There is no `DeclaredIn` keyed by entity, so
155
162
  # this reads the aggregate's — in declaration order — and keeps the ones that
156
- # name this piece. `row[:aggregate]` — an ENTITY row's own `reference_to
163
+ # name this piece. `row[:aggregate]` — an entity row's own `reference_to
157
164
  # Aggregate` (bare, no `_id` since ADR 0025) — not `entity_id`, which
158
- # STAYS suffixed below : that one is Command/Query's own EXPLICIT `as:`,
165
+ # stays suffixed below : that one is Command/Query's own explicit `as:`,
159
166
  # never touched by the rename.
160
167
  def within(category, row)
161
168
  declared(category, text(row[:aggregate]))
@@ -172,7 +179,7 @@ module Hecks
172
179
  attributes: Array(row[:attributes]).map { |field| attribute(field, id) },
173
180
  value_objects: declared("ValueObject", id).map { |shape| value_object(shape) },
174
181
  commands: own("Command", id).map { |verb| command(verb) },
175
- # THE AGGREGATE BOUNDARY, and the precondition a command may
182
+ # The aggregate boundary, and the precondition a command may
176
183
  # reference by name (S10, ADR 0025 — "Rules") — the same
177
184
  # `rule` reader `command`'s own givens/ensures already use
178
185
  # (Assembly::Contracts' generic `declaration()` path), read
@@ -195,19 +202,19 @@ module Hecks
195
202
  def closed_set_of(row) = !text(row[:rows]).nil?
196
203
 
197
204
  # A closed set's admitted rows. S17, ADR 0026 — Member is a genuine
198
- # ENTITY now (`entity "Member" do ... end`, nested under
205
+ # entity now (`entity "Member" do ... end`, nested under
199
206
  # ValueObject), created by `ValueObject.Member` (an ordinary append,
200
207
  # the same way `Account.LogEntry` creates a LedgerEntry) and mutated
201
208
  # by its own dotted `ValueObject.Member.Pair`. Its data therefore
202
- # lives INLINE on the value object's own dispatched state — same as
209
+ # lives inline on the value object's own dispatched state — same as
203
210
  # any other entity list — not behind a separate `DeclaredIn` query:
204
211
  # there is no such query any more, because there is no top-level
205
- # "Member" aggregate left to hold one. Pairs are still an OPEN MAP,
212
+ # "Member" aggregate left to hold one. Pairs are still an open map,
206
213
  # which no value object can hold, so they still come back one pair
207
214
  # at a time.
208
215
  def members_row(row) = members_of(row)
209
216
 
210
- # THE KEY IS STRINGIFIED, NEVER THE VALUE — the same split
217
+ # The key is stringified, never the value — the same split
211
218
  # `Bluebook::ValueObject#to_h`'s own `members:` emission makes
212
219
  # (lib/hecks/bluebook/value_object.rb, L7 docs/audits/
213
220
  # 2026-08-11-bug-triage.md). `Pair.value` is declared `String`
@@ -219,7 +226,7 @@ module Hecks
219
226
  # on the side spec/round_trip_spec.rb compares straight against a
220
227
  # fresh raw load (`Reconstruction.of` directly, no Assembly in
221
228
  # between): `declared 84, read back "84"` the moment `to_h` stopped
222
- # erasing it on the OTHER side and this one kept erasing it alone.
229
+ # erasing it on the other side and this one kept erasing it alone.
223
230
  def members_of(value_object_row)
224
231
  Array(value_object_row[:members]).map do |member|
225
232
  Array(member[:pairs]).map { |pair| [text(pair[:key]).to_s, text(pair[:value])] }
@@ -230,15 +237,15 @@ module Hecks
230
237
 
231
238
  def query(row) = declaration("Query", row).merge(options_of(row))
232
239
 
233
- # EVERY DIRECT ENTITY OF ONE OWNER — S17, ADR 0026. `declared
234
- # ("Entity", root_id)` returns EVERY entity sharing the same
235
- # ROOT aggregate, nested or not (Dispatch and Handler both carry
240
+ # Every direct entity of one owner — S17, ADR 0026. `declared
241
+ # ("Entity", root_id)` returns every entity sharing the same
242
+ # root aggregate, nested or not (Dispatch and Handler both carry
236
243
  # `aggregate: process_manager_id`) — `owner` is the field that
237
244
  # actually tells them apart : `Judge#nest_entities`'s own
238
245
  # comment explains why it is the one to repurpose. Called with
239
246
  # `owner_id == root_id` for an aggregate's own direct entities
240
247
  # (Handler), and with `owner_id == some entity's own id` for
241
- # THAT entity's own nested ones (Dispatch, owned by Handler).
248
+ # that entity's own nested ones (Dispatch, owned by Handler).
242
249
  def direct_entities(root_id, owner_id)
243
250
  declared("Entity", root_id).select { |held| text(held[:owner]).to_s == owner_id.to_s }
244
251
  end
@@ -251,25 +258,25 @@ module Hecks
251
258
  # Symbol there — the IR was not uniform about it, and only a round trip
252
259
  # ever said so.
253
260
  identified_by: identity_paths(row),
254
- # `text(row[:aggregate])` — the OWNING aggregate, the same one
261
+ # `text(row[:aggregate])` — the owning aggregate, the same one
255
262
  # `Judge#owning_aggregate_ref` resolved this piece's own
256
263
  # attribute types against on the way in, so reconstruction reads
257
264
  # a value-object-typed attribute back the identical way an
258
265
  # aggregate's own is (`Shapes#shape_field`'s own comment).
259
266
  attributes: Array(row[:attributes]).map { |field| shape_field(field, text(row[:aggregate])) },
260
- # ADR 0028 — the SAME shape `aggregate(row)`'s own
267
+ # ADR 0028 — the same shape `aggregate(row)`'s own
261
268
  # `preconditions:` reads two hand-typed methods up, read by
262
269
  # hand for the identical reason: `entity(row)` is hand-typed
263
270
  # too, unlike `command`/`value_object`/`query`.
264
271
  preconditions: Array(row[:preconditions]).map { |held| rule(held) },
265
- # Round 7 — the SAME shape `aggregate(row)`'s own
272
+ # Round 7 — the same shape `aggregate(row)`'s own
266
273
  # `invariants:` reads, one level down: a piece's own shape
267
274
  # rule, checked against every instance of this piece.
268
275
  invariants: Array(row[:invariants]).map { |held| rule(held) },
269
276
  commands: within("Command", row).map { |verb| command(verb) },
270
277
  queries: within("Query", row).map { |ask| query(ask) },
271
278
  # S17, ADR 0026 — Dispatch, inside Handler : an entity's own
272
- # NESTED entities, found the same way its own direct ones
279
+ # nested entities, found the same way its own direct ones
273
280
  # were one level up.
274
281
  entities: direct_entities(text(row[:aggregate]), row[:id]).map { |piece| entity(piece) },
275
282
  # An entity has its own state machine, and the language has held it all
@@ -301,7 +308,7 @@ module Hecks
301
308
  # ordinary append, the same way `Account.LogEntry` creates a
302
309
  # LedgerEntry) and mutated by its own dotted `ProcessManager.
303
310
  # Handler.Dispatch`/`...Dispatch.Bind`. Its data therefore lives
304
- # INLINE on the process manager's own dispatched state — same as
311
+ # inline on the process manager's own dispatched state — same as
305
312
  # any other entity list — not behind a separate `DeclaredIn`
306
313
  # query : there is no such query any more, the same fix
307
314
  # `Reconstruction#members_of` already made for Member.
@@ -311,25 +318,25 @@ module Hecks
311
318
  end
312
319
 
313
320
  # S17, ADR 0026 — Dispatch, one level further in : nested under
314
- # Handler, its data lives inline on the HANDLER row this method
315
- # was just handed (`row` here IS one element of `handlers`,
321
+ # Handler, its data lives inline on the handler row this method
322
+ # was just handed (`row` here is one element of `handlers`,
316
323
  # above), not behind any query either.
317
324
  def handler(row)
318
325
  declaration("Handler", row,
319
326
  dispatches: Array(row[:dispatches]).map { |leg| dispatch(leg) })
320
327
  end
321
328
 
322
- # `compensates` — TWO FLAT FIELDS on this same row
329
+ # `compensates` — two flat fields on this same row
323
330
  # (`process_manager.bluebook`'s own comment on `Dispatch` for
324
- # why), assembled BY HAND into the shape its own field actually
331
+ # why), assembled by hand into the shape its own field actually
325
332
  # is — `declaration()`'s generic per-field hash-build has no
326
333
  # way to turn two cells into a second object, so this reads
327
334
  # them directly and passes the result through `extra:`, the
328
335
  # same seam `handler`/`process_manager` already use for a
329
336
  # `:children` shape a flat Contract cannot describe.
330
337
  # `compensates_command_name` absent means no compensation at
331
- # all — a plain dispatch with nothing to undo. A PLAIN HASH, the
332
- # SAME declaration shape `to_h` spells for everything else in
338
+ # all — a plain dispatch with nothing to undo. A plain hash, the
339
+ # same declaration shape `to_h` spells for everything else in
333
340
  # this file (this file's own top comment) — never a real
334
341
  # `DispatchSpec` here; `Assembly#dispatch` is the one place a
335
342
  # declaration hash becomes the real object, and building it
@@ -27,8 +27,8 @@ module Hecks
27
27
  # bluebook that no longer says what it said.
28
28
  optional: text(field[:optional]).to_s == "true",
29
29
  pattern: presence(text(field[:pattern])),
30
- # THE ROUND TRIP IS THE ONLY WAY IN. The grammar registry keeps the
31
- # ASSEMBLED graph — the language as its own judge read it back — so a
30
+ # The round trip is the only way in. The grammar registry keeps the
31
+ # assembled graph — the language as its own judge read it back — so a
32
32
  # fact dropped here is a fact no downstream projection ever sees, no
33
33
  # matter how plainly the .bluebook file declares it.
34
34
  admits: presence(text(field[:admits])),
@@ -36,8 +36,8 @@ module Hecks
36
36
  }
37
37
  end
38
38
 
39
- # A TYPE THIS AGGREGATE OWNS, offered as its id and read back as its name.
40
- # Prefixed with the owner and the identity join, because that IS the value
39
+ # A type this aggregate owns, offered as its id and read back as its name.
40
+ # Prefixed with the owner and the identity join, because that is the value
41
41
  # object's identity — the aggregate it belongs to, then its name.
42
42
  def owned_type(type, aggregate_id)
43
43
  prefix = Naming.identity([aggregate_id, ""])
@@ -46,7 +46,7 @@ module Hecks
46
46
  type.delete_prefix(prefix)
47
47
  end
48
48
 
49
- # ONE PART OF AN IDENTITY, read back as the path it went in as. The inverse
49
+ # One part of an identity, read back as the path it went in as. The inverse
50
50
  # of `Marks#identity_path`, and named the same so the two directions read
51
51
  # as one table.
52
52
  def identity_path(part) = text(part[:value]).to_s
@@ -54,7 +54,7 @@ module Hecks
54
54
  # An argument, a parameter, a piece's attribute — the three places an
55
55
  # attribute is written that carry no owner id to strip... except a
56
56
  # piece's own attribute now does : an entity is its own root (repeating
57
- # the aggregate's whole shape one level down), so ITS attributes name a
57
+ # the aggregate's whole shape one level down), so its attributes name a
58
58
  # value object exactly the way an aggregate's own do (`Judge#cell`'s own
59
59
  # comment), and reconstruction has to undo the same owned-vs-reference
60
60
  # split `attribute`, below, already undoes for an aggregate — not the
@@ -66,11 +66,11 @@ module Hecks
66
66
  # argument or a parameter carries no value-object type at all — see
67
67
  # entity.bluebook's/command.bluebook's own comments on why — so the
68
68
  # generic reader path calls this with one argument and gets the
69
- # OLD reading unchanged), is the piece's OWNING aggregate — the same
69
+ # old reading unchanged), is the piece's owning aggregate — the same
70
70
  # one its own attribute types were resolved against on the way in
71
71
  # (`Judge#owning_aggregate_ref`).
72
72
  #
73
- # A REFERENCE among the other two came in as the head's ID, because
73
+ # A reference among the other two came in as the head's ID, because
74
74
  # that is what Command/Query.Reference offer, so it goes back out as
75
75
  # the encoding the IR spells. A qualified name is the tell : an
76
76
  # ordinary type names something declared beside it (`Money`,
@@ -83,7 +83,7 @@ module Hecks
83
83
 
84
84
  {
85
85
  name: text(field[:name])&.to_sym,
86
- # A QUALIFIED name is the tell : an ordinary type names something
86
+ # A qualified name is the tell : an ordinary type names something
87
87
  # declared beside it (`Money`, `AccountNumber`) and carries no join at
88
88
  # all, where a head's id always does (chapter + name, joined the way
89
89
  # every derived id is).
@@ -97,7 +97,7 @@ module Hecks
97
97
  }
98
98
  end
99
99
 
100
- # An ABSENT pattern is nil, not "". The language holds every field as
100
+ # An absent pattern is nil, not "". The language holds every field as
101
101
  # text, so a field nobody set comes back as the empty string — and ""
102
102
  # is a real regex (it matches everything), so keeping it would turn
103
103
  # "no pattern" into "a pattern that always passes" and quietly cost the
@@ -130,13 +130,17 @@ module Hecks
130
130
  # `default:`.
131
131
  def provenance(row) = decode_literal(text(row[:provenance]))
132
132
 
133
- # `command "Debit", from: "open"` — the SAME literal encoding
133
+ # `command "Debit", from: "open"` — the same literal encoding
134
134
  # `provenance`/`default:` already ride (S10, ADR 0025), one
135
135
  # state or an array of them, or nil for a command with no
136
136
  # lifecycle guard.
137
137
  def from(row) = decode_literal(text(row[:from]))
138
138
 
139
- # THE OPTION ROWS, GATHERED BACK into the shapes `extra_options_to_h` spells.
139
+ # A flag is held as text ("true"/"false") and emitted as a boolean —
140
+ # `Policy#expect_undelivered` on the wire.
141
+ def expect_undelivered?(row) = text(row[:expect_undelivered]).to_s == "true"
142
+
143
+ # The option rows, gathered back into the shapes `extra_options_to_h` spells.
140
144
  #
141
145
  # One row per part, so a compound option is several rows and a repeated one is
142
146
  # several groups told apart by `at`. Grouping by option name and then by `at`
@@ -157,8 +161,8 @@ module Hecks
157
161
  .map { |group| group.to_h { |part| [text(part[:key]).to_sym, text(part[:value])] } }
158
162
  end
159
163
 
160
- # The IR keeps a where's field as a STRING, not a symbol — it is read back
161
- # out, never called. The value stays RAW TEXT here on purpose : this
164
+ # The IR keeps a where's field as a string, not a symbol — it is read back
165
+ # out, never called. The value stays raw text here on purpose : this
162
166
  # feeds the declaration hash Assembly::Marks#where_clause decodes
163
167
  # from (via `read`), and decoding twice is worse than once — a
164
168
  # kwarg reference (":ceiling") decoded here into the Symbol :ceiling
@@ -205,22 +209,22 @@ module Hecks
205
209
 
206
210
  def group_by_field(row) = { field: text(row[:field]) }
207
211
 
208
- # `count`'s own boolean, read back the SAME way `head`'s own
212
+ # `count`'s own boolean, read back the same way `head`'s own
209
213
  # `many` is (`text(row[:many]).to_s == "true"`) — except a
210
- # `ReadModel.Count` command is dispatched AT ALL only when
214
+ # `ReadModel.Count` command is dispatched at all only when
211
215
  # `@count` was truthy (`MetaValidator::Judge#setters` skips a
212
216
  # setter whose every source is absent), so an undeclared read
213
217
  # model's own `count` field never gets written and comes back
214
218
  # `nil` here, never `"false"` — matching `ReadModel#to_h`'s own
215
219
  # `true`/`nil` pair (never `false`) exactly, rather than the
216
220
  # unconditional `true`/`false` `head`'s own `many` needs (every
217
- # head DOES get a `Gather` dispatch, declared or derived).
221
+ # head does get a `Gather` dispatch, declared or derived).
218
222
  def read_model_count(row) = (true if text(row[:count]).to_s == "true")
219
223
 
220
- # THE APPEND FLATTENING, IN REVERSE.
224
+ # The append flattening, in reverse.
221
225
  #
222
226
  # An append binds several fields at once and the language's Change holds one
223
- # field/kind/source triple, so the walk offers an append once PER BINDING.
227
+ # field/kind/source triple, so the walk offers an append once per binding.
224
228
  # Rebuilding groups those rows back into the single mutation the IR keeps —
225
229
  # the only place here that undoes something rather than simply reading it.
226
230
  def mutations(row)
@@ -229,7 +233,7 @@ module Hecks
229
233
  .map { |(target, op), bindings| mutation(target, op, bindings) }
230
234
  end
231
235
 
232
- # `sign:` — read the SAME way the declared side computes it
236
+ # `sign:` — read the same way the declared side computes it
233
237
  # (`Bluebook::Mutation.sign_for`, item #5 of the whole-project
234
238
  # table-unification survey), not stored on any row here — the
235
239
  # meta-domain's own Change entity carries no `sign` field of its
@@ -241,7 +245,7 @@ module Hecks
241
245
  def mutation(target, oper, bindings)
242
246
  base = { target: target.to_sym, op: oper.to_sym, sign: Hecks::Bluebook::Mutation.sign_for(oper) }
243
247
  # `:delegate`/`:corrects` (CommandBuilder#delegates_to's and
244
- # #corrects_impl's own comments) ride the SAME multi-binding
248
+ # #corrects_impl's own comments) ride the same multi-binding
245
249
  # shape `:append` does.
246
250
  return base.merge(fields: appended(bindings)) if ["append", "delegate", "corrects"].include?(oper)
247
251