hecks 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (373) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hecks/adapters/driven/claude_code.rb +72 -7
  3. data/lib/hecks/adapters/driven/d1.rb +187 -23
  4. data/lib/hecks/adapters/driven/folder.rb +83 -10
  5. data/lib/hecks/adapters/driven/google_authentication.rb +33 -12
  6. data/lib/hecks/adapters/driven/governance_authorization.rb +87 -18
  7. data/lib/hecks/adapters/driven/heki/journal.rb +13 -4
  8. data/lib/hecks/adapters/driven/heki/saga_store.rb +56 -10
  9. data/lib/hecks/adapters/driven/heki/snapshot.rb +1 -1
  10. data/lib/hecks/adapters/driven/heki.rb +106 -9
  11. data/lib/hecks/adapters/driven/identity_registry.rb +12 -2
  12. data/lib/hecks/adapters/driven/in_memory_ordering.rb +25 -3
  13. data/lib/hecks/adapters/driven/in_process_key_vault.adapter +3 -0
  14. data/lib/hecks/adapters/driven/in_process_key_vault.rb +53 -0
  15. data/lib/hecks/adapters/driven/lambda/client.rb +67 -14
  16. data/lib/hecks/adapters/driven/lambda.rb +82 -35
  17. data/lib/hecks/adapters/driven/local_storage.rb +83 -10
  18. data/lib/hecks/adapters/driven/memory.rb +205 -9
  19. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +21 -1
  20. data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
  21. data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
  22. data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
  23. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
  24. data/lib/hecks/adapters/driven/postgres.rb +175 -28
  25. data/lib/hecks/adapters/driven/prism.rb +50 -11
  26. data/lib/hecks/adapters/driven/secure_random_identity.rb +3 -0
  27. data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
  28. data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
  29. data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
  30. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
  31. data/lib/hecks/adapters/driven/sqlite.rb +181 -21
  32. data/lib/hecks/adapters/driven/system_clock.rb +3 -0
  33. data/lib/hecks/adapters/driven/tenant_provisioner.adapter +3 -0
  34. data/lib/hecks/adapters/driven/tenant_provisioner.rb +66 -0
  35. data/lib/hecks/adapters/driven.rb +6 -4
  36. data/lib/hecks/adapters/driving/github_webhook.rb +31 -18
  37. data/lib/hecks/behaviors/dsl.rb +60 -2
  38. data/lib/hecks/behaviors/expectations.rb +190 -29
  39. data/lib/hecks/behaviors/ir.rb +12 -1
  40. data/lib/hecks/behaviors/rspec.rb +9 -1
  41. data/lib/hecks/behaviors/runner.rb +21 -2
  42. data/lib/hecks/behaviors.rb +9 -1
  43. data/lib/hecks/bluebook/aggregate.rb +43 -13
  44. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +17 -10
  45. data/lib/hecks/bluebook/assembly/build.rb +26 -5
  46. data/lib/hecks/bluebook/assembly/contract.rb +98 -23
  47. data/lib/hecks/bluebook/assembly/contracts.rb +59 -52
  48. data/lib/hecks/bluebook/assembly/marks.rb +159 -30
  49. data/lib/hecks/bluebook/assembly/specializer.rb +38 -21
  50. data/lib/hecks/bluebook/assembly.rb +32 -14
  51. data/lib/hecks/bluebook/attribute.rb +26 -12
  52. data/lib/hecks/bluebook/behaviour/aggregate.rb +43 -11
  53. data/lib/hecks/bluebook/behaviour/attribute.rb +18 -5
  54. data/lib/hecks/bluebook/behaviour/chapter.rb +76 -5
  55. data/lib/hecks/bluebook/behaviour/command.rb +55 -25
  56. data/lib/hecks/bluebook/behaviour/domain_port.rb +27 -7
  57. data/lib/hecks/bluebook/behaviour/entity.rb +20 -8
  58. data/lib/hecks/bluebook/behaviour/hexagon.rb +30 -4
  59. data/lib/hecks/bluebook/behaviour/lifecycle.rb +27 -6
  60. data/lib/hecks/bluebook/behaviour/policy.rb +42 -17
  61. data/lib/hecks/bluebook/behaviour/process_manager.rb +39 -8
  62. data/lib/hecks/bluebook/behaviour/query.rb +6 -1
  63. data/lib/hecks/bluebook/behaviour/read_model.rb +29 -8
  64. data/lib/hecks/bluebook/behaviour/traits.rb +48 -12
  65. data/lib/hecks/bluebook/behaviour/value_object.rb +21 -9
  66. data/lib/hecks/bluebook/capabilities.rb +27 -0
  67. data/lib/hecks/bluebook/chapter.rb +51 -9
  68. data/lib/hecks/bluebook/command.rb +62 -17
  69. data/lib/hecks/bluebook/domain_port.rb +34 -9
  70. data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
  71. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
  72. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +282 -123
  73. data/lib/hecks/bluebook/dsl/attribute_collector.rb +112 -75
  74. data/lib/hecks/bluebook/dsl/binding_proxy.rb +81 -2
  75. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +486 -117
  76. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +179 -47
  77. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
  78. data/lib/hecks/bluebook/dsl/command_builder.rb +284 -122
  79. data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
  80. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
  81. data/lib/hecks/bluebook/dsl/entity_builder.rb +191 -61
  82. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
  83. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +130 -30
  84. data/lib/hecks/bluebook/dsl/identity_declaration.rb +38 -21
  85. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
  86. data/lib/hecks/bluebook/dsl/policy_builder.rb +86 -36
  87. data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
  88. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
  89. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +111 -47
  90. data/lib/hecks/bluebook/dsl/query_builder.rb +37 -8
  91. data/lib/hecks/bluebook/dsl/read_model_builder.rb +127 -52
  92. data/lib/hecks/bluebook/dsl/rule_reference.rb +97 -43
  93. data/lib/hecks/bluebook/dsl/translation_builder.rb +150 -44
  94. data/lib/hecks/bluebook/dsl/value_object_builder.rb +68 -20
  95. data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
  96. data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
  97. data/lib/hecks/bluebook/entity.rb +40 -11
  98. data/lib/hecks/bluebook/expression/ast_json.rb +128 -36
  99. data/lib/hecks/bluebook/expression/ast_reader.rb +32 -3
  100. data/lib/hecks/bluebook/expression/canonical_form.rb +55 -16
  101. data/lib/hecks/bluebook/expression/evaluator.rb +221 -43
  102. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +54 -18
  103. data/lib/hecks/bluebook/expression/resolver.rb +369 -128
  104. data/lib/hecks/bluebook/hexagon.rb +35 -1
  105. data/lib/hecks/bluebook/lifecycle.rb +12 -1
  106. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +2 -1
  107. data/lib/hecks/bluebook/meta_validator/judge.rb +126 -108
  108. data/lib/hecks/bluebook/meta_validator/plan.rb +81 -46
  109. data/lib/hecks/bluebook/meta_validator/port_judge.rb +3 -2
  110. data/lib/hecks/bluebook/meta_validator/readings.rb +200 -50
  111. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +68 -41
  112. data/lib/hecks/bluebook/meta_validator/shapes.rb +166 -21
  113. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +286 -46
  114. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +11 -10
  115. data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -5
  116. data/lib/hecks/bluebook/meta_validator.rb +235 -139
  117. data/lib/hecks/bluebook/model_check.rb +434 -104
  118. data/lib/hecks/bluebook/pattern_subset.rb +32 -10
  119. data/lib/hecks/bluebook/policy.rb +15 -13
  120. data/lib/hecks/bluebook/process_manager.rb +27 -14
  121. data/lib/hecks/bluebook/project_discovery.rb +5 -0
  122. data/lib/hecks/bluebook/project_loader.rb +40 -0
  123. data/lib/hecks/bluebook/project_register.rb +50 -6
  124. data/lib/hecks/bluebook/query.rb +31 -4
  125. data/lib/hecks/bluebook/read_model.rb +35 -15
  126. data/lib/hecks/bluebook/reference.rb +26 -13
  127. data/lib/hecks/bluebook/smoke_test.rb +46 -23
  128. data/lib/hecks/bluebook/synthesizer.rb +46 -12
  129. data/lib/hecks/bluebook/translation.rb +34 -5
  130. data/lib/hecks/bluebook/value_object.rb +29 -11
  131. data/lib/hecks/bluebook.rb +5 -6
  132. data/lib/hecks/codemod.rb +138 -50
  133. data/lib/hecks/construct.rb +21 -7
  134. data/lib/hecks/corpus.rb +438 -0
  135. data/lib/hecks/deploy/bluebook/deploy.hecksagon +19 -0
  136. data/lib/hecks/doc/reference.rb +200 -31
  137. data/lib/hecks/embryonaut_bluebook.rb +38 -15
  138. data/lib/hecks/facade/cli_door.rb +69 -10
  139. data/lib/hecks/facade/cli_runner.rb +105 -24
  140. data/lib/hecks/facade/command_request.rb +23 -0
  141. data/lib/hecks/facade/handle.rb +155 -35
  142. data/lib/hecks/facade/json_door.rb +106 -25
  143. data/lib/hecks/facade/surface/aggregate_door.rb +50 -27
  144. data/lib/hecks/facade/surface/chapter.rb +26 -17
  145. data/lib/hecks/facade/surface.rb +16 -3
  146. data/lib/hecks/facade.rb +15 -4
  147. data/lib/hecks/forms/app.rb +46 -30
  148. data/lib/hecks/forms/command_form_renderer.rb +70 -9
  149. data/lib/hecks/forms/field_renderer.rb +142 -6
  150. data/lib/hecks/forms/field_shape.rb +183 -19
  151. data/lib/hecks/forms/html.rb +51 -7
  152. data/lib/hecks/forms/index_renderer.rb +14 -2
  153. data/lib/hecks/forms/page.rb +14 -0
  154. data/lib/hecks/forms/params.rb +120 -23
  155. data/lib/hecks/forms/port_argument.rb +14 -2
  156. data/lib/hecks/forms/query_form_renderer.rb +65 -2
  157. data/lib/hecks/forms/record_renderer.rb +60 -2
  158. data/lib/hecks/forms/record_table.rb +28 -1
  159. data/lib/hecks/forms/reference_options.rb +24 -0
  160. data/lib/hecks/forms/value_object_shape.rb +13 -3
  161. data/lib/hecks/forms.rb +24 -4
  162. data/lib/hecks/fqn.rb +59 -1
  163. data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
  164. data/lib/hecks/framework/bluebook/privacy.bluebook +155 -0
  165. data/lib/hecks/framework/oidc.json +15 -0
  166. data/lib/hecks/framework.rb +79 -25
  167. data/lib/hecks/freezer.rb +27 -11
  168. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +241 -106
  169. data/lib/hecks/fuzzing/combination_miner.rb +178 -0
  170. data/lib/hecks/fuzzing/concurrent_dispatch.rb +241 -45
  171. data/lib/hecks/fuzzing/coverage_campaign.rb +161 -0
  172. data/lib/hecks/fuzzing/differential.rb +192 -0
  173. data/lib/hecks/fuzzing/domain_generator.rb +871 -0
  174. data/lib/hecks/fuzzing/era_boundary.rb +68 -19
  175. data/lib/hecks/fuzzing/form_census.rb +121 -20
  176. data/lib/hecks/fuzzing/generated_domain_check.rb +171 -0
  177. data/lib/hecks/fuzzing/invalid_value_generator.rb +45 -6
  178. data/lib/hecks/fuzzing/isolated_boot.rb +137 -80
  179. data/lib/hecks/fuzzing/nondeterministic.rb +79 -0
  180. data/lib/hecks/fuzzing/persistence_parity.rb +111 -21
  181. data/lib/hecks/fuzzing/properties/corrections.rb +34 -9
  182. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +300 -51
  183. data/lib/hecks/fuzzing/properties/guards.rb +86 -42
  184. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +80 -32
  185. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +40 -35
  186. data/lib/hecks/fuzzing/properties/outbox.rb +70 -32
  187. data/lib/hecks/fuzzing/properties/querying.rb +82 -28
  188. data/lib/hecks/fuzzing/properties.rb +84 -51
  189. data/lib/hecks/fuzzing/qa_settings.rb +164 -0
  190. data/lib/hecks/fuzzing/replay.rb +241 -133
  191. data/lib/hecks/fuzzing/rotation_priority.rb +48 -28
  192. data/lib/hecks/fuzzing/rust_gap_manifest.rb +139 -0
  193. data/lib/hecks/fuzzing/self_consistency.rb +315 -137
  194. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +46 -40
  195. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +18 -11
  196. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +13 -12
  197. data/lib/hecks/fuzzing/sequence_generator/picker.rb +21 -12
  198. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +59 -32
  199. data/lib/hecks/fuzzing/sequence_generator.rb +158 -23
  200. data/lib/hecks/fuzzing/shrinker.rb +309 -0
  201. data/lib/hecks/fuzzing/structural_skips.rb +37 -130
  202. data/lib/hecks/fuzzing/sweep_depth.rb +12 -4
  203. data/lib/hecks/fuzzing/target_capabilities.rb +107 -29
  204. data/lib/hecks/fuzzing/value_generator.rb +110 -22
  205. data/lib/hecks/fuzzing.rb +5 -0
  206. data/lib/hecks/grammar/evolve.rb +188 -12
  207. data/lib/hecks/grammar.rb +53 -7
  208. data/lib/hecks/ir.rb +51 -20
  209. data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
  210. data/lib/hecks/language/bluebook/policy.bluebook +11 -1
  211. data/lib/hecks/language/bluebook/vocabulary.bluebook +348 -13
  212. data/lib/hecks/language/hecksagon/hecksagon.bluebook +11 -0
  213. data/lib/hecks/language/oidc.json +5 -0
  214. data/lib/hecks/literal.rb +41 -9
  215. data/lib/hecks/naming.rb +112 -31
  216. data/lib/hecks/ports/access_control.rb +53 -2
  217. data/lib/hecks/ports/agent/answers.rb +83 -6
  218. data/lib/hecks/ports/agent.rb +119 -35
  219. data/lib/hecks/ports/authentication.rb +44 -4
  220. data/lib/hecks/ports/authorization.rb +50 -11
  221. data/lib/hecks/ports/clock.rb +42 -23
  222. data/lib/hecks/ports/extraction.rb +16 -0
  223. data/lib/hecks/ports/identity_assignment.rb +23 -2
  224. data/lib/hecks/ports/identity_generation.rb +17 -3
  225. data/lib/hecks/ports/identity_resolution.rb +17 -1
  226. data/lib/hecks/ports/key_vault.port +6 -0
  227. data/lib/hecks/ports/key_vault.rb +58 -0
  228. data/lib/hecks/ports/loading.rb +4 -0
  229. data/lib/hecks/ports/persistence/append_only.rb +172 -8
  230. data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
  231. data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
  232. data/lib/hecks/ports/persistence/execution.rb +4 -0
  233. data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
  234. data/lib/hecks/ports/persistence/plugin.rb +42 -4
  235. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
  236. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
  237. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
  238. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
  239. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
  241. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
  242. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
  243. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
  244. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +118 -66
  245. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
  246. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +34 -5
  247. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
  248. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
  249. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
  250. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +33 -9
  251. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
  252. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +95 -6
  253. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
  254. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +314 -90
  255. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
  256. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
  257. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
  258. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +48 -8
  259. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
  260. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
  261. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
  262. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +58 -19
  263. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +96 -5
  264. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +15 -0
  265. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +9 -1
  266. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
  267. data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
  268. data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
  269. data/lib/hecks/ports/persistence/repository_factory.rb +23 -3
  270. data/lib/hecks/ports/persistence/state_codec.rb +319 -0
  271. data/lib/hecks/ports/persistence.rb +36 -1
  272. data/lib/hecks/ports/projection.rb +61 -7
  273. data/lib/hecks/ports/query/in_memory.rb +41 -8
  274. data/lib/hecks/ports/query/ordering.rb +21 -6
  275. data/lib/hecks/ports/query.rb +35 -0
  276. data/lib/hecks/ports.rb +1 -0
  277. data/lib/hecks/projections/bootstrap_table.rb +147 -0
  278. data/lib/hecks/projections/diagrams.rb +315 -79
  279. data/lib/hecks/projections/glossary/html.rb +91 -3
  280. data/lib/hecks/projections/glossary/markdown.rb +50 -3
  281. data/lib/hecks/projections/glossary/mermaid.rb +49 -1
  282. data/lib/hecks/projections/glossary/sections.rb +1 -1
  283. data/lib/hecks/projections/glossary/sentences.rb +110 -5
  284. data/lib/hecks/projections/glossary.rb +173 -31
  285. data/lib/hecks/projections/ir.rb +1 -1
  286. data/lib/hecks/projections/model/deviations.rb +62 -17
  287. data/lib/hecks/projections/model.rb +75 -21
  288. data/lib/hecks/projections/oidc.rb +45 -8
  289. data/lib/hecks/projections/parser_table.rb +53 -12
  290. data/lib/hecks/projections/reference.rb +15 -3
  291. data/lib/hecks/projections/rust_vocabulary.rb +646 -0
  292. data/lib/hecks/projections/shape.rb +10 -2
  293. data/lib/hecks/projections/statements.rb +69 -22
  294. data/lib/hecks/projections/vocabulary.rb +26 -9
  295. data/lib/hecks/projections.rb +5 -3
  296. data/lib/hecks/projector/cli_projector.rb +245 -37
  297. data/lib/hecks/projector/docs_projector.rb +154 -28
  298. data/lib/hecks/projector/exporter.rb +104 -29
  299. data/lib/hecks/projector/ir_projector.rb +7 -1
  300. data/lib/hecks/projector/narrate_projector.rb +144 -23
  301. data/lib/hecks/projector/target.rb +42 -18
  302. data/lib/hecks/projector.rb +86 -18
  303. data/lib/hecks/query_ir.rb +94 -47
  304. data/lib/hecks/query_specification/common/comparators.rb +19 -3
  305. data/lib/hecks/query_specification/common/comparison.rb +109 -27
  306. data/lib/hecks/query_specification/common/dsl.rb +65 -9
  307. data/lib/hecks/query_specification/common/null_policy.rb +61 -15
  308. data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
  309. data/lib/hecks/query_specification/common/options.rb +25 -0
  310. data/lib/hecks/query_specification/field_path.rb +69 -15
  311. data/lib/hecks/query_specification/hop_path.rb +57 -20
  312. data/lib/hecks/query_specification/read_model/specification.rb +4 -0
  313. data/lib/hecks/rendering.rb +9 -3
  314. data/lib/hecks/router/namespace_installer.rb +16 -3
  315. data/lib/hecks/router.rb +56 -1
  316. data/lib/hecks/runtime/aggregate_lock.rb +20 -11
  317. data/lib/hecks/runtime/boot_gates.rb +21 -3
  318. data/lib/hecks/runtime/caller.rb +40 -8
  319. data/lib/hecks/runtime/capability_graph.rb +13 -2
  320. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +40 -41
  321. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +45 -67
  322. data/lib/hecks/runtime/command_interpreter.rb +195 -113
  323. data/lib/hecks/runtime/command_rules/admissibility.rb +231 -80
  324. data/lib/hecks/runtime/command_rules/arithmetic.rb +154 -96
  325. data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
  326. data/lib/hecks/runtime/command_rules/emission.rb +18 -1
  327. data/lib/hecks/runtime/command_rules/references.rb +145 -55
  328. data/lib/hecks/runtime/command_rules.rb +3 -0
  329. data/lib/hecks/runtime/dependency_planning.rb +56 -11
  330. data/lib/hecks/runtime/dispatcher.rb +263 -92
  331. data/lib/hecks/runtime/entity_element.rb +304 -67
  332. data/lib/hecks/runtime/entity_interpreter.rb +149 -88
  333. data/lib/hecks/runtime/errors.rb +37 -23
  334. data/lib/hecks/runtime/event.rb +15 -10
  335. data/lib/hecks/runtime/identity.rb +91 -23
  336. data/lib/hecks/runtime/instance.rb +103 -18
  337. data/lib/hecks/runtime/interpreting.rb +24 -16
  338. data/lib/hecks/runtime/invocation.rb +358 -0
  339. data/lib/hecks/runtime/loader.rb +105 -19
  340. data/lib/hecks/runtime/outbox.rb +164 -26
  341. data/lib/hecks/runtime/policy_interpreter.rb +73 -60
  342. data/lib/hecks/runtime/port_operation_interpreter.rb +42 -19
  343. data/lib/hecks/runtime/query_interpreter.rb +93 -74
  344. data/lib/hecks/runtime/reaction_invocation.rb +73 -28
  345. data/lib/hecks/runtime/read_model_interpreter.rb +60 -44
  346. data/lib/hecks/runtime/rebuild_sweep.rb +32 -4
  347. data/lib/hecks/runtime/reference_hop.rb +48 -6
  348. data/lib/hecks/runtime/refusal_wording.rb +142 -115
  349. data/lib/hecks/runtime/registry/saga_persistence.rb +32 -21
  350. data/lib/hecks/runtime/registry/verification.rb +153 -28
  351. data/lib/hecks/runtime/registry.rb +202 -32
  352. data/lib/hecks/runtime/remote_dispatcher.rb +125 -24
  353. data/lib/hecks/runtime/routing.rb +36 -154
  354. data/lib/hecks/runtime/saga_interpreter/correlation.rb +25 -27
  355. data/lib/hecks/runtime/saga_interpreter.rb +90 -76
  356. data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
  357. data/lib/hecks/runtime/tenant_check.rb +33 -13
  358. data/lib/hecks/runtime/tenant_scope.rb +23 -5
  359. data/lib/hecks/runtime/value/admission.rb +75 -30
  360. data/lib/hecks/runtime/value/coercion.rb +555 -142
  361. data/lib/hecks/runtime/value/entity_list_coercion.rb +132 -60
  362. data/lib/hecks/runtime/value.rb +71 -21
  363. data/lib/hecks/runtime.rb +39 -7
  364. data/lib/hecks/storehouse.rb +368 -72
  365. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +130 -0
  366. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +32 -0
  367. data/lib/hecks/version.rb +3 -3
  368. data/lib/hecks/vocabulary.rb +205 -4
  369. data/lib/hecks.rb +91 -11
  370. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +19 -11
  371. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +24 -12
  372. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +38 -14
  373. metadata +28 -2
