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
@@ -5,12 +5,12 @@ module Hecks
5
5
  # Command, ValueObject, Query, ...); see `Contract`'s own header
6
6
  # (contract.rb) for the struct format each entry below fills in.
7
7
  class Assembly
8
- # ONE TABLE, WHERE THERE WERE FIVE HAND-WRITTEN MIRRORS OF IT.
8
+ # One table, where there were five hand-written mirrors of it.
9
9
  #
10
10
  # `bluebook.bluebook` already declares what every construct is made of, and
11
11
  # `Plan` already reads it — parent, fields, lists, setters. What the language
12
12
  # cannot say is the three things Ruby needs to rebuild one, so those are here
13
- # and ONLY those:
13
+ # and only those:
14
14
  #
15
15
  # holder which class holds it
16
16
  # make :declare for a construct that became a class, :new for an
@@ -19,17 +19,17 @@ module Hecks
19
19
  # fields each keyword the constructor takes, as
20
20
  # keyword => [key in the declaration, how to read it]
21
21
  #
22
- # A READER is a symbol naming a method on Marks, or :plain for a value that
22
+ # A reader is a symbol naming a method on Marks, or :plain for a value that
23
23
  # needs no decoding, or [:each, reader] for a list. Nothing here is a rule
24
24
  # about whether a declaration is admissible — the language settled that on the
25
25
  # way in. This is only how a spelling becomes an object again.
26
26
  #
27
- # WHY A TABLE AND NOT A METHOD PER CATEGORY. The judge used to carry one
27
+ # Why a table and not a method per category. The judge used to carry one
28
28
  # hand-written branch per category, and the price was fourteen verbs the
29
29
  # language declared and the walk never offered — every rule hanging off them
30
30
  # decoration, and nothing red, because a branch that does not exist cannot
31
31
  # fail. An assembler with a method per category is the same shape. So the
32
- # table is checked AGAINST the language by spec/assembly_spec: a field the
32
+ # table is checked against the language by spec/assembly_spec: a field the
33
33
  # language declares that no contract consumes is a failure, not a silence.
34
34
  #
35
35
  # The `derived` list is how a field says it needs no assembling — a parent
@@ -47,7 +47,8 @@ module Hecks
47
47
  vision: [:vision, :plain],
48
48
  classification: [:classification, :plain],
49
49
  formerly_known_as: [:formerly_known_as, :plain],
50
- attaches_to: [:attaches_to, :plain]
50
+ attaches_to: [:attaches_to, :plain],
51
+ provides: [:provides, :plain]
51
52
  },
52
53
  rows: { normalisations: :normalisation_table },
53
54
  derived: { normalisations: :elsewhere }
@@ -60,7 +61,7 @@ module Hecks
60
61
  description: [:description, :plain],
61
62
  identified_by: [:identified_by, :plain],
62
63
  attributes: [:attributes, [:each, :attribute]],
63
- # THE AGGREGATE BOUNDARY, and the precondition a command may
64
+ # The aggregate boundary, and the precondition a command may
64
65
  # reference by name (S10, ADR 0025 — "Rules"). Same reader
65
66
  # shapes ValueObject's own `invariants`/Command's own
66
67
  # `givens` already use — `invariant` builds an Invariant,
@@ -101,7 +102,7 @@ module Hecks
101
102
  ensures: [:ensures, [:each, :given]],
102
103
  mutations: [:mutations, [:each, :mutation]],
103
104
  emits: [:emits, :plain],
104
- # LIFECYCLE STATE AS A COMMAND GUARD (S10, ADR 0025) — a
105
+ # Lifecycle state as a command guard (S10, ADR 0025) — a
105
106
  # literal the same way `provenance`/`default:` already are;
106
107
  # one state or an array of them, or nil for a command with
107
108
  # no such guard.
@@ -138,7 +139,7 @@ module Hecks
138
139
  wheres: [:wheres, [:each, :where_clause]],
139
140
  order_by: [:order_by, :order_by],
140
141
  limit: [:limit, :limit],
141
- # Held by the language as an OPEN MAP, so every one of these reads the
142
+ # Held by the language as an open map, so every one of these reads the
142
143
  # same way and a ninth option needs no new field on either side.
143
144
  offset: [:offset, [:option, :offset]],
144
145
  cursor: [:cursor, [:option, :cursor]],
