hecks 2.7.0 → 2.9.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 (463) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +11 -0
  3. data/lib/hecks/adapters/driven/claude_code.rb +4 -104
  4. data/lib/hecks/adapters/driven/d1.rb +44 -237
  5. data/lib/hecks/adapters/driven/folder.rb +17 -76
  6. data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
  7. data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
  8. data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
  9. data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
  10. data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
  11. data/lib/hecks/adapters/driven/heki.rb +13 -42
  12. data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
  13. data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
  14. data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
  15. data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
  16. data/lib/hecks/adapters/driven/lambda.rb +10 -84
  17. data/lib/hecks/adapters/driven/local_storage.rb +5 -40
  18. data/lib/hecks/adapters/driven/memory.rb +18 -99
  19. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
  20. data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
  21. data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
  22. data/lib/hecks/adapters/driven/postgres/reconnect.rb +4 -30
  23. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
  24. data/lib/hecks/adapters/driven/postgres.rb +145 -134
  25. data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
  26. data/lib/hecks/adapters/driven/prism.rb +7 -30
  27. data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
  28. data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
  29. data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
  30. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
  31. data/lib/hecks/adapters/driven/sqlite.rb +128 -65
  32. data/lib/hecks/adapters/driven/tenant_provisioner.rb +15 -37
  33. data/lib/hecks/adapters/driven.rb +5 -36
  34. data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
  35. data/lib/hecks/behaviors/dsl.rb +7 -25
  36. data/lib/hecks/behaviors/expectations.rb +32 -142
  37. data/lib/hecks/behaviors/ir.rb +7 -20
  38. data/lib/hecks/behaviors/rspec.rb +6 -17
  39. data/lib/hecks/behaviors/runner.rb +10 -34
  40. data/lib/hecks/behaviors.rb +4 -8
  41. data/lib/hecks/bluebook/aggregate.rb +9 -75
  42. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
  43. data/lib/hecks/bluebook/assembly/build.rb +4 -15
  44. data/lib/hecks/bluebook/assembly/contract.rb +15 -136
  45. data/lib/hecks/bluebook/assembly/contracts.rb +54 -174
  46. data/lib/hecks/bluebook/assembly/marks.rb +31 -223
  47. data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
  48. data/lib/hecks/bluebook/assembly.rb +6 -45
  49. data/lib/hecks/bluebook/attribute.rb +12 -61
  50. data/lib/hecks/bluebook/behaviour/aggregate.rb +10 -39
  51. data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
  52. data/lib/hecks/bluebook/behaviour/chapter.rb +17 -42
  53. data/lib/hecks/bluebook/behaviour/command.rb +14 -66
  54. data/lib/hecks/bluebook/behaviour/domain_port.rb +4 -20
  55. data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
  56. data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
  57. data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
  58. data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
  59. data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
  60. data/lib/hecks/bluebook/behaviour/read_model.rb +38 -26
  61. data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
  62. data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
  63. data/lib/hecks/bluebook/capabilities.rb +17 -49
  64. data/lib/hecks/bluebook/chapter.rb +10 -48
  65. data/lib/hecks/bluebook/command.rb +23 -81
  66. data/lib/hecks/bluebook/domain_port.rb +14 -63
  67. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
  68. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
  69. data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
  70. data/lib/hecks/bluebook/dsl/binding_proxy.rb +17 -65
  71. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +86 -708
  72. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +56 -170
  73. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +1 -0
  74. data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
  75. data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
  76. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +12 -87
  77. data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
  78. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
  79. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +26 -189
  80. data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
  81. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
  82. data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
  83. data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
  84. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
  85. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
  86. data/lib/hecks/bluebook/dsl/query_builder.rb +11 -42
  87. data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
  88. data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
  89. data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
  90. data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
  91. data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
  92. data/lib/hecks/bluebook/dsl/world_builder.rb +19 -106
  93. data/lib/hecks/bluebook/entity.rb +13 -71
  94. data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
  95. data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
  96. data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
  97. data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
  98. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
  99. data/lib/hecks/bluebook/expression/resolver.rb +37 -660
  100. data/lib/hecks/bluebook/hexagon.rb +5 -28
  101. data/lib/hecks/bluebook/lifecycle.rb +5 -16
  102. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
  103. data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
  104. data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
  105. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
  106. data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
  107. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +24 -176
  108. data/lib/hecks/bluebook/meta_validator/shapes.rb +54 -268
  109. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -308
  110. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
  111. data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
  112. data/lib/hecks/bluebook/meta_validator.rb +79 -349
  113. data/lib/hecks/bluebook/model_check/client_profile.rb +10 -91
  114. data/lib/hecks/bluebook/model_check.rb +102 -600
  115. data/lib/hecks/bluebook/pattern_subset.rb +11 -69
  116. data/lib/hecks/bluebook/process_manager.rb +13 -83
  117. data/lib/hecks/bluebook/project_loader.rb +3 -39
  118. data/lib/hecks/bluebook/project_register.rb +12 -60
  119. data/lib/hecks/bluebook/query.rb +9 -48
  120. data/lib/hecks/bluebook/read_model.rb +57 -81
  121. data/lib/hecks/bluebook/reference.rb +7 -41
  122. data/lib/hecks/bluebook/smoke_test.rb +8 -98
  123. data/lib/hecks/bluebook/synthesizer.rb +13 -62
  124. data/lib/hecks/bluebook/translation.rb +26 -62
  125. data/lib/hecks/bluebook/value_object.rb +11 -36
  126. data/lib/hecks/bluebook.rb +5 -22
  127. data/lib/hecks/cache_dir.rb +84 -0
  128. data/lib/hecks/cli/document.rb +86 -0
  129. data/lib/hecks/cli/ir.rb +45 -0
  130. data/lib/hecks/cli/mcp.rb +31 -0
  131. data/lib/hecks/cli/mcp_door.rb +366 -0
  132. data/lib/hecks/cli/model_check.rb +203 -0
  133. data/lib/hecks/cli/project_cli.rb +90 -0
  134. data/lib/hecks/cli/project_diagrams.rb +36 -0
  135. data/lib/hecks/cli/run.rb +173 -0
  136. data/lib/hecks/cli/smoke_test.rb +45 -0
  137. data/lib/hecks/cli/stores.rb +53 -0
  138. data/lib/hecks/cli.rb +160 -0
  139. data/lib/hecks/construct.rb +8 -34
  140. data/lib/hecks/deploy/bluebook/deploy.bluebook +33 -142
  141. data/lib/hecks/deploy/bluebook/deploy.hecksagon +2 -9
  142. data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
  143. data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
  144. data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
  145. data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
  146. data/lib/hecks/embryonaut_bluebook.rb +4 -71
  147. data/lib/hecks/facade/cli_door.rb +24 -106
  148. data/lib/hecks/facade/cli_runner.rb +28 -172
  149. data/lib/hecks/facade/command_request.rb +13 -33
  150. data/lib/hecks/facade/handle.rb +34 -121
  151. data/lib/hecks/facade/json_door.rb +31 -146
  152. data/lib/hecks/facade/surface/aggregate_door.rb +39 -104
  153. data/lib/hecks/facade/surface/chapter.rb +10 -54
  154. data/lib/hecks/facade/surface.rb +8 -23
  155. data/lib/hecks/facade.rb +10 -25
  156. data/lib/hecks/forms/app.rb +15 -70
  157. data/lib/hecks/forms/command_form_renderer.rb +10 -29
  158. data/lib/hecks/forms/field_renderer.rb +17 -156
  159. data/lib/hecks/forms/field_shape.rb +30 -222
  160. data/lib/hecks/forms/html.rb +12 -47
  161. data/lib/hecks/forms/index_renderer.rb +1 -4
  162. data/lib/hecks/forms/page.rb +3 -9
  163. data/lib/hecks/forms/params.rb +14 -60
  164. data/lib/hecks/forms/port_argument.rb +2 -19
  165. data/lib/hecks/forms/query_form_renderer.rb +4 -79
  166. data/lib/hecks/forms/record_renderer.rb +8 -75
  167. data/lib/hecks/forms/record_table.rb +7 -50
  168. data/lib/hecks/forms/reference_options.rb +3 -30
  169. data/lib/hecks/forms/value_object_shape.rb +8 -35
  170. data/lib/hecks/forms.rb +5 -33
  171. data/lib/hecks/fqn.rb +5 -12
  172. data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
  173. data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
  174. data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
  175. data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
  176. data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
  177. data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
  178. data/lib/hecks/framework.rb +11 -80
  179. data/lib/hecks/freezer.rb +5 -39
  180. data/lib/hecks/grammar/expression.bluebook +15 -40
  181. data/lib/hecks/grammar/translation.bluebook +3 -6
  182. data/lib/hecks/grammar.rb +16 -41
  183. data/lib/hecks/ir.rb +14 -83
  184. data/lib/hecks/language/adapter.bluebook +2 -7
  185. data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
  186. data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
  187. data/lib/hecks/language/bluebook/bluebook.bluebook +15 -83
  188. data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
  189. data/lib/hecks/language/bluebook/command.bluebook +27 -144
  190. data/lib/hecks/language/bluebook/entity.bluebook +24 -97
  191. data/lib/hecks/language/bluebook/policy.bluebook +16 -67
  192. data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
  193. data/lib/hecks/language/bluebook/projection.bluebook +126 -60
  194. data/lib/hecks/language/bluebook/query.bluebook +12 -43
  195. data/lib/hecks/language/bluebook/shape.bluebook +23 -73
  196. data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
  197. data/lib/hecks/language/bluebook/vocabulary.bluebook +98 -197
  198. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
  199. data/lib/hecks/language/hecksagon/domain_port.bluebook +4 -19
  200. data/lib/hecks/language/hecksagon/hecksagon.bluebook +6 -25
  201. data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
  202. data/lib/hecks/language/oidc.json +35 -0
  203. data/lib/hecks/language/port.bluebook +4 -17
  204. data/lib/hecks/language/translation/translation.bluebook +3 -9
  205. data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
  206. data/lib/hecks/language/world/wiring.bluebook +1 -3
  207. data/lib/hecks/language/world/world.bluebook +5 -7
  208. data/lib/hecks/literal.rb +8 -50
  209. data/lib/hecks/mcp_door_scope.rb +95 -0
  210. data/lib/hecks/mcp_stdio_guard.rb +4 -41
  211. data/lib/hecks/naming.rb +29 -137
  212. data/lib/hecks/ports/access_control.rb +7 -23
  213. data/lib/hecks/ports/agent/answers.rb +5 -23
  214. data/lib/hecks/ports/agent.rb +47 -172
  215. data/lib/hecks/ports/authentication.rb +12 -39
  216. data/lib/hecks/ports/authorization.rb +16 -43
  217. data/lib/hecks/ports/clock.rb +5 -45
  218. data/lib/hecks/ports/extraction.rb +7 -12
  219. data/lib/hecks/ports/identity_assignment.rb +8 -29
  220. data/lib/hecks/ports/identity_generation.rb +6 -29
  221. data/lib/hecks/ports/identity_resolution.rb +2 -10
  222. data/lib/hecks/ports/key_vault.rb +9 -45
  223. data/lib/hecks/ports/persistence/append_only.rb +62 -65
  224. data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
  225. data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
  226. data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
  227. data/lib/hecks/ports/persistence/plugin.rb +13 -42
  228. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +38 -141
  229. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
  230. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +16 -84
  231. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +7 -26
  232. data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +3 -22
  233. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
  234. data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
  235. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
  236. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
  237. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
  238. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
  239. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
  241. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +18 -75
  242. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
  243. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
  244. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
  245. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
  246. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
  247. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +14 -115
  248. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
  249. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +127 -554
  250. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
  251. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
  252. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
  253. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
  254. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
  255. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
  256. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +9 -25
  257. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +22 -122
  258. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
  259. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
  260. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
  261. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
  262. data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
  263. data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
  264. data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
  265. data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
  266. data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
  267. data/lib/hecks/ports/persistence/state_codec.rb +23 -103
  268. data/lib/hecks/ports/persistence.rb +7 -14
  269. data/lib/hecks/ports/projection.rb +42 -84
  270. data/lib/hecks/ports/query/in_memory.rb +10 -58
  271. data/lib/hecks/ports/query/ordering.rb +11 -32
  272. data/lib/hecks/ports/query.rb +14 -37
  273. data/lib/hecks/ports.rb +2 -8
  274. data/lib/hecks/projections/bootstrap_table.rb +11 -43
  275. data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
  276. data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
  277. data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
  278. data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
  279. data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
  280. data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
  281. data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
  282. data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
  283. data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
  284. data/lib/hecks/projections/deploy/fargate.rb +35 -202
  285. data/lib/hecks/projections/deploy/lambda.rb +151 -679
  286. data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
  287. data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
  288. data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
  289. data/lib/hecks/projections/deploy/preview/script.rb +2 -14
  290. data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
  291. data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
  292. data/lib/hecks/projections/deploy/preview/template.rb +2 -58
  293. data/lib/hecks/projections/deploy/preview.rb +2 -67
  294. data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
  295. data/lib/hecks/projections/deploy/scripts.rb +4 -57
  296. data/lib/hecks/projections/deploy/shared.rb +47 -146
  297. data/lib/hecks/projections/deploy/smoke.rb +4 -61
  298. data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
  299. data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
  300. data/lib/hecks/projections/deploy/template_diff.rb +5 -57
  301. data/lib/hecks/projections/diagrams.rb +20 -582
  302. data/lib/hecks/projections/glossary/html.rb +14 -130
  303. data/lib/hecks/projections/glossary/markdown.rb +8 -69
  304. data/lib/hecks/projections/glossary/mermaid.rb +9 -66
  305. data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
  306. data/lib/hecks/projections/glossary/sentences.rb +14 -159
  307. data/lib/hecks/projections/glossary.rb +30 -222
  308. data/lib/hecks/projections/ir.rb +3 -10
  309. data/lib/hecks/projections/model/deviations.rb +15 -42
  310. data/lib/hecks/projections/model.rb +12 -51
  311. data/lib/hecks/projections/oidc.rb +12 -56
  312. data/lib/hecks/projections/parser_table.rb +9 -28
  313. data/lib/hecks/projections/reference.rb +9 -16
  314. data/lib/hecks/projections/rust_vocabulary.rb +12 -250
  315. data/lib/hecks/projections/shape.rb +3 -29
  316. data/lib/hecks/projections/statements.rb +7 -86
  317. data/lib/hecks/projections/vocabulary.rb +6 -22
  318. data/lib/hecks/projections.rb +2 -16
  319. data/lib/hecks/projector/cli_projector.rb +60 -375
  320. data/lib/hecks/projector/docs_projector.rb +10 -201
  321. data/lib/hecks/projector/exporter.rb +46 -138
  322. data/lib/hecks/projector/ir_projector.rb +2 -9
  323. data/lib/hecks/projector/narrate_projector.rb +15 -189
  324. data/lib/hecks/projector/target.rb +13 -76
  325. data/lib/hecks/projector.rb +30 -121
  326. data/lib/hecks/query_specification/common/comparators.rb +5 -26
  327. data/lib/hecks/query_specification/common/comparison.rb +35 -143
  328. data/lib/hecks/query_specification/common/dsl.rb +8 -24
  329. data/lib/hecks/query_specification/common/null_policy.rb +20 -70
  330. data/lib/hecks/query_specification/common/options.rb +2 -6
  331. data/lib/hecks/query_specification/common/where_clause.rb +2 -10
  332. data/lib/hecks/query_specification/field_path.rb +37 -77
  333. data/lib/hecks/query_specification/hop_path.rb +12 -76
  334. data/lib/hecks/release/gem_pin.rb +2 -26
  335. data/lib/hecks/release/runner/ci_publisher.rb +93 -0
  336. data/lib/hecks/release/runner/commands.rb +66 -0
  337. data/lib/hecks/release/runner/console.rb +52 -0
  338. data/lib/hecks/release/runner/gem_publisher.rb +43 -0
  339. data/lib/hecks/release/runner/git.rb +48 -0
  340. data/lib/hecks/release/runner/npm_publisher.rb +75 -0
  341. data/lib/hecks/release/runner/preflight.rb +104 -0
  342. data/lib/hecks/release/runner/published.rb +55 -0
  343. data/lib/hecks/release/runner/tagger.rb +80 -0
  344. data/lib/hecks/release/runner.rb +215 -0
  345. data/lib/hecks/rendering.rb +4 -26
  346. data/lib/hecks/router/namespace_installer.rb +12 -36
  347. data/lib/hecks/router.rb +4 -8
  348. data/lib/hecks/runtime/aggregate_lock.rb +8 -33
  349. data/lib/hecks/runtime/boot_gates.rb +3 -18
  350. data/lib/hecks/runtime/caller.rb +19 -59
  351. data/lib/hecks/runtime/capability_graph.rb +5 -21
  352. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
  353. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +23 -160
  354. data/lib/hecks/runtime/command_interpreter.rb +125 -307
  355. data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
  356. data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
  357. data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
  358. data/lib/hecks/runtime/command_rules/emission.rb +8 -21
  359. data/lib/hecks/runtime/command_rules/references.rb +23 -202
  360. data/lib/hecks/runtime/dependency_planning.rb +30 -102
  361. data/lib/hecks/runtime/dispatcher.rb +82 -241
  362. data/lib/hecks/runtime/entity_element.rb +40 -462
  363. data/lib/hecks/runtime/entity_interpreter.rb +65 -220
  364. data/lib/hecks/runtime/errors.rb +32 -115
  365. data/lib/hecks/runtime/event.rb +3 -25
  366. data/lib/hecks/runtime/identity.rb +18 -154
  367. data/lib/hecks/runtime/instance.rb +18 -150
  368. data/lib/hecks/runtime/interpreting.rb +11 -70
  369. data/lib/hecks/runtime/invocation.rb +28 -164
  370. data/lib/hecks/runtime/loader.rb +48 -186
  371. data/lib/hecks/runtime/outbox.rb +38 -261
  372. data/lib/hecks/runtime/policy_interpreter.rb +38 -200
  373. data/lib/hecks/runtime/port_operation_interpreter.rb +26 -87
  374. data/lib/hecks/runtime/query_interpreter.rb +45 -187
  375. data/lib/hecks/runtime/reaction_invocation.rb +36 -138
  376. data/lib/hecks/runtime/read_model_interpreter.rb +139 -208
  377. data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
  378. data/lib/hecks/runtime/reference_hop.rb +8 -81
  379. data/lib/hecks/runtime/refusal_wording.rb +8 -89
  380. data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
  381. data/lib/hecks/runtime/registry/verification.rb +52 -225
  382. data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
  383. data/lib/hecks/runtime/registry.rb +103 -244
  384. data/lib/hecks/runtime/remote_dispatcher.rb +37 -152
  385. data/lib/hecks/runtime/routing.rb +4 -15
  386. data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
  387. data/lib/hecks/runtime/saga_interpreter.rb +79 -263
  388. data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
  389. data/lib/hecks/runtime/tenant_check.rb +6 -68
  390. data/lib/hecks/runtime/tenant_scope.rb +3 -28
  391. data/lib/hecks/runtime/value/admission.rb +16 -67
  392. data/lib/hecks/runtime/value/coercion.rb +155 -641
  393. data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
  394. data/lib/hecks/runtime/value.rb +12 -84
  395. data/lib/hecks/runtime.rb +17 -65
  396. data/lib/hecks/storehouse.rb +146 -567
  397. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +8 -32
  398. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
  399. data/lib/hecks/vendoring/git_environment.rb +2 -8
  400. data/lib/hecks/vendoring/git_source.rb +4 -10
  401. data/lib/hecks/vendoring.rb +7 -46
  402. data/lib/hecks/version.rb +3 -14
  403. data/lib/hecks/vocabulary.rb +5 -0
  404. data/lib/hecks.rb +32 -82
  405. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
  406. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
  407. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
  408. metadata +30 -59
  409. data/lib/hecks/bench/cli.rb +0 -74
  410. data/lib/hecks/bench/environment.rb +0 -100
  411. data/lib/hecks/bench/postgres_probe.rb +0 -41
  412. data/lib/hecks/bench/report.rb +0 -116
  413. data/lib/hecks/bench/ruby_runner.rb +0 -151
  414. data/lib/hecks/bench/run.rb +0 -55
  415. data/lib/hecks/bench/rust_runner.rb +0 -165
  416. data/lib/hecks/bench/stats.rb +0 -75
  417. data/lib/hecks/bench/suite.rb +0 -172
  418. data/lib/hecks/bench/workload.rb +0 -137
  419. data/lib/hecks/bench.rb +0 -28
  420. data/lib/hecks/codemod.rb +0 -443
  421. data/lib/hecks/corpus.rb +0 -479
  422. data/lib/hecks/doc/reference.rb +0 -585
  423. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -684
  424. data/lib/hecks/fuzzing/combination_miner.rb +0 -178
  425. data/lib/hecks/fuzzing/concurrent_dispatch.rb +0 -469
  426. data/lib/hecks/fuzzing/coverage_campaign.rb +0 -161
  427. data/lib/hecks/fuzzing/differential.rb +0 -192
  428. data/lib/hecks/fuzzing/domain_generator.rb +0 -871
  429. data/lib/hecks/fuzzing/era_boundary.rb +0 -154
  430. data/lib/hecks/fuzzing/form_census.rb +0 -285
  431. data/lib/hecks/fuzzing/generated_domain_check.rb +0 -171
  432. data/lib/hecks/fuzzing/invalid_value_generator.rb +0 -125
  433. data/lib/hecks/fuzzing/isolated_boot.rb +0 -658
  434. data/lib/hecks/fuzzing/nondeterministic.rb +0 -79
  435. data/lib/hecks/fuzzing/persistence_parity.rb +0 -253
  436. data/lib/hecks/fuzzing/properties/corrections.rb +0 -125
  437. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +0 -688
  438. data/lib/hecks/fuzzing/properties/guards.rb +0 -398
  439. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +0 -399
  440. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +0 -137
  441. data/lib/hecks/fuzzing/properties/outbox.rb +0 -180
  442. data/lib/hecks/fuzzing/properties/querying.rb +0 -260
  443. data/lib/hecks/fuzzing/properties.rb +0 -267
  444. data/lib/hecks/fuzzing/qa_settings.rb +0 -164
  445. data/lib/hecks/fuzzing/replay.rb +0 -930
  446. data/lib/hecks/fuzzing/rotation_priority.rb +0 -114
  447. data/lib/hecks/fuzzing/rust_gap_manifest.rb +0 -139
  448. data/lib/hecks/fuzzing/self_consistency.rb +0 -825
  449. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +0 -532
  450. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +0 -171
  451. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +0 -127
  452. data/lib/hecks/fuzzing/sequence_generator/picker.rb +0 -116
  453. data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +0 -138
  454. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +0 -344
  455. data/lib/hecks/fuzzing/sequence_generator.rb +0 -311
  456. data/lib/hecks/fuzzing/shrinker.rb +0 -309
  457. data/lib/hecks/fuzzing/structural_skips.rb +0 -53
  458. data/lib/hecks/fuzzing/sweep_depth.rb +0 -61
  459. data/lib/hecks/fuzzing/target_capabilities.rb +0 -255
  460. data/lib/hecks/fuzzing/value_generator.rb +0 -340
  461. data/lib/hecks/fuzzing.rb +0 -23
  462. data/lib/hecks/grammar/evolve.rb +0 -524
  463. data/lib/hecks/query_ir.rb +0 -482