@@ -3,14 +3,14 @@ require_relative "../../forms/html"
3
3
  module Hecks
4
4
  module Projections
5
5
  module Glossary
6
- # THE PAGE, RENDERED FROM THE MARKDOWN — `html/index.html` is
6
+ # **The page, rendered from the markdown** — `html/index.html` is
7
7
  # `glossary.md` read back and dressed: a navigation rail built from
8
8
  # its `##` headings, each `###` a term entry, every ```mermaid fence
9
9
  # a diagram, every `[x](#y)` an in-page link. Nothing here reads
10
10
  # the bluebook; if the page shows it, the Markdown says it, so the
11
11
  # two cannot drift.
12
12
  #
13
- # A SUBSET RENDERER, NOT A MARKDOWN LIBRARY — the projector emits
13
+ # A subset renderer, not a markdown library — the projector emits
14
14
  # a fixed handful of constructs (`Markdown`'s own header lists
15
15
  # them), and this reads exactly those. The Gemfile keeps every
16
16
  # dependency justified in its own comment; a full Markdown engine
@@ -30,6 +30,10 @@ module Hecks
30
30
 
31
31
  module_function
32
32
 
33
+ # Renders `glossary.md`'s Markdown source as a self-contained HTML page.
34
+ #
35
+ # @param markdown [String] `glossary.md`'s own rendered Markdown source
36
+ # @return [String] the complete `html/index.html` source
33
37
  def render(markdown)