@@ -162,20 +163,20 @@ module Hecks
162
163
  fields: {
163
164
  name: [:name, :plain],
164
165
  description: [:description, :plain],
165
- # A LIST OF PATHS, exactly as an aggregate's is. The two used to differ
166
+ # A list of paths, exactly as an aggregate's is. The two used to differ
166
167
  # — a Symbol here and a String there, which byte equality with `to_h`
167
- # COULD NOT SEE because both render as a string, so the assembled graph
168
+ # could not see because both render as a string, so the assembled graph
168
169
  # got a String and `element_of` looked up `args["sequence"]` in a
169
170
  # symbol-keyed payload and found nothing: "Reverse acts on one
170
171
  # LedgerEntry — pass sequence:", while passing sequence. There is one
171
172
  # spelling now, and no room left for that difference.
172
173
  identified_by: [:identified_by, :plain],
173
174
  attributes: [:attributes, [:each, :shape_field]],
174
- # ADR 0028 — the SAME shape Aggregate's own `preconditions`
175
+ # ADR 0028 — the same shape Aggregate's own `preconditions`
175
176
  # already carries, one level down: a piece's own named
176
177
  # `given`, referenced back by one of its own commands.
177
178
  preconditions: [:preconditions, [:each, :given]],
178
- # Round 7 — the SAME shape Aggregate's own `invariants`
179
+ # Round 7 — the same shape Aggregate's own `invariants`
179
180
  # already carries, one level down: checked against every
180
181
  # instance of this piece, not the aggregate's own flat state.
181
182
  invariants: [:invariants, [:each, :invariant]]
@@ -195,17 +196,18 @@ module Hecks
195
196
  "Policy" => Contract.new(
196
197
  holder: Policy, make: :new,
197
198
  fields: {
198
- name: [:name, :plain],
199
- aggregate: [:aggregate, :plain],
200
- on_event: [:on_event, :plain],
201
- trigger_command: [:trigger_command, :plain],
202
- target_domain: [:target_domain, :plain],
203
- where: [:where, :plain],
204
- for_each: [:for_each, :plain],
205
- with_spec: [:with_spec, :bindings]
199
+ name: [:name, :plain],
200
+ aggregate: [:aggregate, :plain],
201
+ on_event: [:on_event, :plain],
202
+ trigger_command: [:trigger_command, :plain],
203
+ target_domain: [:target_domain, :plain],
204
+ expect_undelivered: [:expect_undelivered, :plain],
205
+ where: [:where, :plain],
206
+ for_each: [:for_each, :plain],
207
+ with_spec: [:with_spec, :bindings]
206
208
  },
207
209
  rows: { with_spec: :with_spec_rows },
208
- reads: { with_spec: [:from, :with_spec] },
210
+ reads: { with_spec: [:from, :with_spec], expect_undelivered: :expect_undelivered? },
209
211
  derived: { position: :walk }
210
212
  ),
211
213
 
@@ -213,7 +215,7 @@ module Hecks
213
215
  holder: ProcessManager, make: :new,
214
216
  fields: {
215
217
  name: [:name, :plain],
216
- # A SYMBOL. `SagaInterpreter` does `event.payload[pm.correlates_by]` — a
218
+ # **A symbol**. `SagaInterpreter` does `event.payload[pm.correlates_by]` — a
217
219
  # hash lookup on a symbol-keyed payload — and `value == pm.correlates_by`
218
220
  # when resolving a leg s bindings. A String there finds nothing and
219
221
  # resolves to nothing, so the wire never advanced and a drawer that
@@ -224,7 +226,7 @@ module Hecks
224
226
  states: [:states, :plain]
225
227
  },
226
228
  reads: { states: :names },
227
- # S17, ADR 0026 — `handlers` is a REAL feature of the LANGUAGE's
229
+ # S17, ADR 0026 — `handlers` is a real feature of the language's
228
230
  # own "ProcessManager" declaration now (`attribute :handlers,
229
231
  # list_of(Handler)`, reaction.bluebook), consumed by the judge
230
232
  # walking `Plan`'s own containment tree (`Handler`'s own
@@ -237,7 +239,7 @@ module Hecks
237
239
  # S17, ADR 0026 — Handler is a genuine entity now, nested under
238
240
  # ProcessManager (`entity "Handler"`, reaction.bluebook). Neither
239
241
  # `position` nor `handler` is a stored field any more: a saga
240
- # answers each event ONCE, so `event_type` is Handler's own real,
242
+ # answers each event once, so `event_type` is Handler's own real,
241
243
  # non-positional identity (no walk-minted `position` to derive),
242
244
  # and the process manager it belongs to is structural now — which
243
245
  # list this element sits in, not a stored field to fold a parent
@@ -251,7 +253,7 @@ module Hecks
251
253
  },
252
254
  # `dispatches` — same reason ProcessManager's own `handlers`
253
255
  # claim, above, is `:children` : a real feature of the
254
- # LANGUAGE's own "Handler" declaration (`attribute :dispatches,
256
+ # language's own "Handler" declaration (`attribute :dispatches,
255
257
  # list_of(Dispatch)`), consumed by the judge walking `Plan`'s
