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,25 +1,29 @@
1
+ require_relative "bootstrap_table"
2
+
1
3
  module Hecks
2
4
  module Bluebook
3
5
  module DSL
4
- # ITEM #13's FULL METAPROGRAMMED DISPATCH — slices 1-2 of 4, whole-
6
+ # Item #13's full metaprogrammed dispatch — slices 1-2 of 4, whole-
5
7
  # project table-unification survey. WordGate (the first slice,
6
- # already shipped) only CHECKS a word's admissibility; this module
7
- # EXECUTES the safe, mechanical subset of what a word actually
8
- # DOES, read live off the SAME self-hosted grammar table — so a
8
+ # already shipped) only checks a word's admissibility; this module
9
+ # executes the safe, mechanical subset of what a word actually
10
+ # does, read live off the same self-hosted grammar table — so a
9
11
  # builder method for one of these words no longer needs to be
10
12
  # hand-written at all. Called from `WordGate#method_missing`'s own
11
13
  # "admitted here, no builder method for it yet" branch, so it only
12
14
  # ever sees a word whose (context, word) pair the grammar already
13
15
  # admits.
14
16
  #
15
- # SCOPE, deliberately narrow and VERIFIED word-by-word — a full
17
+ # ## What is covered
18
+ #
19
+ # Scope, deliberately narrow and verified word-by-word — a full
16
20
  # audit read every real Ruby builder method's own source before
17
21
  # any of this was written, not inferred from the table's shape
18
22
  # alone (which fooled a first pass: `ReadModelBuilder#group_by`/
19
- # `#include` LOOK like plain fills from `kind`/`fills` alone, but
23
+ # `#include` look like plain fills from `kind`/`fills` alone, but
20
24
  # actually wrap their arguments in a Hash/tuple). What's covered:
21
25
  #
22
- # - a SINGLE, non-variadic, positional Argument row whose value
26
+ # - a single, non-variadic, positional Argument row whose value
23
27
  # is stored with nothing beyond a uniform, kind-driven
24
28
  # coercion (`COERCE_BY_KIND`) — or, for `kind: "text"`, no
25
29
  # coercion at all when the row's own `coerce: "false"` says so
@@ -27,43 +31,45 @@ module Hecks
27
31
  # is a same-object no-op for every real corpus use, but a
28
32
  # genuine behavior change for a direct Ruby API call passing
29
33
  # something else)
30
- # - a scalar ASSIGN (`@ivar = value`) or list APPEND (`@ivar <<
34
+ # - a scalar assign (`@ivar = value`) or list append (`@ivar <<
31
35
  # value`), chosen by whether the ivar `fills:` names is
32
- # ALREADY an Array at call time (every candidate's own
36
+ # already an Array at call time (every candidate's own
33
37
  # `initialize` pre-populates its accumulating ivars as `[]` —
34
38
  # read live, not assumed)
35
- # - a ZERO-ARGUMENT word, either (a) one of several sibling
36
- # Keyword rows in the SAME context sharing the SAME `fills:`
37
- # target — derives its own stored value from ITS OWN word
39
+ # - a zero-argument word, either (a) one of several sibling
40
+ # Keyword rows in the same context sharing the same `fills:`
41
+ # target — derives its own stored value from its own word
38
42
  # name as a symbol (`core`/`generic`/`supporting` all fill
39
- # `classification`), or (b) the ONLY Keyword row filling its
43
+ # `classification`), or (b) the only Keyword row filling its
40
44
  # own `fills:` target — a bare marker, stores literal `true`
41
45
  # (`ReadModel#count`)
42
46
  # - an OPENS_BLOCK word named in `SAFE_OPENS_BLOCK` below,
43
- # verified to do NOTHING beyond "build the child, instance_
47
+ # verified to do nothing beyond "build the child, instance_
44
48
  # eval the block against it, append the result" — see that
45
49
  # constant's own comment
46
50
  # - (slice 2) a single-fill word whose row also names a `blank_