34
38
  blocks = parse(markdown)
35
39
  slugs = heading_slugs(blocks)
@@ -40,6 +44,12 @@ module Hecks
40
44
 
41
45
  # ── reading the Markdown ─────────────────────────────────────────
42
46
 
47
+ # Parses the subset of Markdown the glossary projector emits into
48
+ # structured blocks.
49
+ #
50
+ # @param markdown [String] the Markdown source to parse
51
+ # @return [Array<Block>] one block per heading, quote, list, mermaid
52
+ # fence, or paragraph, in document order
43
53
  def parse(markdown)
44
54
  lines = markdown.lines.map(&:chomp)
45
55
  blocks = []
@@ -70,6 +80,11 @@ module Hecks
70
80
 
71
81
  # The mermaid source between the opening fence at `index` and its
72
82
  # closing one, and the index just past that.
83
+ #
84
+ # @param lines [Array<String>] the document's lines
85
+ # @param index [Integer] the opening ` ```mermaid ` fence's line index
86
+ # @return [Array(Block, Integer)] the parsed `:mermaid` block, and the line
87
+ # index just past its closing fence
73
88
  def fence(lines, index)
74
89
  close = ((index + 1)...lines.size).find { |at| lines[at] == "```" } || lines.size
75
90
  [Block.new(type: :mermaid, text: lines[(index + 1)...close].join("\n")), close + 1]