256
258
  # own containment tree rather than by any field this contract
257
259
  # reads.
@@ -261,7 +263,7 @@ module Hecks
261
263
  # S17, ADR 0026 — Dispatch is a genuine entity now, nested under
262
264
  # Handler (`entity "Dispatch"`, process_manager.bluebook) — two
263
265
  # levels deep, "no life outside its Handler" (the ADR's own
264
- # words). `command_name` ALONE used to be Dispatch's own
266
+ # words). `command_name` alone used to be Dispatch's own
265
267
  # identity, until items #151/#152 (`process_manager.bluebook`'s
266
268
  # own `DispatchPosition` comment) found it collided the instant a
267
269
  # real handler fanned the same command out more than once —
@@ -270,22 +272,22 @@ module Hecks
270
272
  # the same entry ProcessManager's own contract carries above) —
271
273
  # never a stored field on `DispatchSpec` itself, exactly like
272
274
  # `handler` before it.
273
- # `compensates_command_name`/`compensates_with_spec` — FOLDED,
274
- # the SAME kind `Lifecycle`'s own `state_field`/`default` claim
275
- # (one IR OBJECT, `DispatchSpec#compensates`, feeding two
275
+ # `compensates_command_name`/`compensates_with_spec` — folded,
276
+ # the same kind `Lifecycle`'s own `state_field`/`default` claim
277
+ # (one IR object, `DispatchSpec#compensates`, feeding two
276
278
  # separate language fields): `Readings#field_value`'s own
277
279
  # `contract.folded` branch reads
278
280
  # `node.compensates.to_h[:command_name]` / `[:with_spec]` for
279
- # the JUDGE'S offering side, nil-safe when there is no
281
+ # the judge's offering side, nil-safe when there is no
280
282
  # compensation at all (`through`'s own `return nil unless
281
- # held`). `compensates_with_spec` ALSO needs its own row shaper
282
- # (`compensates_with_spec_rows`, readings.rb) for the JUDGE'S
283
+ # held`). `compensates_with_spec` also needs its own row shaper
284
+ # (`compensates_with_spec_rows`, readings.rb) for the judge's
283
285
  # list-offering side — the with_spec pairs still need one
284
286
  # "BindCompensation" append per pair, the same reason
285
287
  # `with_spec` itself needs `with_spec_rows`, one level deeper.
286
288
  # `Reconstruction#dispatch` reads the two flat fields back off
287
289
  # the row and assembles the nested `DispatchSpec` by hand — a
288
- # nested OBJECT is not one of the shapes `declaration()`'s own
290
+ # nested object is not one of the shapes `declaration()`'s own
289
291
  # generic per-field hash-build can produce, the identical reason
290
292
  # `handler`/`process_manager` pass a `:children` list through
291
293
  # `extra:` instead.
@@ -372,7 +374,7 @@ module Hecks
372
374
  # is what `Assembly::Build` needs (fed the native `to_h`
373
375
  # value directly, already `true`/`nil`/a String), and the
374
376
  # `reads:` entry below is what `Reconstruction` needs
375
- # instead (fed the STRINGIFIED meta-domain row).
377
+ # instead (fed the stringified meta-domain row).
376
378
  count: [:count, :plain],
377
379
  median_field: [:median_field, :plain],
378
380
  # A read model inherits every option an ask has, so it reads them the
@@ -392,12 +394,12 @@ module Hecks
392
394
  # `nil` — even though a read model's row never carries `wheres` as a
393
395
  # native field the way Query's does (`[:each, :where_clause]` over an
394
396
  # absent `row[:wheres]` is `Array(nil).map { ... }`, i.e. `[]`, always).
395
- # The REAL values, when a read model declares any, arrive through
397
+ # The real values, when a read model declares any, arrive through
396
398
  # `options_of(row)`'s merge in `read_model` below (dispatched as
397
399
  # generic Option rows, `read_model_option_rows`/`filter_options` — not
398
400
  # as dedicated where-clause rows), which overrides this default. Until
399
401
  # `ReadModel#to_h` spelled `wheres`/`order_by`/`limit`
400
- # unconditionally, `round_trip_spec`'s own "SOURCE KEYS ONLY" +compare
402
+ # unconditionally, `round_trip_spec`'s own "source keys only" +compare
401
403
  # never asked about this key at all, so the `nil`-vs-`[]` gap between
402
404
  # this contract's default and `to_h`'s own `[]` default went unnoticed.
403
405
  # `order_by`/`limit` need no matching entry — the generic reader's
@@ -419,7 +421,7 @@ module Hecks
419
421
  }