47
- # message:` — raises that EXACT Malformed text if the coerced
51
+ # message:` — raises that exact Malformed text if the coerced
48
52
  # value is blank, before storing it, matching a real hand-
49
53
  # written guard exactly (`Translation#retired`/
50
54
  # `TranslationAggregate#drop`, the only two words in the whole
51
55
  # grammar with this precise shape — `required: "true"` alone
52
56
  # only gates Ruby's own arity, never a present-but-blank
53
- # value, and most `required: "true"` words do NOT raise on
57
+ # value, and most `required: "true"` words do not raise on
54
58
  # blank, so this needed a real per-row signal, not an
55
59
  # assumption from `required:` alone)
56
60
  #
57
- # Explicitly OUT of this slice (found live, during the audit, not
61
+ # ## What stays hand-written
62
+ #
63
+ # Explicitly out of this slice (found live, during the audit, not
58
64
  # assumed) — stays hand-written, unaffected, until a later slice's
59
65
  # own new table columns (`gated_by:`/`calls:`) can name
60
66
  # what it really does: variadic accumulation with a real transform
61
67
  # (`attaches_to`); source-block extraction (`ensures`, `where`);
62
68
  # Struct/Hash-wrapping (`limit`, `group_by`, `rekey`); a guard
63
- # clause NOT reducible to a plain blank-check (`role`'s own "raise
64
- # if ALREADY set" uniqueness gate — a genuinely different shape
69
+ # clause not reducible to a plain blank-check (`role`'s own "raise
70
+ # if already set" uniqueness gate — a genuinely different shape
65
71
  # from `retired`/`drop`'s own blank-check, needing its own
66
- # design); a dynamically-BUILT refusal message rather than one
72
+ # design); a dynamically-built refusal message rather than one
67
73
  # fixed string (`TranslationAggregateBuilder#unresolved` — real
68
74
  # branching logic choosing between several message shapes, not a
69
75
  # simple "always refuses" flag; belongs with `calls:`, slice 4,
@@ -74,7 +80,7 @@ module Hecks
74
80
  # `Bluebook#aggregate`, `Translation#aggregate`) or doing anything
75
81
  # beyond a bare fold after building (`Aggregate#policy`'s stamp,
76
82
  # `Aggregate#value_object`'s flatten, `Hecksagon#port`'s resolver-
77
- # swap-and-branch); the DEFERRED-build queue pattern (`Aggregate`/
83
+ # swap-and-branch); the deferred-build queue pattern (`Aggregate`/
78
84
  # `Entity`'s own `command`/`entity`/`query`); the shadow_parsing?-
79
85
  # gated words (`has_many`/`has_one`/`belongs_to`/`then_set`/
80
86
  # `trigger`/`dispatch`/`one_of` — each delegates to its own
@@ -84,18 +90,20 @@ module Hecks
84
90
  # `File`-context word (routes through `Runtime.current_registry`,
85
91
  # a side effect this module has no business performing).
86
92
  #
87
- # TWO FURTHER, DIFFERENT reasons a word can look table-safe and
93
+ # ## Words that look table-safe and are not
94
+ #
95
+ # Two further, different reasons a word can look table-safe and
88
96
  # still be excluded, both found live rather than assumed:
89
- # - BOOTSTRAP REACHABILITY. `WordGate`'s own gate steps aside
97
+ # - Bootstrap reachability. `WordGate`'s own gate steps aside
90
98
  # entirely while `MetaValidator.bootstrapping?` (the meta-
91
99
  # domain's own circularity — its grammar table doesn't exist
92
- # yet to read), and `load_grammar_into` loads REAL `.port`/
93
- # `.adapter` files, plus every core `.bluebook` chapter, DURING
100
+ # yet to read), and `load_grammar_into` loads real `.port`/
101
+ # `.adapter` files, plus every core `.bluebook` chapter, during
94
102
  # that exact window. Any word those files actually call (found
95
103
  # to be nearly every common one — `vision`/`core`/`generic`/