@@ -77,6 +92,13 @@ module Hecks
77
92
 
78
93
  # The consecutive lines from `index` that satisfy the block, and
79
94
  # the index just past them.
95
+ #
96
+ # @param lines [Array<String>] the document's lines
97
+ # @param index [Integer] the line index to start scanning from
98
+ # @yieldparam text [String] one candidate line
99
+ # @yieldreturn [Boolean] whether that line belongs to the run
100
+ # @return [Array(Array<String>, Integer)] the consecutive matching lines, and
101
+ # the line index just past them
80
102
  def run(lines, index)
81
103
  taken = []
82
104
  while index < lines.size && yield(lines[index])
@@ -89,10 +111,14 @@ module Hecks
89
111
  # The same slugs GitHub would give these headings, in the same
90
112
  # order — so the links the Markdown carries land here too.
91
113
  #
92
- # KEYED BY THE BLOCK ITSELF, NOT ITS VALUE — a Struct compares by
114
+ # Keyed by the block itself, not its value — a Struct compares by
93
115
  # members, so two "### Open" headings in different sections would
94
116
  # otherwise be one key, and the first would answer with the
95
117
  # second's "-1" slug, leaving `#open` with nothing to land on.
118
+ #
119
+ # @param blocks [Array<Block>] every parsed block, in document order
120
+ # @return [Hash{Block => String}] each heading block, mapped to its GitHub-style
121
+ # slug, keyed by object identity
96
122
  def heading_slugs(blocks)