@@ -2,27 +2,12 @@ require_relative "../runtime/registry"
2
2
 
3
3
  module Hecks
4
4
  module Ports
5
- # The OIDC handshake itself — building the URL a browser goes to,
6
- # and turning the code a provider sends back into a Hash of verified
7
- # claims (`issuer`, `subject`, `email`, `email_verified`). Resolved the same way every
8
- # other port here resolves its adapter: one adapter registry-wide
9
- # answers this, not a per-aggregate binding, since a domain has no
10
- # reason to want a different sign-in provider per aggregate.
11
- #
12
- # The other half of "who is this" — what a verified pair means to
13
- # this app, whether it resolves to an existing Identity — is
14
- # `Ports::IdentityResolution`'s job, not this one's. This port only
15
- # ever talks to the external provider; it never touches the
16
- # registry's own Identity/Governance data (it takes `registry`
17
- # purely to resolve which adapter answers it, same as every port
18
- # here already does).
5
+ # The OIDC handshake: builds the provider URL and turns the returned code into verified claims.
6
+ # One adapter registry-wide answers it; it never touches the registry's Identity data.
19
7
  module Authentication
20
8
  NAME = "authentication".freeze
21
9
 
22
- # A sign-in that could not be verified — a state mismatch, a failed code
23
- # exchange, a missing or invalid ID token. An adapter wraps its own
24
- # libraries' errors into this, so a caller rescues one class whichever
25
- # provider answers the port.
10
+ # A sign-in that could not be verified (state mismatch, failed code exchange, bad ID token).
26
11
  class ValidationError < StandardError