420
422
  ),
421
423
 
422
- # A member's pairs are an OPEN MAP, which is why Member is its own root in
424
+ # A member's pairs are an open map, which is why Member is its own root in
423
425
  # the language. The IR keeps them as a plain hash on the value object, so
424
426
  # they are assembled with their shape rather than as a construct.
425
427
  # S17, ADR 0026 — Member is a genuine entity now, nested under
@@ -6,10 +6,10 @@ module Hecks
6
6
  # `to_h` spells things as text so the export stands on its own, and every
7
7
  # one of those spellings has to come back apart here. This is the same family
8
8
  # of work `MetaValidator::Shapes` does for the reconstruction — the difference
9
- # is that Shapes rebuilds HASHES and this rebuilds OBJECTS, so it has to
9
+ # is that Shapes rebuilds hashes and this rebuilds objects, so it has to
10
10
  # recover types rather than just strings.
11
11
  #
12
- # ENCODING LOSSES ARE THE LARGEST FAMILY OF BUG IN THIS CODEBASE, and every
12
+ # Encoding losses are the LARGEST family of bug in this codebase, and every
13
13
  # member has the same shape: reading an object where `to_h` holds a spelling.
14
14
  # So each method below names the spelling it inverts.
15
15
  module Marks
@@ -27,7 +27,7 @@ module Hecks
27
27
  type: target ? Reference.new(target) : type,
28
28
  list: field[:list] ? true : false,
29
29
  default: field[:default],
30
- # The LAST place optionality can be dropped, and the one that was
30
+ # The last place optionality can be dropped, and the one that was
31
31
  # dropping it. Every bluebook in the registry is the round-trip
32
32
  # product — MetaValidator dispatches the declaration in and reads it
33
33
  # back — so a fact this constructor does not carry is a fact the
@@ -35,9 +35,9 @@ module Hecks
35
35
  # wrote it.
36
36
  optional: field[:optional] ? true : false,
37
37
  pattern: field[:pattern],
38
- # THE SAME LESSON, ONE FACT LATER. `admits` is not on `to_h` — the
38
+ # **The same lesson, one fact later**. `admits` is not on `to_h` — the
39
39
  # wire does not carry it, on purpose — but it must still survive the
40
- # round trip, because the grammar registry keeps the ASSEMBLED graph
40
+ # round trip, because the grammar registry keeps the assembled graph
41
41
  # and downstream projections read the link off that. Dropped here, the
42
42
  # language could not say `admits` about itself no matter how plainly
43
43
  # the source wrote it, which is word for word what the note above
@@ -52,15 +52,15 @@ module Hecks
52
52
  # both — `Aggregate.Attribute` and `Command.Argument` are separate verbs.
53
53
  def shape_field(field) = attribute(field)
54
54
 
55
- # ONE PART OF AN IDENTITY. It goes in as a row so the language can hold an
55
+ # One part of an identity. It goes in as a row so the language can hold an
56
56
  # ordered list of them, and comes back out as the path it always was —
57
57
  # a String, because `identity_paths` splits paths and never symbols.
58
58
  def identity_path(part) = part[:value].to_s
59
59
 
60
- # A member's fields — an OPEN MAP, which is why Member is its own root in
60
+ # A member's fields — an open map, which is why Member is its own root in
61
61
  # the language and why the pairs arrive as a list rather than a value object.
62
62
  #
63
- # The values are UNMARKED, because `ValueObject#to_h` spells them with `to_s`
63
+ # The values are unmarked, because `ValueObject#to_h` spells them with `to_s`
64
64
  # and the language stores them as text: `member code: "JPY", minor_units: 0`
65
65
  # came back with a minor_units of "0", and a closed set that admits the string
66
66
  # would refuse the number the caller passes.
@@ -69,7 +69,7 @@ module Hecks
69
69
  end
70
70
 
71
71
  # A read model's gathered head. The keys must be symbols whichever way the
72
- # declaration arrived, and `as` must be one too: it NAMES the reader the
72
+ # declaration arrived, and `as` must be one too: it names the reader the
73
73
  # projection answers to, and `ReadModel#to_h` spells it `to_s`.
74
74
  def head(row)
75
75
  row.to_h { |key, value| [key.to_sym, key.to_sym == :as ? value.to_sym : value] }
@@ -118,8 +118,8 @@ module Hecks
118
118
 
119
119
  # `Mutation#to_h` branches on the operation, so this does too.
120
120
  #
121
- # An APPEND binds several fields at once, each either an ARGUMENT (a
122
- # Symbol, wearing its colon) or a LITERAL — the distinction that is the
121
+ # An append binds several fields at once, each either an argument (a
122
+ # Symbol, wearing its colon) or a literal — the distinction that is the
123
123
  # whole reason `append: { direction: "out" }` was once indistinguishable