97
123
  seen = Hash.new(0)
98
124
  slugs = {}.compare_by_identity
@@ -106,6 +132,11 @@ module Hecks
106
132
 
107
133
  # Everything before the first `##` is the front matter; each `##`
108
134
  # opens a section that runs to the next.
135
+ #
136
+ # @param blocks [Array<Block>] every parsed block, in document order
137
+ # @return [Array<Hash{Symbol => Object}>] one Hash per section: `:heading`
138
+ # (the `Block`, or nil for the leading front matter) and `:blocks` (its
139
+ # own `Array<Block>`)
109
140
  def split_sections(blocks)
110
141
  sections = [{ heading: nil, blocks: [] }]
111
142
  blocks.each do |block|
@@ -117,6 +148,13 @@ module Hecks
117
148
 
118
149
  # ── writing the page ─────────────────────────────────────────────
119
150
 
151
+ # Renders the full HTML page shell around the navigation rail and content.
152
+ #
153
+ # @param title [String] the document's `#` heading text
154
+ # @param sections [Array<Hash{Symbol => Object}>] every `##` section, as
155
+ # `split_sections` builds (the front matter excluded by the caller)
156
+ # @param slugs [Hash{Block => String}] every heading block's own slug
157
+ # @return [String] the complete HTML page source
120
158
  def page(title, sections, slugs)
121
159
  front, *rest = sections
122
160
  <<~HTML
@@ -148,6 +186,14 @@ module Hecks
148
186
  HTML
149
187
  end
150
188
 
