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
@@ -1,267 +0,0 @@
1
- require "json"
2
- require_relative "../bluebook/model_check"
3
- require_relative "../bluebook/meta_validator"
4
- require_relative "../ports/query/in_memory"
5
- require_relative "../query_specification/field_path"
6
- require_relative "../runtime/value"
7
- require_relative "properties/lifecycle_and_replay"
8
- require_relative "properties/querying"
9
- require_relative "properties/guards"
10
- require_relative "properties/dispatch_and_mutations"
11
- require_relative "properties/invariants_and_aggregation"
12
- require_relative "properties/corrections"
13
- require_relative "properties/outbox"
14
-
15
- module Hecks
16
- module Fuzzing
17
- # Declared properties, checked over a replayed history — the other
18
- # half of property-based testing the fuzzer was missing: it already
19
- # generates and (with bin/fuzz's shrinker) minimizes, but checked
20
- # nothing beyond "did the interpreter crash" and "did the replay
21
- # match the claim." A property here is a fact that should hold of
22
- # any history a valid domain produces, independent of which seed
23
- # produced it.
24
- #
25
- # ## Property shape
26
- #
27
- # Each property is `name => ->(history) { true/false, or a message
28
- # string naming what broke }` — a truthy return (including `true`)
29
- # is a pass; a String return is a failure, and the string is the
30
- # finding. `history` is Replay's return shape.
31
- #
32
- # ## Feature coverage
33
- #
34
- # Every property declares the language feature it covers, in
35
- # `FEATURE_COVERAGE` below — a "Construct#attribute" pair spelled
36
- # exactly as `Bluebook::MetaValidator.grammar_registry` names it,
37
- # the same meta-domain that judges every real bluebook (see that
38
- # module's own header: "the language IS the source"). That is the
39
- # link this file exists to make real: a construct the language
40
- # declares is a fact `spec/meta_domain_coverage_spec.rb` can
41
- # enumerate on its own, without anyone re-typing the list here —
42
- # so a new attribute added to `language/bluebook/*.bluebook` shows
43
- # up in that spec as unclaimed the moment it lands, not whenever
44
- # someone remembers to go looking. Claiming a feature here is a
45
- # deliberate act (a real property, checked at least once failing
46
- # and once passing — `spec/fuzzing/properties_spec.rb`'s own
47
- # discipline) or an explicit, reasoned exemption in that same
48
- # spec — never silence.
49
- module Properties
50
- # Grouped by responsibility across properties/*.rb (lifecycle_and_
51
- # replay, querying, guards, dispatch_and_mutations, invariants_and_
52
- # aggregation) — `extend`ed here rather than `include`d, matching
53
- # `module_function` below: every property is reachable as
54
- # `Properties.foo(history)`, a module-level call with no instance in
55
- # play, the same relationship AggregateBuilder::Sealing's `include`
56
- # has to instance methods and BluebookBuilder::Validation's `extend`
57
- # has to `self.` methods — the same "one namespace, its methods,
58
- # filed across files by responsibility" pattern, `module_function`
59
- # already made this module's own particular shape.
60
- extend LifecycleAndReplay
61
- extend Querying
62
- extend Guards
63
- extend DispatchAndMutations
64
- extend DryRuns
65
- extend InvariantsAndAggregation
66
- extend Corrections
67
- extend Outbox
68
-
69
- module_function
70
-
71
- # Which language feature each property is answerable for. Not
72
- # exhaustive of everything a property's body happens to touch —
73
- # `Command#attributes`, say, is exercised by nearly every property
74
- # here without being what any of them was written to guard — but
75
- # exhaustive of the feature that would go unchecked if this
76
- # property did not exist. That is the question the coverage gate
77
- # actually asks.
78
- FEATURE_COVERAGE = {
79
- lifecycle_values_are_declared: %w[Aggregate#state_field Aggregate#state_start Aggregate#transitions
80
- Entity#state_field Entity#state_start Entity#transitions],
81
- saga_advances_follow_declared_handlers: %w[Handler#from_state Handler#to_state Handler#event_type],
82
- query_answers_match_reference: %w[Query#wheres Query#order_field Query#order_way Query#limit],
83
- paging_offset_partitions_correctly: %w[Query#options],
84
- authorize_scopes_or_refuses: %w[Query#options],
85
- guard_refusals_are_declared: %w[Command#givens Command#ensures],
86
- lifecycle_guard_and_given_violations_are_refused: %w[Command#from Aggregate#preconditions Entity#preconditions],
87
- # Dispatch#command_name/Dispatch#with_spec are not claimable
88
- # feature names — META_DOMAIN_ALL_FEATURES only walks one level
89
- # of entity nesting (`agg.entities.flat_map`, meta_domain_
90
- # coverage_spec.rb), and Dispatch sits two deep (ProcessManager
91
- # -> Handler -> Dispatch), so those strings never exist there
92
- # to claim — a pre-existing meta-domain coverage-generation gap,
93
- # found here (their old META_DOMAIN_KNOWN_GAPS entries were
94
- # themselves already-orphaned strings no completeness check ever
95
- # verified, since KNOWN_GAPS has no "never lets a gap rot" check
96
- # the way FEATURE_COVERAGE/GUARANTEED_BY_CONSTRUCTION both do).
97
- # This property still closes the real behavior both would have
98
- # named — a Dispatch's own command_name/with_spec are exactly
99
- # what dispatch_args resolves and this property checks — the
100
- # grammar just has no feature string for either one.
101
- dispatch_binding_fidelity: %w[Handler#dispatches Policy#with_spec],
102
- mutations_match_recompute: %w[Command#mutations],
103
- sagas_rehydrate_cleanly: %w[ProcessManager#states ProcessManager#correlates_by
104
- ProcessManager#starts_on ProcessManager#ends_on],
105
- fanout_dispatches_once_per_matching_row: %w[Policy#for_each Policy#where],
106
- aggregation_matches_recompute: %w[ReadModel#count ReadModel#median_field],
107
- stored_records_satisfy_declared_invariants: %w[Aggregate#invariants Entity#invariants],
108
- group_by_matches_recompute: %w[ReadModel#group_by],
109
- # A runtime door, not a grammar construct — `Dispatcher#dry_run?`
110
- # is something an application asks of a booted domain, not a
111
- # word a bluebook can declare, so there is no feature string
112
- # for it to claim. Listed (empty) rather than omitted so the
113
- # discipline this table states — every property names what it
114
- # is answerable for — has no silent exception.
115
- dry_runs_leave_no_trace: [],
116
- # Another runtime door, not a grammar construct — same reasoning
117
- # as dry_runs_leave_no_trace right above: `Runtime::Outbox` is
118
- # something a persistence adapter provides underneath a booted
119
- # domain, never a word a bluebook declares.
120
- outbox_rows_match_reactions: [],
121
- # **The `corrects` mutation's own target** — this property reads
122
- # `command.mutations.select { op == :corrects }` and asks whether
123
- # the event each one names was ever actually emitted, so the
124
- # feature it answers for is the mutation list, the same one
125
- # `mutations_match_recompute` reads for a different question.
126
- # (Not `Command#references`: that field is the dangling-reference
127
- # question no property asks yet, and it stays a named gap.)
128
- corrections_reference_an_emitted_event: %w[Command#mutations],
129
- # No feature string exists for what this one reads. It depends on
130
- # an argument's own `relationship` (which reference-typed argument
131
- # points at which aggregate) — but `Argument` is a value object,
132
- # and the meta-domain walk enumerates aggregate and entity fields
133
- # only, so no `Argument#…` name is claimable. The declaration side
134
- # it shares with queries, `authorize …, tenant:`, is
135
- # `Query#options`, already claimed by `authorize_scopes_or_refuses`;
136
- # claiming it twice would say this property covers a query
137
- # question it never asks. Listed (empty) rather than omitted, the
138
- # same discipline the two runtime doors above keep.
139
- commands_respect_tenant_scope: []
140
- }.freeze
141
-
142
- # Features a replay property could never catch violated, because the
143
- # runtime's own construction makes the violation impossible to
144
- # produce in the first place — not "untested," but unfalsifiable by
145
- # a history, the same class of guarantee this codebase already
146
- # states for identity ("nothing is minted" — command_interpreter.rb's
147
- # own header) and now generalises. Each entry names the one place in
148
- # the runtime that makes it true, universally, for every domain and
149
- # every adapter — never per-domain logic a future domain could
150
- # accidentally route around.
151
- #
152
- # The bluebook/hecksagon boundary is why this works: a bluebook
153
- # declares shape (attribute types, patterns, closed sets, VO
154
- # invariants — see docs/decisions/0009), and shape is enforced by
155
- # one coercion door every domain's every attribute passes through
156
- # (`Runtime::Value.build`, via value/coercion.rb + value/admission.rb)
157
- # regardless of which hecksagon later binds the aggregate to Memory,
158
- # Postgres, or anything else. A value that violated its own declared
159
- # pattern, invariant, or closed set could never be coerced, so it
160
- # could never be stored, so it could never appear in a replay's own
161
- # `:instances` to be caught violating it. Checking for it after the
162
- # fact would be watching for something the construction path already
163
- # made impossible.
164
- #
165
- # Not a place to hide a real gap — a feature belongs here only once
166
- # the specific enforcing code path has been read and confirmed, the
167
- # same discipline `spec/fuzzing/meta_domain_coverage_spec.rb` demands
168
- # of `KNOWN_GAPS` in the other direction. `Entity#identified_by`
169
- # illustrates the discipline: `command_interpreter.rb`'s
170
- # `AlreadyExists` refusal covers every creating aggregate command
171
- # uniformly, but nothing else on its own covers an entity's own
172
- # append — so this entry names the path that actually does,
173
- # `MutationApplier#check_entity_collision` (command_interpreter/
174
- # mutation_applier.rb), which runs unconditionally on both branches
175
- # an entity identity can arrive by (caller-supplied, or composite —
176
- # the two the auto-mint branch doesn't cover), the same way
177
- # `command_interpreter#hydrate`'s own check is unconditional for
178
- # every creating aggregate command. The collision this closes is
179
- # real, not hypothetical: SafeDepositBox's Visit/KeyIssuance entities
180
- # reproduce it, confirmed by spec/runtime/safe_deposit_box_spec.rb.
181
- GUARANTEED_BY_CONSTRUCTION = {
182
- "Aggregate#attributes" => "every field's pattern/closed-set/type passes through Value.build's one coercion " \
183
- "door (value/coercion.rb#check_patterns, value/admission.rb) before it can exist " \
184
- "— a stored value that violated its own declared shape was never producible to " \
185
- "begin with",
186
- "Aggregate#value_objects" => "the shape being coerced above — same door, same guarantee",
187
- # S17, ADR 0026 — the list `saga_advances_follow_declared_handlers`
188
- # (below) already walks to find each handler's own event_type/
189
- # from_state/to_state (the three it claims) — a property cannot
190
- # check a handler's own fields without iterating the list that
191
- # holds them, so the list itself is exercised by the same door.
192
- "ProcessManager#handlers" => "saga_advances_follow_declared_handlers already walks this list to find " \
193
- "event_type/from_state/to_state — same door, same guarantee",
194
- "Aggregate#identified_by" => "CommandInterpreter's data-driven dispatch order refuses AlreadyExists " \
195
- "(command_interpreter.rb, command.creates?) for every creating command uniformly, " \
196
- "before a duplicate id can ever be stored — collision is refused at the door, not " \
197
- "produced and later caught",
198
- "Entity#identified_by" => "EntityElement.check_entity_collision (runtime/entity_element.rb, moved there " \
199
- "BUG#145 so both call sites share it) checks Array(current) against every part " \
200
- "of the entity's own identity before an append can land — MutationApplier#" \
201
- "entity_element's aggregate-owned call (Workspace.boards, on both branches " \
202
- "identity arrives by: caller-supplied, or composite) AND EntityElement#" \
203
- "appended_to_element's entity-owned, nested-one-hop-further call (Board.cards — " \
204
- "unconditional, no auto-mint branch exists at that depth) — the same " \
205
- "AlreadyExists refusal Aggregate#identified_by gets above, one or two levels " \
206
- "down. Auto-minted (aggregate-owned) entities never reach the check " \
207
- "(current.size + 1 can't repeat unless something remove:s from the list between " \
208
- "mints, which no real domain does today — see the comment on #entity_element " \
209
- "itself)",
210
- "Command#attributes" => "command arguments are coerced through the SAME Value.build door as any other " \
211
- "attribute — an accepted dispatch's own args already passed pattern/admits/invariant checks",
212
- "Command#emits" => "CommandRules::Emission#emit iterates command.emits ITSELF to construct every " \
213
- "announced Event (command_rules/emission.rb) — there is no other path to emit, so " \
214
- "a command can never announce a name its own declaration doesn't list",
215
- "Query#attributes" => "query arguments are coerced through the same Value.build door — same guarantee as " \
216
- "Command#attributes",
217
- "Entity#attributes" => "same coercion door, one level in — an entity's own attributes are Value-typed exactly " \
218
- "the way an aggregate's are",
219
- "ValueObject#attributes" => "the shape Value.build enforces IS this declaration — the guarantee and the " \
220
- "feature are the same fact seen from two sides",
221
- "ValueObject#invariants" => "run inside the SAME coercion call (coercion.rb, before construction returns) " \
222
- "that pattern-checks a VO's fields — a VO whose invariant did not hold could not " \
223
- "finish being built",
224
- "ValueObject#rows" => "closed-set membership is checked in value/admission.rb, the second half of the same " \
225
- "one construction door",
226
- # S17, ADR 0026 — Member is a genuine entity now (nested under
227
- # ValueObject), so this reads "Member#pairs", not "Member#shape" —
228
- # the free-text, un-parsed spelling a standalone root once needed
229
- # no longer exists at all, an entity's own element is never
230
- # serialized as text. "ValueObject#members" is the same fact
231
- # "ValueObject#rows" already counts, seen from the other side — a
232
- # value object cannot declare admitted rows without a members list
233
- # to hold them, and vice versa.
234
- "ValueObject#members" => "the members list IS what ValueObject#rows counts — same door, same guarantee",
235
- "Member#pairs" => "one level into ValueObject#rows — same door"
236
- }.freeze
237
-
238
- # Runs the standard property battery over one replayed history —
239
- # everything except determinism, which needs to replay twice itself
240
- # and so takes the steps directly rather than a single history.
241
- #
242
- # @param history [Hash] a replayed history, as returned by `Fuzzing::Replay.call`
243
- # @return [Hash{Symbol => true, String}] each property name mapped to `true`
244
- # (passed) or a message string naming what broke
245
- def check(history)
246
- { lifecycle_values_are_declared: lifecycle_values_are_declared(history),
247
- saga_advances_follow_declared_handlers: saga_advances_follow_declared_handlers(history),
248
- query_answers_match_reference: query_answers_match_reference(history),
249
- guard_refusals_are_declared: guard_refusals_are_declared(history),
250
- sagas_rehydrate_cleanly: sagas_rehydrate_cleanly(history),
251
- fanout_dispatches_once_per_matching_row: fanout_dispatches_once_per_matching_row(history),
252
- aggregation_matches_recompute: aggregation_matches_recompute(history),
253
- stored_records_satisfy_declared_invariants: stored_records_satisfy_declared_invariants(history),
254
- group_by_matches_recompute: group_by_matches_recompute(history),
255
- paging_offset_partitions_correctly: paging_offset_partitions_correctly(history),
256
- lifecycle_guard_and_given_violations_are_refused: lifecycle_guard_and_given_violations_are_refused(history),
257
- authorize_scopes_or_refuses: authorize_scopes_or_refuses(history),
258
- commands_respect_tenant_scope: commands_respect_tenant_scope(history),
259
- dispatch_binding_fidelity: dispatch_binding_fidelity(history),
260
- mutations_match_recompute: mutations_match_recompute(history),
261
- dry_runs_leave_no_trace: dry_runs_leave_no_trace(history),
262
- corrections_reference_an_emitted_event: corrections_reference_an_emitted_event(history),
263
- outbox_rows_match_reactions: outbox_rows_match_reactions(history) }
264
- end
265
- end
266
- end
267
- end
@@ -1,164 +0,0 @@
1
- require "yaml"
2
-
3
- module Hecks
4
- module Fuzzing
5
- # Reads `qa/settings.yml` — the hecks_qa practice's own dials, now
6
- # data in a file rather than Ruby constant literals. The why of each
7
- # dial (what it does, who reads it) stays exactly one place: the
8
- # comments on `QualityControlDials` in `qa/bluebook/quality_control.
9
- # bluebook`, which now sources every value from an instance of this
10
- # class instead of writing it inline. This class is only the loading
11
- # and the validation — no dial policy lives here.
12
- #
13
- # **Fails loud, not quiet** — the whole practice's own opening line
14
- # ("the enemy is the quiet divergence") applies to its own settings
15
- # file too: a missing key, an extra key nothing recognises, or a
16
- # value of the wrong shape all raise immediately, at load time
17
- # (which is bluebook-load time, i.e. `Hecks.boot`), naming exactly
18
- # what's wrong — never a `nil` dial silently reaching a script that
19
- # assumes a number.
20
- #
21
- # **Plain data in, frozen data out**. `.load` parses the YAML with
22
- # `Psych.safe_load_file` (no custom tags, no arbitrary Ruby objects)
23
- # and hands back an instance whose accessors are the exact values a
24
- # human wrote in the file — a `Hash`/`Array` for the nested dials,
25
- # never a second, richer wrapper type nothing else in this practice
26
- # expects.
27
- class QaSettings
28
- # One entry per dial this class knows about: the accessor name
29
- # (matching `qa/settings.yml`'s own key, and `QualityControlDials`'
30
- # constant name snake_cased) mapped to the class (or classes) a
31
- # valid value must be an instance of. `TrueClass`/`FalseClass`
32
- # both name a boolean dial — Ruby has no single class both `true`
33
- # and `false` share. `Numeric` admits both an Integer and a Float
34
- # for a fraction dial (`0` and `0.0` are both a human plausibly
35
- # types for "off").
36
- EXPECTED_TYPES = {
37
- cadence_seconds: Integer,
38
- pr_cap_per_day: Integer,
39
- widening_tiers: Array,
40
- sweep_max_parallel: Integer,
41
- liveness_fallback_seconds: Integer,
42
- draft_only: [TrueClass, FalseClass],
43
- auto_merge: [TrueClass, FalseClass],
44
- branch_prefix: String,
45
- adversarial_fraction: Numeric,
46
- guided_generation: [TrueClass, FalseClass],
47
- corpus_splice_probability: Numeric,
48
- favor_rare_verbs: Integer,
49
- self_consistency_checks: [TrueClass, FalseClass],
50
- shrink_budget: Integer,
51
- yield_weight_seconds: Integer,
52
- yield_decay_percent: Integer,
53
- rotation_stale_floor_seconds: Integer,
54
- persistence_parity_seed_cap: Integer,
55
- concurrency_seed_cap: Integer,
56
- adapter_parity_pairs: Hash,
57
- modes: Hash,
58
- role_draw_probability: Numeric,
59
- dry_run_fraction: Numeric,
60
- generated_domains_per_tick: Integer,
61
- generated_domains_rust: [TrueClass, FalseClass],
62
- generated_domain_seeds: Integer,
63
- structural_refusal_boundary: Array
64
- }.freeze
65
-
66
- attr_reader(*EXPECTED_TYPES.keys)
67
-
68
- # **The real file, always** — resolved off this file's own `__dir__`
69
- # (lib/hecks/fuzzing/), never off the caller's. `QualityControlDials`
70
- # is defined inside `qa/bluebook/quality_control.bluebook`, and that
71
- # exact directory gets copied to a tmpdir for every isolated/replayed
72
- # boot (`Hecks::Fuzzing::IsolatedBoot#copy_dereferencing` copies only
73
- # `qa/bluebook`'s own contents, never its parent `qa/`) — a path
74
- # resolved from the bluebook's own `__dir__` would silently point at
75
- # a copy with no `settings.yml` beside it at all. `qa/settings.yml`
76
- # is read-only, human-edited data with no lifecycle (see this class's
77
- # own header) — there is no isolation reason to ever read a copy of
78
- # it, real boot or fuzzed one, so every caller gets the one real file
79
- # by default. `qa_settings_spec.rb` passes its own fixture paths
80
- # explicitly instead, the same way every other test in this practice
81
- # that needs a non-default dial passes one in rather than mutating
82
- # global state.
83
- DEFAULT_PATH = File.expand_path("../../../qa/settings.yml", __dir__)
84
-
85
- class << self
86
- # Loads and validates `qa/settings.yml` (or `path`), returning a frozen instance.
87
- #
88
- # @param path [String] path to the YAML settings file; defaults to `DEFAULT_PATH`
89
- # @return [Hecks::Fuzzing::QaSettings] the validated, frozen settings
90
- # @raise [ArgumentError] if `path` does not exist, is not valid YAML, is not a
91
- # YAML mapping at the top level, is missing a required key, declares an
92
- # unknown key, or gives a value the wrong type for its dial
93
- def load(path = DEFAULT_PATH)
94
- raise ArgumentError, "qa settings file not found: #{path}" unless File.file?(path)
95
-
96
- raw = begin
97
- YAML.safe_load_file(path, symbolize_names: true)
98
- rescue Psych::SyntaxError => e
99
- raise ArgumentError, "#{path} is not valid YAML: #{e.message}"
100
- end
101
- raise ArgumentError, "#{path} must be a YAML mapping at the top level, got #{raw.class}" unless raw.is_a?(Hash)
102
-
103
- new(raw, path)
104
- end
105
- end
106
-
107
- # @param raw [Hash] parsed YAML settings keyed by symbol, one entry per dial in
108
- # `EXPECTED_TYPES`
109
- # @param path [String] path to the settings file, used only in error messages
110
- # @raise [ArgumentError] if `raw` is missing a required key, declares an unknown
111
- # key, or gives a value the wrong type for its dial
112
- def initialize(raw, path)
113
- missing = EXPECTED_TYPES.keys - raw.keys
114
- raise ArgumentError, "#{path} is missing #{missing.sort.join(', ')}" if missing.any?
115
-
116
- extra = raw.keys - EXPECTED_TYPES.keys
117
- if extra.any?
118
- raise ArgumentError,
119
- "#{path} declares unknown key(s) #{extra.sort.join(', ')} — " \
120
- "Hecks::Fuzzing::QaSettings::EXPECTED_TYPES doesn't recognise them"
121
- end
122
-
123
- EXPECTED_TYPES.each do |key, expected|
124
- value = raw.fetch(key)
125
- expected_classes = Array(expected)
126
- unless expected_classes.any? { |klass| value.is_a?(klass) }
127
- raise ArgumentError,
128
- "#{path}: #{key} must be a #{expected_classes.map(&:name).join(' or ')}, " \
129
- "got #{value.class} (#{value.inspect})"
130
- end
131
-
132
- instance_variable_set(:"@#{key}", value)
133
- end
134
-
135
- symbolize_adapter_parity_pairs!(path)
136
- freeze_values!
137
- end
138
-
139
- private
140
-
141
- # `left:`/`right:` name adapters `IsolatedBoot` case-matches by
142
- # symbol (`case adapter when :memory ...`), and YAML has no way to
143
- # spell a bare Ruby Symbol as a mapping value — only
144
- # `symbolize_names:` turns a key into one. So `adapter_parity_
145
- # pairs` is the one dial that needs a coercion step after the
146
- # type check above, rather than every dial growing one.
147
- def symbolize_adapter_parity_pairs!(path)
148
- @adapter_parity_pairs = @adapter_parity_pairs.to_h do |mode, pair|
149
- unless pair.is_a?(Hash) && pair.key?(:left) && pair.key?(:right)
150
- raise ArgumentError,
151
- "#{path}: adapter_parity_pairs.#{mode} must have both left and right, got #{pair.inspect}"
152
- end
153
-
154
- [mode, { left: pair[:left].to_sym, right: pair[:right].to_sym }]
155
- end
156
- end
157
-
158
- def freeze_values!
159
- EXPECTED_TYPES.each_key { |key| instance_variable_get(:"@#{key}").freeze }
160
- freeze
161
- end
162
- end
163
- end
164
- end