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
@@ -16,12 +16,17 @@ module Hecks
16
16
 
17
17
  attr_reader :root, :bluebooks, :hecksagons, :ports, :adapters, :worlds, :event_log,
18
18
  :reaction_log, :saga_log, :saga_instances, :translations, :saga_mutex,
19
- :saga_dispatch_log, :policy_dispatch_log
19
+ :saga_dispatch_log, :policy_dispatch_log, :bluebook_sources,
20
+ :pending_privacy_markings
20
21
 
22
+ # @param root [String, nil] the booting project's root directory, the base
23
+ # a shared ports/adapters root and a `.world`'s own relative paths resolve
24
+ # against; nil for a registry with no such root
21
25
  def initialize(root: nil)
22
26
  @root = root
23
27
  @bluebooks = {}
24
- @hecksagons = {}
28
+ @bluebook_sources = {}
29
+ @hecksagons = {}
25
30
  @ports = {}
26
31
  @adapters = {}
27
32
  @worlds = {}
@@ -29,8 +34,16 @@ module Hecks
29
34
  @event_log = []
30
35
  @reaction_log = []
31
36
  @saga_log = []
32
- # ADDITIVE, RUBY-ONLY — never merged into saga_log/reaction_log.
33
- # rust/src/kernel/orchestrate.rs ports THOSE two arrays' exact
37
+ # A DECLARATIVE FACT, NOT YET A DISPATCHED ONE — `AggregateDoor#
38
+ # mark_sensitive` (called from a `.hecksagon` file, the same way
39
+ # `port`/`persisted_by` already are) appends here at
40
+ # hecksagon-build time; `Runtime::Loader.boot`'s own post-dispatcher
41
+ # step turns each entry into a real `Privacy::Marking.Mark`,
42
+ # idempotently, the same "declared here, taken effect once boot
43
+ # actually has a dispatcher" shape `redrive_outbox!` already has.
44
+ @pending_privacy_markings = []
45
+ # **Additive, Ruby-only** — never merged into saga_log/reaction_log.
46
+ # rust/src/kernel/orchestrate.rs ports those two arrays' exact
34
47
  # shape byte-for-byte (spec/rust_conformance_spec.rb's own
35
48
  # equality check) — a landmine found by reading that spec before
36
49
  # touching anything, not by hitting it. These carry the raw
@@ -43,7 +56,7 @@ module Hecks
43
56
  @saga_dispatch_log = []
44
57
  @policy_dispatch_log = []
45
58
  @saga_instances = Hash.new { |h, k| h[k] = {} }
46
- # GUARDS `saga_instances`' OWN mutation+checkpoint sequence
59
+ # Guards `saga_instances`' own mutation+checkpoint sequence
47
60
  # (`SagaInterpreter`'s 4 write points, §7) — the same shape of
48
61
  # hazard this codebase's own prior audit already flagged for
49
62
  # `Dispatcher#reenter`'s reaction-depth counter (M20: a
@@ -51,7 +64,7 @@ module Hecks
51
64
  # `Thread.current`, dispatcher.rb), made meaningfully easier to
52
65
  # hit here once a persistence write sits in the same critical
53
66
  # section. Held across the in-memory
54
- # mutation AND the checkpoint write together, never across a
67
+ # mutation and the checkpoint write together, never across a
55
68
  # saga's own dispatch cascade — see `SagaInterpreter#advance_saga`'s
56
69
  # own comment for why that distinction matters (non-reentrant
57
70
  # Mutex, recursive re-entry is real).
@@ -59,18 +72,18 @@ module Hecks
59
72
  @repositories = {}
60
73
  @projection_repositories = {}
61
74
  @bluebook_builders = {}
62
- # EAGER, NOT LAZY — see `#resolved_eras`'s own comment for why. Built
75
+ # **Eager, not lazy** — see `#resolved_eras`'s own comment for why. Built
63
76
  # here rather than `@resolved_eras ||= {}` on first access so there is
64
77
  # no window, post-boot, where two concurrently dispatching threads
65
78
  # could race creating this Hash (Hecks/ThreadSharedIvarMutation; the
66
79
  # same shape of hazard `Dispatcher#reenter`'s `@reaction_depth` was
67
- # fixed for). Every WRITE into it still only ever happens at boot,
80
+ # fixed for). Every write into it still only ever happens at boot,
68
81
  # single-threaded (`EraResolver.check!`, a `:pre_verify` boot gate) —