27
12
  end
28
13
 
@@ -30,17 +15,13 @@ module Hecks
30
15
 
31
16
  # Builds the provider URL that starts a sign-in, with the CSRF state minted for it.
32
17
  #
33
- # The caller keeps the state (in a session, typically) and hands it back to `verify`
34
- # as `expected_state`.
18
+ # The caller keeps the state and hands it back to `verify` as `expected_state`.
35
19
  #
36
20
  # @param registry [Runtime::Registry] the booted registry to resolve the adapter against
37
21
  # @return [Array(String, String)] the URL to send the browser to, then the fresh
38
22
  # `state` value embedded in it
39
23
  # @raise [Runtime::WiringError] if this port does not resolve to exactly one adapter
40
- # (see `adapter`)
41
24
  # @raise [KeyError] if the adapter's required configuration is unset
42
- # (`GoogleAuthentication` reads `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET` and
43
- # `GOOGLE_REDIRECT_URI` with no defaults)
44
25
  def authorization_url(registry)
45
26
  adapter(registry).authorization_url
46
27
  end
@@ -50,28 +31,20 @@ module Hecks
50
31
  # @param registry [Runtime::Registry] the booted registry to resolve the adapter against
51
32
  # @param code [String] the authorization code the provider sent back
52
33
  # @param state [String, nil] the state parameter the provider returned; nil is refused