189
+ # Renders the navigation rail: the domain name, a search box, and one
190
+ # link per section.
191
+ #
192
+ # @param title [String] the document's `#` heading text, `"Domain — Glossary"`
193
+ # @param sections [Array<Hash{Symbol => Object}>] every `##` section (the
194
+ # front matter excluded)
195
+ # @param slugs [Hash{Block => String}] every heading block's own slug
196
+ # @return [String] the rail's HTML source
151
197
  def rail(title, sections, slugs)
152
198
  domain = title.split(" — ").first
153
199
  items = sections.map do |section|
@@ -167,6 +213,10 @@ module Hecks
167
213
  HTML
168
214
  end
169
215
 
216
+ # Renders the page's `<header>`: the title, vision, lede, and overview diagram.
217
+ #
218
+ # @param blocks [Array<Block>] the front matter's own blocks
219
+ # @return [String] the header's HTML source
170
220
  def front_matter(blocks)
171
221
  parts = ["<header>"]
172
222
  blocks.each do |block|
@@ -185,6 +235,11 @@ module Hecks
185
235
  # rules list), then its terms — each `###` opens an article that
186
236
  # runs to the next. A bold-only paragraph is the caption of
187
237
  # whatever figure or list follows it.
238
+ #
239
+ # @param section [Hash{Symbol => Object}] one `##` section, as `split_sections`
240
+ # builds
241
+ # @param slugs [Hash{Block => String}] every heading block's own slug
242
+ # @return [String] the section's `<section>` HTML source
188
243
  def section_html(section, slugs)
189
244
  heading = section[:heading]
