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
@@ -1,25 +1,29 @@
1
1
  require_relative "runtime/registry"
2
2
 
3
3
  module Hecks
4
- # THE REGISTRY OF FRAMEWORK BLUEBOOKS — Governance, Identity, and
4
+ # **The registry of framework bluebooks** — Governance, Identity, and
5
5
  # whatever lands beside them in `lib/hecks/framework/bluebook/`:
6
6
  # domain-agnostic chapters no single example owns, shared by reference
7
7
  # rather than copied into every domain that wants one.
8
8
  #
9
- # UNDER `lib/`, not a top-level sibling — a real consumer (embryonaut)
10
- # vendors ONLY `lib/` (`bin/vendor-hecks`, and this gem's own
9
+ # ## Where it lives
10
+ #
11
+ # Under `lib/`, not a top-level sibling — a real consumer (embryonaut)
12
+ # vendors only `lib/` (`bin/vendor-hecks`, and this gem's own
11
13
  # `hecks.gemspec`, both glob `lib/**/*`), so a `framework/`
12
14
  # sitting beside `lib/` rather than inside it packaged and vendored
13
15
  # cleanly but left `uses_framework` finding nothing at runtime —
14
16
  # `Framework::ROOT` pointed at a directory that simply never shipped.
15
- # Nothing in THIS repo's own suite caught it, since every spec here
17
+ # Nothing in this repo's own suite caught it, since every spec here
16
18
  # reads the working tree directly; only vendoring into a real consumer
17
19
  # did. Same reasoning `lib/hecks/language/bluebook/` already
18
20
  # settled for the self-hosted grammar's own `.bluebook` files —
19
21
  # non-Ruby data a module owns lives inside `lib/` with the code that
20
22
  # reads it, not beside it.
21
23
  #
22
- # DERIVED FROM THE DIRECTORY, not hand-listed a second time — the same
24
+ # ## Derived, not hand-listed
25
+ #
26
+ # Derived from the directory, not hand-listed a second time — the same
23
27
  # reasoning `Assembly::CONTRACTS` gives for reading the language's own
24
28
  # fields from a table instead of restating them: a member added here
25
29
  # and forgotten in a list would be a member `uses_framework` could
@@ -27,55 +31,105 @@ module Hecks
27
31
  # stale in silence. `spec/corpus_spec.rb`'s own `FRAMEWORK_MEMBERS`
28
32
  # glob is the precedent this mirrors.
29
33
  #
30
- # NAMED BY FILE STEM, capitalized — `governance.bluebook` holds
34
+ # ## Naming
35
+ #
36
+ # Named by file stem, capitalized — `governance.bluebook` holds
31
37
  # `Hecks.bluebook "Governance"`, the same one-to-one spelling every
32
38
  # other chapter in this codebase already keeps between its filename
33
39
  # and its declared name.
34
40
  module Framework
35
- ROOT = File.expand_path("framework/bluebook", __dir__).freeze
36
-
37
- def self.members
38
- Dir.glob(File.join(ROOT, "*.bluebook")).to_h do |path|
39
- [Naming.pascal(File.basename(path, ".bluebook")), path]
40
- end
41
- end
42
-
43
- # LOADED FROM ITS OWN REAL PATH, always — never a copy. A domain
41
+ # Loaded from its own real path, always — never a copy. A domain
44
42
  # booted through `Fuzzing::IsolatedBoot`'s tmp-directory copy still
45
- # reaches the SAME `framework/bluebook/governance.bluebook` this
43
+ # reaches the same `framework/bluebook/governance.bluebook` this
46
44
  # constant points at, because `uses_framework` runs `Kernel.load`
47
45
  # against `ROOT`, not against anything inside the copied domain
48
46
  # directory — there is nothing here for a relocated copy to break,
49
47
  # the way a symlink carried along with the copy would.
50
48
  #
51
- # ONLY THE BLUEBOOK — a framework member's own `.hecksagon`, if it
52
- # has one, is NOT auto-loaded. Persistence is a WIRING decision, the
49
+ # Only the bluebook — a framework member's own `.hecksagon`, if it
50
+ # has one, is not auto-loaded. Persistence is a wiring decision, the
53
51
  # same as any other aggregate's, and belongs to whoever is doing the
54
52
  # deploying, not to a default baked into the framework member
55
53
  # itself: a consuming app needs `Governance::RoleAssignment` durable
56
54
  # (Postgres, say), and a framework member hard-coding Memory for its
57
- # own specs would silently make that decision FOR every app that
58
- # attaches it. The consuming app declares its OWN, SEPARATE
55
+ # own specs would silently make that decision for every app that
56
+ # attaches it. The consuming app declares its own, separate
59
57
  # `Hecks.hecksagon "Governance" do ... end` block for that — not