53
- # @param expected_state [String, nil] the state `authorization_url` handed out before
54
- # the redirect; nil is refused
55
- # @return [Hash{Symbol => Object}] the verified claims: `issuer:` and `subject:`
56
- # (String), `email:` (String, or nil if the token carries none) and
57
- # `email_verified:` (Boolean) — never the raw token
58
- # @raise [Ports::Authentication::ValidationError] if either state is nil or the two
59
- # differ, the code exchange fails, the response has no ID token, or the ID token
60
- # does not verify
34
+ # @param expected_state [String, nil] the state `authorization_url` returned; nil is refused
35
+ # @return [Hash{Symbol => Object}] the verified claims: `issuer:`, `subject:`, `email:`
36
+ # (nil if the token carries none) and `email_verified:` -- never the raw token
37
+ # @raise [Ports::Authentication::ValidationError] if a state is nil or they differ, the
38
+ # code exchange fails, or the ID token is missing or does not verify
61
39
  # @raise [Runtime::WiringError] if this port does not resolve to exactly one adapter
62
- # (see `adapter`)
63
- # @raise [KeyError] if the adapter's required configuration is unset, or a verified
64
- # token lacks an `iss` or `sub` claim
40
+ # @raise [KeyError] if required configuration is unset, or the token lacks `iss`/`sub`
65
41
  def verify(registry, code:, state:, expected_state:)