96
104
  # `supporting`/`description`/`goal`/`emits`/`role`/`identified_
97
105
  # by` describe literally every self-hosted aggregate/command)
98
- # has NO working method to fall back on if its hand-written
106
+ # has no working method to fall back on if its hand-written
99
107
  # `def` is removed — `super` from `WordGate#method_missing`
100
108
  # just raises `NoMethodError`. `PortBuilder`/`AdapterBuilder`/
101
109
  # `BluebookBuilder` turned out to be entirely off-limits to
@@ -103,13 +111,13 @@ module Hecks
103
111
  # booting `MetaValidator.grammar_registry` after each
104
112
  # candidate removal, not assumed safe from reading the table
105
113
  # alone.
106
- # - A CONFLICTING HAND-WRITTEN `method_missing`. `WorldBuilder`
107
- # and `HecksagonBuilder` each define their OWN `method_missing`
114
+ # - A conflicting hand-written `method_missing`. `WorldBuilder`
115
+ # and `HecksagonBuilder` each define their own `method_missing`
108
116
  # directly on the class (for genuinely open-ended settings/
109
117
  # collector verbs) — a method defined directly on a class always
110
118
  # wins over one from an included module in Ruby's own method
111
119
  # resolution, so `WordGate`'s (and this module's) own
112
- # `method_missing` never runs for THEIR builders at all. Their
120
+ # `method_missing` never runs for their builders at all. Their
113
121
  # own candidate words (`realm`/`latest`, `subscribe`) stay
114
122
  # hand-written for this structural reason, independent of
115
123
  # whether their own behavior would otherwise qualify.
@@ -119,10 +127,10 @@ module Hecks
119
127
  COERCE_BY_KIND = { "text" => :to_s, "symbol" => :to_sym }.freeze
120
128
 
121
129
  # (context, word) OPENS_BLOCK pairs verified, by reading every
122
- # real Ruby method, to do NOTHING beyond building the child and
130
+ # real Ruby method, to do nothing beyond building the child and
123
131
  # appending it — see this file's own header for the full account
124
132
  # of what was excluded and why. Value: the ivar the built child
125
- # is appended into. NOT derivable from `fills:` — every one of
133
+ # is appended into. Not derivable from `fills:` — every one of
126
134
  # these Keyword rows carries `fills: ""`; the append target is
127
135
  # implicit in the hand-written code today, never named by the
128
136
  # table at all, so this is the one place slice 1 hand-names a
@@ -134,122 +142,72 @@ module Hecks
134
142
  %w[Bluebook read_model] => :read_models
135
143
  }.freeze
136
144
 
137
- # `WordGate#method_missing`'s OWN bootstrap-window fallback,
138
- # consulted ONLY while `MetaValidator.bootstrapping?` (the real
145
+ # `WordGate#method_missing`'s own bootstrap-window fallback,
146
+ # consulted only while `MetaValidator.bootstrapping?` (the real
139
147
  # table doesn't exist yet to read `keyword[:calls]` from). Names