69
82
  # this only removes the race on standing up the container itself for
70
83
  # a boot with no era-plugin domain at all, whose first touch would
71
84
  # otherwise be a live dispatch's own `RepositoryFactory.build` read.
72
85
  @resolved_eras = {}
73
- # THE SIBLING FACT `EraResolver.check!` records for an OLD checkout:
86
+ # The sibling fact `EraResolver.check!` records for an old checkout:
74
87
  # domain name -> the newest held ordinal that superseded the era this
75
88
  # boot resolved to; absent for every domain booting the current era.
76
89
  # `RepositoryFactory.build` hands it to the adapter as
@@ -79,7 +92,7 @@ module Hecks
79
92
  # half that holds even for a connection row-level security cannot
80
93
  # bite (BUG#24). Eager for exactly the reason `@resolved_eras` is.
81
94
  @superseded_eras = {}
82
- # EAGER, NOT LAZY — see `#capability_graph`'s own comment for why.
95
+ # **Eager, not lazy** — see `#capability_graph`'s own comment for why.
83
96
  # `CapabilityGraph.new` only stores the registry reference; there is
84
97
  # no reason to defer it, and doing so removes the exact same
85
98
  # first-access race `#resolved_eras` above does, while preserving the
@@ -87,10 +100,10 @@ module Hecks
87
100
  # spec.rb` already requires.
88
101
  @capability_graph = CapabilityGraph.new(self)
89
102
  # `@saga_persistence` itself is eager (see `#saga_persistence`'s own
90
- # comment) — only the PER-DOMAIN resolution inside it is genuinely
91
- # expensive and lazy, guarded by this dedicated mutex. NOT the same
103
+ # comment) — only the per-domain resolution inside it is genuinely
104
+ # expensive and lazy, guarded by this dedicated mutex. Not the same
92
105
  # mutex as `@saga_mutex`: `checkpoint` (saga_interpreter.rb) calls
93
- # `saga_persistence(domain)` from INSIDE an `@saga_mutex.synchronize`
106
+ # `saga_persistence(domain)` from inside an `@saga_mutex.synchronize`
94
107
  # block, so reusing `@saga_mutex` here would deadlock the very first
95
108
  # time a saga advanced (a `Mutex` is not reentrant — the exact
96
109
  # warning `@saga_mutex`'s own comment already gives for a different
@@ -100,23 +113,31 @@ module Hecks
100
113
  @outbox = Outbox::Relay.new(self)
101
114
  end
102
115
 
103
- # THE OUTBOX RELAY — one per registry, for its whole life (built
116
+ # **The outbox relay** — one per registry, for its whole life (built
104
117
  # here, never swapped, so no thread ever sees a different one).
105
118
  # It can enqueue from the moment the registry exists; a Dispatcher
106
119
  # attaches the interpreters that let it deliver. See
107
120
  # `Runtime::Outbox`.
108
121
  attr_reader :outbox
109
122
 
110
- # THE BUILDER STAYS OPEN FOR THE LIFE OF THIS REGISTRY, keyed by chapter
123
+ # The builder stays open for the life of this registry, keyed by chapter
111
124
  # name — see the comment on `BluebookBuilder.build`. A chapter split across
112
125
  # several files (`language/bluebook/*.bluebook`, all `Hecks.bluebook "Bluebook"`)
113
- # needs its declarations to accumulate into ONE builder rather than each
126
+ # needs its declarations to accumulate into one builder rather than each
114
127
  # file minting its own and silently discarding the one before.
128
+ #
129
+ # @param name [String, Symbol] the chapter name the builder accumulates
130
+ # declarations for
131
+ # @yield the block that mints a fresh builder, called only the first time
132
+ # `name` is asked for
133
+ # @yieldreturn [Bluebook::DSL::BluebookBuilder] a fresh builder for `name`
134
+ # @return [Bluebook::DSL::BluebookBuilder] the builder already open for
135
+ # `name`, or the block's freshly minted one on the first call
115
136
  def bluebook_builder(name)
116
137
  @bluebook_builders[name.to_s] ||= yield
117
138
  end
118
139
 
119
- # BOOT-TIME-ONLY, SINGLE-THREADED — every `add_*` below (through
140
+ # Boot-time-only, single-threaded — every `add_*` below (through
120
141
  # `add_translation`) is called exclusively from `Hecks.collect`