66
42
  adapter(registry).verify(code: code, state: state, expected_state: expected_state)
67
43
  end
68
44
 
69
- # Finds the single adapter bound to this port, refusing an ambiguous wiring.
45
+ # Finds the single adapter bound to this port.
70
46
  #
71
- # @param registry [Runtime::Registry] the booted registry to search
72
- # @return [Module] the adapter module or class implementing this port
73
- # @raise [Runtime::WiringError] if no adapter, or more than one, implements this port,
74
- # or the one that does has no Ruby implementation under `Hecks::Adapters`
47
+ # @raise [Runtime::WiringError] if none, or more than one, implements this port
75
48
  def adapter(registry)
76
49
  implementations = registry.adapters.values.select { |a| a.port == NAME }
77
50
 
@@ -2,28 +2,8 @@ require_relative "../runtime/registry"
2
2
 
3
3
  module Hecks
4
4
  module Ports
5
- # Two yes/no questions and one value an application asks before
6
- # binding a caller — resolved the same way `Ports::IdentityGeneration`
7
- # resolves its own adapter: one adapter registry-wide answers this
8
- # port, not a per-aggregate binding, since a domain has no reason to
9
- # want a different authorization source per aggregate. What answers
10
- # it is deliberately not named here — the governance-backed adapter
11
- # is one implementation, not the only possible one, the same way
12
- # `SequentialIdentity` and `SecureRandomIdentity` are two
13
- # implementations of `identity_generation`.
14
- #
15
- # A caller decides what to do with the answer — dispatch under that
16
- # role, refuse, log, prefer it over some other fallback value — this
17
- # only answers the question asked. Nothing here binds a
18
- # `Runtime::Caller`.
19
- #
20
- # `CommandRules::Authorization#refuse_role_mismatch` calls `holds_role?`
21
- # directly, once a caller binds an `actor_id` and the command's domain
22
- # has Governance attached (see that rule's own header). `spec/
23
- # act_as_spec.rb` remains the precedent for the other shape — two
24
- # separate registries, queried directly by name — for whenever
25
- # Governance is not in the same boot as the caller; this port is the
26
- # same questions asked through one adapter when it is.
5
+ # Role questions an application asks before binding a caller. One adapter registry-wide
6
+ # answers them; it only answers, and never binds a `Runtime::Caller`.
27
7
  module Authorization
28
8
  NAME = "authorization".freeze
29
9
 
@@ -35,15 +15,11 @@ module Hecks
35
15
  # @param actor_id [String] the actor whose grants are checked
36
16
  # @param role [String, Symbol] the role name to look for, compared as a String
37
17
  # @param as_of [Integer, nil] Unix epoch seconds (from `Ports::Clock.now`); a grant whose
38
- # `starts_at` is later, or does not parse as a time, does not count. nil skips the
39
- # `starts_at` check entirely
40
- # @param scope [String, nil] the scope the caller acts in; only a grant made for that
41
- # scope counts. nil skips the scope check, so a grant in any scope counts
42
- # @return [Boolean] true if at least one live grant of `role` to `actor_id` passes the
43
- # `as_of` and `scope` checks
44
- # @raise [Runtime::WiringError] if this port does not resolve to exactly one adapter
45
- # (see `adapter`), or the governance-backed adapter finds no single loaded chapter
46
- # providing `"authorization"`
18
+ # `starts_at` is later, or does not parse as a time, does not count. nil skips the check
19
+ # @param scope [String, nil] only a grant made for this scope counts; nil counts any scope
20
+ # @return [Boolean] true if at least one live grant of `role` to `actor_id` passes
21
+ # @raise [Runtime::WiringError] if this port does not resolve to exactly one adapter,
22
+ # or the governance-backed adapter finds no single chapter providing `"authorization"`
47
23
  def holds_role?(registry, actor_id:, role:, as_of: nil, scope: nil)
48
24
  adapter(registry).holds_role?(registry, actor_id: actor_id, role: role, as_of: as_of, scope: scope)
49
25
  end
@@ -56,32 +32,29 @@ module Hecks
56
32
  # String
57
33
  # @return [Boolean] true if a live (not ended) allowance lets `from_role` act as
58
34
  # `to_role`
59
- # @raise [Runtime::WiringError] if this port does not resolve to exactly one adapter
60
- # (see `adapter`), or the governance-backed adapter finds no single loaded chapter
61
- # providing `"authorization"`
35
+ # @raise [Runtime::WiringError] if this port does not resolve to exactly one adapter,
36
+ # or the governance-backed adapter finds no single loaded chapter providing
37
+ # `"authorization"`
62
38
  def authorized_as?(registry, from_role:, to_role:)