60
58
  # binds folded into its own hecksagon, which would build but never
61
59
  # resolve: `Ports::Persistence::BindingPolicy.resolve` looks up
62
- # `registry.hecksagon` by the AGGREGATE's own domain name, not the
60
+ # `registry.hecksagon` by the aggregate's own domain name, not the
63
61
  # domain doing the binding, the one invariant this runtime holds
64
62
  # everywhere else too. See `examples/banking/bluebook/banking.hecksagon`
65
63
  # for the pattern — a real `.hecksagon` file can hold more than one
66
64
  # `Hecks.hecksagon` call, one per domain it wires.
67
- # IDEMPOTENT, PER REGISTRY — `uses_framework` is now called more than
68
- # once for the SAME member within a single boot (S8: a domain
65
+ ROOT = File.expand_path("framework/bluebook", __dir__).freeze
66
+
67
+ # Every framework member available to attach, by declared name.
68
+ #
69
+ # @return [Hash{String => String}] each member's capitalized bluebook name,
70
+ # mapped to the absolute path of its `.bluebook` file
71
+ def self.members
72
+ Dir.glob(File.join(ROOT, "*.bluebook")).to_h do |path|
73
+ [Naming.pascal(File.basename(path, ".bluebook")), path]
74
+ end
75
+ end
76
+
77
+ # Every member whose own bluebook declares `provides capability` —
78
+ # read off the member's real IR (each loaded into a scratch registry,
79
+ # never the caller's), not off its name. Used where a check needs to
80
+ # say which member would satisfy it (`refuse_ungoverned_roles!`'s own
81
+ # suggestion, `Fuzzing::TargetCapabilities`).
82
+ #
83
+ # @param capability [String, Symbol] the capability name to look for
84
+ # @return [Array<String>] the names of every framework member that provides it,
85
+ # sorted
86
+ def self.providers_of(capability)
87
+ members.keys.select { |name| chapter(name).provides?(capability) }.sort
88
+ end
89
+
90
+ # One member's chapter, built in isolation.
91
+ #
92
+ # @param name [String, Symbol] the member's name, such as `"Governance"`
93
+ # @return [Bluebook::Chapter] the member's chapter, loaded into a scratch registry
94
+ # @raise [Runtime::WiringError] if no framework member has that name
95
+ def self.chapter(name)
96
+ path = members.fetch(name.to_s) do
97
+ raise Runtime::WiringError,
98
+ "no framework member named #{name.inspect} — known: #{members.keys.sort.join(', ')}"
99
+ end
100
+
101
+ lib = File.expand_path("..", __dir__)
102
+ registry = Runtime::Registry.new
103
+ Hecks.with_registry(registry) do
104
+ # The same four a chapter needs to build at all (a predicate's
105
+ # source is recovered through the extraction port) — the seed
106
+ # `Grammar#grammar_chapters` and `bin/model_check` use.
107
+ Kernel.load(File.join(lib, "hecks/ports/persistence.port"))
108
+ Kernel.load(File.join(lib, "hecks/ports/extraction.port"))
109
+ Kernel.load(File.join(lib, "hecks/adapters/driven/memory.adapter"))
110
+ Kernel.load(File.join(lib, "hecks/adapters/driven/prism.adapter"))
111
+ Kernel.load(path)
112
+ end
113
+ registry.bluebook(name.to_s)
114
+ end
115
+
116
+ # Idempotent, per registry — `uses_framework` is now called more than
117
+ # once for the same member within a single boot (S8: a domain
69
118
  # attaching Governance for its own role check, plus a framework
70
119
  # sibling attaching it too, e.g. `banking.hecksagon`'s Identity
71
120
  # block). `Kernel.load` always re-executes the file, unlike
72
121
  # `require`, so a second call would re-run `Hecks.bluebook
73
122
  # "Governance"` a second time — and the self-hosting meta-domain
74
123
  # records every declaration as a real dispatched command against its
75
- # own ledger, so a second `Declare` for the SAME aggregate is a real
124
+ # own ledger, so a second `Declare` for the same aggregate is a real
76
125
  # `AlreadyExists`, not a no-op. Skipped once the member's bluebook is
77
- # already registered in THIS registry — the same chapter, not merely
126
+ # already registered in this registry — the same chapter, not merely
78
127
  # a same-named one from a stale prior boot.
128
+ #
129
+ # @param name [String, Symbol] the member's name, such as `"Governance"`
130
+ # @return [Boolean, nil] true when this call loaded the member's bluebook, nil when
131
+ # the current registry already held it
132
+ # @raise [Runtime::WiringError] if no framework member has that name
79
133
  def self.load!(name)
80
134
  path = members.fetch(name.to_s) do
81
135
  raise Runtime::WiringError,