121
142
  # (hecks.rb), which is what `Hecks.bluebook`/`.hecksagon`/`.port`/
122
143
  # `.adapter`/`.world`/`.translation` run inside while a `.bluebook`/
@@ -130,23 +151,56 @@ module Hecks
130
151
  # registry/saga_persistence.rb) there is no concurrent caller for
131
152
  # `Hecks/ThreadSharedIvarMutation` to actually be warning about here.
132
153
  # rubocop:disable Hecks/ThreadSharedIvarMutation
154
+ # Registers a loaded chapter, keyed by its own declared name.
155
+ #
156
+ # @param item [Bluebook::Chapter] the loaded, judged chapter
157
+ # @return [Bluebook::Chapter] `item`, unchanged
133
158
  def add_bluebook(item) = @bluebooks[item.name] = item
134
159
 
135
- # MERGED, NOT REPLACED — RECOVERED, not new (see Runtime::Loader
160
+ # PROVENANCE, SIDE-CHANNEL — which real `.bluebook` file(s)
161
+ # contributed to a chapter name, never part of the exported IR (a
162
+ # boot-time loading fact, not a domain fact) and never Rust-mirrored
163
+ # (the same "additive, Ruby-only" shape `@translations` above already
164
+ # is). Legitimate accumulation (several files declaring the SAME
165
+ # chapter name on purpose — `lib/hecks/language/bluebook/*.bluebook`
166
+ # all open `Hecks.bluebook "Bluebook"`) pushes more than one path
167
+ # here too; that alone is not a problem. What this exists to let
168
+ # `refuse_cross_package_bluebook_merge!` (registry/verification.rb)
169
+ # catch is TWO UNRELATED PACKAGES accumulating into the same name by
170
+ # coincidence — a stale vendored fork's own copy of a real gem's
171
+ # chapter, still reachable on the load path, silently merging its
172
+ # aggregates into the real one via this exact accumulation mechanism.
173
+ def record_bluebook_source(name, path)
174
+ (@bluebook_sources[name.to_s] ||= []) << path
175
+ end
176
+
177
+ # Merged, not replaced — recovered, not new (see Runtime::Loader
136
178
  # .boot's own comment for the provenance). A domain's hecksagon can
137
179
  # now load in more than one block for the same domain (base file
138
180
  # plus an `environments/<name>.hecksagon` overlay), and the second
139
- # block should ADD to what the first declared, not silently
181
+ # block should add to what the first declared, not silently
140
182
  # discard it.
183
+ #
184
+ # @param item [Bluebook::Hecksagon] the declared wiring to register
185
+ # @return [void]
141
186
  def add_hecksagon(item)
142
187
  existing = @hecksagons[item.domain]
143
188
  @hecksagons[item.domain] = existing ? merge_hecksagons(existing, item) : item
144
189
  end
145
190
 
191
+ # Registers a loaded port, keyed by its own declared name.
192
+ #
193
+ # @param item [Bluebook::Port, Bluebook::DomainPort] the loaded port
194
+ # @return [Bluebook::Port, Bluebook::DomainPort] `item`, unchanged
146
195
  def add_port(item) = @ports[item.name] = item
196
+
197
+ # Registers a loaded adapter, keyed by its own declared name.
198
+ #
199
+ # @param item [Bluebook::Adapter] the loaded, judged adapter
200
+ # @return [Bluebook::Adapter] `item`, unchanged
147
201
  def add_adapter(item) = @adapters[item.name] = item
148
202
 
149
- # MERGED, NOT REPLACED — the same generalization for `World` that
203
+ # Merged, not replaced — the same generalization for `World` that
150
204
  # `add_hecksagon` above recovers for `Hecksagon`: an
151
205
  # `environments/<name>.world` overlay (or a host-owned tenancy
152
206
  # overlay world, same mechanism) can now add or override settings
@@ -156,16 +210,44 @@ module Hecks
156
210
  # bare verb key and the `"verb:adapter"` qualified key point at the
157
211
  # same resolved hash) — an overlay's key wins over the base's same
158
212
  # key; a key only the base declares survives untouched.
213
+ #
214
+ # @param item [Bluebook::World] the declared world settings to register
215
+ # @return [void]
159
216
  def add_world(item)