190
245
  state = { parts: [%(<section id="#{slugs[heading]}">), "<h2>#{inline(heading.text)}</h2>"],
@@ -195,6 +250,15 @@ module Hecks
195
250
  state[:parts].join("\n")
196
251
  end
197
252
 
253
+ # Renders one block into `state[:parts]`, mutating `state` as it goes.
254
+ #
255
+ # @param block [Block] the block to render
256
+ # @param state [Hash{Symbol => Object}] the section's own render state:
257
+ # `:parts` (the growing `Array<String>` of HTML), `:caption` (a pending
258
+ # bold-only paragraph's text, or nil), `:in_terms` (whether a `###` term
259
+ # article is currently open)
260
+ # @param slugs [Hash{Block => String}] every heading block's own slug
261
+ # @return [void]
198
262
  def section_block(block, state, slugs)
199
263
  parts = state[:parts]
200
264
  case block.type
@@ -214,6 +278,13 @@ module Hecks
214
278
  end
215
279
  end
216
280
 
281
+ # Renders one paragraph, either capturing it as a pending caption (a
282
+ # bold-only line) or appending it to `state[:parts]`.
283
+ #
284
+ # @param text [String] the paragraph's own text
285
+ # @param state [Hash{Symbol => Object}] the section's own render state (see
286
+ # `section_block`); `:caption` and `:parts` may be mutated
287
+ # @return [void]
217
288
  def paragraph(text, state)
218
289
  if text.match?(/\A\*\*[^*]+\*\*\z/)
219
290
  state[:caption] = text.delete("*")
@@ -223,6 +294,11 @@ module Hecks
223
294
  end
224
295
  end
225
296
 
297
+ # Renders a mermaid block as a `<figure>`, with an optional caption.
298
+ #
299
+ # @param block [Block] the `:mermaid` block to render
300
+ # @param caption [String, nil] the figure's caption text, or nil for none
301
+ # @return [String] the `<figure>`'s HTML source
226
302
  def figure(block, caption)
227
303
  parts = ["<figure>"]
228
304
  parts << "<figcaption>#{escape(caption)}</figcaption>" if caption
@@ -232,10 +308,18 @@ module Hecks
232
308
 
233
309
  # ── inline text ──────────────────────────────────────────────────
234
310
 
311
+ # Escapes text for HTML.
312
+ #
313
+ # @param text [Object, nil] the value to escape, rendered with `to_s`
314
+ # @return [String] `text`, HTML-escaped
235
315
  def escape(text) = Forms::Escape.html(text)
236
316
 
237
317
  # Escape first, so nothing in the prose ever becomes a tag; then
238
318
  # the three inline forms the Markdown uses, on the escaped text.
319
+ #
320
+ # @param text [String] the inline text to render
321
+ # @return [String] `text`, HTML-escaped, with `[x](#y)` links, `**bold**` and
322
+ # `*italic*` spans converted to their HTML equivalents
239
323
  def inline(text)
240
324
  escape(text)
241
325
  .gsub(/\[([^\]]+)\]\(#([^)]+)\)/) { %(<a href="##{Regexp.last_match(2)}">#{Regexp.last_match(1)}</a>) }
@@ -243,6 +327,10 @@ module Hecks
243
327
  .gsub(/\*(.+?)\*/) { "<em>#{Regexp.last_match(1)}</em>" }
244
328
  end
245
329
 
330
+ # Reads one static asset file from beside this file.
331
+ #
332
+ # @param name [String] the asset's filename, such as `"page.css"`
333
+ # @return [String] the asset file's contents, read from beside this file
246
334
  def asset(name) = File.read(File.join(__dir__, name))
247
335
  end
248
336
  end
@@ -6,7 +6,7 @@ require_relative "../statements"
6
6
  module Hecks
7
7
  module Projections
8
8
  module Glossary
9
- # THE DOCUMENT ITSELF — `glossary.md`, the one source the page is
9
+ # **The document itself** — `glossary.md`, the one source the page is
10
10
  # rendered from. Written in the handful of Markdown constructs
11
11
  # GitHub renders as-is (headings, blockquotes, ```mermaid fences,
12
12
  # lists, in-page links), so the file is a complete, readable
@@ -39,14 +39,27 @@ module Hecks
39
39
 
40
40
  module_function
41
41
 
42
+ # Titles the document after its chapter.
43
+ #
44
+ # @param bluebook [Bluebook::Behaviour::Chapter] the chapter to title after
45
+ # @return [String] the document's `#` heading text
42
46
  def title(bluebook) = "#{bluebook.name} — Glossary"
43
47
 
48
+ # Renders the full `glossary.md` document.
49
+ #
50
+ # @param document [Glossary::Document] the assembled document to render
51
+ # @return [String] the complete Markdown source, ending in a newline
44
52
  def render(document)
45
53
  parts = [header(document.bluebook)]
46
54
  parts += document.sections.map { |section| section_text(section, document) }
47
55
  "#{parts.join("\n\n")}\n"
48
56
  end
49
57
 
58
+ # Renders the document's title, vision blockquote, lede, and overview map.
59
+ #
60
+ # @param bluebook [Bluebook::Behaviour::Chapter] the chapter to render a
61
+ # header for
62
+ # @return [String] the header's Markdown source
50
63
  def header(bluebook)
51
64
  parts = ["# #{title(bluebook)}"]
52
65
  parts << "> #{bluebook.vision}" if bluebook.vision
@@ -55,6 +68,13 @@ module Hecks
55
68
  parts.join("\n\n")
56
69
  end
57
70
 
71
+ # Renders one `##` section: its opening (an aggregate's, or a standing
72
+ # group's blurb), followed by every term inside it.
73
+ #
74
+ # @param section [Glossary::Section] the section to render
75
+ # @param document [Glossary::Document] the document `section` belongs to,
76
+ # for its bluebook and link index
77
+ # @return [String] the section's Markdown source
58
78
  def section_text(section, document)
59
79
  parts = ["## #{section.title}"]
60
80
  parts += section.aggregate ? opening(section.aggregate, document.bluebook) : ["> #{STANDING[section.name]}"]
@@ -62,8 +82,14 @@ module Hecks
62
82
  parts.join("\n\n")
63
83
  end
64
84
 
65
- # What an aggregate IS, what it can be, how it fits and moves,
85
+ # What an aggregate is, what it can be, how it fits and moves,
66
86
  # and what is always true of it — before a single term.
87
+ #
88
+ # @param aggregate [Bluebook::Aggregate] the aggregate to render an opening for
89
+ # @param bluebook [Bluebook::Behaviour::Chapter] the chapter `aggregate` belongs
90
+ # to, for drawing its context diagram
91
+ # @return [Array<String>] the opening's Markdown blocks, one per paragraph or
92
+ # diagram, not yet joined
67
93
  def opening(aggregate, bluebook)
68
94
  parts = []
69
95
  parts << "> #{aggregate.description}" if aggregate.description
@@ -75,13 +101,19 @@ module Hecks
75
101
  parts
76
102
  end
77
103
 
78
- # THE STATEMENTS PROJECTION'S OWN SENTENCES, SPOKEN. An invariant
104
+ # The statements projection's own sentences, spoken. An invariant
79
105
  # is the author's words and stays exactly so. A relationship
80
106
  # sentence is built mechanically from construct names ("An
81
107
  # ATMCard references an Account."), and a construct name is the
82
108
  # one thing this page never shows as an identifier — so each is
83
109
  # replaced with how it is said, whole-word, and nothing else in
84
110
  # the sentence is touched.
111
+ #
112
+ # @param aggregate [Bluebook::Aggregate] the aggregate to gather rules for
113
+ # @param bluebook [Bluebook::Behaviour::Chapter] the chapter to read every
114
+ # construct name from, for de-identifying relationship sentences
115
+ # @return [Array<String>] `aggregate`'s (and its entities') attribute and
116
+ # invariant statements, spoken and deduplicated
85
117
  def always_true(aggregate, bluebook)
86
118
  names = bluebook.aggregates.flat_map { |other| [other.hecks_name, *other.entities.map(&:hecks_name)] }
87
119
  [aggregate, *aggregate.entities].flat_map do |holder|
@@ -90,14 +122,29 @@ module Hecks
90
122
  end.uniq
91
123
  end
92
124
 
125
+ # Replaces every whole-word construct name in `sentence` with how it is said.
126
+ #
127
+ # @param sentence [String] the sentence to de-identify
128
+ # @param names [Array<String>] every construct name to replace, whole-word
129
+ # @return [String] `sentence` with each name in `names` replaced by
130
+ # `Naming.words(name)`
93
131
  def spoken(sentence, names)
94
132
  names.reduce(sentence) { |text, name| text.gsub(/\b#{Regexp.escape(name)}\b/, Naming.words(name)) }
95
133
  end
96
134
 
135
+ # Renders one term's `###` heading and its paragraphs.
136
+ #
137
+ # @param entry [Glossary::Entry] the term to render
138
+ # @param index [Glossary::Index] the document's link index
139
+ # @return [String] the term's Markdown source
97
140
  def term_text(entry, index)
98
141
  ["### #{entry.headword}", *Sentences.paragraphs(entry, index)].join("\n\n")
99
142
  end
100
143
 
144
+ # Wraps a Mermaid diagram's source in a fenced code block.
145
+ #
146
+ # @param source [String] a Mermaid diagram's own source
147
+ # @return [String] `source` wrapped in a ` ```mermaid ` fence
101
148
  def fence(source) = "```mermaid\n#{source}\n```"
102
149
  end
103
150
  end
@@ -3,7 +3,7 @@ require_relative "../../naming"
3
3
  module Hecks
4
4
  module Projections
5
5
  module Glossary
6
- # THE THREE PICTURES THE GLOSSARY DRAWS, each kept to the handful of
6
+ # The three pictures the glossary draws, each kept to the handful of
7
7
  # things that matter — Evans' "three to five objects central to the
8
8
  # issue at hand", never the whole model at once.
9
9
  #
@@ -25,6 +25,10 @@ module Hecks
25
25
  module Mermaid
26
26
  module_function
27
27
 
28
+ # Draws the whole chapter's aggregates and which points at which.
29
+ #
30
+ # @param bluebook [Bluebook::Behaviour::Chapter] the chapter to draw
31
+ # @return [String] a Mermaid `flowchart LR` source
28
32
  def map(bluebook)
29
33
  names = bluebook.aggregates.map(&:hecks_name)
30
34
  lines = ["flowchart LR"]
@@ -39,6 +43,12 @@ module Hecks
39
43
  lines.join("\n")
40
44
  end
41
45
 
46
+ # Draws one aggregate, its entities, and its neighbours.
47
+ #
48
+ # @param aggregate [Bluebook::Aggregate] the aggregate to focus on
49
+ # @param bluebook [Bluebook::Behaviour::Chapter] the chapter to find
50
+ # neighbouring aggregates in
51
+ # @return [String] a Mermaid `flowchart LR` source
42
52
  def context(aggregate, bluebook)
43
53
  focus = aggregate.hecks_name
44
54
  lines = ["flowchart LR", node(focus, focus: true)]
@@ -58,6 +68,11 @@ module Hecks
58
68
  lines.uniq.join("\n")
59
69
  end
60
70
 
71
+ # Draws the states a holder can be in and what moves it between them.
72
+ #
73
+ # @param holder [Bluebook::Aggregate, Bluebook::Entity] the holder whose
74
+ # lifecycle to draw
75
+ # @return [String] a Mermaid `stateDiagram-v2` source
61
76
  def lifecycle(holder)
62
77
  lifecycle = holder.lifecycle
63
78
  lines = ["stateDiagram-v2"]
@@ -74,15 +89,33 @@ module Hecks
74
89
 
75
90
  # ── the facts drawn ──────────────────────────────────────────────
76
91
 
92
+ # Names a holder's own reference attributes.
93
+ #
94
+ # @param holder [Bluebook::Aggregate, Bluebook::Entity] the holder to
95
+ # read reference attributes from
96
+ # @return [Array<Bluebook::Attribute>] `holder`'s own reference attributes
77
97
  def references(holder) = holder.attributes.select(&:reference?)
78
98
 
79
99
  # An entity is held as `list_of(LedgerEntry)` — the attribute
80
100
  # whose element type names one of the aggregate's own entities.
101
+ #
102
+ # @param aggregate [Bluebook::Aggregate] the aggregate to read entity
103
+ # attributes from
104
+ # @return [Array<Bluebook::Attribute>] attributes whose element type is one
105
+ # of `aggregate`'s own entities
81
106
  def entities(aggregate)
82
107
  names = aggregate.entities.map(&:hecks_name)
83
108
  aggregate.attributes.select { |attribute| !attribute.reference? && names.include?(attribute.type.to_s) }
84
109
  end
85
110
 
111
+ # Finds every other aggregate that references `aggregate`.
112
+ #
113
+ # @param aggregate [Bluebook::Aggregate] the aggregate to find pointers to
114
+ # @param bluebook [Bluebook::Behaviour::Chapter] the chapter to search other
115
+ # aggregates in
116
+ # @return [Array<Array(Bluebook::Aggregate, Bluebook::Attribute)>] every other
117
+ # aggregate's own reference attribute that targets `aggregate`, paired
118
+ # with its holder
86
119
  def pointing_at(aggregate, bluebook)
87
120
  bluebook.aggregates.reject { |other| other.equal?(aggregate) }.flat_map do |other|
88
121
  references(other).select { |attribute| attribute.type.target_name == aggregate.hecks_name }
@@ -94,13 +127,28 @@ module Hecks
94
127
 
95
128
  # A node id the page source can carry without an identifier in
96
129
  # it — `n_atm_card`, never `n_ATMCard`.
130
+ #
131
+ # @param name [String, Symbol] the construct name to derive an id from
132
+ # @return [String] a Mermaid-safe node id, such as `"n_atm_card"`
97
133
  def id(name) = "n_#{Naming.snake(name).gsub(/[^a-z0-9_]/, '_')}"
98
134
 
135
+ # Renders one Mermaid node declaration.
136
+ #
137
+ # @param name [String, Symbol] the node's construct name
138
+ # @param focus [Boolean] whether to mark this node with the `focus` CSS class
139
+ # @return [String] a Mermaid node declaration line
99
140
  def node(name, focus: false)
100
141
  line = " #{id(name)}[\"#{Naming.words(name)}\"]"
101
142
  focus ? "#{line}:::focus" : line
102
143
  end
103
144
 
145
+ # Renders one Mermaid edge declaration.
146
+ #
147
+ # @param from [String, Symbol] the source node's construct name
148
+ # @param attribute [Bluebook::Attribute] the attribute the edge is labelled after
149
+ # @param to [String, Symbol] the target node's construct name
150
+ # @return [String] a Mermaid edge declaration line, labelled with the
151
+ # attribute's spoken name
104
152
  def edge(from, attribute, to)
105
153
  " #{id(from)} -->|\"#{Naming.words(attribute.name).downcase}\"| #{id(to)}"
106
154
  end
@@ -1,7 +1,7 @@
1
1
  module Hecks
2
2
  module Projections
3
3
  module Glossary
4
- # THE THREE SECTIONS NOTHING HOMES TO ONE AGGREGATE. In their own
4
+ # The three sections nothing homes to one aggregate. In their own
5
5
  # file because `Markdown` reads them and loads before the
6
6
  # projector's own body does.
7
7
  ROLES = "Roles".freeze