63
39
  adapter(registry).authorized_as?(registry, from_role: from_role, to_role: to_role)
64
40
  end
65
41
 
66
- # Looks up the role an actor holds right now, rather than checking a guessed one.
42
+ # Looks up the role an actor holds right now.
67
43
  #
68
44
  # @param registry [Runtime::Registry] the booted registry to resolve the adapter against
69
45
  # @param actor_id [String] the actor to look up
70
46
  # @return [String, nil] the role name of the actor's first live (not ended) grant, or
71
47
  # nil if it has none; the caller supplies any fallback
72
- # @raise [Runtime::WiringError] if this port does not resolve to exactly one adapter
73
- # (see `adapter`), or the governance-backed adapter finds no single loaded chapter
74
- # providing `"authorization"`
48
+ # @raise [Runtime::WiringError] if this port does not resolve to exactly one adapter,
49
+ # or the governance-backed adapter finds no single loaded chapter providing
50
+ # `"authorization"`
75
51
  def live_role_for(registry, actor_id:)
76
52
  adapter(registry).live_role_for(registry, actor_id: actor_id)
77
53
  end
78
54
 
79
- # Finds the single adapter bound to this port, refusing an ambiguous wiring.
55
+ # Finds the single adapter bound to this port.
80
56
  #
81
- # @param registry [Runtime::Registry] the booted registry to search
82
- # @return [Module] the adapter module or class implementing this port
83
- # @raise [Runtime::WiringError] if no adapter, or more than one, implements this port,
84
- # or the one that does has no Ruby implementation under `Hecks::Adapters`
57
+ # @raise [Runtime::WiringError] if none, or more than one, implements this port
85
58
  def adapter(registry)
86
59
  implementations = registry.adapters.values.select { |a| a.port == NAME }
87
60
 
@@ -2,42 +2,8 @@ require_relative "../runtime/registry"
2
2
 
3
3
  module Hecks
4
4
  module Ports
5
- # What time it is — the one fact a domain cannot derive and must not invent.
6
- #
7
- # Resolved exactly the way `Ports::IdentityGeneration` resolves its own
8
- # adapter: one adapter registry-wide implements this, not a per-aggregate
9
- # binding, because two aggregates in one running app have no real reason to
10
- # disagree about the time.
11
- #
12
- # ## Why a port and not `Time.now`
13
- #
14
- # A staleness rule — "another agent may take this claim after fifteen
15
- # minutes" — is untestable against the real clock: a spec for it would
16
- # either sleep for fifteen minutes or never run at all. Bound to a fixed
17
- # adapter, the same rule is three lines. That is the whole argument, and
18
- # it is the same one `SequentialIdentity` makes next door.
19
- #
20
- # ## Why a predicate still can't ask the time
21
- #
22
- # The expression sublanguage has no clock and should not: a `given` that
23
- # read the time would evaluate differently on two runs over the same
24
- # record, and every replay, audit and fuzz oracle in this repository
25
- # assumes it does not. So `now` remains an argument the predicate merely
26
- # reads, and this port is what lets a caller stop typing it — the door
27
- # fills it in, the value is baked into the dispatch, and the recorded
28
- # step carries the concrete number forever after.
29
- #
30
- # ## Why the runtime never calls this directly
31
- #
32
- # `IdentityGeneration`'s own note works through the replay question for
33
- # a minted uuid and lands on "the value gets baked into the caller's
34
- # args at the first live dispatch". A clock consulted inside the
35
- # interpreter would not have that property: a recorded corpus step
36
- # replayed tomorrow would silently get tomorrow's time, and the
37
- # fuzzer's oracle and the adapter-agreement gate both compare runs of
38
- # exactly that shape. So the filling happens at the door, where a
39
- # human or an agent is typing, and never on the dispatch path a replay
40
- # uses.
5
+ # What time it is, as one registry-wide adapter answers it.
6
+ # Predicates cannot read the clock (replays must be deterministic), so the door fills `now`.
41
7
  module Clock
42
8
  NAME = "clock".freeze
43
9
 
@@ -45,23 +11,17 @@ module Hecks
45
11
 
46
12
  # Reads the current time from the bound clock adapter.
47
13
  #
48
- # Seconds, as an integer, because that is what the sublanguage can do
49
- # arithmetic on. `claimed_at.value + window.value <= now.value` is
50
- # addition and comparison — the only two things it has — and a Time
14
+ # Integer seconds, because the expression sublanguage can add and compare but a Time
51
15
  # object supports neither.
52
16
  #
53
17
  # @param registry [Runtime::Registry] the booted registry to resolve the adapter against
54
18
  # @return [Integer] the current time, in Unix epoch seconds
55
19
  # @raise [Runtime::WiringError] if this port does not resolve to exactly one adapter
56
- # (see `adapter`)
57
20
  def now(registry) = adapter(registry).now
58
21
 
59
- # Finds the single adapter bound to this port, refusing an ambiguous wiring.
22
+ # Finds the single adapter bound to this port.
60
23
  #
61
- # @param registry [Runtime::Registry] the booted registry to search
62
- # @return [Module] the adapter module or class implementing this port
63
- # @raise [Runtime::WiringError] if no adapter, or more than one, implements this port,
64
- # or the one that does has no Ruby implementation under `Hecks::Adapters`
24
+ # @raise [Runtime::WiringError] if none, or more than one, implements this port
65
25
  def adapter(registry)
66
26
  implementations = registry.adapters.values.select { |a| a.port == NAME }
67
27
 
@@ -2,10 +2,8 @@ require_relative "../runtime/registry"
2
2
 
3
3
  module Hecks
4
4
  module Ports
5
- # The `extraction` port: resolves whichever adapter can recover a
6
- # predicate's own source (`canonical`). Reads `Hecks.current_registry`
7
- # directly rather than taking a registry argument, since extraction only
8
- # ever happens while a bluebook is loading, never after boot.
5
+ # Resolves the adapter that recovers a predicate's own source (`canonical`).
6
+ # Reads `Hecks.current_registry`, since extraction only happens while a bluebook loads.
9
7
  module Extraction
10
8
  NAME = "extraction".freeze
11
9
 
@@ -16,19 +14,16 @@ module Hecks
16
14
  # @param block [Proc] a block written in a bluebook file, such as a `given` predicate
17
15
  # or an `identified_by` path