data/lib/hecks/freezer.rb CHANGED
@@ -1,30 +1,30 @@
1
1
  module Hecks
2
- # THE ONE PLACE THAT KNOWS HOW TO FREEZE A DOMAIN VALUE.
2
+ # The one place that knows how to freeze a domain value.
3
3
  #
4
4
  # Freezing here has been fixed four times in four places, each time by
5
5
  # topping the container and leaving the contents: list attributes, the
6
6
  # event log, query rows, and value objects. `.freeze` on a Hash stops a
7
- # key being added or removed and NOTHING ELSE — the String, Array or
7
+ # key being added or removed and nothing else — the String, Array or
8
8
  # Hash a field holds stays mutable, so a caller reaches straight
9
9
  # through and edits in place. Each fix looked complete and none was.
10
10
  #
11
- # WHAT SHOULD BE FROZEN, and why it is not everything:
11
+ # ## What should be frozen, and why it is not everything
12
12
  #
13
- # A VALUE OBJECT has no identity to change over. `with` already
13
+ # a value object has no identity to change over. `with` already
14
14
  # answers a new one rather than mutating, so freezing it through is
15
15
  # what it always claimed to be.
16
16
  #
17
- # AN EMITTED EVENT is a record of something that happened. A mutable
17
+ # an emitted event is a record of something that happened. A mutable
18
18
  # audit trail is not one.
19
19
  #
20
- # A QUERY ROW is an answer, not a handle — mutating one edits nobody's
20
+ # a query row is an answer, not a handle — mutating one edits nobody's
21
21
  # state and silently disagrees with the store.
22
22
  #
23
- # AN INSTANCE'S STATE is NOT frozen, deliberately: the interpreter
23
+ # an instance's state is not frozen, deliberately: the interpreter
24
24
  # builds it up across a dispatch, and a command's whole job is to
25
- # change it. Its VALUES are frozen; the holder is not.
25
+ # change it. Its values are frozen; the holder is not.
26
26
  #
27
- # A COMMAND'S ARGUMENTS are not frozen either. They arrive from
27
+ # a command's arguments are not frozen either. They arrive from
28
28
  # outside, are normalised and coerced on the way in, and the coerced
29
29
  # result is what becomes a frozen value.
30
30
  module Freezer
@@ -32,7 +32,11 @@ module Hecks
32
32
 
33
33
  # Numbers, symbols, nil and booleans are already immediate or frozen;
34
34
  # a Value froze itself when it was built. What is left is the mutable
35
- # trio, and each has to be WALKED rather than topped.
35
+ # trio, and each has to be walked rather than topped.
36
+ #
37
+ # @param held [Object] any domain value
38
+ # @return [Object] `held`, recursively frozen if it is a Hash, Array, or
39
+ # String; returned unchanged otherwise
36
40
  def deep(held)
37
41
  case held
38
42
  when Hash then held.each_value { |inner| deep(inner) }.freeze
@@ -43,13 +47,22 @@ module Hecks
43
47
  end
44
48
 
45
49
  # The question a gate asks, rather than the act. Answers false for the
46
- # FIRST thing that is reachable and mutable, which is what makes a
50
+ # first thing that is reachable and mutable, which is what makes a
47
51
  # failure message worth reading.
52
+ #
53
+ # @param held [Object] any domain value
54
+ # @return [Boolean] true if `held` and everything reachable from it is frozen
48
55
  def deeply_frozen?(held) = unfrozen_within(held).nil?
49
56
 
50
57
  # The path to the first mutable thing reachable from `held`, or nil.
51
58
  # A path rather than a boolean because "something in this event is
52
59
  # mutable" is not an actionable sentence.
60
+ #
61
+ # @param held [Object] any domain value
62
+ # @param path [Array<String>] the owner path accumulated by the recursive
63
+ # walk so far; callers pass nothing and get the default
64
+ # @return [String, nil] the dotted path (Hash keys, Array indices, or
65
+ # `"(the value itself)"`) to the first mutable value found, or nil if none
53
66
  def unfrozen_within(held, path = [])
54
67
  return (path.empty? ? "(the value itself)" : path.join(".")) unless immune?(held) || held.frozen?
55
68
 
@@ -62,6 +75,9 @@ module Hecks
62
75
  # Immediates are frozen in every Ruby that matters, but asking
63
76
  # `frozen?` of them and trusting the answer has bitten enough people
64
77
  # that it is worth being explicit.
78
+ #
79
+ # @param held [Object] any domain value
80
+ # @return [Boolean] true if `held` is nil, true, false, a Numeric, or a Symbol
65
81
  def immune?(held) = held.nil? || held == true || held == false || held.is_a?(Numeric) || held.is_a?(Symbol)
66
82
  end
67
83
  end