140
- # the SAME (context, word) -> method pairs the real table's own
141
- # `calls:` column carries for these rows kept in sync by hand,
142
- # the one place in this whole arc that was worth it: it
143
- # duplicates a METHOD NAME, never the method's own logic, so
144
- # there is nothing here that could drift into a WRONG ANSWER,
145
- # only (if ever forgotten) into `attribute` staying unreachable
146
- # during bootstrap, the same loud `NoMethodError` failure this
147
- # whole mechanism already had before slice 3 existed.
148
- BOOTSTRAP_CALLS_FALLBACK = {
149
- %w[Aggregate attribute] => :attribute_impl,
150
- %w[Entity attribute] => :attribute_impl,
151
- %w[Command attribute] => :attribute_impl,
152
- %w[ValueObject attribute] => :attribute_impl,
153
- %w[Query attribute] => :attribute_impl,
154
- %w[PortOperation attribute] => :attribute_impl,
155
- %w[Command role] => :role_impl,
156
- # given/invariant/reference_to — slice 4b. Each is a SEPARATE
157
- # per-builder implementation (not a shared mixin like
158
- # attribute_impl), so every (context, word) pair below names
159
- # its OWN builder's own method, even where several share a
160
- # name.
161
- %w[Aggregate given] => :given_impl,
162
- %w[Entity given] => :given_impl,
163
- %w[Command given] => :given_impl,
164
- %w[Aggregate invariant] => :invariant_impl,
165
- %w[Entity invariant] => :invariant_impl,
166
- %w[ValueObject invariant] => :invariant_impl,
167
- %w[Aggregate reference_to] => :reference_to_impl,
168
- %w[Entity reference_to] => :reference_to_impl,
169
- %w[Command reference_to] => :reference_to_impl,
170
- %w[Query reference_to] => :reference_to_impl,
171
- %w[ReadModel reference_to] => :reference_to_impl,
172
- %w[PortOperation reference_to] => :reference_to_impl,
173
- # `belongs_to` — genuinely NEW bootstrap-reachability, post-dating
174
- # the "not bootstrap-reachable" determination above: has_many/
175
- # has_one/belongs_to were retired everywhere when that check was
176
- # made, so nothing core/attached used one to describe itself.
177
- # Wave 6 (identity-and-relationships arc) un-deprecates all three
178
- # for real, and syntax.bluebook's own Bluebook.Declare relationship
179
- # (`belongs_to Bluebook`) now uses one describing itself — checked
180
- # directly (only `belongs_to`, not `has_many`/`has_one`, is
181
- # actually used this way by any core/attached chapter today).
182
- %w[Aggregate belongs_to] => :belongs_to_impl,
183
- # slice 4c — the remaining hand-written words a fresh survey
184
- # found still un-migrated across every builder. Each checked
185
- # for bootstrap-reachability individually (grepped directly
186
- # against every core/attached chapter, not assumed); only the
187
- # ones below actually are.
188
- %w[Bluebook aggregate] => :aggregate_impl,
189
- %w[Aggregate provenance] => :provenance_impl,
190
- %w[Aggregate identified_by] => :identified_by_impl,
191
- %w[Aggregate lifecycle] => :lifecycle_impl,
192
- %w[Aggregate entity] => :entity_impl,
193
- %w[Aggregate query] => :query_impl,
194
- %w[Aggregate policy] => :policy_impl,
195
- %w[Aggregate command] => :command_impl,
196
- %w[Aggregate projects] => :projects_impl,
197
- %w[Entity identified_by] => :identified_by_impl,
198
- %w[Entity command] => :command_impl,
199
- %w[Entity query] => :query_impl,
200
- %w[Entity lifecycle] => :lifecycle_impl,
201
- %w[Command provenance] => :provenance_impl,
202
- %w[Command sets] => :sets_impl,
203
- %w[Lifecycle transition] => :transition_impl,
204
- %w[ReadModel where] => :where_impl,
205
- %w[ReadModel order_by] => :order_by_impl,
206
- %w[ReadModel include] => :include_impl,
207
- %w[Query where] => :where_impl,
208
- %w[Query order_by] => :order_by_impl,
209
- %w[Entity entity] => :entity_impl,
210
- %w[ValueObject member] => :member_impl,
211
- # slice 5. `port`/`realm`/`latest` — real, closed-set words
212
- # that sat unreachable behind Hecksagon/World's own class-level
213
- # `method_missing` (see WordGate#word_gate_dispatch's own
214
- # header), not bootstrap circularity as such, but the SAME
215
- # fallback table serves them: this hash is looked up before
216
- # `word_gate_dispatch` even runs, keyed by whichever context
217
- # the caller's own class reports.
218
- %w[Hecksagon port] => :port_impl,
219
- %w[World realm] => :realm_impl,
220
- %w[World latest] => :latest_impl,
221
- # `["Type", word]` — ONE entry each covers `list_of`/`one_of`
222
- # for EVERY calling context (Aggregate/Entity/Command/Query/
223
- # PortOperation/ValueObject all use them in an attribute's own
224
- # type position, and `self.class::GRAMMAR_CONTEXT` can never
225
- # actually equal "Type" — see `word_gate_dispatch`'s own
226
- # header). The bootstrap branch checks this key directly, the
227
- # same way the ordinary `word_gate_dispatch` path's own
228
- # "Type"-context fallback does.
229
- %w[Type list_of] => :list_of_impl,
230
- %w[Type one_of] => :one_of_impl
231
- }.freeze
148
+ # the same (context, word) -> method pairs the real table's own
149
+ # `calls:` column carries every live row, projected ahead of
150
+ # time into the committed lib/hecks/bluebook/dsl/bootstrap_table.rb
151
+ # (bin/project_bootstrap_table, pinned by spec/bootstrap_table_spec.rb).
152
+ #
153
+ # Every row is carried, rather than a hand-kept subset checked for
154
+ # bootstrap-reachability by grepping the core chapters. Carrying
155
+ # all of them costs nothing: a builder with its own `def` never
156
+ # reaches `method_missing`, and one without gains the same dispatch
157
+ # it gets once bootstrapping ends. `["Type", word]` rows still cover
158
+ # `list_of`/`one_of` in an attribute's type position for every
159
+ # calling context (see `word_gate_dispatch`'s own header).
160
+ BOOTSTRAP_CALLS_FALLBACK = BootstrapTable::CALLS
232
161
 