124
124
  # from an argument named `out`.
125
125
  def mutation(change)
@@ -127,7 +127,7 @@ module Hecks
127
127
  op = change[:op].to_sym
128
128
 
129
129
  # `:delegate`/`:corrects` (CommandBuilder#delegates_to's and
130
- # #corrects_impl's own comments) ride the SAME multi-binding
130
+ # #corrects_impl's own comments) ride the same multi-binding
131
131
  # shape `:append` does.
132
132
  return Mutation.new(target: target, op: op, source: appended(change[:fields])) if [:append, :delegate,
133
133
  :corrects].include?(op)
@@ -139,7 +139,7 @@ module Hecks
139
139
  Array(fields).to_h { |field, source| [field.to_sym, read(source)] }
140
140
  end
141
141
 
142
- # A SET reads one thing, and `classified_source` said which: an argument by
142
+ # A set reads one thing, and `classified_source` said which: an argument by
143
143
  # name, or a literal by value.
144
144
  def classified(source)
145
145
  return nil if source.nil?
@@ -151,7 +151,7 @@ module Hecks
151
151
  end
152
152
  end
153
153
 
154
- # EVERY LITERAL FIELD ON THE WIRE, read back — one spelling, one reader.
154
+ # Every literal field on the wire, read back — one spelling, one reader.
155
155
  #
156
156
  # A where-clause value, a saga's argument bindings, an append binding, a
157
157
  # limit: all of them ride Literal's self-describing form, so all of them
@@ -159,7 +159,7 @@ module Hecks
159
159
  # that disagreed about quoted strings and numbers, and which one a call
160
160
  # site got was a coin toss the comments had to keep apologising for.
161
161
  #
162
- # AN OBJECT LITERAL is the one that bit. A saga leg binds `narrative: {
162
+ # An object literal is the one that bit. A saga leg binds `narrative: {
163
163
  # text: "transfer out" }` — a value object's fields written inline — and
164
164
  # `to_s` on a Hash used to be its inspect form, so it came back as text.
165
165
  # Read as a string it reached the runtime as `"{:text=>\"transfer out\"}"`,
@@ -171,10 +171,10 @@ module Hecks
171
171
  def read(value) = Literal.read(value)
172
172
 
173
173
  # `target:` (ADR 0055) — read straight off the wire, unconverted:
174
- # it's already the bare aggregate-name STRING `WhereClause#to_h`/
174
+ # it's already the bare aggregate-name string `WhereClause#to_h`/
175
175
  # `OrderBy#to_h`/`LimitSpec#to_h` wrote (`resolve_target`'s own
176
176
  # `Naming.demodulise` already ran once, at DSL-build time; this is
177
- # the REPLAY path every real boot actually goes through, reading
177
+ # the replay path every real boot actually goes through, reading
178
178
  # that same wire shape back — see this class's own header). Absent
179
179
  # from `clause`/`declared` entirely on older wire data that never
180
180
  # declared `on:` — `clause[:target]`/`declared[:target]` reads
@@ -200,7 +200,7 @@ module Hecks
200
200
  QuerySpecification::Common::LimitSpec.new(value: read(declared[:value]), target: declared[:target])
201
201
  end
202
202
 
203
- # EVERY OTHER SPECIFICATION OPTION, from one table.
203
+ # Every other specification option, from one table.
204
204
  #
205
205
  # Each entry names the struct and which of its members carry a value that
206
206
  # rode Literal's spelling rather than plain text. A
@@ -1,45 +1,31 @@
1
1
  module Hecks
2
2
  module Bluebook
3
3
  class Assembly
4
- # THE FIRST SPECIALIZER — a projection of `contracts.rb`'s `fields:` table,
4
+ # **The first specializer** — a projection of `contracts.rb`'s `fields:` table,
5
5
  # derived from the language's own description of a category instead of
6
6
  # hand-written beside it.
7
7
  #
8
8
  # `Plan` already reads `grammar_registry` to build the judge's walk ; this
9
- # reads the same chapter to build the OTHER table this arc's own header
10
- # names as duplication — "SPELLED AS THE IR SPELLS THEM," field for field,
9
+ # reads the same chapter to build the other table this arc's own header
10
+ # names as duplication — "spelled as the IR spells them," field for field,
11
11
  # for every category simple enough to say so.
12
12
  #
13
- # ONE CASE, PROVEN, NOT THE WHOLE TABLE. A field this can speak for is
13
+ # One case, proven, not the whole table. A field this can speak for is
14
14
  # scalar and not a reference — every other field (a list, a reference, a