160
217
  existing = @worlds[item.domain]
161
218
  @worlds[item.domain] = existing ? merge_worlds(existing, item) : item
162
219
  end
163
220
 
221
+ # Registers a loaded translation.
222
+ #
223
+ # @param item [Bluebook::Translation] the loaded, judged translation
224
+ # @return [Array<Bluebook::Translation>] every translation registered so far,
225
+ # `item` last
164
226
  def add_translation(item) = @translations << item
227
+
228
+ # Declares one attribute of one domain's own aggregate sensitive — called from a
229
+ # terminal `has_<category>(readable_by:)` on a `Bluebook::DSL::AttributePath`
230
+ # (reached by chaining off a bare `Domain::Aggregate` inside a `.hecksagon` file
231
+ # being `Kernel.load`ed, or off an already-installed `AggregateDoor`), same timing
232
+ # (and same thread-safety argument, above) as `add_bluebook`/`add_port`. Recorded,
233
+ # not dispatched: `Runtime::Loader.boot`'s own `seed_privacy_markings!` turns each
234
+ # entry into a real `Privacy::Marking.Mark` once a dispatcher exists.
235
+ #
236
+ # @param domain [String] the marked attribute's own aggregate FQN, e.g.
237
+ # `"Lifeadelics::Registration"`
238
+ # @param attribute_path [String] the dotted path within that aggregate, e.g.
239
+ # `"attendee.medications"`
240
+ # @param category [String] the marking's own sensitivity category, e.g. `"phi"`
241
+ # @param readable_by [String] the Governance role a read must hold, unredacted
242
+ # @return [void]
243
+ def add_pending_privacy_marking(domain:, attribute_path:, category:, readable_by:)
244
+ @pending_privacy_markings << { domain: domain, attribute_path: attribute_path,
245
+ category: category, readable_by: readable_by }
246
+ end
165
247
  # rubocop:enable Hecks/ThreadSharedIvarMutation
166
248
 
167
249
  # {domain name => era ordinal} as resolved by the boot-time era
168
- # gate. A lineage adapter writes into ITS OWN era's partition —
250
+ # gate. A lineage adapter writes into its own era's partition —
169
251
  # which, for an old checkout booting a held-but-superseded shape,
170
252
  # is not the newest one. The Hash itself is stood up in `initialize`
171
253
  # (see that comment) — this is a plain reader, not a memoizer;
@@ -176,18 +258,73 @@ module Hecks
176
258
  # an old checkout only — see `initialize`'s own comment on it.
177
259
  attr_reader :superseded_eras
178
260
 
261
+ # Finds a loaded chapter by name.
262
+ #
263
+ # @param name [String, Symbol] the chapter's declared name
264
+ # @return [Bluebook::Chapter, nil] the chapter, or nil if none is registered
265
+ # under `name`
179
266
  def bluebook(name) = @bluebooks[name.to_s]
267
+
268
+ # Finds a domain's registered wiring by name.
269
+ #
270
+ # @param name [String, Symbol] the domain name
271
+ # @return [Bluebook::Hecksagon, nil] the domain's wiring, or nil if none is
272
+ # registered under `name`
180
273
  def hecksagon(name) = @hecksagons[name.to_s]
274
+
275
+ # Finds a domain's registered world settings by name.
276
+ #
277
+ # @param name [String, Symbol] the domain name
278
+ # @return [Bluebook::World, nil] the domain's world, or nil if none is
279
+ # registered under `name`
181
280
  def world(name) = @worlds[name.to_s]
182
281
 
282
+ # Every verb every loaded chapter declares, sorted.
283
+ #
284
+ # @return [Array<String>] every declared verb, across every loaded chapter
183
285
  def verbs = @bluebooks.values.flat_map(&:verbs).sort
184
286
 