233
162
  module_function
234
163
 
235
- # THE STATIC PREDICATE does this (context, word) pair fall
236
- # within this slice's own verified scope, WITHOUT executing
164
+ # Reports whether `try` would execute a (context, word) pair, without executing anything.
165
+ #
166
+ # **The static predicate** — does this (context, word) pair fall
167
+ # within this slice's own verified scope, without executing
237
168
  # anything? The same row-shape checks `try` itself runs before
238
169
  # ever touching a real argument, shared so a conformance spec
239
170
  # (which has no real call, no real builder instance) can ask the
240
- # SAME question `method_missing` answers live.
171
+ # same question `method_missing` answers live.
172
+ #
173
+ # @param context [String] the grammar context, a builder's `GRAMMAR_CONTEXT` such as
174
+ # `"Aggregate"`, or `"Type"`
175
+ # @param word [String] the DSL word; a Symbol never matches a row
176
+ # @param rows [Hash{Symbol => Array<Hash{Symbol => String}>}] the grammar table, with
177
+ # `:keywords` and `:arguments` row lists; defaults to the live self-hosted table
178
+ # @return [Boolean] true when `try` would execute the word rather than answer `NOT_HANDLED`
241
179
  def handles?(context, word, rows: MetaValidator::SyntaxBoot.call)
242
180
  !shape_for(context, word, rows).nil?
243
181
  end
244
182
 
183
+ # Executes a grammar-admitted word straight off the table when its row shape is one of
184
+ # the four verified safe ones.
185
+ #
245
186
  # `NOT_HANDLED` for anything outside this slice's own verified
246
187
  # scope — the caller (`WordGate#method_missing`) falls through
247
- # to its own existing "not yet implemented" refusal, UNCHANGED,
188
+ # to its own existing "not yet implemented" refusal, unchanged,
248
189
  # the exact same message a word not yet migrated to any slice
249
190
  # already gets today. A real `ArgumentError` — matching what a
250
191
  # hand-written method of the same arity would raise — for a
251
- # call whose SHAPE the grammar admits but whose actual argument
192
+ # call whose shape the grammar admits but whose actual argument
252
193
  # count doesn't match; never a silent wrong answer.