15
15
  # fold like Lifecycle) is exactly what `contracts.rb`'s `reads:`/`derived:`
16
16
  # exist to say, and stays hand-written until a later projection learns to
17
17
  # derive readers and folds too. Restricting the claim to what can be
18
- # PROVEN CORRECT — checked in spec/specializer_spec.rb against two
18
+ # proven correct — checked in spec/specializer_spec.rb against two
19
19
  # independent categories — is the same discipline `derived:` itself
20
20
  # enforces : a claim needs a kind, and this one's kind is "plain, checked."
21
21
  module Specializer
22
22
  module_function
23
23
 
24
- # `position` IS THE FIRST FOLD THIS RUNS INTO, and it is a universal
25
- # one : every category declares `attribute :position, Position` — for
26
- # the JUDGE's own walk, `order_by :position` on its `DeclaredIn` ask —
27
- # but no `*` constructor takes it as an argument. `contracts.rb`
28
- # already says so, in the language every other derived field speaks :
29
- # `derived: { position: :walk }`. The language says a category HAS a
30
- # position ; it does not say a category's OWN constructor is handed
31
- # one, and that second fact is exactly what `fields:` needs to answer.
32
- # So this is not silently special-cased — it is the one fold named
33
- # here because it is the one fold that is not a lucky accident of
34
- # Policy or Handler, but a fact true of every category this arc will
35
- # ever reach.
36
- DERIVED_EVERYWHERE = %i[position].freeze
37
-
38
24
  # S17, ADR 0026 — `Handler` is a genuine entity now, nested under
39
25
  # `ProcessManager`, so `.aggregate` alone no longer finds it —
40
26
  # it hangs off some aggregate's own `.entities` instead
41
27
  # (searched recursively, the same reason `Value::Coercion#find_
42
- # entity` does: a NESTED entity, like `Dispatch` inside
28
+ # entity` does: a nested entity, like `Dispatch` inside
43
29
  # `Handler`, is not a direct child of any aggregate either).
44
30
  def construct_for(chapter, name)
45
31
  chapter.aggregate(name) || chapter.aggregates.filter_map { |a| find_entity(a, name) }.first
@@ -55,11 +41,23 @@ module Hecks
55
41
  nil
56
42
  end
57
43
 
44
+ # `position` is the first fold this runs into : a category declares
45
+ # `attribute :position, Position` — for the judge's own walk,
46
+ # `order_by :position` on its `DeclaredIn` ask — but no `*`
47
+ # constructor takes it as an argument. `contracts.rb` already says so,
48
+ # in the language every other derived field speaks :
49
+ # `derived: { position: :walk }`. The language says a category has a
50
+ # position ; it does not say a category's own constructor is handed
51
+ # one, and that second fact is exactly what `fields:` needs to answer.
52
+ # So the skip reads the category's own walk claims (`Contract#walked`)
53
+ # rather than restating `position` here — Handler, which has no
54
+ # walk-minted position, skips nothing.
58
55
  def fields_for(category)
59
56
  language = construct_for(MetaValidator.grammar_registry.bluebook("Bluebook"), category.to_s)
57
+ walked = Assembly.contract(category).walked
60
58
  language.attributes.each_with_object({}) do |attribute, fields|
61
59
  next if attribute.list? || attribute.reference?
62
- next if DERIVED_EVERYWHERE.include?(attribute.name)
60
+ next if walked.include?(attribute.name)
63
61
 
64
62
  fields[attribute.name] = [attribute.name, :plain]
65
63
  end
@@ -1,6 +1,6 @@
1
1
  module Hecks
2
2
  module Bluebook
3
- # A GRAPH BUILT FROM DECLARATIONS, rather than from DSL calls.
3
+ # A graph built from declarations, rather than from DSL calls.
4
4
  #
5
5
  # This is the half that lets the language orchestrate. `Reconstruction` reads a
6
6
  # chapter back out of the meta-domain, in declaration order, as plain
@@ -8,24 +8,24 @@ module Hecks
8
8
  # into the graph the runtime runs: IR aggregates with their verbs, value
9
9
  # objects, entities and asks, owned by the chapter that declares them.
10
10
  #
11
- # It takes a HASH, not a runtime, on purpose. That makes it a pure inverse of
11
+ # It takes a hash, not a runtime, on purpose. That makes it a pure inverse of
12
12
  # `to_h` and testable without the meta-domain in the picture at all:
13
13
  #
14
14
  # Assembly.call(built.to_h).to_h == built.to_h
15
15
  #
16
16
  # which is the check `spec/assembly_spec` makes for every chapter in the tree.
17
17
  # Feed it the reconstruction instead and the same code assembles what the