287
+ # The chapter that answers a role check for `domain` — the domain's
288
+ # own chapter, or any framework member its hecksagon attaches, that
289
+ # declares `provides "authorization"`. Nil when none does. Replaces
290
+ # every check for the literal name "Governance": Governance is
291
+ # recognised by what it declares, and a chapter that declares the
292
+ # same thing is recognised the same way.
293
+ #
294
+ # @param domain [String, Symbol] the domain whose role checks are being resolved
295
+ # @return [Bluebook::Chapter, nil] the chapter that answers `domain`'s role
296
+ # checks, or nil if none does
297
+ def authorization_provider_for(domain)
298
+ names = [domain.to_s, *Array(hecksagon(domain)&.framework_members)]
299
+ names.filter_map { |name| bluebook(name) }
300
+ .find { |chapter| chapter.provides?(Bluebook::Capabilities::AUTHORIZATION) }
301
+ end
302
+
303
+ # Every loaded chapter declaring `provides "authorization"`.
304
+ #
305
+ # @return [Array<Bluebook::Chapter>] every loaded chapter that provides
306
+ # authorization
307
+ def authorization_providers
308
+ @bluebooks.values.select { |chapter| chapter.provides?(Bluebook::Capabilities::AUTHORIZATION) }
309
+ end
310
+
311
+ # Resolves and memoizes `aggregate`'s authoritative repository.
312
+ #
313
+ # @param domain [String, Symbol] name of the domain `aggregate` belongs to
314
+ # @param aggregate [Bluebook::Aggregate] the aggregate to resolve a repository for
315
+ # @return [Persistence::AppendOnly] repository over the aggregate's authoritative
316
+ # adapter, or over a `Memory` adapter when the domain declares no hecksagon
317
+ # @raise [Runtime::WiringError] if the aggregate has no authoritative bind, more than
318
+ # one, or a bind with a role this port does not support; or if the bound adapter is
319
+ # unknown, answers a different verb, is given a setting it does not declare, has no
320
+ # Ruby implementation, or lacks a method its port's `answers` list or the
321
+ # append-only contract (`append`, `project`, `entries`) requires
185
322
  def repository(domain, aggregate)
186
323
  @repositories[[domain.to_s, aggregate.hecks_name]] ||= Ports::Persistence.repository(self, domain, aggregate)
187
324
  end
188
325
 
189
- # EVERYTHING A DISPATCH WROTE, CLEARED; NOTHING A BOOT DECLARED,
190
- # TOUCHED. Bluebooks, hecksagons, ports, adapters, worlds and the
326
+ # Everything a dispatch wrote, cleared; nothing a boot declared,
327
+ # touched. Bluebooks, hecksagons, ports, adapters, worlds and the
191
328
  # resolved eras are what loading the files produced and stay as
192
329
  # they are; the logs, the saga instances and the repositories are
193
330
  # what running commands against them produced, and go back to
@@ -199,19 +336,21 @@ module Hecks
199
336
  # that store again, the way `Loader.boot_files` does after
200
337
  # `verify!`.
201
338
  #
202
- # What this is for: a test runner that used to boot a runtime per
203
- # test to get isolation (`Behaviors::Expectations.run_one`) — ~2s a
339
+ # What this is for: a test runner that would otherwise boot a runtime
340
+ # per test to get isolation (`Behaviors::Expectations.run_one`) — ~2s a
204
341
  # boot, 76 chess behaviours = two and a half minutes of booting the
205
342
  # same two files — can now boot once and reset between tests.
206
343
  #
207
- # SINGLE-THREADED CALLER, THE SAME REASON THE `add_*` CLUSTER ABOVE
208
- # IS EXEMPT — `Behaviors::Expectations.run_one` is this method's ONLY
344
+ # Single-threaded caller, the same reason the `add_*` cluster above
345
+ # is exempt — `Behaviors::Expectations.run_one` is this method's only
209
346
  # caller (verified by grep before writing this), and it runs one
210
347
  # test at a time: `Runner#run` maps over tests sequentially, and
211
348
  # `Behaviors.rspec`'s generated examples run under RSpec's own
212
349
  # single-threaded example loop. No production dispatch path calls
213
350
  # this at all — a live Puma worker pool never resets a registry out
214
351
  # from under itself mid-flight.
352
+ #
353
+ # @return [Runtime::Registry] self
215
354
  # rubocop:disable-next Hecks/ThreadSharedIvarMutation
216
355
  def reset_runtime_state!
217
356
  @event_log.clear
@@ -229,10 +368,21 @@ module Hecks
229
368
 
230
369
  # Built eagerly in `initialize` (see that comment) — this is a plain
231
370
  # reader, not a memoizer; `spec/runtime/capability_graph_spec.rb`
232
- # asserts the SAME instance comes back every call, which this still
371
+ # asserts the same instance comes back every call, which this still
233
372
  # gives, just without a lazy `||=` race on standing it up.