194
+ #
195
+ # @param builder [Bluebook::DSL::WordGate] the builder instance the word was called on
196
+ # @param context [String] the grammar context the word was admitted under
197
+ # @param word [String] the DSL word being executed
198
+ # @param args [Array<Object>] the call's positional arguments
199
+ # @param kwargs [Hash{Symbol => Object}] the call's keyword arguments
200
+ # @param block [Proc, nil] the block given to the word, if any
201
+ # @param rows [Hash{Symbol => Array<Hash{Symbol => String}>}] the grammar table, with
202
+ # `:keywords` and `:arguments` row lists
203
+ # @return [Object] what executing the word produced — the target method's own result
204
+ # for a `calls:` row, otherwise the stored value or the list appended to — or
205
+ # `NOT_HANDLED` when the word is outside the verified scope
206
+ # @raise [ArgumentError] if the word is table-executed and the positional argument count
207
+ # does not match what its row admits
208
+ # @raise [Bluebook::DSL::Malformed] if a single-fill row names a `blank_message:` and the
209
+ # value is blank, or the `calls:` target itself refuses the declaration
210
+ # @raise [Runtime::WiringError] if `shape_for` names a kind this method has no arm for
253
211
  def try(builder, context, word, args, kwargs, block, rows)
254
212
  shape = shape_for(context, word, rows)
255
213
  return NOT_HANDLED unless shape
@@ -274,7 +232,9 @@ module Hecks
274
232
  end
275
233
  end
276
234
 
277
- # THE ONE PLACE ROW SHAPE IS JUDGED returns a small Hash naming
235
+ # Classifies a (context, word) pair into the table-executable shape its rows describe.
236
+ #
237
+ # The one place row shape is judged — returns a small Hash naming
278
238
  # which of the four safe shapes (context, word) is, or `nil` if
279
239
  # it falls outside this slice's own verified scope. No argument
280
240
  # values are read here; this only ever looks at the table.
@@ -284,6 +244,14 @@ module Hecks
284
244
  # checks before it. Splitting per shape would mean re-deriving or
285
245
  # threading those locals across method boundaries for a
286
246
  # classification that is only ever read top-to-bottom once, here.
247
+ #
248
+ # @param context [String] the grammar context to look the word up under
249
+ # @param word [String] the DSL word; retired rows never match
250
+ # @param rows [Hash{Symbol => Array<Hash{Symbol => String}>}] the grammar table, with
251
+ # `:keywords` and `:arguments` row lists
252
+ # @return [Hash{Symbol => Object}, nil] `:kind` is `:calls_through` (with `:calls`, the
253
+ # target method name), `:opens_block` or `:zero_arg` (with `:keyword`, the row), or
254
+ # `:single_fill` (with `:fills` and `:argument`); nil when the word is out of scope
287
255
  # rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
288
256
  def shape_for(context, word, rows)
289
257
  keyword = rows[:keywords].find { |k| k[:context] == context && k[:word] == word && k[:status] != "retired" }
@@ -309,19 +277,44 @@ module Hecks
309
277
  { kind: :single_fill, fills: fills, argument: arg }
310
278
  end
311
279
 
280
+ # Forwards a word's whole call to the builder method its row's `calls:` column names.
281
+ #
312
282
  # `keyword[:calls]` names a real Ruby method whose whole call —
313
283
  # every positional, every kwarg, the block, all of it — forwards
314
- # here UNCHANGED. No argument-shape interpretation at all,
284
+ # here unchanged. No argument-shape interpretation at all,
315
285
  # deliberately: the target method (`AttributeCollector#
316
286
  # attribute_impl`, etc.) already does its own, real, hand-
317
287
  # written argument handling; this is a pure, transparent `send`,
318
288
  # the lowest-risk possible shape for a word whose own logic is
319
289
  # too complex to re-derive from the table (type-quoting refusal,
320
290
  # closed-set synthesis, pattern validation, ...).