18
16
  # @return [String, nil] the block body's source, normalised by
19
- # `Bluebook::Expression::CanonicalForm` (whitespace collapsed, linked replacements
20
- # applied); nil if the block's file cannot be read, no block starts on its line, or
21
- # the block has an empty body
17
+ # `Bluebook::Expression::CanonicalForm`; nil if the block's file cannot be read, no
18
+ # block starts on its line, or the block has an empty body
22
19
  # @raise [Runtime::WiringError] if called outside a boot, or this port does not resolve
23
- # to exactly one adapter (see `adapter`)
20
+ # to exactly one adapter
24
21
  def canonical(block) = adapter.canonical(block)
25
22
 
26
23
  # Finds the single adapter bound to this port in the registry currently booting.
27
24
  #
28
- # @return [Module] the adapter module or class implementing this port
29
- # @raise [Runtime::WiringError] if `Hecks.current_registry` is nil (resolved outside a
30
- # boot), if no adapter, or more than one, implements this port, or if the one that
31
- # does has no Ruby implementation under `Hecks::Adapters`
25
+ # @raise [Runtime::WiringError] if called outside a boot, or none, or more than one,
26
+ # implements this port
32
27
  def adapter
33
28
  registry = Hecks.current_registry
34
29
  unless registry
@@ -2,21 +2,8 @@ require_relative "../runtime/registry"
2
2
 
3
3
  module Hecks
4
4
  module Ports
5
- # Which value a creating command's own identity field gets, when
6
- # neither a slug-from-another-field nor a sequence-with-prefix
7
- # mechanically answers it — a driving app's own console, say,
8
- # falls back to this when a collection's identity strategy names
9
- # "port" rather than "slug"/"sequence" (both of those stay pure
10
- # config-driven mechanics, computed by whoever is dispatching,
11
- # never by this port).
12
- #
13
- # Pure delegation, same as every sibling port (AccessControl,
14
- # IdentityGeneration): an app's own domain declares what "port"
15
- # actually means for it — mint a real UUID via
16
- # Ports::IdentityGeneration, derive something else entirely — this
17
- # port just resolves the one adapter that domain wired and calls
18
- # it, the same "one adapter registry-wide, refuse if zero or many"
19
- # resolution every other port here already uses.
5
+ # Which value a creating command's identity field gets when its strategy names "port".
6
+ # Delegates to the one adapter the domain wired.
20
7
  module IdentityAssignment
21
8
  NAME = "identity_assignment".freeze
22
9
 
@@ -24,29 +11,21 @@ module Hecks
24
11
 
25
12
  # Asks the domain's adapter which value a creating command's identity field gets.
26
13
  #
27
- # No adapter, spec double or caller of this port ships in this repository, so every
28
- # shape below other than `registry` is adapter-defined: the port forwards it untouched.
14
+ # Every argument other than `registry` is adapter-defined and forwarded untouched.
29
15
  #
30
16
  # @param registry [Runtime::Registry] the booted registry to resolve the adapter against
31
- # @param agg_name [Object] adapter-defined, forwarded unchanged; names the aggregate
32
- # whose identity field is being assigned
33
- # @param field_name [Object] adapter-defined, forwarded unchanged; names the identity
34
- # field
35
- # @param args [Object] adapter-defined, forwarded unchanged; the creating command's own
36
- # arguments
17
+ # @param agg_name [Object] adapter-defined; names the aggregate being assigned
18
+ # @param field_name [Object] adapter-defined; names the identity field
19
+ # @param args [Object] adapter-defined; the creating command's own arguments
37
20
  # @return [Object] adapter-defined value to assign as the identity
38
21
  # @raise [Runtime::WiringError] if this port does not resolve to exactly one adapter
39
- # (see `adapter`)
40
22
  def assign(registry, agg_name:, field_name:, args:)
41
23
  adapter(registry).assign(registry, agg_name: agg_name, field_name: field_name, args: args)
42
24
  end
43
25
 
44
- # Finds the single adapter bound to this port, refusing an ambiguous wiring.
26
+ # Finds the single adapter bound to this port.
45
27
  #
46
- # @param registry [Runtime::Registry] the booted registry to search
47
- # @return [Module] the adapter module or class implementing this port
48
- # @raise [Runtime::WiringError] if no adapter, or more than one, implements this port,
49
- # or the one that does has no Ruby implementation under `Hecks::Adapters`
28
+ # @raise [Runtime::WiringError] if none, or more than one, implements this port
50
29
  def adapter(registry)
51
30
  implementations = registry.adapters.values.select { |a| a.port == NAME }
52
31
 
@@ -2,27 +2,9 @@ require_relative "../runtime/registry"
2
2
 
3
3
  module Hecks
4
4
  module Ports
5
- # A creating command with no natural key needs a value from
6
- # somewhere to be its identity — this is that somewhere. Resolved
7
- # the same way `Ports::Extraction` resolves its own adapter (one
8
- # adapter registry-wide implements this port, not a per-aggregate
9
- # binding the way persistence needs — different aggregates have no
10
- # real reason to want different id-generation strategies within
11
- # one running app).
12
- #
13
- # Replay needs no suppression here, on purpose. A UUID minted for a
14
- # creating command's identity gets baked into that step's own args
15
- # — an ordinary string value — the moment it's generated, by
16
- # whoever issues the first, live dispatch. A recorded corpus
17
- # script or a captured fuzz-replay step already holds that
18
- # concrete value; replaying it calls `dispatch` with the same
19
- # args, and this module is never consulted again, for the same
20
- # reason `SecureRandom.uuid` never runs twice for one
21
- # already-recorded step today. `Event#occurred_at`
22
- # (`command_rules/emission.rb`) is the one other "environmental
23
- # fact, not caller-supplied" this codebase has, and it's handled
24
- # the identical way: it fires on every dispatch, replay included,
25
- # and comparison simply excludes it.
5
+ # Supplies the identity for a creating command with no natural key.
6
+ # One adapter registry-wide implements it. Replay never calls it: the minted value is
7
+ # already baked into the recorded step's args.
26
8
  module IdentityGeneration
27
9
  NAME = "identity_generation".freeze
28
10
 
@@ -32,18 +14,13 @@ module Hecks
32
14
  #
33
15
  # @param registry [Runtime::Registry] the booted registry to resolve the adapter against
34
16
  # @return [String] a newly minted identity: a random UUID from `SecureRandomIdentity`,