234
373
  attr_reader :capability_graph
235
374
 
375
+ # Resolves and memoizes the repository to read `aggregate` from — a caught-up
376
+ # projection when one is bound and current, otherwise the authoritative repository.
377
+ #
378
+ # @param domain [String, Symbol] name of the domain `aggregate` belongs to
379
+ # @param aggregate [Bluebook::Aggregate] the aggregate to resolve a read
380
+ # repository for
381
+ # @return [Persistence::AppendOnly] the projection repository when one is bound
382
+ # and caught up with the authoritative store; the authoritative repository
383
+ # otherwise
384
+ # @raise [Runtime::WiringError] if the authoritative or projection bind cannot
385
+ # be resolved
236
386
  def read_repository(domain, aggregate)
237
387
  key = [domain.to_s, aggregate.hecks_name]
238
388
  binding = Ports::Projection.binds_for(self, domain, aggregate).first
@@ -247,6 +397,15 @@ module Hecks
247
397
  projection_current?(projection, authoritative) ? projection : authoritative
248
398
  end
249
399
 
400
+ # Reports whether `projection`'s own journal entries and rows agree with
401
+ # `authoritative`'s, entry-for-entry.
402
+ #
403
+ # @param projection [Persistence::AppendOnly] the projection repository to check
404
+ # @param authoritative [Persistence::AppendOnly] the authoritative repository to
405
+ # check `projection` against
406
+ # @return [Boolean] true when `projection` holds the same entries and rows as
407
+ # `authoritative`, in the same order; false on any mismatch, or if comparing
408
+ # them raises
250
409
  def projection_current?(projection, authoritative)
251
410
  projected_entries = projection.entries
252
411
  source_entries = authoritative.entries
@@ -262,15 +421,21 @@ module Hecks
262
421
  false
263
422
  end
264
423
 
265
- # RECOVERED — see `add_hecksagon`'s own comment for provenance.
424
+ # Recovered — see `add_hecksagon`'s own comment for provenance.
266
425
  # Concatenates every list-shaped fact; `binds` in particular is
267
- # additive because an overlay REBINDING an aggregate (a new
426
+ # additive because an overlay rebinding an aggregate (a new
268
427
  # `persisted_by` for the same aggregate/verb) is meant to shadow
269
428
  # the base's own bind at resolution time, not erase it outright —
270
429
  # `Ports::Persistence::BindingPolicy.resolve`'s own "exactly one
271
430
  # authoritative bind" check is what actually catches a genuine
272
431
  # double-bind; this merge only concatenates, it does not itself
273
432
  # decide which of two binds for the same aggregate wins.
433
+ #
434
+ # @param base [Bluebook::Hecksagon] the domain's already-registered wiring
435
+ # @param overlay [Bluebook::Hecksagon] the newly loaded block's own wiring to
436
+ # fold in
437
+ # @return [Bluebook::Hecksagon] a new wiring with every list-shaped fact
438
+ # concatenated, `base` then `overlay`
274
439
  def merge_hecksagons(base, overlay)
275
440
  Bluebook::Hecksagon.new(
276
441
  domain: base.domain,
@@ -281,13 +446,18 @@ module Hecks
281
446
  )
282
447
  end
283
448
 
284
- # RECOVERED AND GENERALIZED — see `add_world`'s own comment. `realm`/
449
+ # Recovered and generalized — see `add_world`'s own comment. `realm`/
285
450
  # `latest` are scalars, so the overlay's value wins when present,
286
451
  # else the base's survives; `settings` is a shallow merge keyed by
287
452
  # verb (and `"verb:adapter"`) — an overlay entry for a key the base
288
- # also declares REPLACES that key's whole resolved hash (the same
453
+ # also declares replaces that key's whole resolved hash (the same
289
454
  # all-or-nothing shape `WorldBuilder#method_missing` already builds
290
455
  # each entry as), it does not deep-merge field by field within it.
456
+ #
457
+ # @param base [Bluebook::World] the domain's already-registered world
458
+ # @param overlay [Bluebook::World] the newly loaded block's own world to fold in
459
+ # @return [Bluebook::World] a new world with `overlay`'s scalars winning when
460
+ # present, and `settings` shallow-merged, `overlay`'s keys winning
291
461
  def merge_worlds(base, overlay)
292
462
  Bluebook::World.new(
293
463
  domain: base.domain,