18
- # LANGUAGE holds — the only difference being where the declarations came from.
18
+ # language holds — the only difference being where the declarations came from.
19
19
  #
20
- # EVERY FIELD IS READ FROM ONE TABLE. There is no method per category here:
20
+ # Every field is read from one table. There is no method per category here:
21
21
  # `Contracts` names what the language cannot say about a construct, `Build`
22
22
  # reads it, and the coverage gate holds the table to the language. The first
23
23
  # draft of this file did have a method each, which is the shape the judge used
24
24
  # to have — and the price of that shape was fourteen verbs the language declared
25
25
  # and nothing ever offered.
26
26
  #
27
- # What stays hand-written is the CONTAINMENT: which construct holds which.
28
- # That is not a field table. (The runtime SURFACE is no longer built here at
27
+ # What stays hand-written is the containment: which construct holds which.
28
+ # That is not a field table. (The runtime surface is no longer built here at
29
29
  # all — the door is a per-boot projection, facade/surface.rb.)
30
30
  class Assembly
31
31
  def self.call(declaration) = new(declaration).bluebook
@@ -50,7 +50,7 @@ module Hecks
50
50
  private
51
51
 
52
52
  # Every reaction the chapter holds, and each one also handed back to the head
53
- # that declared it — the builder keeps a policy in BOTH places, hoisting it onto
53
+ # that declared it — the builder keeps a policy in both places, hoisting it onto
54
54
  # the chapter where the runtime reads it while the head keeps its own list. The
55
55
  # language records which head, so the assembly can put it back.
56
56
  def reactions(aggregates)
@@ -72,10 +72,10 @@ module Hecks
72
72
  dispatches: Array(row[:dispatches]).map { |leg| dispatch(leg) })
73
73
  end
74
74
 
75
- # `compensates` — a PLAIN HASH on the declaration (`Reconstruction#
75
+ # `compensates` — a plain hash on the declaration (`Reconstruction#
76
76
  # dispatch`'s own comment for why), built into the real
77
77
  # `DispatchSpec` its own field actually is by recursing through
78
- # THIS SAME method, one level in — the identical move `handler`
78
+ # this same method, one level in — the identical move `handler`
79
79
  # itself takes into `dispatches`, one level up. `nil` when there
80
80
  # is nothing to compensate; `Build.call` never sees a
81
81
  # `compensates:` key it does not know how to read either way, the
@@ -28,15 +28,15 @@ module Hecks
28
28
 
29
29
  attr_reader :name, :type, :default, :pattern, :admits, :relationship
30
30
 
31
- # A Reference is kept AS ITSELF. Every other type is still a name, and
31
+ # A Reference is kept as itself. Every other type is still a name, and
32
32
  # crosses over as its construct does.
33
33
  #
34
- # `admits` names an ALREADY-DECLARED closed set the value must belong
34
+ # `admits` names an already-declared closed set the value must belong
35
35
  # to — `Vocabulary::QueryComparator` — spelled aggregate-qualified
36
- # because the set is a value object INSIDE an aggregate, and the
36
+ # because the set is a value object inside an aggregate, and the
37
37
  # aggregate is the only thing `reference_to` can reach.
38
38
  #
39
- # ON THE WIRE, because it is a RULE and not only a typing hint.
39
+ # On the wire, because it is a rule and not only a typing hint.
40
40
  #
41
41
  # It began as neither. The link existed so a generator could type
42
42
  # `WhereClause.op` as `WhereOp` — a typing convenience, not worth
@@ -48,7 +48,7 @@ module Hecks
48
48
  # refused "burnt" through one reading and emitted the event through
49
49
  # another.
50
50
  #
51
- # The wire carries the NAME, not the members. A reader resolves it
51
+ # The wire carries the name, not the members. A reader resolves it
52
52
  # against the IR it holds, so the members are declared once and
53
53
  # copied nowhere — which is the same reason `admits` exists at all.