291
+ #
292
+ # @param builder [Bluebook::DSL::WordGate] the builder instance to send the call to
293
+ # @param calls [String, Symbol] the target method's name, such as `"attribute_impl"`
294
+ # @param args [Array<Object>] positional arguments, forwarded unchanged
295
+ # @param kwargs [Hash{Symbol => Object}] keyword arguments, forwarded unchanged
296
+ # @param block [Proc, nil] the block, forwarded unchanged
297
+ # @return [Object] whatever the target method returns
298
+ # @raise [Bluebook::DSL::Malformed] if the target method refuses the declaration
321
299
  def try_calls_through(builder, calls, args, kwargs, block)
322
300
  builder.send(calls, *args, **kwargs, &block)
323
301
  end
324
302
 
303
+ # Builds a child construct from a block-opening word and appends it to the builder's list.
304
+ #
305
+ # @param builder [Bluebook::DSL::WordGate] the builder whose list receives the child
306
+ # @param keyword [Hash{Symbol => String}] the word's Keyword row; `:opens` names the
307
+ # child builder class without its `Builder` suffix, and the pair of `:context` and
308
+ # `:word` must be a `SAFE_OPENS_BLOCK` key
309
+ # @param args [Array<Object>] the call's positional arguments; exactly one, the child's
310
+ # name
311
+ # @param kwargs [Hash{Symbol => Object}] the call's keyword arguments
312
+ # @param block [Proc, nil] the child's body, evaluated against the child builder
313
+ # @return [Array<Object>, Object] the builder's list with the built child appended, or
314
+ # `NOT_HANDLED` when any keyword argument was given
315
+ # @raise [ArgumentError] if the call does not carry exactly one positional argument
316
+ # @raise [KeyError] if the row's context and word are not in `SAFE_OPENS_BLOCK`
317
+ # @raise [Bluebook::DSL::Malformed] if the child builder refuses its own body
325
318
  def try_opens_block(builder, keyword, args, kwargs, block)
326
319
  return NOT_HANDLED unless kwargs.empty?
327
320
 
@@ -337,6 +330,15 @@ module Hecks
337
330
  list << child
338
331
  end
339
332
 
333
+ # Stores a zero-argument word's value into the instance variable its row's `fills:` names.
334
+ #
335
+ # @param builder [Bluebook::DSL::WordGate] the builder whose instance variable is set
336
+ # @param keyword [Hash{Symbol => String}] the word's Keyword row, read for `:context`,
337
+ # `:fills` and `:word`
338
+ # @param args [Array<Object>] the call's positional arguments, which must be empty
339
+ # @return [Symbol, true] the stored value: the word itself as a Symbol when sibling words
340
+ # share the same `fills:` target (`core`/`generic`/`supporting`), otherwise `true`
341
+ # @raise [ArgumentError] if any positional argument was given
340
342
  def try_zero_arg(builder, keyword, args)
341
343
  raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 0)" unless args.empty?
342
344
 
@@ -349,6 +351,20 @@ module Hecks
349
351
  builder.instance_variable_set(:"@#{keyword[:fills]}", value)
350
352
  end
351
353
 
354
+ # Coerces a word's one positional argument and stores it, appending when the target
355
+ # instance variable already holds an Array and assigning otherwise.
356
+ #
357
+ # @param builder [Bluebook::DSL::WordGate] the builder whose instance variable is filled
358
+ # @param fills [String] the instance variable's name, without the `@`
359
+ # @param arg [Hash{Symbol => String}] the word's single Argument row, read for `:kind`,
360
+ # `:coerce` and `:blank_message`
361
+ # @param args [Array<Object>] the call's positional arguments; exactly one
362
+ # @param kwargs [Hash{Symbol => Object}] the call's keyword arguments
363
+ # @return [Object] the stored value, or the Array it was appended to, or `NOT_HANDLED`
364
+ # when any keyword argument was given
365
+ # @raise [ArgumentError] if the call does not carry exactly one positional argument
366
+ # @raise [Bluebook::DSL::Malformed] if the row names a `blank_message:` and the coerced
367
+ # value is blank
352
368
  def try_single_fill(builder, fills, arg, args, kwargs)
353
369
  return NOT_HANDLED unless kwargs.empty?
354
370