35
- # or a decimal counter (`"1"`, `"2"`, …) from the deterministic `SequentialIdentity`
36
- # spec double — unique per adapter, not guaranteed UUID-shaped
17
+ # or a decimal counter from the deterministic `SequentialIdentity` spec double
37
18
  # @raise [Runtime::WiringError] if this port does not resolve to exactly one adapter
38
- # (see `adapter`)
39
19
  def uuid(registry) = adapter(registry).uuid
40
20
 
41
- # Finds the single adapter bound to this port, refusing an ambiguous wiring.
21
+ # Finds the single adapter bound to this port.
42
22
  #
43
- # @param registry [Runtime::Registry] the booted registry to search
44
- # @return [Module] the adapter module or class implementing this port
45
- # @raise [Runtime::WiringError] if no adapter, or more than one, implements this port,
46
- # or the one that does has no Ruby implementation under `Hecks::Adapters`
23
+ # @raise [Runtime::WiringError] if none, or more than one, implements this port
47
24
  def adapter(registry)
48
25
  implementations = registry.adapters.values.select { |a| a.port == NAME }
49
26
 
@@ -2,16 +2,8 @@ require_relative "../runtime/registry"
2
2
 
3
3
  module Hecks
4
4
  module Ports
5
- # An authenticated (issuer, subject) pair, resolved to the id of a stable
6
- # `Identity` — the other half of the same symmetry `Authorization`
7
- # already has for Governance: one adapter registry-wide answers this
8
- # port, resolved the same zero/one/many way, so an application never
9
- # has to name `Identity` directly to ask "who is this."
10
- #
11
- # Answers `nil` for a pair nothing has linked — the caller decides
12
- # what that means (refuse, prompt to register, whatever), the same
13
- # way `Authorization#holds_role?` answering `false` decides nothing
14
- # on its own.
5
+ # Resolves an authenticated (issuer, subject) pair to a stable identity id.
6
+ # One adapter registry-wide answers this port.
15
7
  module IdentityResolution
16
8
  NAME = "identity_resolution".freeze
17
9
 
@@ -2,55 +2,23 @@ require_relative "../runtime/registry"
2
2
 
3
3
  module Hecks
4
4
  module Ports
5
- # A subject's own encryption key lives here, one boundary removed from
6
- # any event or bluebook attribute — cryptoshredding depends on the key
7
- # material never being reachable except through this port's opaque
8
- # reference (see `Privacy::SubjectKey`, `lib/hecks/framework/bluebook/
9
- # privacy.bluebook`). Resolved the same way `Ports::IdentityGeneration`
10
- # resolves its own adapter: one adapter registry-wide answers this
11
- # port, not a per-aggregate binding.
5
+ # A subject's encryption key, one boundary removed from any event or
6
+ # bluebook attribute, so cryptoshredding never exposes key material.
12
7
  module KeyVault
13
8
  NAME = "key_vault".freeze
14
9
 
15
10
  module_function
16
11
 
17
- # Mints a fresh per-subject encryption key and hands back an opaque reference to it.
18
- #
19
- # @param registry [Runtime::Registry] the booted registry to resolve the adapter against
20
- # @param subject_id [String] the data subject the key is being issued for
21
- # @return [String] an opaque key reference; the key material itself never leaves the
22
- # bound adapter, and is never suitable to store on an event or a bluebook attribute
12
+ # Mints a per-subject key; the key material itself never leaves the bound adapter.
23
13
  def issue(registry, subject_id:) = adapter(registry).issue(subject_id: subject_id)
24
14
 
25
- # Irrevocably destroys a key that {#issue} already returned a reference for.
26
- #
27
- # Ciphertext produced under `key_reference` becomes permanently unrecoverable the
28
- # moment this returns — the mechanism a right-to-erasure request satisfies without
29
- # rewriting or deleting any event.
30
- #
31
- # @param registry [Runtime::Registry] the booted registry to resolve the adapter against
32
- # @param key_reference [String] the opaque reference {#issue} returned
33
- # @return [Boolean] true when a live key was destroyed; false when this reference was
34
- # already destroyed, or was never issued
15
+ # Irrevocably destroys a key; ciphertext under it becomes unrecoverable at once —
16
+ # how a right-to-erasure request is satisfied without rewriting or deleting events.
35
17
  def destroy(registry, key_reference:) = adapter(registry).destroy(key_reference: key_reference)
36
18
 
37
- # Erases one subject: destroys their key in the vault, then durably records that it
38
- # happened — in that fixed order, so a caller cannot dispatch `Shred` before the key
39
- # is actually gone the way calling {#destroy} and `dispatch_flat` separately would
40
- # allow. `Privacy::SubjectKey.Shred`'s own lifecycle guard (`from: "active"`) still
41
- # refuses a raw double-dispatch; this is what closes the gap one level up, where the
42
- # danger isn't a duplicate `Shred` but `Shred` running *before* {#destroy} does.
43
- #
44
- # Idempotent: a subject with no live `SubjectKey` record, or one already shredded,
45
- # is left alone and answered `false` — a retried erasure request never re-destroys
46
- # an already-gone key or double-dispatches `Shred`.
47
- #
48
- # @param dispatcher [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted
49
- # dispatcher both the lookup query and the `Shred` dispatch run through
50
- # @param domain [String] the subject's own domain FQN, e.g. `"Site::Registration"`
51
- # @param subject_id [String] the data subject to erase
52
- # @return [Boolean] true when a live key was found and shredded by this call; false
53
- # when no `SubjectKey` record exists for this subject, or it was already shredded
19
+ # Destroys the subject's key, then dispatches Shred, in that fixed order — never the
20
+ # reverse, so Shred cannot be dispatched before the key is actually gone. Idempotent:
21
+ # a subject with no live key, or one already shredded, is left alone and returns false.
54
22
  def shred!(dispatcher, domain:, subject_id:) # rubocop:disable Naming/PredicateMethod
55
23
  record = dispatcher.query("Privacy::SubjectKey.ForSubject", domain: domain, subject_id: subject_id).first
56
24
  return false unless record
@@ -61,11 +29,7 @@ module Hecks
61
29
  true
62
30
  end
63
31
 
64
- # Finds the single adapter bound to this port, refusing an ambiguous wiring.
65
- #
66
- # @param registry [Runtime::Registry] the booted registry to search
67
- # @return [Module] the adapter module or class implementing this port
68
- # @raise [Runtime::WiringError] if no adapter, or more than one, implements this port
32
+ # Refuses an ambiguous wiring rather than choosing an adapter arbitrarily.
69
33
  def adapter(registry)
70
34
  implementations = registry.adapters.values.select { |a| a.port == NAME }
71
35