54
54
  def initialize(name:, type:, list: false, default: nil, optional: false, pattern: nil,
@@ -63,13 +63,13 @@ module Hecks
63
63
  @relationship = relationship&.to_s
64
64
  end
65
65
 
66
- # A BARE CONSTANT IN A BLUEBOOK IS A NAME, EVEN WHEN RUBY HAS HEARD OF IT.
66
+ # A bare constant in a bluebook is a name, even when Ruby has heard of it.
67
67
  #
68
68
  # `BluebookBuilder.build` says exactly this and installs a `const_missing`
69
69
  # resolver that hands back the symbol — `attribute :target, Target` becomes
70
70
  # the name "Target" and nothing looks Target up. That works only while the
71
- # lookup FAILS, and `Facade::Surface` installs every aggregate name as a
72
- # TOP-LEVEL constant (its own comment, and `ConstShim`'s, both say so).
71
+ # lookup fails, and `Facade::Surface` installs every aggregate name as a
72
+ # top-level constant (its own comment, and `ConstShim`'s, both say so).
73
73
  #
74
74
  # So in one process: boot a domain with an aggregate named `Target`, then
75
75
  # load a chapter whose own value object is called `Target`, and Ruby
@@ -81,7 +81,7 @@ module Hecks
81
81
  # `QualityControl::Target` are both "Target". A plain class stays itself —
82
82
  # `String` demodulises to "String" — so the ordinary case is untouched.
83
83
  # This does not undo the constant leak; it makes the leak unable to change
84
- # what a chapter MEANS, which is the part that has to hold.
84
+ # what a chapter means, which is the part that has to hold.
85
85
  def spell(type)
86
86
  return type if type.is_a?(Reference)
87
87
  return Naming.demodulise(type) if type.is_a?(Module)
@@ -3,14 +3,14 @@ require_relative "traits"
3
3
  module Hecks
4
4
  module Bluebook
5
5
  module Behaviour
6
- # WHAT AN AGGREGATE DOES, as opposed to what it holds.
6
+ # What an aggregate does, as opposed to what it holds.
7
7
  #
8
8
  # The holding half — the field list, the readers, the emission — is
9
9
  # the same list the language already declares in
10
10
  # `language/bluebook/aggregate.bluebook`, said a second and third
11
11
  # time in Ruby. This half is not: derived identity, the name
12
12
  # indexes, the owner stamping and the finders are decisions about
13
- # HOW the declared shape is used, and no grammar states them.
13
+ # how the declared shape is used, and no grammar states them.
14
14
  #
15
15
  # Split so the holding half can be generated from the language
16
16
  # without any of this being in the blast radius of a regeneration.
@@ -24,11 +24,11 @@ module Hecks
24
24
  include Indexed
25
25
  include Owns
26
26
 
27
- # An aggregate is a MEMBER of its chapter's namespace — "Pizzas::Pizza" —
28
- # where everything else is declared ON its owner and joins with ".".
27
+ # An aggregate is a member of its chapter's namespace — "Pizzas::Pizza" —
28
+ # where everything else is declared on its owner and joins with ".".
29
29
  def hecks_separator = "::"
30
30
 
31
- # THE HOOK THE GENERATED CONSTRUCTOR CALLS once every declared
31
+ # The hook the generated constructor calls once every declared
32
32
  # field is assigned. Nothing here is derivable from the
33
33
  # declaration, which is exactly why it is not generated.
34
34
  def settle
@@ -46,7 +46,7 @@ module Hecks
46
46
  @commands_by_name = index_by_hecks_name(@commands)
47
47
  @queries_by_name = index_by_hecks_name(@queries)
48
48
  @ports_by_name = @ports.to_h { |port| [port.name, port] }
49
- # S12, ADR 0025 — keyed by SYMBOL, the same convention
49
+ # S12, ADR 0025 — keyed by symbol, the same convention
50
50
  # `Indexed#attribute` already uses; `GuardState` asks for one
51
51
  # by name at every dispatch, the rebuild sweep walks all of
52
52
  # them once per pass.
@@ -55,18 +55,18 @@ module Hecks
55
55
 
56
56
  def projected_field(named) = @projected_fields_by_name[named.to_sym]
57
57
 
58
- # A value object is a CLASS now, so `name` is Ruby's answer (the constant
58
+ # A value object is a class now, so `name` is Ruby's answer (the constant
59
59
  # path) and the declared name is `hecks_name`. This finder is on its way
60
- # out — once an attribute's type IS the class there is nothing to find —
60
+ # out — once an attribute's type is the class there is nothing to find —
61
61
  # but every consumer still asks by type string, so it stays until they
62
62
  # stop.
63
63
  def value_object(named) = @value_objects_by_name[named.to_s]
64
64
  def port(named) = @ports_by_name[named.to_s]
65
65
 
66
- # A PORT IS DECLARED IN THE HECKSAGON, NOT THE BLUEBOOK — the
66
+ # A port is declared in the hecksagon, not the bluebook — the
67
67
  # boundary between the domain and its adapters, in hexagonal terms,
68
- # is exactly what a `.hecksagon` file already IS for every other
69
- # port (persistence, projection, ...). So this attaches AFTER the
68
+ # is exactly what a `.hecksagon` file already is for every other
69
+ # port (persistence, projection, ...). So this attaches after the
70
70
  # aggregate already exists and is registered — `HecksagonBuilder`
71
71
  # calls it once per `port` declaration, having already stamped each
72
72
  # operation's reference attributes with `declared_in = self`, since