hecks 3.5.0 → 3.7.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 (1156) hide show
  1. checksums.yaml +4 -4
  2. data/examples/pizzas/bluebook/hecksagon/mock_stripe_payment_adapter.rb +1 -1
  3. data/lib/hecks/adapters/driven/claude_code.rb +11 -7
  4. data/lib/hecks/adapters/driven/d1/connection.rb +90 -0
  5. data/lib/hecks/adapters/driven/d1.rb +48 -314
  6. data/lib/hecks/adapters/driven/folder.rb +20 -10
  7. data/lib/hecks/adapters/driven/google_authentication.rb +18 -4
  8. data/lib/hecks/adapters/driven/governance_authorization.rb +2 -2
  9. data/lib/hecks/adapters/driven/heki/journal.rb +11 -10
  10. data/lib/hecks/adapters/driven/heki/saga_store.rb +4 -6
  11. data/lib/hecks/adapters/driven/heki/sagas.rb +55 -0
  12. data/lib/hecks/adapters/driven/heki.rb +21 -66
  13. data/lib/hecks/adapters/driven/in_memory_ordering.rb +37 -12
  14. data/lib/hecks/adapters/driven/lambda/client.rb +1 -1
  15. data/lib/hecks/adapters/driven/lambda.rb +1 -8
  16. data/lib/hecks/adapters/driven/memory/outbox_rows.rb +76 -0
  17. data/lib/hecks/adapters/driven/memory/shared_elements/values.rb +117 -0
  18. data/lib/hecks/adapters/driven/memory/shared_elements.rb +10 -97
  19. data/lib/hecks/adapters/driven/memory.rb +3 -65
  20. data/lib/hecks/adapters/driven/postgres/codec.rb +29 -26
  21. data/lib/hecks/adapters/driven/postgres/ddl.rb +50 -0
  22. data/lib/hecks/adapters/driven/postgres/dialect.rb +93 -0
  23. data/lib/hecks/adapters/driven/postgres/events.rb +57 -0
  24. data/lib/hecks/adapters/driven/postgres/journal.rb +127 -0
  25. data/lib/hecks/adapters/driven/postgres/outbox.rb +39 -31
  26. data/lib/hecks/adapters/driven/postgres/repository.rb +190 -0
  27. data/lib/hecks/adapters/driven/postgres/sagas.rb +72 -0
  28. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +13 -41
  29. data/lib/hecks/adapters/driven/postgres.rb +61 -528
  30. data/lib/hecks/adapters/driven/prism.rb +1 -1
  31. data/lib/hecks/adapters/driven/sql_query_builder.rb +45 -53
  32. data/lib/hecks/adapters/driven/sql_value_members.rb +57 -0
  33. data/lib/hecks/adapters/driven/sqlite/codec.rb +32 -29
  34. data/lib/hecks/adapters/driven/sqlite/ddl.rb +68 -0
  35. data/lib/hecks/adapters/driven/sqlite/dialect.rb +55 -0
  36. data/lib/hecks/adapters/driven/sqlite/events.rb +61 -0
  37. data/lib/hecks/adapters/driven/sqlite/journal.rb +125 -0
  38. data/lib/hecks/adapters/driven/sqlite/outbox.rb +98 -0
  39. data/lib/hecks/adapters/driven/sqlite/projection.rb +82 -63
  40. data/lib/hecks/adapters/driven/sqlite/repository.rb +146 -0
  41. data/lib/hecks/adapters/driven/sqlite/sagas.rb +69 -0
  42. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +8 -55
  43. data/lib/hecks/adapters/driven/sqlite.rb +36 -513
  44. data/lib/hecks/adapters/driven/tenant_provisioner.rb +13 -7
  45. data/lib/hecks/adapters/driving/github_webhook.rb +11 -8
  46. data/lib/hecks/behaviors/dsl.rb +17 -12
  47. data/lib/hecks/behaviors/expectations/boot.rb +81 -0
  48. data/lib/hecks/behaviors/expectations/checks.rb +178 -0
  49. data/lib/hecks/behaviors/expectations/dispatching.rb +93 -0
  50. data/lib/hecks/behaviors/expectations/qualify.rb +81 -0
  51. data/lib/hecks/behaviors/expectations.rb +39 -355
  52. data/lib/hecks/behaviors/rspec.rb +12 -12
  53. data/lib/hecks/behaviors/runner.rb +20 -11
  54. data/lib/hecks/bench/cli.rb +16 -13
  55. data/lib/hecks/bench/environment.rb +1 -1
  56. data/lib/hecks/bench/report.rb +11 -7
  57. data/lib/hecks/bench/ruby_runner.rb +13 -8
  58. data/lib/hecks/bench/rust_runner.rb +19 -11
  59. data/lib/hecks/bench/suite.rb +48 -20
  60. data/lib/hecks/bench/workload.rb +42 -31
  61. data/lib/hecks/bluebook/aggregate.rb +15 -21
  62. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +18 -21
  63. data/lib/hecks/bluebook/assembly/build.rb +12 -7
  64. data/lib/hecks/bluebook/assembly/contracts/read_models.rb +70 -0
  65. data/lib/hecks/bluebook/assembly/contracts/rules.rb +84 -0
  66. data/lib/hecks/bluebook/assembly/contracts/sagas.rb +109 -0
  67. data/lib/hecks/bluebook/assembly/contracts/structure.rb +91 -0
  68. data/lib/hecks/bluebook/assembly/contracts.rb +9 -319
  69. data/lib/hecks/bluebook/assembly/marks.rb +9 -8
  70. data/lib/hecks/bluebook/attribute.rb +13 -10
  71. data/lib/hecks/bluebook/behaviour/aggregate.rb +10 -3
  72. data/lib/hecks/bluebook/behaviour/read_model.rb +26 -13
  73. data/lib/hecks/bluebook/chapter.rb +22 -14
  74. data/lib/hecks/bluebook/command.rb +14 -18
  75. data/lib/hecks/bluebook/domain_port.rb +11 -8
  76. data/lib/hecks/bluebook/dsl/aggregate_builder/correction_sealing.rb +78 -0
  77. data/lib/hecks/bluebook/dsl/aggregate_builder/draining.rb +74 -0
  78. data/lib/hecks/bluebook/dsl/aggregate_builder/query_field_sealing.rb +105 -0
  79. data/lib/hecks/bluebook/dsl/aggregate_builder/query_sealing.rb +121 -0
  80. data/lib/hecks/bluebook/dsl/aggregate_builder/relationships.rb +128 -0
  81. data/lib/hecks/bluebook/dsl/aggregate_builder/rules.rb +84 -0
  82. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +61 -249
  83. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +51 -285
  84. data/lib/hecks/bluebook/dsl/attribute_collector/identity_resolution.rb +113 -0
  85. data/lib/hecks/bluebook/dsl/attribute_collector.rb +58 -117
  86. data/lib/hecks/bluebook/dsl/binding_proxy.rb +24 -19
  87. data/lib/hecks/bluebook/dsl/bluebook_builder/pending_givens.rb +109 -0
  88. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/correlation_keys.rb +105 -0
  89. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/event_shapes.rb +126 -0
  90. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/hop_tails.rb +79 -0
  91. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/projected_fields.rb +76 -0
  92. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/provisions.rb +65 -0
  93. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/query_hops.rb +123 -0
  94. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/references.rb +112 -0
  95. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/with_projections.rb +126 -0
  96. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +34 -595
  97. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +18 -107
  98. data/lib/hecks/bluebook/dsl/command_builder/implicit_attributes.rb +132 -0
  99. data/lib/hecks/bluebook/dsl/command_builder/mutations.rb +190 -0
  100. data/lib/hecks/bluebook/dsl/command_builder/owner.rb +22 -0
  101. data/lib/hecks/bluebook/dsl/command_builder/rules.rb +57 -0
  102. data/lib/hecks/bluebook/dsl/command_builder.rb +60 -360
  103. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +19 -13
  104. data/lib/hecks/bluebook/dsl/entity_builder/rules.rb +96 -0
  105. data/lib/hecks/bluebook/dsl/entity_builder/scope.rb +25 -0
  106. data/lib/hecks/bluebook/dsl/entity_builder/sealing.rb +94 -0
  107. data/lib/hecks/bluebook/dsl/entity_builder.rb +35 -169
  108. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +53 -24
  109. data/lib/hecks/bluebook/dsl/hecksagon_builder/chapter_scope.rb +133 -0
  110. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +3 -97
  111. data/lib/hecks/bluebook/dsl/identity_declaration.rb +73 -73
  112. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +7 -3
  113. data/lib/hecks/bluebook/dsl/need_word.rb +1 -1
  114. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +34 -29
  115. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +57 -41
  116. data/lib/hecks/bluebook/dsl/query_builder.rb +12 -15
  117. data/lib/hecks/bluebook/dsl/read_model_builder/sealing.rb +116 -0
  118. data/lib/hecks/bluebook/dsl/read_model_builder.rb +25 -102
  119. data/lib/hecks/bluebook/dsl/rule_reference.rb +26 -12
  120. data/lib/hecks/bluebook/dsl/translation_builder.rb +24 -14
  121. data/lib/hecks/bluebook/dsl/value_object_builder.rb +29 -19
  122. data/lib/hecks/bluebook/dsl/word_gate.rb +34 -27
  123. data/lib/hecks/bluebook/entity.rb +13 -17
  124. data/lib/hecks/bluebook/expression/ast_json/emitters.rb +93 -0
  125. data/lib/hecks/bluebook/expression/ast_json/emitters.rb-e +88 -0
  126. data/lib/hecks/bluebook/expression/ast_json.rb +49 -76
  127. data/lib/hecks/bluebook/expression/ast_reader.rb +95 -28
  128. data/lib/hecks/bluebook/expression/canonical_form.rb +6 -26
  129. data/lib/hecks/bluebook/expression/evaluator/parser.rb +62 -0
  130. data/lib/hecks/bluebook/expression/evaluator/scanning.rb +122 -0
  131. data/lib/hecks/bluebook/expression/evaluator.rb +11 -111
  132. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +28 -44
  133. data/lib/hecks/bluebook/expression/resolver/lookups.rb +77 -0
  134. data/lib/hecks/bluebook/expression/resolver/operations.rb +78 -0
  135. data/lib/hecks/bluebook/expression/resolver/parsing.rb +110 -0
  136. data/lib/hecks/bluebook/expression/resolver/scanning.rb +139 -0
  137. data/lib/hecks/bluebook/expression/resolver/values.rb +115 -0
  138. data/lib/hecks/bluebook/expression/resolver.rb +16 -414
  139. data/lib/hecks/bluebook/{hexagon.rb → hecksagon.rb} +22 -14
  140. data/lib/hecks/bluebook/keyword_fields.rb +42 -0
  141. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +7 -6
  142. data/lib/hecks/bluebook/meta_validator/judge/cells.rb +99 -0
  143. data/lib/hecks/bluebook/meta_validator/judge/dispatching.rb +111 -0
  144. data/lib/hecks/bluebook/meta_validator/judge/identity.rb +108 -0
  145. data/lib/hecks/bluebook/meta_validator/judge/walking.rb +141 -0
  146. data/lib/hecks/bluebook/meta_validator/judge.rb +31 -376
  147. data/lib/hecks/bluebook/meta_validator/modes.rb +137 -0
  148. data/lib/hecks/bluebook/meta_validator/plan/category.rb +44 -0
  149. data/lib/hecks/bluebook/meta_validator/plan/verbs.rb +73 -0
  150. data/lib/hecks/bluebook/meta_validator/plan.rb +38 -122
  151. data/lib/hecks/bluebook/meta_validator/readings/fields.rb +100 -0
  152. data/lib/hecks/bluebook/meta_validator/readings.rb +10 -95
  153. data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +89 -0
  154. data/lib/hecks/bluebook/meta_validator/reconstruction/reading.rb +96 -0
  155. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +25 -151
  156. data/lib/hecks/bluebook/meta_validator/shapes/helpers.rb +83 -0
  157. data/lib/hecks/bluebook/meta_validator/shapes.rb +8 -75
  158. data/lib/hecks/bluebook/meta_validator/syntax_boot/disk_cache.rb +102 -0
  159. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +31 -95
  160. data/lib/hecks/bluebook/meta_validator/translation_judge/rules.rb +74 -0
  161. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +15 -65
  162. data/lib/hecks/bluebook/meta_validator/verdict_cache/prebuilt.rb +44 -0
  163. data/lib/hecks/bluebook/meta_validator/verdict_cache/tagging.rb +63 -0
  164. data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +25 -60
  165. data/lib/hecks/bluebook/meta_validator/world_judge.rb +8 -4
  166. data/lib/hecks/bluebook/meta_validator.rb +59 -175
  167. data/lib/hecks/bluebook/model_check/lifecycle_checks.rb +122 -0
  168. data/lib/hecks/bluebook/model_check/policy_checks.rb +129 -0
  169. data/lib/hecks/bluebook/model_check/saga_checks.rb +134 -0
  170. data/lib/hecks/bluebook/model_check/verbs.rb +69 -0
  171. data/lib/hecks/bluebook/model_check.rb +73 -413
  172. data/lib/hecks/bluebook/pattern_subset/refusals.rb +54 -0
  173. data/lib/hecks/bluebook/pattern_subset/scan.rb +58 -0
  174. data/lib/hecks/bluebook/pattern_subset.rb +93 -134
  175. data/lib/hecks/bluebook/process_manager.rb +10 -9
  176. data/lib/hecks/bluebook/project_discovery.rb +10 -7
  177. data/lib/hecks/bluebook/project_register.rb +42 -41
  178. data/lib/hecks/bluebook/query.rb +19 -12
  179. data/lib/hecks/bluebook/read_model.rb +41 -39
  180. data/lib/hecks/bluebook/smoke_test.rb +51 -36
  181. data/lib/hecks/bluebook/synthesizer.rb +13 -5
  182. data/lib/hecks/bluebook/translation.rb +12 -12
  183. data/lib/hecks/bluebook.rb +1 -1
  184. data/lib/hecks/cache_dir.rb +10 -0
  185. data/lib/hecks/chapters.rb +32 -16
  186. data/lib/hecks/cli/behaviors.rb +22 -15
  187. data/lib/hecks/cli/check_era.rb +2 -2
  188. data/lib/hecks/cli/command_table.rb +72 -0
  189. data/lib/hecks/cli/console.rb +10 -7
  190. data/lib/hecks/cli/deploy_template_diff.rb +22 -9
  191. data/lib/hecks/cli/document.rb +14 -10
  192. data/lib/hecks/cli/domain_stub.rb +1 -1
  193. data/lib/hecks/cli/domain_writer.rb +1 -1
  194. data/lib/hecks/cli/expression_projection.rb +8 -6
  195. data/lib/hecks/cli/follow.rb +10 -4
  196. data/lib/hecks/cli/interview_aggregate.rb +132 -0
  197. data/lib/hecks/cli/interview_draft.rb +16 -200
  198. data/lib/hecks/cli/interview_record.rb +130 -0
  199. data/lib/hecks/cli/interview_run.rb +19 -8
  200. data/lib/hecks/cli/interview_session/agent_state.rb +70 -0
  201. data/lib/hecks/cli/interview_session/catalog.rb +76 -0
  202. data/lib/hecks/cli/interview_session/manual_findings.rb +48 -0
  203. data/lib/hecks/cli/interview_session/proposals.rb +90 -0
  204. data/lib/hecks/cli/interview_session.rb +8 -205
  205. data/lib/hecks/cli/interview_shape.rb +13 -6
  206. data/lib/hecks/cli/ir.rb +8 -11
  207. data/lib/hecks/cli/launcher_words.rb +168 -0
  208. data/lib/hecks/cli/model_check/examination.rb +93 -0
  209. data/lib/hecks/cli/model_check/sources.rb +57 -0
  210. data/lib/hecks/cli/model_check.rb +28 -134
  211. data/lib/hecks/cli/project_cli/launcher_source.rb +177 -0
  212. data/lib/hecks/cli/project_cli/templates.rb +106 -0
  213. data/lib/hecks/cli/project_cli.rb +57 -236
  214. data/lib/hecks/cli/project_diagrams.rb +26 -4
  215. data/lib/hecks/cli/project_glossary.rb +19 -9
  216. data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +29 -13
  217. data/lib/hecks/cli/release.rb +29 -22
  218. data/lib/hecks/cli/release_gem.rb +12 -6
  219. data/lib/hecks/cli/rspec_io_parallel_files.rb +87 -30
  220. data/lib/hecks/cli/rspec_shard_files.rb +24 -9
  221. data/lib/hecks/cli/run.rb +25 -44
  222. data/lib/hecks/cli/run_expectations.rb +63 -0
  223. data/lib/hecks/cli/seed_semantics_corpus.rb +37 -17
  224. data/lib/hecks/cli/smoke_http/checks.rb +66 -0
  225. data/lib/hecks/cli/smoke_http/settings.rb +63 -0
  226. data/lib/hecks/cli/smoke_http/transport.rb +45 -0
  227. data/lib/hecks/cli/smoke_http.rb +8 -142
  228. data/lib/hecks/cli/smoke_test.rb +18 -4
  229. data/lib/hecks/cli/stores.rb +7 -4
  230. data/lib/hecks/cli/stress_concurrency_specs/reporting.rb +44 -0
  231. data/lib/hecks/cli/stress_concurrency_specs/usage.rb +28 -0
  232. data/lib/hecks/cli/stress_concurrency_specs.rb +82 -80
  233. data/lib/hecks/cli.rb +32 -208
  234. data/lib/hecks/codemod/runner.rb +92 -0
  235. data/lib/hecks/codemod/sweep.rb +94 -0
  236. data/lib/hecks/codemod.rb +22 -165
  237. data/lib/hecks/corpus/routes.rb +34 -0
  238. data/lib/hecks/corpus/rust.rb +193 -0
  239. data/lib/hecks/corpus/sources.rb +46 -0
  240. data/lib/hecks/corpus.rb +28 -265
  241. data/lib/hecks/deploy/bluebook/deploy.bluebook +109 -0
  242. data/lib/hecks/deploy/oidc.json +10 -0
  243. data/lib/hecks/doc/reference/coverage.rb +70 -0
  244. data/lib/hecks/doc/reference/harvester.rb +55 -0
  245. data/lib/hecks/doc/reference/readme.rb +89 -0
  246. data/lib/hecks/doc/reference/rendering.rb +149 -0
  247. data/lib/hecks/doc/reference.rb +14 -273
  248. data/lib/hecks/doors/cli_door/nesting.rb +34 -0
  249. data/lib/hecks/doors/cli_door/shorthand.rb +85 -0
  250. data/lib/hecks/doors/cli_door.rb +23 -95
  251. data/lib/hecks/doors/cli_runner/answers.rb +138 -0
  252. data/lib/hecks/doors/cli_runner/resolution.rb +146 -0
  253. data/lib/hecks/doors/cli_runner/settling.rb +115 -0
  254. data/lib/hecks/doors/cli_runner/streaming.rb +90 -0
  255. data/lib/hecks/doors/cli_runner/suggestions.rb +43 -0
  256. data/lib/hecks/doors/cli_runner.rb +12 -336
  257. data/lib/hecks/doors/command_request.rb +42 -31
  258. data/lib/hecks/doors/handle.rb +32 -30
  259. data/lib/hecks/doors/launcher_options.rb +62 -7
  260. data/lib/hecks/doors/mcp_door/properties.rb +47 -0
  261. data/lib/hecks/doors/mcp_door/tool_calls.rb +113 -0
  262. data/lib/hecks/doors/mcp_door/tool_definitions/auditing.rb +51 -0
  263. data/lib/hecks/doors/mcp_door/tool_definitions/calling.rb +69 -0
  264. data/lib/hecks/doors/mcp_door/tool_definitions/reading.rb +97 -0
  265. data/lib/hecks/doors/mcp_door/tool_definitions.rb +15 -0
  266. data/lib/hecks/doors/mcp_door.rb +55 -301
  267. data/lib/hecks/doors/mcp_door_scope/argument_policy.rb +92 -0
  268. data/lib/hecks/doors/mcp_door_scope/env_problems.rb +55 -0
  269. data/lib/hecks/doors/mcp_door_scope/presenter.rb +78 -0
  270. data/lib/hecks/doors/mcp_door_scope.rb +16 -172
  271. data/lib/hecks/doors/ruby_door/aggregate_door.rb +1 -1
  272. data/lib/hecks/doors/ruby_door/chapter.rb +33 -16
  273. data/lib/hecks/doors/ruby_door.rb +14 -11
  274. data/lib/hecks/doors/usage_cache.rb +32 -16
  275. data/lib/hecks/doors.rb +10 -4
  276. data/lib/hecks/embryonaut_bluebook/manifest.rb +11 -3
  277. data/lib/hecks/embryonaut_bluebook/registry/changelog.rb +26 -0
  278. data/lib/hecks/embryonaut_bluebook/registry/versions.rb +27 -0
  279. data/lib/hecks/embryonaut_bluebook/registry.rb +27 -37
  280. data/lib/hecks/embryonaut_bluebook/vendor/acceptance.rb +37 -0
  281. data/lib/hecks/embryonaut_bluebook/vendor.rb +22 -36
  282. data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +9 -6
  283. data/lib/hecks/embryonaut_bluebook.rb +16 -11
  284. data/lib/hecks/engine_agreement.rb +24 -17
  285. data/lib/hecks/forms/app/commands.rb +98 -0
  286. data/lib/hecks/forms/app/queries.rb +62 -0
  287. data/lib/hecks/forms/app/records.rb +67 -0
  288. data/lib/hecks/forms/app/responses.rb +46 -0
  289. data/lib/hecks/forms/app.rb +33 -221
  290. data/lib/hecks/forms/banking_presentation.rb +5 -0
  291. data/lib/hecks/forms/command_form_renderer.rb +55 -14
  292. data/lib/hecks/forms/field_controls.rb +95 -0
  293. data/lib/hecks/forms/field_renderer.rb +34 -88
  294. data/lib/hecks/forms/field_shape.rb +9 -34
  295. data/lib/hecks/forms/html.rb +1 -1
  296. data/lib/hecks/forms/index_renderer.rb +14 -9
  297. data/lib/hecks/forms/page.rb +2 -106
  298. data/lib/hecks/forms/page_assets.rb +88 -0
  299. data/lib/hecks/forms/page_script.rb +28 -0
  300. data/lib/hecks/forms/params.rb +17 -8
  301. data/lib/hecks/forms/query_form_renderer.rb +11 -7
  302. data/lib/hecks/forms/record_renderer.rb +28 -19
  303. data/lib/hecks/forms/reference_options.rb +1 -1
  304. data/lib/hecks/forms/text_shape.rb +40 -0
  305. data/lib/hecks/fqn.rb +64 -32
  306. data/lib/hecks/framework.rb +10 -3
  307. data/lib/hecks/freezer.rb +10 -1
  308. data/lib/hecks/fuzzing/bounded_exhaustive_expressions/fragments.rb +61 -0
  309. data/lib/hecks/fuzzing/bounded_exhaustive_expressions/productions.rb +217 -0
  310. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +5 -194
  311. data/lib/hecks/fuzzing/combination_miner.rb +23 -12
  312. data/lib/hecks/fuzzing/concurrent_dispatch/racing.rb +64 -0
  313. data/lib/hecks/fuzzing/concurrent_dispatch/world_copy.rb +66 -0
  314. data/lib/hecks/fuzzing/concurrent_dispatch.rb +31 -107
  315. data/lib/hecks/fuzzing/coverage_campaign.rb +49 -24
  316. data/lib/hecks/fuzzing/differential/wire_comparison.rb +74 -0
  317. data/lib/hecks/fuzzing/differential.rb +59 -84
  318. data/lib/hecks/fuzzing/domain_generator/block_rendering.rb +70 -0
  319. data/lib/hecks/fuzzing/domain_generator/builder/attribute_shapes.rb +105 -0
  320. data/lib/hecks/fuzzing/domain_generator/builder/shapes.rb +97 -0
  321. data/lib/hecks/fuzzing/domain_generator/builder/wiring.rb +128 -0
  322. data/lib/hecks/fuzzing/domain_generator/builder.rb +105 -0
  323. data/lib/hecks/fuzzing/domain_generator/pruning.rb +90 -0
  324. data/lib/hecks/fuzzing/domain_generator/removals.rb +62 -0
  325. data/lib/hecks/fuzzing/domain_generator/rendering.rb +94 -0
  326. data/lib/hecks/fuzzing/domain_generator/tokens.rb +38 -0
  327. data/lib/hecks/fuzzing/domain_generator.rb +7 -555
  328. data/lib/hecks/fuzzing/era_boundary.rb +34 -24
  329. data/lib/hecks/fuzzing/failure_triage.rb +80 -0
  330. data/lib/hecks/fuzzing/form_census/chapter_forms.rb +38 -0
  331. data/lib/hecks/fuzzing/form_census/reference_forms.rb +49 -0
  332. data/lib/hecks/fuzzing/form_census.rb +44 -58
  333. data/lib/hecks/fuzzing/generated_domain_check.rb +23 -11
  334. data/lib/hecks/fuzzing/isolated_boot/copying.rb +62 -0
  335. data/lib/hecks/fuzzing/isolated_boot/postgres_scratch.rb +148 -0
  336. data/lib/hecks/fuzzing/isolated_boot/scratch_schema.rb +27 -0
  337. data/lib/hecks/fuzzing/isolated_boot/worlds.rb +102 -0
  338. data/lib/hecks/fuzzing/isolated_boot.rb +29 -252
  339. data/lib/hecks/fuzzing/mutation/checks.rb +76 -0
  340. data/lib/hecks/fuzzing/mutation/finders.rb +136 -0
  341. data/lib/hecks/fuzzing/mutation/judge.rb +94 -0
  342. data/lib/hecks/fuzzing/mutation/observation.rb +38 -0
  343. data/lib/hecks/fuzzing/mutation/operators.rb +52 -0
  344. data/lib/hecks/fuzzing/mutation/report.rb +78 -0
  345. data/lib/hecks/fuzzing/mutation/run.rb +99 -0
  346. data/lib/hecks/fuzzing/mutation/selection.rb +32 -0
  347. data/lib/hecks/fuzzing/mutation/site.rb +21 -0
  348. data/lib/hecks/fuzzing/mutation/source_map.rb +59 -0
  349. data/lib/hecks/fuzzing/mutation.rb +12 -0
  350. data/lib/hecks/fuzzing/persistence_parity.rb +5 -5
  351. data/lib/hecks/fuzzing/properties/aggregation_recompute.rb +121 -0
  352. data/lib/hecks/fuzzing/properties/catalog.rb +89 -0
  353. data/lib/hecks/fuzzing/properties/corrections.rb +23 -20
  354. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +64 -185
  355. data/lib/hecks/fuzzing/properties/group_by_recompute.rb +69 -0
  356. data/lib/hecks/fuzzing/properties/guaranteed_by_construction.rb +63 -0
  357. data/lib/hecks/fuzzing/properties/guards.rb +76 -108
  358. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +66 -227
  359. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +46 -35
  360. data/lib/hecks/fuzzing/properties/mutation_recompute.rb +162 -0
  361. data/lib/hecks/fuzzing/properties/outbox.rb +41 -24
  362. data/lib/hecks/fuzzing/properties/piece_invariants.rb +61 -0
  363. data/lib/hecks/fuzzing/properties/policy_wiring.rb +140 -0
  364. data/lib/hecks/fuzzing/properties/query_rows.rb +67 -0
  365. data/lib/hecks/fuzzing/properties/querying.rb +69 -90
  366. data/lib/hecks/fuzzing/properties/read_model_names.rb +50 -0
  367. data/lib/hecks/fuzzing/properties/read_models.rb +138 -0
  368. data/lib/hecks/fuzzing/properties/references.rb +100 -0
  369. data/lib/hecks/fuzzing/properties/role_checks.rb +50 -0
  370. data/lib/hecks/fuzzing/properties/tenant_scope.rb +84 -0
  371. data/lib/hecks/fuzzing/properties.rb +13 -119
  372. data/lib/hecks/fuzzing/qa_settings.rb +23 -17
  373. data/lib/hecks/fuzzing/replay/fan_out.rb +78 -0
  374. data/lib/hecks/fuzzing/replay/filters.rb +72 -0
  375. data/lib/hecks/fuzzing/replay/guard_check.rb +88 -0
  376. data/lib/hecks/fuzzing/replay/mutation_trace.rb +117 -0
  377. data/lib/hecks/fuzzing/replay/observation.rb +60 -0
  378. data/lib/hecks/fuzzing/replay/read_only_steps.rb +84 -0
  379. data/lib/hecks/fuzzing/replay/role_check.rb +49 -0
  380. data/lib/hecks/fuzzing/replay/session.rb +167 -0
  381. data/lib/hecks/fuzzing/replay.rb +36 -442
  382. data/lib/hecks/fuzzing/runtime_coverage.rb +70 -0
  383. data/lib/hecks/fuzzing/rust_gap_manifest.rb +3 -4
  384. data/lib/hecks/fuzzing/self_consistency/saga_redelivery.rb +133 -0
  385. data/lib/hecks/fuzzing/self_consistency/sagas.rb +93 -0
  386. data/lib/hecks/fuzzing/self_consistency/value_objects.rb +87 -0
  387. data/lib/hecks/fuzzing/self_consistency.rb +8 -213
  388. data/lib/hecks/fuzzing/sequence_generator/adversary/argument_mutations.rb +116 -0
  389. data/lib/hecks/fuzzing/sequence_generator/adversary/caller_draw.rb +68 -0
  390. data/lib/hecks/fuzzing/sequence_generator/adversary/identity_mutations.rb +62 -0
  391. data/lib/hecks/fuzzing/sequence_generator/adversary/precedence_mutations.rb +126 -0
  392. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +23 -283
  393. data/lib/hecks/fuzzing/sequence_generator/argument_drawing.rb +78 -0
  394. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +69 -53
  395. data/lib/hecks/fuzzing/sequence_generator/identity_shaping.rb +85 -0
  396. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +20 -16
  397. data/lib/hecks/fuzzing/sequence_generator/picker.rb +12 -6
  398. data/lib/hecks/fuzzing/sequence_generator/prefixing.rb +45 -0
  399. data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +19 -8
  400. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +43 -144
  401. data/lib/hecks/fuzzing/sequence_generator.rb +65 -63
  402. data/lib/hecks/fuzzing/shrinker/value_simplification.rb +64 -0
  403. data/lib/hecks/fuzzing/shrinker.rb +36 -29
  404. data/lib/hecks/fuzzing/target_capabilities.rb +10 -4
  405. data/lib/hecks/fuzzing/value_generator.rb +27 -17
  406. data/lib/hecks/fuzzing.rb +3 -0
  407. data/lib/hecks/gate/stages.yml +11 -1
  408. data/lib/hecks/grammar/evolve/arguments.rb +90 -0
  409. data/lib/hecks/grammar/evolve/keywords.rb +81 -0
  410. data/lib/hecks/grammar/evolve/seeds.rb +172 -0
  411. data/lib/hecks/grammar/evolve.rb +22 -263
  412. data/lib/hecks/grammar/operators.rb +111 -0
  413. data/lib/hecks/grammar.rb +53 -126
  414. data/lib/hecks/hecks/adapters/bluebook_report.rb +6 -6
  415. data/lib/hecks/hecks/adapters/codebase/codemods.rb +1 -1
  416. data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +23 -9
  417. data/lib/hecks/hecks/adapters/codebase/language/edits.rb +75 -0
  418. data/lib/hecks/hecks/adapters/codebase/language.rb +30 -72
  419. data/lib/hecks/hecks/adapters/codebase/promotion/candidates.rb +54 -0
  420. data/lib/hecks/hecks/adapters/codebase/promotion/gate.rb +50 -0
  421. data/lib/hecks/hecks/adapters/codebase/promotion/move.rb +70 -0
  422. data/lib/hecks/hecks/adapters/codebase/promotion/standing.rb +88 -0
  423. data/lib/hecks/hecks/adapters/codebase/promotion/watch.rb +83 -0
  424. data/lib/hecks/hecks/adapters/codebase/promotion.rb +115 -0
  425. data/lib/hecks/hecks/adapters/codebase/publishing.rb +31 -12
  426. data/lib/hecks/hecks/adapters/codebase/regeneration.rb +43 -6
  427. data/lib/hecks/hecks/adapters/codebase/release_facts.rb +16 -5
  428. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +9 -1
  429. data/lib/hecks/hecks/adapters/codebase/sqlite_fixture.rb +1 -1
  430. data/lib/hecks/hecks/adapters/codebase/style.rb +1 -1
  431. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +11 -5
  432. data/lib/hecks/hecks/adapters/codebase/test_suite.rb +27 -8
  433. data/lib/hecks/hecks/adapters/console_capture.rb +21 -17
  434. data/lib/hecks/hecks/adapters/cost_explorer.rb +11 -6
  435. data/lib/hecks/hecks/adapters/deploy_plans.rb +3 -3
  436. data/lib/hecks/hecks/adapters/deploy_toolchain/answers.rb +142 -0
  437. data/lib/hecks/hecks/adapters/deploy_toolchain/scripts.rb +95 -0
  438. data/lib/hecks/hecks/adapters/deploy_toolchain/statuses.rb +74 -0
  439. data/lib/hecks/hecks/adapters/deploy_toolchain.rb +21 -239
  440. data/lib/hecks/hecks/adapters/finding_github.rb +2 -2
  441. data/lib/hecks/hecks/adapters/first_admin.rb +22 -8
  442. data/lib/hecks/hecks/adapters/git.rb +18 -5
  443. data/lib/hecks/hecks/adapters/git_refs.rb +144 -0
  444. data/lib/hecks/hecks/adapters/github_rulesets.rb +128 -0
  445. data/lib/hecks/hecks/adapters/host_http.rb +16 -6
  446. data/lib/hecks/hecks/adapters/in_process_boot.rb +9 -5
  447. data/lib/hecks/hecks/adapters/in_process_operations/tailing.rb +61 -0
  448. data/lib/hecks/hecks/adapters/in_process_operations.rb +33 -35
  449. data/lib/hecks/hecks/adapters/journal_store/changes.rb +21 -15
  450. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +29 -12
  451. data/lib/hecks/hecks/adapters/journal_store/readings/attestation.rb +52 -0
  452. data/lib/hecks/hecks/adapters/journal_store/readings/scaffolding.rb +52 -0
  453. data/lib/hecks/hecks/adapters/journal_store/readings.rb +5 -62
  454. data/lib/hecks/hecks/adapters/local_files.rb +27 -10
  455. data/lib/hecks/hecks/adapters/pg_admin/ownership.rb +115 -0
  456. data/lib/hecks/hecks/adapters/pg_admin.rb +14 -87
  457. data/lib/hecks/hecks/adapters/process_pool.rb +75 -21
  458. data/lib/hecks/hecks/adapters/rust_toolchain.rb +12 -4
  459. data/lib/hecks/hecks/adapters/site_toolchain.rb +16 -7
  460. data/lib/hecks/hecks/adapters/terminal.rb +13 -9
  461. data/lib/hecks/hecks/codebase.bluebook +322 -5
  462. data/lib/hecks/hecks/custodian.behaviors +6 -0
  463. data/lib/hecks/hecks/custodian.bluebook +37 -0
  464. data/lib/hecks/hecks/hecks.hecksagon +22 -0
  465. data/lib/hecks/hecks/hecks.world +10 -2
  466. data/lib/hecks/kernel_capabilities/templates.rb +92 -0
  467. data/lib/hecks/kernel_capabilities.rb +18 -85
  468. data/lib/hecks/language/bluebook/vocabulary.bluebook +46 -1
  469. data/lib/hecks/literal/item_splitter.rb +50 -0
  470. data/lib/hecks/literal.rb +29 -38
  471. data/lib/hecks/mcp_stdio_guard.rb +8 -8
  472. data/lib/hecks/naming.rb +9 -3
  473. data/lib/hecks/persistence_legacy_fixture/postgres_stores.rb +81 -0
  474. data/lib/hecks/persistence_legacy_fixture/regenerate.rb +26 -66
  475. data/lib/hecks/persistence_legacy_fixture.rb +13 -10
  476. data/lib/hecks/ports/access_control.rb +13 -10
  477. data/lib/hecks/ports/agent/answers.rb +2 -2
  478. data/lib/hecks/ports/agent.rb +13 -10
  479. data/lib/hecks/ports/authentication.rb +13 -10
  480. data/lib/hecks/ports/authorization.rb +13 -10
  481. data/lib/hecks/ports/clock.rb +13 -10
  482. data/lib/hecks/ports/extraction.rb +13 -12
  483. data/lib/hecks/ports/identity_assignment.rb +13 -10
  484. data/lib/hecks/ports/identity_generation.rb +13 -10
  485. data/lib/hecks/ports/identity_resolution.rb +13 -10
  486. data/lib/hecks/ports/key_vault.rb +13 -10
  487. data/lib/hecks/ports/persistence/append_only.rb +5 -5
  488. data/lib/hecks/ports/persistence/binding_policy.rb +33 -9
  489. data/lib/hecks/ports/persistence/codec_boundary.rb +22 -11
  490. data/lib/hecks/ports/persistence/constants.rb +10 -0
  491. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +18 -16
  492. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +27 -18
  493. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +52 -23
  494. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +14 -8
  495. data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +17 -6
  496. data/lib/hecks/ports/persistence/plugins/era/lineage/coverage.rb +58 -0
  497. data/lib/hecks/ports/persistence/plugins/era/lineage/rewrite.rb +130 -0
  498. data/lib/hecks/ports/persistence/plugins/era/lineage/rules.rb +25 -0
  499. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +20 -180
  500. data/lib/hecks/ports/persistence/plugins/era/postgres_era/boot.rb +41 -0
  501. data/lib/hecks/ports/persistence/plugins/era/postgres_era/class_methods.rb +105 -0
  502. data/lib/hecks/ports/persistence/plugins/era/postgres_era/dialect.rb +137 -0
  503. data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +25 -28
  504. data/lib/hecks/ports/persistence/plugins/era/postgres_era/head_writes.rb +62 -0
  505. data/lib/hecks/ports/persistence/plugins/era/postgres_era/journal.rb +128 -0
  506. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/base_sql.rb +74 -0
  507. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/chain_sql.rb +169 -0
  508. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/domain_rename.rb +91 -0
  509. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_integrity.rb +99 -0
  510. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +0 -73
  511. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +55 -39
  512. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +51 -222
  513. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/merge_writes.rb +120 -0
  514. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +85 -60
  515. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +97 -181
  516. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +19 -19
  517. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/sql_templates.rb +88 -0
  518. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +77 -118
  519. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +3 -117
  520. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_sql.rb +116 -0
  521. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +3 -1
  522. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/context.rb +38 -0
  523. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +43 -25
  524. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +62 -38
  525. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +21 -16
  526. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +66 -86
  527. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/refusals.rb +75 -0
  528. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +27 -9
  529. data/lib/hecks/ports/persistence/plugins/era/postgres_era/query_phases.rb +63 -0
  530. data/lib/hecks/ports/persistence/plugins/era/postgres_era/sagas.rb +78 -0
  531. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +28 -482
  532. data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +40 -12
  533. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +22 -15
  534. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +39 -19
  535. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -16
  536. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +48 -25
  537. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +60 -99
  538. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/path_diff.rb +57 -0
  539. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +21 -11
  540. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +13 -4
  541. data/lib/hecks/ports/persistence/postgres_dump/connection.rb +4 -2
  542. data/lib/hecks/ports/persistence/postgres_dump.rb +13 -7
  543. data/lib/hecks/ports/persistence/repository_factory.rb +35 -11
  544. data/lib/hecks/ports/persistence/state_codec.rb +10 -0
  545. data/lib/hecks/ports/persistence.rb +1 -10
  546. data/lib/hecks/ports/projection.rb +34 -21
  547. data/lib/hecks/ports/query/in_memory.rb +16 -8
  548. data/lib/hecks/projection_files/expression_tables.rb +64 -0
  549. data/lib/hecks/projection_files/texts.rb +67 -0
  550. data/lib/hecks/projection_files.rb +19 -103
  551. data/lib/hecks/projections/bootstrap_table.rb +43 -29
  552. data/lib/hecks/projections/deploy/bastion_lines.rb +32 -0
  553. data/lib/hecks/projections/deploy/box/access.rb +73 -0
  554. data/lib/hecks/projections/deploy/box/caddy.rb +87 -0
  555. data/lib/hecks/projections/deploy/box/compose.rb +70 -0
  556. data/lib/hecks/projections/deploy/box/hosting.rb +4 -105
  557. data/lib/hecks/projections/deploy/box/hosting_parts.rb +97 -0
  558. data/lib/hecks/projections/deploy/box/hosting_settings.rb +1 -1
  559. data/lib/hecks/projections/deploy/box/roll_recipe.rb +1 -1
  560. data/lib/hecks/projections/deploy/box/roll_scripts.rb +137 -0
  561. data/lib/hecks/projections/deploy/box/settings/checks.rb +38 -0
  562. data/lib/hecks/projections/deploy/box/settings/containers.rb +123 -0
  563. data/lib/hecks/projections/deploy/box/settings/origin.rb +56 -0
  564. data/lib/hecks/projections/deploy/box/settings/patterns.rb +47 -0
  565. data/lib/hecks/projections/deploy/box/settings/types.rb +76 -0
  566. data/lib/hecks/projections/deploy/box/settings.rb +76 -263
  567. data/lib/hecks/projections/deploy/box/shared_database.rb +69 -0
  568. data/lib/hecks/projections/deploy/box/stack_yaml.rb +107 -0
  569. data/lib/hecks/projections/deploy/box/templates/MIGRATION.md.tmpl +39 -0
  570. data/lib/hecks/projections/deploy/box/templates/Makefile.tmpl +23 -0
  571. data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +42 -2
  572. data/lib/hecks/projections/deploy/box/templates/deploy-service.services-roll.part +2 -1
  573. data/lib/hecks/projections/deploy/box/templates/deploy-service.taskdef-roll.part +2 -1
  574. data/lib/hecks/projections/deploy/box/templates/deploy-usage-services.tmpl +4 -0
  575. data/lib/hecks/projections/deploy/box/templates/deploy-usage-taskdef.tmpl +5 -0
  576. data/lib/hecks/projections/deploy/box/templates/ecr-repository.yaml.tmpl +9 -0
  577. data/lib/hecks/projections/deploy/box/templates/mode-summary-services.tmpl +2 -0
  578. data/lib/hecks/projections/deploy/box/templates/mode-summary-taskdef.tmpl +4 -0
  579. data/lib/hecks/projections/deploy/box/templates/provision-database.sh.tmpl +97 -0
  580. data/lib/hecks/projections/deploy/box/templates/restore-to-rds.sh.tmpl +4 -2
  581. data/lib/hecks/projections/deploy/box/templates/services-block.tmpl +9 -0
  582. data/lib/hecks/projections/deploy/box/templates/tunnel-egress.yaml.tmpl +11 -0
  583. data/lib/hecks/projections/deploy/box/templates/verify-copy.sh.tmpl +2 -1
  584. data/lib/hecks/projections/deploy/box/templates/writable-secrets.yaml.tmpl +7 -0
  585. data/lib/hecks/projections/deploy/box.rb +43 -491
  586. data/lib/hecks/projections/deploy/fargate/assembly.rb +13 -142
  587. data/lib/hecks/projections/deploy/fargate/cdn/behaviors.rb +76 -0
  588. data/lib/hecks/projections/deploy/fargate/cdn/lines.rb +112 -0
  589. data/lib/hecks/projections/deploy/fargate/cdn/options.rb +85 -0
  590. data/lib/hecks/projections/deploy/fargate/cdn.rb +23 -215
  591. data/lib/hecks/projections/deploy/fargate/check.rb +16 -6
  592. data/lib/hecks/projections/deploy/fargate/containers/definition_lines.rb +61 -0
  593. data/lib/hecks/projections/deploy/fargate/containers/reading.rb +86 -0
  594. data/lib/hecks/projections/deploy/fargate/containers/rendering.rb +132 -0
  595. data/lib/hecks/projections/deploy/fargate/containers/routing.rb +93 -0
  596. data/lib/hecks/projections/deploy/fargate/containers.rb +10 -286
  597. data/lib/hecks/projections/deploy/fargate/extras/reading.rb +90 -0
  598. data/lib/hecks/projections/deploy/fargate/extras/rendering.rb +81 -0
  599. data/lib/hecks/projections/deploy/fargate/extras.rb +9 -158
  600. data/lib/hecks/projections/deploy/fargate/monitoring/alarms.rb +115 -0
  601. data/lib/hecks/projections/deploy/fargate/monitoring/reading.rb +84 -0
  602. data/lib/hecks/projections/deploy/fargate/monitoring/topic.rb +59 -0
  603. data/lib/hecks/projections/deploy/fargate/monitoring/warmer.rb +90 -0
  604. data/lib/hecks/projections/deploy/fargate/monitoring/warmer_roles.rb +76 -0
  605. data/lib/hecks/projections/deploy/fargate/monitoring.rb +14 -348
  606. data/lib/hecks/projections/deploy/fargate/sections.rb +115 -0
  607. data/lib/hecks/projections/deploy/fargate/settings/ids.rb +55 -0
  608. data/lib/hecks/projections/deploy/fargate/settings/tuning.rb +77 -0
  609. data/lib/hecks/projections/deploy/fargate/settings.rb +17 -104
  610. data/lib/hecks/projections/deploy/fargate/stack/blocks.rb +91 -0
  611. data/lib/hecks/projections/deploy/fargate/stack/readers.rb +87 -0
  612. data/lib/hecks/projections/deploy/fargate/stack/recipes.rb +106 -0
  613. data/lib/hecks/projections/deploy/fargate/stack.rb +146 -0
  614. data/lib/hecks/projections/deploy/fargate/task_sections.rb +56 -0
  615. data/lib/hecks/projections/deploy/fargate/yaml.rb +1 -1
  616. data/lib/hecks/projections/deploy/fargate.rb +51 -756
  617. data/lib/hecks/projections/deploy/lambda/pii.rb +49 -0
  618. data/lib/hecks/projections/deploy/lambda/stack/blocks.rb +118 -0
  619. data/lib/hecks/projections/deploy/lambda/stack/checks.rb +64 -0
  620. data/lib/hecks/projections/deploy/lambda/stack/deploy_chain.rb +119 -0
  621. data/lib/hecks/projections/deploy/lambda/stack/readers.rb +62 -0
  622. data/lib/hecks/projections/deploy/lambda/stack/reading.rb +170 -0
  623. data/lib/hecks/projections/deploy/lambda/stack/reading_web.rb +53 -0
  624. data/lib/hecks/projections/deploy/lambda/stack/recipes.rb +112 -0
  625. data/lib/hecks/projections/deploy/lambda/stack/web.rb +57 -0
  626. data/lib/hecks/projections/deploy/lambda/stack.rb +54 -0
  627. data/lib/hecks/projections/deploy/lambda.rb +77 -1885
  628. data/lib/hecks/projections/deploy/preview/access_yaml.rb +8 -74
  629. data/lib/hecks/projections/deploy/preview/containers.rb +18 -7
  630. data/lib/hecks/projections/deploy/preview/routing_yaml.rb +15 -87
  631. data/lib/hecks/projections/deploy/preview/settings.rb +7 -4
  632. data/lib/hecks/projections/deploy/preview/task_yaml.rb +42 -106
  633. data/lib/hecks/projections/deploy/preview/template.rb +11 -106
  634. data/lib/hecks/projections/deploy/preview/yaml_text.rb +1 -1
  635. data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +1 -1
  636. data/lib/hecks/projections/deploy/scripts/settings.rb +14 -6
  637. data/lib/hecks/projections/deploy/scripts.rb +11 -9
  638. data/lib/hecks/projections/deploy/shared/rows.rb +48 -0
  639. data/lib/hecks/projections/deploy/shared.rb +89 -449
  640. data/lib/hecks/projections/deploy/shared_database_instance/templates/Makefile.tmpl +11 -0
  641. data/lib/hecks/projections/deploy/shared_database_instance/templates/README.md.tmpl +25 -0
  642. data/lib/hecks/projections/deploy/shared_database_instance/templates/rds.yaml.tmpl +180 -0
  643. data/lib/hecks/projections/deploy/shared_database_instance.rb +106 -0
  644. data/lib/hecks/projections/deploy/smoke.rb +15 -10
  645. data/lib/hecks/projections/deploy/template_diff/comparer.rb +21 -147
  646. data/lib/hecks/projections/deploy/template_diff/normalizer.rb +60 -0
  647. data/lib/hecks/projections/deploy/template_diff/value_diff.rb +136 -0
  648. data/lib/hecks/projections/deploy/template_diff.rb +8 -3
  649. data/lib/hecks/projections/deploy/templates/fargate/Dockerfile.tmpl +28 -0
  650. data/lib/hecks/projections/deploy/templates/fargate/Makefile.tmpl +63 -0
  651. data/lib/hecks/projections/deploy/templates/fargate/always_params.tmpl +4 -0
  652. data/lib/hecks/projections/deploy/templates/fargate/deploy_plain.tmpl +1 -0
  653. data/lib/hecks/projections/deploy/templates/fargate/deploy_shared.tmpl +11 -0
  654. data/lib/hecks/projections/deploy/templates/fargate/mint_era_own.tmpl +44 -0
  655. data/lib/hecks/projections/deploy/templates/fargate/mint_era_shared.tmpl +8 -0
  656. data/lib/hecks/projections/deploy/templates/fargate/missing_owner.tmpl +9 -0
  657. data/lib/hecks/projections/deploy/templates/fargate/oauth_params.tmpl +7 -0
  658. data/lib/hecks/projections/deploy/templates/fargate/oauth_task_env.tmpl +4 -0
  659. data/lib/hecks/projections/deploy/templates/fargate/oauth_task_policy.tmpl +7 -0
  660. data/lib/hecks/projections/deploy/templates/fargate/owning_params.tmpl +33 -0
  661. data/lib/hecks/projections/deploy/templates/fargate/template.yaml.tmpl +281 -0
  662. data/lib/hecks/projections/deploy/templates/lambda/Makefile.tmpl +218 -0
  663. data/lib/hecks/projections/deploy/templates/lambda/aurora_depends.tmpl +18 -0
  664. data/lib/hecks/projections/deploy/templates/lambda/build_dispatch_none.tmpl +10 -0
  665. data/lib/hecks/projections/deploy/templates/lambda/build_pg.tmpl +15 -0
  666. data/lib/hecks/projections/deploy/templates/lambda/build_plain.tmpl +2 -0
  667. data/lib/hecks/projections/deploy/templates/lambda/build_web.tmpl +11 -0
  668. data/lib/hecks/projections/deploy/templates/lambda/env_blind_guard.tmpl +4 -0
  669. data/lib/hecks/projections/deploy/templates/lambda/mint_era_own.tmpl +122 -0
  670. data/lib/hecks/projections/deploy/templates/lambda/mint_era_shared.tmpl +47 -0
  671. data/lib/hecks/projections/deploy/templates/lambda/missing_owner.tmpl +9 -0
  672. data/lib/hecks/projections/deploy/templates/lambda/nat_comment_oauth.tmpl +14 -0
  673. data/lib/hecks/projections/deploy/templates/lambda/nat_comment_plain.tmpl +3 -0
  674. data/lib/hecks/projections/deploy/templates/lambda/oauth_note.tmpl +8 -0
  675. data/lib/hecks/projections/deploy/templates/lambda/params_oauth.tmpl +13 -0
  676. data/lib/hecks/projections/deploy/templates/lambda/params_shared.tmpl +33 -0
  677. data/lib/hecks/projections/deploy/templates/lambda/pg_native.tmpl +71 -0
  678. data/lib/hecks/projections/deploy/templates/lambda/pii_oac.tmpl +8 -0
  679. data/lib/hecks/projections/deploy/templates/lambda/pii_permission.tmpl +8 -0
  680. data/lib/hecks/projections/deploy/templates/lambda/pii_resources.tmpl +116 -0
  681. data/lib/hecks/projections/deploy/templates/lambda/predeploy_bridge.tmpl +30 -0
  682. data/lib/hecks/projections/deploy/templates/lambda/predeploy_bridge_oauth.tmpl +12 -0
  683. data/lib/hecks/projections/deploy/templates/lambda/predeploy_bridge_plain.tmpl +7 -0
  684. data/lib/hecks/projections/deploy/templates/lambda/rename_schema_own.tmpl +93 -0
  685. data/lib/hecks/projections/deploy/templates/lambda/rename_schema_shared.tmpl +7 -0
  686. data/lib/hecks/projections/deploy/templates/lambda/rust_oauth_env.tmpl +17 -0
  687. data/lib/hecks/projections/deploy/templates/lambda/rust_oauth_policy.tmpl +16 -0
  688. data/lib/hecks/projections/deploy/templates/lambda/rust_session_secret.tmpl +13 -0
  689. data/lib/hecks/projections/deploy/templates/lambda/samconfig.toml.tmpl +12 -0
  690. data/lib/hecks/projections/deploy/templates/lambda/shared_note.tmpl +6 -0
  691. data/lib/hecks/projections/deploy/templates/lambda/sync_oauth.tmpl +23 -0
  692. data/lib/hecks/projections/deploy/templates/lambda/template.yaml.tmpl +187 -0
  693. data/lib/hecks/projections/deploy/templates/lambda/translation_own.tmpl +46 -0
  694. data/lib/hecks/projections/deploy/templates/lambda/translation_shared.tmpl +2 -0
  695. data/lib/hecks/projections/deploy/templates/lambda/web_function.tmpl +207 -0
  696. data/lib/hecks/projections/deploy/templates/lambda/web_google_oauth_env.tmpl +12 -0
  697. data/lib/hecks/projections/deploy/templates/lambda/web_no_oauth_env.tmpl +7 -0
  698. data/lib/hecks/projections/deploy/templates/lambda/web_oauth_policy.tmpl +4 -0
  699. data/lib/hecks/projections/deploy/templates/lambda/webhook_secret_resource.tmpl +20 -0
  700. data/lib/hecks/projections/deploy/templates/preview/alb.tmpl +8 -0
  701. data/lib/hecks/projections/deploy/templates/preview/alb_security_group.tmpl +11 -0
  702. data/lib/hecks/projections/deploy/templates/preview/assume_role.tmpl +6 -0
  703. data/lib/hecks/projections/deploy/templates/preview/base_parameters.tmpl +24 -0
  704. data/lib/hecks/projections/deploy/templates/preview/cluster.tmpl +4 -0
  705. data/lib/hecks/projections/deploy/templates/preview/container_secret.tmpl +9 -0
  706. data/lib/hecks/projections/deploy/templates/preview/db_init_script.sh.tmpl +23 -0
  707. data/lib/hecks/projections/deploy/templates/preview/db_init_secrets.tmpl +5 -0
  708. data/lib/hecks/projections/deploy/templates/preview/db_init_task.tmpl +39 -0
  709. data/lib/hecks/projections/deploy/templates/preview/desired_count.tmpl +5 -0
  710. data/lib/hecks/projections/deploy/templates/preview/distribution.tmpl +24 -0
  711. data/lib/hecks/projections/deploy/templates/preview/execution_role.tmpl +16 -0
  712. data/lib/hecks/projections/deploy/templates/preview/header.tmpl +16 -0
  713. data/lib/hecks/projections/deploy/templates/preview/ingress.tmpl +8 -0
  714. data/lib/hecks/projections/deploy/templates/preview/listener.tmpl +9 -0
  715. data/lib/hecks/projections/deploy/templates/preview/listener_rule.tmpl +11 -0
  716. data/lib/hecks/projections/deploy/templates/preview/log_group.tmpl +5 -0
  717. data/lib/hecks/projections/deploy/templates/preview/log_options.tmpl +5 -0
  718. data/lib/hecks/projections/deploy/templates/preview/outputs.tmpl +14 -0
  719. data/lib/hecks/projections/deploy/templates/preview/service.tmpl +17 -0
  720. data/lib/hecks/projections/deploy/templates/preview/session_secret.tmpl +11 -0
  721. data/lib/hecks/projections/deploy/templates/preview/target_group.tmpl +9 -0
  722. data/lib/hecks/projections/deploy/templates/preview/task_definition.tmpl +15 -0
  723. data/lib/hecks/projections/deploy/templates/preview/task_role.tmpl +22 -0
  724. data/lib/hecks/projections/deploy/templates/shared/aurora_db.tmpl +52 -0
  725. data/lib/hecks/projections/deploy/templates/shared/bastion.tmpl +74 -0
  726. data/lib/hecks/projections/deploy/templates/shared/bastion_own_public.tmpl +41 -0
  727. data/lib/hecks/projections/deploy/templates/shared/bastion_reuse_public.tmpl +10 -0
  728. data/lib/hecks/projections/deploy/templates/shared/nat_gateway.tmpl +102 -0
  729. data/lib/hecks/projections/deploy/templates/shared/oauth_egress.tmpl +17 -0
  730. data/lib/hecks/projections/deploy/templates/shared/plain_db.tmpl +16 -0
  731. data/lib/hecks/projections/deploy/templates/shared/vpc_and_database.tmpl +67 -0
  732. data/lib/hecks/projections/deploy/text_template.rb +35 -0
  733. data/lib/hecks/projections/deploy/vercel/settings.rb +83 -0
  734. data/lib/hecks/projections/deploy/vercel.rb +134 -0
  735. data/lib/hecks/projections/diagrams/dispatch.rb +114 -0
  736. data/lib/hecks/projections/diagrams/statecharts.rb +59 -0
  737. data/lib/hecks/projections/diagrams/structure.rb +114 -0
  738. data/lib/hecks/projections/diagrams.rb +33 -256
  739. data/lib/hecks/projections/glossary/entries.rb +140 -0
  740. data/lib/hecks/projections/glossary/html/page.rb +96 -0
  741. data/lib/hecks/projections/glossary/html/parser.rb +66 -0
  742. data/lib/hecks/projections/glossary/html/sections.rb +78 -0
  743. data/lib/hecks/projections/glossary/html.rb +7 -179
  744. data/lib/hecks/projections/glossary/index.rb +45 -0
  745. data/lib/hecks/projections/glossary/markdown.rb +22 -11
  746. data/lib/hecks/projections/glossary/mermaid.rb +44 -31
  747. data/lib/hecks/projections/glossary/sensitivity.rb +7 -4
  748. data/lib/hecks/projections/glossary/sentences/value_objects.rb +77 -0
  749. data/lib/hecks/projections/glossary/sentences.rb +42 -81
  750. data/lib/hecks/projections/glossary/slugs.rb +33 -0
  751. data/lib/hecks/projections/glossary.rb +22 -190
  752. data/lib/hecks/projections/model.rb +20 -14
  753. data/lib/hecks/projections/rust_vocabulary/arguments/support.rb +33 -0
  754. data/lib/hecks/projections/rust_vocabulary/arguments.rb +171 -0
  755. data/lib/hecks/projections/rust_vocabulary/enum_body.rb +114 -0
  756. data/lib/hecks/projections/rust_vocabulary/tests.rb +144 -0
  757. data/lib/hecks/projections/rust_vocabulary.rb +24 -293
  758. data/lib/hecks/projections/site/admin.rb +15 -9
  759. data/lib/hecks/projections/site/admin_cms/templates/membership.rb +115 -0
  760. data/lib/hecks/projections/site/admin_cms/templates/session_strategy.rb +90 -0
  761. data/lib/hecks/projections/site/admin_cms/templates/sso.rb +101 -0
  762. data/lib/hecks/projections/site/admin_cms/templates/sso_tail.rb +54 -0
  763. data/lib/hecks/projections/site/admin_cms/templates/users.rb +83 -0
  764. data/lib/hecks/projections/site/admin_cms/templates.rb +14 -369
  765. data/lib/hecks/projections/site/admin_cms.rb +15 -9
  766. data/lib/hecks/projections/site/edge/behaviours.rb +10 -6
  767. data/lib/hecks/projections/site/edge/checks.rb +30 -80
  768. data/lib/hecks/projections/site/edge/findings.rb +28 -0
  769. data/lib/hecks/projections/site/edge/route_checks.rb +110 -0
  770. data/lib/hecks/projections/site/edge/row_reader.rb +52 -0
  771. data/lib/hecks/projections/site/edge/rules.rb +28 -26
  772. data/lib/hecks/projections/site/edge.rb +20 -31
  773. data/lib/hecks/projections/site/live_edge.rb +9 -7
  774. data/lib/hecks/projections/site/payload/fields/definitions.rb +90 -0
  775. data/lib/hecks/projections/site/payload/fields/readers.rb +69 -0
  776. data/lib/hecks/projections/site/payload/fields.rb +14 -111
  777. data/lib/hecks/projections/site/payload/lifecycle/text.rb +84 -0
  778. data/lib/hecks/projections/site/payload/lifecycle/text_tail.rb +106 -0
  779. data/lib/hecks/projections/site/payload/lifecycle.rb +8 -166
  780. data/lib/hecks/projections/site/payload/model.rb +22 -22
  781. data/lib/hecks/projections/site/payload/specs/wire.rb +69 -0
  782. data/lib/hecks/projections/site/payload/specs.rb +24 -68
  783. data/lib/hecks/projections/site/payload_driver.rb +19 -17
  784. data/lib/hecks/projections/site/root_rows.rb +12 -4
  785. data/lib/hecks/projections/site/routes_ts/helpers.rb +79 -0
  786. data/lib/hecks/projections/site/routes_ts/listings.rb +75 -0
  787. data/lib/hecks/projections/site/routes_ts/navigation.rb +79 -0
  788. data/lib/hecks/projections/site/routes_ts.rb +27 -175
  789. data/lib/hecks/projections/site/site_admin/access.rb +104 -0
  790. data/lib/hecks/projections/site/site_admin/session.rb +127 -0
  791. data/lib/hecks/projections/site/site_admin.rb +12 -219
  792. data/lib/hecks/projections/site/site_cdn.rb +12 -7
  793. data/lib/hecks/projections/site/site_host/dockerfile.rb +75 -0
  794. data/lib/hecks/projections/site/site_host/templates.rb +19 -67
  795. data/lib/hecks/projections/site/site_root/workflow.rb +65 -0
  796. data/lib/hecks/projections/site/site_root.rb +3 -54
  797. data/lib/hecks/projections/site/table/checks.rb +28 -57
  798. data/lib/hecks/projections/site/table/link_builder.rb +14 -5
  799. data/lib/hecks/projections/site/table/navigation_checks.rb +75 -0
  800. data/lib/hecks/projections/site/table/row_builder.rb +31 -53
  801. data/lib/hecks/projections/site/table/row_defaults.rb +65 -0
  802. data/lib/hecks/projections/site/table.rb +9 -5
  803. data/lib/hecks/projections/vocabulary.rb +34 -31
  804. data/lib/hecks/projections.rb +2 -0
  805. data/lib/hecks/projector/cli_audience.rb +42 -0
  806. data/lib/hecks/projector/cli_projector/claims.rb +149 -0
  807. data/lib/hecks/projector/cli_projector/command_help.rb +65 -0
  808. data/lib/hecks/projector/cli_projector/command_specs.rb +133 -0
  809. data/lib/hecks/projector/cli_projector/listing.rb +100 -0
  810. data/lib/hecks/projector/cli_projector/option_specs.rb +116 -0
  811. data/lib/hecks/projector/cli_projector/query_specs.rb +67 -0
  812. data/lib/hecks/projector/cli_projector/usage.rb +101 -0
  813. data/lib/hecks/projector/cli_projector.rb +15 -532
  814. data/lib/hecks/projector/docs_projector/attributes.rb +78 -0
  815. data/lib/hecks/projector/docs_projector/behaviour.rb +127 -0
  816. data/lib/hecks/projector/docs_projector/closing.rb +40 -0
  817. data/lib/hecks/projector/docs_projector.rb +58 -192
  818. data/lib/hecks/projector/exporter/bindings.rb +174 -0
  819. data/lib/hecks/projector/exporter/translations.rb +127 -0
  820. data/lib/hecks/projector/exporter.rb +8 -279
  821. data/lib/hecks/projector/narrate_projector/commands.rb +108 -0
  822. data/lib/hecks/projector/narrate_projector/reactions.rb +33 -0
  823. data/lib/hecks/projector/narrate_projector.rb +60 -160
  824. data/lib/hecks/projector.rb +22 -13
  825. data/lib/hecks/quality_control/adapters/agent_profile.rb +25 -16
  826. data/lib/hecks/quality_control/adapters/github_checks.rb +49 -6
  827. data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +1 -1
  828. data/lib/hecks/quality_control/adapters/github_issues.rb +22 -10
  829. data/lib/hecks/quality_control/cli/qa_discover_external_domains/parsing.rb +54 -0
  830. data/lib/hecks/quality_control/cli/qa_discover_external_domains/reporting.rb +44 -0
  831. data/lib/hecks/quality_control/cli/qa_discover_external_domains/scanning.rb +119 -0
  832. data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +28 -155
  833. data/lib/hecks/quality_control/cli/qa_domain_novelty/verdict.rb +76 -0
  834. data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +33 -66
  835. data/lib/hecks/quality_control/cli/qa_generated_domains/arguments.rb +62 -0
  836. data/lib/hecks/quality_control/cli/qa_generated_domains/blueprints.rb +45 -0
  837. data/lib/hecks/quality_control/cli/qa_generated_domains/evaluation.rb +107 -0
  838. data/lib/hecks/quality_control/cli/qa_generated_domains/promotion.rb +107 -0
  839. data/lib/hecks/quality_control/cli/qa_generated_domains/reporting.rb +97 -0
  840. data/lib/hecks/quality_control/cli/qa_generated_domains/shrinking.rb +70 -0
  841. data/lib/hecks/quality_control/cli/qa_generated_domains.rb +43 -327
  842. data/lib/hecks/quality_control/cli/qa_log_bug/arguments.rb +55 -0
  843. data/lib/hecks/quality_control/cli/qa_log_bug/proof.rb +65 -0
  844. data/lib/hecks/quality_control/cli/qa_log_bug.rb +18 -81
  845. data/lib/hecks/quality_control/cli/qa_mine_combinations/arguments.rb +54 -0
  846. data/lib/hecks/quality_control/cli/qa_mine_combinations/booting.rb +96 -0
  847. data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +45 -109
  848. data/lib/hecks/quality_control/cli/qa_open_pr/arguments.rb +55 -0
  849. data/lib/hecks/quality_control/cli/qa_open_pr/recording.rb +79 -0
  850. data/lib/hecks/quality_control/cli/qa_open_pr/rules.rb +122 -0
  851. data/lib/hecks/quality_control/cli/qa_open_pr.rb +41 -200
  852. data/lib/hecks/quality_control/cli/qa_postgres_migrate/copying.rb +45 -0
  853. data/lib/hecks/quality_control/cli/qa_postgres_migrate/reporting.rb +33 -0
  854. data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +37 -63
  855. data/lib/hecks/quality_control/cli/qa_postgres_role/ownership.rb +57 -0
  856. data/lib/hecks/quality_control/cli/qa_postgres_role.rb +66 -71
  857. data/lib/hecks/quality_control/cli/qa_pr_check/checking.rb +118 -0
  858. data/lib/hecks/quality_control/cli/qa_pr_check/reporting.rb +54 -0
  859. data/lib/hecks/quality_control/cli/qa_pr_check.rb +28 -145
  860. data/lib/hecks/quality_control/cli/qa_seed_angles/seed.rb +80 -0
  861. data/lib/hecks/quality_control/cli/qa_seed_angles.rb +13 -86
  862. data/lib/hecks/quality_control/cli/qa_sweep/all_mode/children.rb +80 -0
  863. data/lib/hecks/quality_control/cli/qa_sweep/all_mode/report.rb +125 -0
  864. data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +63 -193
  865. data/lib/hecks/quality_control/cli/qa_sweep/checks/boundary.rb +92 -0
  866. data/lib/hecks/quality_control/cli/qa_sweep/checks/engines.rb +92 -0
  867. data/lib/hecks/quality_control/cli/qa_sweep/checks/seeds.rb +86 -0
  868. data/lib/hecks/quality_control/cli/qa_sweep/checks/shrinking.rb +69 -0
  869. data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +10 -248
  870. data/lib/hecks/quality_control/cli/qa_sweep/conclusion.rb +60 -0
  871. data/lib/hecks/quality_control/cli/qa_sweep/depth.rb +61 -0
  872. data/lib/hecks/quality_control/cli/qa_sweep/dials.rb +27 -13
  873. data/lib/hecks/quality_control/cli/qa_sweep/finding_report/shrunk.rb +42 -0
  874. data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +40 -41
  875. data/lib/hecks/quality_control/cli/qa_sweep/parsing/validation.rb +70 -0
  876. data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +35 -65
  877. data/lib/hecks/quality_control/cli/qa_sweep/release_mode.rb +41 -22
  878. data/lib/hecks/quality_control/cli/qa_sweep/scratch.rb +67 -0
  879. data/lib/hecks/quality_control/cli/qa_sweep/seat.rb +94 -0
  880. data/lib/hecks/quality_control/cli/qa_sweep/seed_loop.rb +157 -0
  881. data/lib/hecks/quality_control/cli/qa_sweep/target_setup.rb +115 -0
  882. data/lib/hecks/quality_control/cli/qa_sweep.rb +22 -445
  883. data/lib/hecks/quality_control/cli/qa_tick/output.rb +107 -0
  884. data/lib/hecks/quality_control/cli/qa_tick/preflight.rb +95 -0
  885. data/lib/hecks/quality_control/cli/qa_tick.rb +42 -175
  886. data/lib/hecks/query_ir/formatting.rb +86 -0
  887. data/lib/hecks/query_ir/rules.rb +132 -0
  888. data/lib/hecks/query_ir/touchpoints.rb +104 -0
  889. data/lib/hecks/query_ir.rb +33 -281
  890. data/lib/hecks/query_ir_mcp/tools.rb +68 -0
  891. data/lib/hecks/query_ir_mcp.rb +27 -71
  892. data/lib/hecks/query_specification/common/comparison.rb +25 -5
  893. data/lib/hecks/query_specification/common/dsl.rb +1 -1
  894. data/lib/hecks/query_specification/common/null_policy.rb +9 -6
  895. data/lib/hecks/query_specification/common/options.rb +21 -14
  896. data/lib/hecks/query_specification/field_path.rb +5 -2
  897. data/lib/hecks/query_specification/hop_path.rb +15 -18
  898. data/lib/hecks/release/lane.rb +22 -0
  899. data/lib/hecks/release/runner/clean_tree.rb +2 -2
  900. data/lib/hecks/release/runner/commands.rb +1 -1
  901. data/lib/hecks/release/runner/options.rb +82 -0
  902. data/lib/hecks/release/runner/preflight.rb +12 -7
  903. data/lib/hecks/release/runner/publishing.rb +86 -0
  904. data/lib/hecks/release/runner/tagger.rb +8 -3
  905. data/lib/hecks/release/runner.rb +40 -156
  906. data/lib/hecks/rendering.rb +13 -9
  907. data/lib/hecks/router/door.rb +37 -0
  908. data/lib/hecks/router/namespace_installer.rb +45 -83
  909. data/lib/hecks/router/options_proxy.rb +44 -0
  910. data/lib/hecks/runtime/adapter_lookup.rb +45 -24
  911. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -8
  912. data/lib/hecks/runtime/command_interpreter/delegation.rb +116 -0
  913. data/lib/hecks/runtime/command_interpreter/enforcement.rb +38 -0
  914. data/lib/hecks/runtime/command_interpreter/hydration.rb +139 -0
  915. data/lib/hecks/runtime/command_interpreter/list_mutations.rb +98 -0
  916. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +67 -114
  917. data/lib/hecks/runtime/command_interpreter/persisting.rb +96 -0
  918. data/lib/hecks/runtime/command_interpreter.rb +57 -352
  919. data/lib/hecks/runtime/command_rules/admissibility.rb +64 -147
  920. data/lib/hecks/runtime/command_rules/arithmetic.rb +13 -72
  921. data/lib/hecks/runtime/command_rules/authorization.rb +9 -9
  922. data/lib/hecks/runtime/command_rules/emission.rb +13 -14
  923. data/lib/hecks/runtime/command_rules/guard_state.rb +49 -0
  924. data/lib/hecks/runtime/command_rules/invariants.rb +84 -0
  925. data/lib/hecks/runtime/command_rules/operands.rb +88 -0
  926. data/lib/hecks/runtime/command_rules/references.rb +59 -57
  927. data/lib/hecks/runtime/command_rules/tenant_boundary.rb +69 -0
  928. data/lib/hecks/runtime/dependency_planning/analyzer.rb +90 -0
  929. data/lib/hecks/runtime/dependency_planning/expression_reads.rb +73 -0
  930. data/lib/hecks/runtime/dependency_planning/mutation_analysis.rb +89 -0
  931. data/lib/hecks/runtime/dependency_planning/rule_analysis.rb +82 -0
  932. data/lib/hecks/runtime/dependency_planning.rb +3 -250
  933. data/lib/hecks/runtime/dispatcher/queries.rb +62 -0
  934. data/lib/hecks/runtime/dispatcher/result.rb +55 -0
  935. data/lib/hecks/runtime/dispatcher/routing.rb +107 -0
  936. data/lib/hecks/runtime/dispatcher.rb +64 -209
  937. data/lib/hecks/runtime/entity_element/location.rb +124 -0
  938. data/lib/hecks/runtime/entity_element/mutations.rb +150 -0
  939. data/lib/hecks/runtime/entity_element.rb +5 -177
  940. data/lib/hecks/runtime/entity_interpreter/enforcement.rb +51 -0
  941. data/lib/hecks/runtime/entity_interpreter/locating.rb +62 -0
  942. data/lib/hecks/runtime/entity_interpreter/resolution.rb +42 -0
  943. data/lib/hecks/runtime/entity_interpreter/saving.rb +49 -0
  944. data/lib/hecks/runtime/entity_interpreter.rb +45 -164
  945. data/lib/hecks/runtime/identity.rb +15 -9
  946. data/lib/hecks/runtime/instance.rb +11 -7
  947. data/lib/hecks/runtime/interpreting.rb +16 -8
  948. data/lib/hecks/runtime/invocation.rb +3 -155
  949. data/lib/hecks/runtime/invocation_builder.rb +132 -0
  950. data/lib/hecks/runtime/invocation_facts.rb +87 -0
  951. data/lib/hecks/runtime/loader/boot_steps.rb +96 -0
  952. data/lib/hecks/runtime/loader/described.rb +27 -0
  953. data/lib/hecks/runtime/loader.rb +27 -114
  954. data/lib/hecks/runtime/outbox/consumer_runner.rb +40 -0
  955. data/lib/hecks/runtime/outbox/fanout.rb +82 -0
  956. data/lib/hecks/runtime/outbox/relay.rb +149 -0
  957. data/lib/hecks/runtime/outbox.rb +3 -214
  958. data/lib/hecks/runtime/policy_interpreter/arguments.rb +67 -0
  959. data/lib/hecks/runtime/policy_interpreter/fan_out.rb +96 -0
  960. data/lib/hecks/runtime/policy_interpreter.rb +22 -137
  961. data/lib/hecks/runtime/port_operation_interpreter.rb +18 -17
  962. data/lib/hecks/runtime/query_interpreter/arguments.rb +51 -0
  963. data/lib/hecks/runtime/query_interpreter/entity_rows.rb +82 -0
  964. data/lib/hecks/runtime/query_interpreter/outside_answer.rb +89 -0
  965. data/lib/hecks/runtime/query_interpreter.rb +43 -191
  966. data/lib/hecks/runtime/reaction_invocation/identities.rb +92 -0
  967. data/lib/hecks/runtime/reaction_invocation/target_resolution.rb +88 -0
  968. data/lib/hecks/runtime/reaction_invocation.rb +66 -183
  969. data/lib/hecks/runtime/reaction_outcome.rb +7 -3
  970. data/lib/hecks/runtime/read_model_interpreter/head_ordering.rb +49 -0
  971. data/lib/hecks/runtime/read_model_interpreter/reductions.rb +123 -0
  972. data/lib/hecks/runtime/read_model_interpreter/shaping.rb +100 -0
  973. data/lib/hecks/runtime/read_model_interpreter.rb +71 -214
  974. data/lib/hecks/runtime/reference_hop.rb +11 -11
  975. data/lib/hecks/runtime/refusal_wording.rb +11 -8
  976. data/lib/hecks/runtime/registry/chapter_verification.rb +84 -0
  977. data/lib/hecks/runtime/registry/declarations.rb +17 -0
  978. data/lib/hecks/runtime/registry/durability_warnings.rb +71 -0
  979. data/lib/hecks/runtime/registry/hecksagon_rules.rb +124 -0
  980. data/lib/hecks/runtime/registry/merging.rb +49 -0
  981. data/lib/hecks/runtime/registry/providers.rb +139 -0
  982. data/lib/hecks/runtime/registry/query_verification.rb +144 -0
  983. data/lib/hecks/runtime/registry/read_repository.rb +61 -0
  984. data/lib/hecks/runtime/registry/runtime_state.rb +27 -0
  985. data/lib/hecks/runtime/registry/saga_persistence.rb +12 -8
  986. data/lib/hecks/runtime/registry/verification.rb +45 -389
  987. data/lib/hecks/runtime/registry/world_defaults.rb +3 -3
  988. data/lib/hecks/runtime/registry.rb +58 -296
  989. data/lib/hecks/runtime/remote_dispatcher.rb +47 -31
  990. data/lib/hecks/runtime/saga_interpreter/compensation.rb +90 -0
  991. data/lib/hecks/runtime/saga_interpreter/correlation.rb +19 -10
  992. data/lib/hecks/runtime/saga_interpreter/delivery.rb +147 -0
  993. data/lib/hecks/runtime/saga_interpreter/lifecycle.rb +63 -0
  994. data/lib/hecks/runtime/saga_interpreter/transitions.rb +112 -0
  995. data/lib/hecks/runtime/saga_interpreter.rb +41 -320
  996. data/lib/hecks/runtime/tenant_check.rb +14 -9
  997. data/lib/hecks/runtime/value/admission.rb +28 -19
  998. data/lib/hecks/runtime/value/coercion.rb +55 -404
  999. data/lib/hecks/runtime/value/entity_list_coercion.rb +27 -29
  1000. data/lib/hecks/runtime/value/field_checks.rb +57 -100
  1001. data/lib/hecks/runtime/value/flags.rb +65 -0
  1002. data/lib/hecks/runtime/value/identifiers.rb +64 -0
  1003. data/lib/hecks/runtime/value/references.rb +195 -0
  1004. data/lib/hecks/runtime/value/shape_checks.rb +61 -0
  1005. data/lib/hecks/runtime/value/validation.rb +125 -0
  1006. data/lib/hecks/runtime/value.rb +18 -6
  1007. data/lib/hecks/rust_build/conformance/surface.rb +75 -0
  1008. data/lib/hecks/rust_build/conformance.rb +27 -59
  1009. data/lib/hecks/rust_build/conformance_fuzz.rb +26 -15
  1010. data/lib/hecks/rust_build/coverage.rb +32 -104
  1011. data/lib/hecks/rust_build/coverage_parts/expected.rb +68 -0
  1012. data/lib/hecks/rust_build/coverage_parts/printer.rb +75 -0
  1013. data/lib/hecks/rust_build/host.rb +23 -13
  1014. data/lib/hecks/rust_build/kernel_input.rb +19 -12
  1015. data/lib/hecks/rust_build/native_build.rb +48 -16
  1016. data/lib/hecks/rust_build/project_rust/domain_loader.rb +75 -0
  1017. data/lib/hecks/rust_build/project_rust/root_mod/notes.rb +66 -0
  1018. data/lib/hecks/rust_build/project_rust/root_mod.rb +22 -55
  1019. data/lib/hecks/rust_build/project_rust/target_ir.rb +74 -0
  1020. data/lib/hecks/rust_build/project_rust.rb +21 -89
  1021. data/lib/hecks/rust_build/wasm.rb +27 -7
  1022. data/lib/hecks/rust_build/wasm_browser.rb +7 -7
  1023. data/lib/hecks/rust_build/write_if_changed.rb +3 -6
  1024. data/lib/hecks/rust_build.rb +7 -3
  1025. data/lib/hecks/storehouse/audit.rb +106 -0
  1026. data/lib/hecks/storehouse/callers.rb +73 -0
  1027. data/lib/hecks/storehouse/dispatching.rb +149 -0
  1028. data/lib/hecks/storehouse/introspection.rb +145 -0
  1029. data/lib/hecks/storehouse/querying.rb +78 -0
  1030. data/lib/hecks/storehouse.rb +43 -451
  1031. data/lib/hecks/tickets/bluebook/tickets.bluebook +29 -0
  1032. data/lib/hecks/tools/argument_gate_matrix/dispatching.rb +69 -0
  1033. data/lib/hecks/tools/argument_gate_matrix/rows.rb +121 -0
  1034. data/lib/hecks/tools/argument_gate_matrix/violations.rb +108 -0
  1035. data/lib/hecks/tools/argument_gate_matrix.rb +43 -212
  1036. data/lib/hecks/tools/ci_gate_decision.rb +21 -14
  1037. data/lib/hecks/tools/ci_gates.rb +40 -26
  1038. data/lib/hecks/tools/comment_style/baseline.rb +41 -0
  1039. data/lib/hecks/tools/comment_style/caps_words.rb +104 -0
  1040. data/lib/hecks/tools/comment_style/cli.rb +121 -0
  1041. data/lib/hecks/tools/comment_style/dictionary.rb +60 -0
  1042. data/lib/hecks/tools/comment_style/fixing.rb +119 -0
  1043. data/lib/hecks/tools/comment_style/long_blocks.rb +51 -0
  1044. data/lib/hecks/tools/comment_style/masking.rb +94 -0
  1045. data/lib/hecks/tools/comment_style/patterns.rb +61 -0
  1046. data/lib/hecks/tools/comment_style/run.rb +161 -0
  1047. data/lib/hecks/tools/comment_style/signature.rb +59 -0
  1048. data/lib/hecks/tools/comment_style/source_file.rb +105 -0
  1049. data/lib/hecks/tools/comment_style/structure_checks.rb +113 -0
  1050. data/lib/hecks/tools/comment_style/text_checks.rb +67 -0
  1051. data/lib/hecks/tools/comment_style/vocabulary.rb +55 -0
  1052. data/lib/hecks/tools/comment_style/walker.rb +136 -0
  1053. data/lib/hecks/tools/comment_style.rb +17 -1000
  1054. data/lib/hecks/tools/corpus_report.rb +26 -16
  1055. data/lib/hecks/tools/deploy_recipe/generation.rb +59 -0
  1056. data/lib/hecks/tools/deploy_recipe/targets.rb +115 -0
  1057. data/lib/hecks/tools/deploy_recipe/worlds.rb +115 -0
  1058. data/lib/hecks/tools/deploy_recipe.rb +72 -176
  1059. data/lib/hecks/tools/deploy_recipe_lint/checks.rb +78 -0
  1060. data/lib/hecks/tools/deploy_recipe_lint/fixtures.rb +88 -0
  1061. data/lib/hecks/tools/deploy_recipe_lint/makefile.rb +84 -0
  1062. data/lib/hecks/tools/deploy_recipe_lint.rb +29 -192
  1063. data/lib/hecks/tools/drop_implicit_append_fields.rb +20 -12
  1064. data/lib/hecks/tools/era_projection_backfill.rb +50 -33
  1065. data/lib/hecks/tools/era_reattest/reporting.rb +55 -0
  1066. data/lib/hecks/tools/era_reattest.rb +32 -43
  1067. data/lib/hecks/tools/evolve_run/arguments.rb +49 -0
  1068. data/lib/hecks/tools/evolve_run/words.rb +60 -0
  1069. data/lib/hecks/tools/evolve_run.rb +43 -90
  1070. data/lib/hecks/tools/fuzz_sweep/findings.rb +106 -0
  1071. data/lib/hecks/tools/fuzz_sweep/options.rb +80 -0
  1072. data/lib/hecks/tools/fuzz_sweep/pool.rb +74 -0
  1073. data/lib/hecks/tools/fuzz_sweep/reporting.rb +110 -0
  1074. data/lib/hecks/tools/fuzz_sweep.rb +91 -272
  1075. data/lib/hecks/tools/gate.rb +31 -16
  1076. data/lib/hecks/tools/heki_compaction.rb +63 -42
  1077. data/lib/hecks/tools/hoist_local_givens/rewriting.rb +119 -0
  1078. data/lib/hecks/tools/hoist_local_givens.rb +89 -157
  1079. data/lib/hecks/tools/journal_compaction.rb +40 -31
  1080. data/lib/hecks/tools/lanes/files.rb +80 -0
  1081. data/lib/hecks/tools/lanes/live.rb +40 -0
  1082. data/lib/hecks/tools/lanes/rows.rb +45 -0
  1083. data/lib/hecks/tools/lanes/ruleset.rb +66 -0
  1084. data/lib/hecks/tools/lanes/watch_workflow.rb +82 -0
  1085. data/lib/hecks/tools/lanes/workflow.rb +79 -0
  1086. data/lib/hecks/tools/lanes.rb +82 -0
  1087. data/lib/hecks/tools/mutation_run.rb +73 -0
  1088. data/lib/hecks/tools/oidc_manifests.rb +10 -9
  1089. data/lib/hecks/tools/query_ir_run.rb +7 -3
  1090. data/lib/hecks/tools/regeneration_run.rb +40 -26
  1091. data/lib/hecks/tools/rust_comment_style/caps_words.rb +98 -0
  1092. data/lib/hecks/tools/rust_comment_style/fixing.rb +102 -0
  1093. data/lib/hecks/tools/rust_comment_style/masking.rb +85 -0
  1094. data/lib/hecks/tools/rust_comment_style/run.rb +94 -0
  1095. data/lib/hecks/tools/rust_comment_style/source_file.rb +71 -0
  1096. data/lib/hecks/tools/rust_comment_style/structure.rb +79 -0
  1097. data/lib/hecks/tools/rust_comment_style/text_checks.rb +63 -0
  1098. data/lib/hecks/tools/rust_comment_style/tokenizer.rb +102 -0
  1099. data/lib/hecks/tools/rust_comment_style.rb +38 -535
  1100. data/lib/hecks/tools/sequence_script.rb +20 -14
  1101. data/lib/hecks/tools/site_routes/cli.rb +70 -0
  1102. data/lib/hecks/tools/site_routes/root_files.rb +59 -0
  1103. data/lib/hecks/tools/site_routes/templates.rb +77 -0
  1104. data/lib/hecks/tools/site_routes.rb +84 -160
  1105. data/lib/hecks/tools/tail_merge.rb +45 -37
  1106. data/lib/hecks/tools/tenant_provisioning.rb +45 -31
  1107. data/lib/hecks/tools/tools_doc.rb +42 -19
  1108. data/lib/hecks/tools/translation_audit/domain_loading.rb +71 -0
  1109. data/lib/hecks/tools/translation_audit/edges.rb +71 -0
  1110. data/lib/hecks/tools/translation_audit/verdicts.rb +107 -0
  1111. data/lib/hecks/tools/translation_audit.rb +30 -161
  1112. data/lib/hecks/tools/translation_scaffold/reporting.rb +40 -0
  1113. data/lib/hecks/tools/translation_scaffold.rb +77 -60
  1114. data/lib/hecks/tools.rb +2 -0
  1115. data/lib/hecks/vendoring.rb +37 -11
  1116. data/lib/hecks/version.rb +1 -1
  1117. data/lib/hecks/vocabulary.rb +18 -1
  1118. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +7 -9
  1119. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +8 -6
  1120. data/prebuilt/945481eefbdb584649d45f256307053558966a868b9c38dee7ee88f8169610f8.marshal +0 -0
  1121. data/prebuilt/a0818e2de67364dc1ab22868b6cbf869c62da6f8d9b924c778fa5cce2e76ee94.marshal +0 -0
  1122. data/prebuilt/verdicts-be73f0df9eee0abe2f4aadc968321c4b919d19d424a3ccfe1777a71dabf7d9e7.json +1 -0
  1123. data/qa/settings.yml +1 -0
  1124. data/rust/.cargo/mutants.toml +8 -0
  1125. data/rust/host/Cargo.toml +5 -0
  1126. data/rust/host/HECKS_RELEASE +1 -1
  1127. data/rust/host/src/api.rs +28 -5
  1128. data/rust/host/src/auth.rs +43 -1
  1129. data/rust/host/src/boundary_fuzz/api.rs +260 -0
  1130. data/rust/host/src/boundary_fuzz/auth.rs +119 -0
  1131. data/rust/host/src/boundary_fuzz/expr_json.rs +158 -0
  1132. data/rust/host/src/boundary_fuzz/ir.rs +78 -0
  1133. data/rust/host/src/boundary_fuzz/server.rs +227 -0
  1134. data/rust/host/src/boundary_fuzz/web.rs +125 -0
  1135. data/rust/host/src/fuzz_support.rs +165 -0
  1136. data/rust/host/src/ir.rs +4 -0
  1137. data/rust/host/src/main.rs +9 -4
  1138. data/rust/host/src/secrets.rs +44 -0
  1139. data/rust/host/src/server.rs +6 -1
  1140. data/rust/host/src/web.rs +14 -5
  1141. data/rust/parser/fuzz/.gitignore +4 -0
  1142. data/rust/parser/fuzz/Cargo.lock +89 -0
  1143. data/rust/parser/fuzz/Cargo.toml +27 -0
  1144. data/rust/parser/fuzz/README.md +19 -0
  1145. data/rust/parser/fuzz/fuzz_targets/chapter.rs +50 -0
  1146. data/rust/parser/fuzz/fuzz_targets/resolve.rs +35 -0
  1147. data/rust/parser/src/parse/command.rs +14 -2
  1148. data/rust/parser/src/parse/mod.rs +25 -0
  1149. data/rust/parser/src/ruby_value.rs +95 -6
  1150. data/rust/src/kernel/dispatch.rs +4 -0
  1151. data/rust/src/kernel/dispatch_guard_tests.rs +506 -0
  1152. data/rust/src/kernel/json.rs +34 -3
  1153. data/rust/src/kernel/orchestrate.rs +4 -0
  1154. data/rust/src/kernel/orchestrate_guard_tests.rs +708 -0
  1155. metadata +640 -3
  1156. /data/lib/hecks/bluebook/behaviour/{hexagon.rb → hecksagon.rb} +0 -0
@@ -13,49 +13,60 @@ module Hecks
13
13
  # @return [true, String] true, or a message naming each offending instance
14
14
  def lifecycle_values_are_declared(history)
15
15
  bluebook = history.fetch(:bluebook)
16
- declared = {}
17
- bluebook.aggregates.each do |aggregate|
18
- declared[aggregate.hecks_name] = Bluebook::ModelCheck.full_states(aggregate.lifecycle) if aggregate.lifecycle
16
+ declared = bluebook.aggregates.select(&:lifecycle).to_h do |aggregate|
17
+ [aggregate.hecks_name, Bluebook::ModelCheck.full_states(aggregate.lifecycle)]
19
18
  end
20
19
  return true if declared.empty?
21
20
 
22
21
  offenders = history.fetch(:instances).filter_map do |key, state|
23
- aggregate_name = key.split("::").last.split("#").first
24
- states = declared[aggregate_name]
25
- next unless states
26
-
27
- lifecycle = bluebook.aggregate(aggregate_name).lifecycle
28
- value = state[lifecycle.field]
29
- next if value.nil? || states.include?(value.to_s)
30
-
31
- "#{key} holds #{lifecycle.field}=#{value.inspect}, which #{aggregate_name} never declares as a state"
22
+ undeclared_state_offense(bluebook, declared, key, state)
32
23
  end
33
24
 
34
25
  offenders.empty? || offenders.join("; ")
35
26
  end
36
27
 
28
+ # The message for one stored record holding an undeclared lifecycle state, or nil.
29
+ def undeclared_state_offense(bluebook, declared, key, state)
30
+ aggregate_name = key.split("::").last.split("#").first
31
+ states = declared[aggregate_name]
32
+ return unless states
33
+
34
+ lifecycle = bluebook.aggregate(aggregate_name).lifecycle
35
+ value = state[lifecycle.field]
36
+ return if value.nil? || states.include?(value.to_s)
37
+
38
+ "#{key} holds #{lifecycle.field}=#{value.inspect}, which #{aggregate_name} never declares as a state"
39
+ end
40
+
37
41
  # Every logged saga advance follows a `(from_state, to_state)` pair some handler declares.
38
42
  #
39
43
  # @param history [Hash] a replayed history as returned by `Replay.call`
40
44
  # @return [true, String] true, or a message naming the process manager and undeclared pair
41
45
  def saga_advances_follow_declared_handlers(history)
42
- bluebook = history.fetch(:bluebook)
46
+ edges = saga_edges(history.fetch(:bluebook))
47
+ return true if edges.empty?
48
+
49
+ offenders = history.fetch(:sagas).filter_map { |entry| saga_advance_offense(edges, entry) }
50
+ offenders.empty? || offenders.join("; ")
51
+ end
52
+
53
+ # The `(from_state, to_state)` pairs each process manager's handlers declare.
54
+ def saga_edges(bluebook)
43
55
  edges = Hash.new { |h, k| h[k] = [] }
44
56
  bluebook.process_managers.each do |pm|
45
57
  pm.handlers.each { |handler| edges[pm.name] << [handler.from_state, handler.to_state] }
46
58
  end
47
- return true if edges.empty?
48
-
49
- offenders = history.fetch(:sagas).filter_map do |entry|
50
- next unless entry[:advanced]
59
+ edges
60
+ end
51
61
 
52
- pair = [entry[:from], entry[:to]]
53
- next if edges[entry[:process_manager]].include?(pair)
62
+ # The message for one logged saga advance no handler declares, or nil.
63
+ def saga_advance_offense(edges, entry)
64
+ return unless entry[:advanced]
54
65
 
55
- "#{entry[:process_manager]} advanced #{pair.inspect}, which no declared handler names"
56
- end
66
+ pair = [entry[:from], entry[:to]]
67
+ return if edges[entry[:process_manager]].include?(pair)
57
68
 
58
- offenders.empty? || offenders.join("; ")
69
+ "#{entry[:process_manager]} advanced #{pair.inspect}, which no declared handler names"
59
70
  end
60
71
 
61
72
  # Replaying the same steps on a fresh boot yields identical events, refusals and instances.
@@ -70,22 +81,22 @@ module Hecks
70
81
  def replay_is_deterministic(domain_path, steps, adapter: :memory)
71
82
  first = Replay.call(domain_path, steps, adapter: adapter)
72
83
  second = Replay.call(domain_path, steps, adapter: adapter)
84
+ return true if comparable_history(first) == comparable_history(second)
73
85
 
74
- # What is stripped is declared in `Nondeterministic::FIELDS`. Outbox rows are stripped
75
- # per row, not dropped, so status, consumer and event payload stay checked.
76
- strip_outbox_nondeterminism = lambda do |history|
77
- traces = Array(history[:outbox_traces]).map do |trace|
78
- trace.merge(rows: trace[:rows].map do |row|
79
- Nondeterministic.strip(row, :outbox_row).merge(event: Nondeterministic.strip(row[:event], :event))
80
- end)
81
- end
82
- history.merge(outbox_traces: traces)
83
- end
86
+ "two replays of the same #{steps.length} steps produced different histories"
87
+ end
84
88
 
85
- comparable = ->(history) { Nondeterministic.strip(strip_outbox_nondeterminism.call(history), :history) }
86
- return true if comparable.call(first) == comparable.call(second)
89
+ # What is stripped is declared in `Nondeterministic::FIELDS`. Outbox rows are stripped
90
+ # per row, not dropped, so status, consumer and event payload stay checked.
91
+ def comparable_history(history)
92
+ traces = Array(history[:outbox_traces]).map do |trace|
93
+ trace.merge(rows: trace[:rows].map { |row| stripped_outbox_row(row) })
94
+ end
95
+ Nondeterministic.strip(history.merge(outbox_traces: traces), :history)
96
+ end
87
97
 
88
- "two replays of the same #{steps.length} steps produced different histories"
98
+ def stripped_outbox_row(row)
99
+ Nondeterministic.strip(row, :outbox_row).merge(event: Nondeterministic.strip(row[:event], :event))
89
100
  end
90
101
  end
91
102
  end
@@ -0,0 +1,162 @@
1
+ module Hecks
2
+ module Fuzzing
3
+ module Properties
4
+ # Independent recomputations of what each mutation op leaves behind, for
5
+ # `DispatchAndMutations#mutations_match_recompute` to compare against the real dispatch.
6
+ module MutationRecompute
7
+ # What a recomputation needs of the step it re-derives.
8
+ #
9
+ # `before` is the entity's state before the dispatch; `owner` is the construct declaring
10
+ # the mutated attribute, the root aggregate unless a dot-shaped command names an entity.
11
+ Context = Struct.new(:aggregate, :command, :owner, :before, :args)
12
+
13
+ # Dispatches to the recompute rule for `mutation.op`.
14
+ #
15
+ # @param mutation [Object] the mutation the command declares
16
+ # @param current [Object] the mutated attribute's value before the dispatch
17
+ # @param context [Context] the step being re-derived
18
+ # @return [Object, Symbol] the recomputed after-value, or `:unrecomputable`
19
+ def recompute_mutation(mutation, current, context)
20
+ case mutation.op
21
+ when :append then recompute_append(current, mutation.source, context, mutation.target)
22
+ when :remove then recompute_remove(current, mutation.source, context.args)
23
+ when :multiply then recompute_multiply(current, resolve_mutation_source(mutation.source, context.args))
24
+ when :clamp then recompute_clamp(current, mutation.source)
25
+ when :set then recompute_set(mutation.source, context, mutation.target)
26
+ end
27
+ end
28
+
29
+ # Re-derives the `:set` branch of `EntityElement#apply_to_element`. The
30
+ # attribute comes from `owner`, not the root aggregate, which would leave a
31
+ # nested entity's value uncoerced and disagree with the real after-state.
32
+ # Any raise means the raw material was wrong, so the result is `:unrecomputable`.
33
+ def recompute_set(source, context, target)
34
+ raw = resolve_mutation_source(source, context.args)
35
+ attribute = context.owner&.attribute(target)
36
+ coerced = attribute ? Runtime::Value.for_attribute(context.aggregate, attribute, raw) : raw
37
+ Runtime::Value.materialize(coerced)
38
+ rescue StandardError
39
+ :unrecomputable
40
+ end
41
+
42
+ # Re-derives `EntityElement#appended_to_element`: each field resolves from a
43
+ # caller arg (coerced as `Interpreting#coerce_declared_arguments` does) or from
44
+ # the entity's current field (already materialized), then the element is appended.
45
+ # A nested-entity element also gets its declared defaults.
46
+ def recompute_append(current, source_map, context, target = nil)
47
+ fields = source_map.transform_values { |source| resolve_mutation_append_field(source, context) }
48
+ fill_recompute_declared_defaults(context, target, fields)
49
+ Array(current) + [symbolize_deep(fields)]
50
+ end
51
+
52
+ # Fills defaults for a nested-entity element via `Instance.default_for`, which is
53
+ # independently tested. No-op unless `target` names an entity under `owner`
54
+ # (`owner.entities`, not `aggregate.entities`).
55
+ #
56
+ # A value-object element type (the more common shape: `list_of` a plain composite,
57
+ # not a nested entity) defaults the other way real dispatch does — through
58
+ # `Runtime::Value.apply_defaults`, the exact primitive `EntityElement#appended_to_
59
+ # element`'s own `Value.build` call uses. Without this branch, a caller-omitted,
60
+ # VO-declared `default:` field is left out of the recomputed element entirely,
61
+ # disagreeing with real dispatch's fully-defaulted one.
62
+ def fill_recompute_declared_defaults(context, target, fields)
63
+ element_type = target && context.owner&.attribute(target)&.type
64
+ return fields unless element_type
65
+
66
+ entity = context.owner.entities.find { |piece| piece.hecks_name == element_type.to_s }
67
+ return fill_entity_defaults(context.aggregate, entity, fields) if entity
68
+
69
+ fill_value_object_defaults(context.aggregate, element_type, fields)
70
+ end
71
+
72
+ def fill_entity_defaults(aggregate, entity, fields)
73
+ entity.attributes.each do |attribute|
74
+ next if fields.key?(attribute.name)
75
+
76
+ fields[attribute.name] = attribute.list? ? [] : Runtime::Instance.default_for(aggregate, attribute)
77
+ end
78
+ fields
79
+ end
80
+
81
+ def fill_value_object_defaults(aggregate, element_type, fields)
82
+ value_object = aggregate.value_object(element_type)
83
+ value_object ? Runtime::Value.apply_defaults(value_object, fields) : fields
84
+ end
85
+
86
+ # Resolves one appended field's value from its declared source.
87
+ def resolve_mutation_append_field(source, context)
88
+ return source unless source.is_a?(Symbol)
89
+ return context.before[source] unless context.args.key?(source)
90
+
91
+ coerce_recompute_append_arg(context, source, context.args[source])
92
+ end
93
+
94
+ # Coerces a raw arg only when `source` is a declared attribute of the command,
95
+ # as a real dispatch does. Materialized so the comparison is plain data on both sides.
96
+ def coerce_recompute_append_arg(context, source, raw)
97
+ attribute = context.command.attribute(source)
98
+ return raw unless attribute
99
+
100
+ Runtime::Value.materialize(Runtime::Value.for_attribute(context.aggregate, attribute, raw, argument: true))
101
+ end
102
+
103
+ # Re-derives `MutationApplier#removed`: removes every value-equal element.
104
+ # `Value.materialize` first: once `args` arrives normalized (replay.rb's
105
+ # `build_mutation_trace`), a composite `remove:` source is already a built
106
+ # `Runtime::Value` with its own declared defaults filled — comparing it
107
+ # unmaterialized against `current`'s plain Hashes would never match, wrongly
108
+ # keeping an element real dispatch correctly removed.
109
+ def recompute_remove(current, source, args)
110
+ target = symbolize_deep(Runtime::Value.materialize(resolve_mutation_source(source, args)))
111
+ Array(current).reject { |element| symbolize_deep(element) == target }
112
+ end
113
+
114
+ # Re-derives `CommandRules::Arithmetic#multiply` on plain data: a Hash with one
115
+ # numeric field scales that field, a bare Numeric scales itself. A nil
116
+ # `current` is treated as 0.
117
+ def recompute_multiply(current, amount)
118
+ return :unrecomputable unless amount.is_a?(Numeric)
119
+
120
+ apply_to_number(current) { |number| number * amount }
121
+ end
122
+
123
+ # Re-derives `CommandRules::Arithmetic#clamp` like #recompute_multiply. The
124
+ # source is always a literal `[min, max]`, never an argument reference.
125
+ def recompute_clamp(current, bounds)
126
+ return :unrecomputable unless bounds.is_a?(Array) && bounds.size == 2
127
+
128
+ min, max = bounds
129
+ apply_to_number(current) { |number| number.clamp(min, max) }
130
+ end
131
+
132
+ # Yields a bare Numeric, or the first numeric field of a Hash, and puts the result back.
133
+ # Anything else, or a Hash with no numeric field, is `:unrecomputable`; nil counts as 0.
134
+ def apply_to_number(current)
135
+ current ||= 0
136
+ return yield(current) if current.is_a?(Numeric)
137
+ return :unrecomputable unless current.is_a?(Hash)
138
+
139
+ field = current.keys.find { |f| current[f].is_a?(Numeric) }
140
+ return :unrecomputable unless field
141
+
142
+ current.merge(field => yield(current[field]))
143
+ end
144
+
145
+ # A mutation source is an argument name (Symbol) or a literal.
146
+ def resolve_mutation_source(source, args)
147
+ source.is_a?(Symbol) ? args[source] : source
148
+ end
149
+
150
+ # Symbolizes hash keys recursively. Generated args carry string keys while
151
+ # materialized trace state carries symbols, and `Hash#==` would otherwise differ.
152
+ def symbolize_deep(value)
153
+ case value
154
+ when Hash then value.to_h { |key, val| [key.to_sym, symbolize_deep(val)] }
155
+ when Array then value.map { |val| symbolize_deep(val) }
156
+ else value
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
@@ -28,20 +28,24 @@ module Hecks
28
28
  on = row.dig(:event, :name)
29
29
 
30
30
  case row[:status]
31
- when "pending", "claimed"
32
- ["outbox row #{row[:delivery_id]} (#{row[:consumer]} on #{on}) never drained inline — status stayed " \
33
- "#{row[:status].inspect} though delivery is inline by contract (Runtime::Outbox's own header)"]
34
- when "failed"
35
- ["outbox row #{row[:delivery_id]} (#{row[:consumer]} on #{on}) failed to deliver: #{row[:error]} — " \
36
- "a domain refusal never reaches this far; a failed row names a defect in the relay's own consumer " \
37
- "resolution"]
38
- when "delivered"
39
- outbox_delivered_policy_offenders(row, on, trace, bluebooks)
40
- else
41
- []
31
+ when "pending", "claimed" then [undrained_message(row, on)]
32
+ when "failed" then [failed_message(row, on)]
33
+ when "delivered" then outbox_delivered_policy_offenders(row, on, trace, bluebooks)
34
+ else []
42
35
  end
43
36
  end
44
37
 
38
+ def undrained_message(row, on)
39
+ "outbox row #{row[:delivery_id]} (#{row[:consumer]} on #{on}) never drained inline — status stayed " \
40
+ "#{row[:status].inspect} though delivery is inline by contract (Runtime::Outbox's own header)"
41
+ end
42
+
43
+ def failed_message(row, on)
44
+ "outbox row #{row[:delivery_id]} (#{row[:consumer]} on #{on}) failed to deliver: #{row[:error]} — " \
45
+ "a domain refusal never reaches this far; a failed row names a defect in the relay's own consumer " \
46
+ "resolution"
47
+ end
48
+
45
49
  # Offending messages for a delivered `policy:` row that has no `reaction_log` entry.
46
50
  #
47
51
  # Legitimate only when the policy's `where` does not hold; a saga row gets no such check.
@@ -50,21 +54,34 @@ module Hecks
50
54
  return [] unless kind == "policy"
51
55
 
52
56
  home, name = fqn.to_s.split("::", 2)
53
- return [] if trace[:reactions].any? { |entry| entry[:policy] == name && entry[:on] == on }
57
+ return [] if reacted?(trace, name, on)
54
58
 
55
59
  policy = bluebooks[home]&.policies&.find { |candidate| candidate.name == name }
56
- # Undeclared policy: inconclusive, not a mismatch.
57
- return [] unless policy
58
- # Fan-out counts belong to fanout_dispatches_once_per_matching_row.
59
- return [] if policy.fans_out?
60
-
61
- held = independently_re_evaluate_policy_where(policy, row[:event])
62
- # False or inconclusive (the where raised): never a mismatch.
63
- return [] if held != true
64
-
65
- ["outbox row #{row[:delivery_id]} (#{row[:consumer]} on #{on}) drained as delivered, but no matching " \
66
- "reaction_log entry exists and the policy's own where clause independently re-evaluates true — " \
67
- "PolicyInterpreter#deliver only ever returns nil (no reaction_log entry) when where does not hold"]
60
+ return [] unless dropped_reaction_suspected?(policy, row[:event])
61
+
62
+ [dropped_reaction_message(row, on)]
63
+ end
64
+
65
+ def reacted?(trace, policy_name, on)
66
+ trace[:reactions].any? { |entry| entry[:policy] == policy_name && entry[:on] == on }
67
+ end
68
+
69
+ def dropped_reaction_message(row, on)
70
+ "outbox row #{row[:delivery_id]} (#{row[:consumer]} on #{on}) drained as delivered, but no matching " \
71
+ "reaction_log entry exists and the policy's own where clause independently re-evaluates true — " \
72
+ "PolicyInterpreter#deliver only ever returns nil (no reaction_log entry) when where does not hold"
73
+ end
74
+
75
+ # Whether a delivered policy row with no reaction should have produced one.
76
+ #
77
+ # An undeclared policy is inconclusive, not a mismatch; fan-out counts belong to
78
+ # fanout_dispatches_once_per_matching_row; a `where` that is false, or raised, is never a
79
+ # mismatch.
80
+ def dropped_reaction_suspected?(policy, event)
81
+ return false unless policy
82
+ return false if policy.fans_out?
83
+
84
+ independently_re_evaluate_policy_where(policy, event) == true
68
85
  end
69
86
 
70
87
  # Re-evaluates the policy's `where` against the row's recorded payload.
@@ -0,0 +1,61 @@
1
+ module Hecks
2
+ module Fuzzing
3
+ module Properties
4
+ # Re-checks the invariants of stored records and of the entity elements nested in them,
5
+ # independently of the call site that was supposed to refuse a violation live.
6
+ module PieceInvariants
7
+ # The message for one stored record that violates an invariant, or nil.
8
+ def stored_record_offense(bluebooks, key, state)
9
+ domain_name = key.split("::").first
10
+ aggregate_name = key.split("::").last.split("#").first
11
+ aggregate = bluebooks[domain_name]&.aggregate(aggregate_name)
12
+ return unless aggregate
13
+
14
+ violated = violated_invariant(aggregate, state)
15
+ return "#{key} violates #{aggregate_name}'s own declared invariant #{violated.description.inspect}" if violated
16
+
17
+ check_piece_invariants(aggregate, state, key)
18
+ end
19
+
20
+ # The first invariant of `construct` that `state` does not satisfy, or nil.
21
+ def violated_invariant(construct, state)
22
+ construct.invariants.find { |invariant| !Bluebook::Expression::Evaluator.call(invariant.canonical, state) }
23
+ end
24
+
25
+ # A piece's own invariant, checked against every element its owner's
26
+ # `list_of` field holds — reapplies Admissibility#check_entity_invariants'
27
+ # own lookup against a plain Hash state rather than a live Instance.
28
+ def check_piece_invariants(owner_construct, owner_state, key)
29
+ owner_construct.entities.each do |entity|
30
+ next if entity.invariants.empty?
31
+
32
+ list_attr = list_attribute_for(owner_construct, entity)
33
+ next unless list_attr
34
+
35
+ Array(owner_state[list_attr.name]).each do |element|
36
+ problem = piece_problem(entity, element, key)
37
+ return problem if problem
38
+ end
39
+ end
40
+ nil
41
+ end
42
+
43
+ # The owner's `list_of` attribute holding `entity`'s elements.
44
+ def list_attribute_for(owner_construct, entity)
45
+ owner_construct.attributes.find { |a| a.list? && a.type.to_s == entity.hecks_name }
46
+ end
47
+
48
+ # The message for one piece element that violates, or whose own nested pieces violate.
49
+ def piece_problem(entity, element, key)
50
+ violated = violated_invariant(entity, element)
51
+ if violated
52
+ return "#{key}'s own #{entity.hecks_name} violates its declared invariant " \
53
+ "#{violated.description.inspect}"
54
+ end
55
+
56
+ check_piece_invariants(entity, element, key)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,140 @@
1
+ module Hecks
2
+ module Fuzzing
3
+ module Properties
4
+ # Property: every reaction a replay logged is the one its policy declares.
5
+ #
6
+ # `PolicyInterpreter` selects policies by `event_name` and builds the trigger from
7
+ # `target_domain` and `trigger_command`; this reads each logged reaction back against the
8
+ # declaration, so a policy that fired on an event it never named, or dispatched somewhere
9
+ # it never declared, is caught.
10
+ module PolicyWiring
11
+ # Every `history[:reactions]` entry names a declared policy, was logged for the event
12
+ # that policy answers (and one that happened), and triggered the declared target.
13
+ #
14
+ # @param history [Hash] a replayed history, as returned by `Fuzzing::Replay.call`
15
+ # @return [true, String] true, or a message naming each reaction that disagrees
16
+ def policy_reactions_follow_declared_wiring(history)
17
+ bluebooks = history.fetch(:bluebooks, {})
18
+ events = Array(history[:events])
19
+
20
+ offenders = Array(history[:reactions]).filter_map { |reaction| wiring_offender(reaction, bluebooks, events) }
21
+ offenders.empty? || offenders.uniq.join("; ")
22
+ end
23
+
24
+ # A policy declared `expect_undelivered` is held to its word at runtime: its reaction is
25
+ # never delivered, and an event it answers is never silently dropped.
26
+ #
27
+ # model_check holds the static half (a reachable target makes the declaration stale);
28
+ # this is the dynamic half, over a replay. A policy with a `where` or a `for_each` may
29
+ # legitimately log nothing, so the missing-reaction check skips those.
30
+ #
31
+ # @param history [Hash] a replayed history, as returned by `Fuzzing::Replay.call`
32
+ # @return [true, String] true, or a message naming each policy that broke its declaration
33
+ def declared_undelivered_policies_stay_undelivered(history)
34
+ bluebooks = history.fetch(:bluebooks, {})
35
+ reactions = Array(history[:reactions])
36
+ events = Array(history[:events])
37
+
38
+ offenders = declared_undelivered(bluebooks).flat_map do |policy, home|
39
+ delivered_offenders(policy, reactions) + silent_offenders(policy, home, reactions, events)
40
+ end
41
+ offenders.empty? || offenders.uniq.join("; ")
42
+ end
43
+
44
+ # Every `[policy, home]` pair across the bluebooks that declares `expect_undelivered`.
45
+ def declared_undelivered(bluebooks)
46
+ bluebooks.flat_map do |home, bluebook|
47
+ bluebook.policies.select(&:expect_undelivered).map { |policy| [policy, home.to_s] }
48
+ end
49
+ end
50
+
51
+ def delivered_offenders(policy, reactions)
52
+ delivered = reactions.select { |reaction| reaction[:policy] == policy.name && reaction[:delivered] == true }
53
+ delivered.map do |reaction|
54
+ "policy #{policy.name} declares expect_undelivered, but its reaction to #{reaction[:on]} was delivered"
55
+ end
56
+ end
57
+
58
+ # An event the policy answers, with no reaction logged at all: a silent drop.
59
+ def silent_offenders(policy, home, reactions, events)
60
+ return [] if policy.guarded? || policy.fans_out?
61
+
62
+ events.select { |event| answers_event?(policy, event) && !reacted_to?(reactions, policy, event) }
63
+ .map { |event| silent_message(policy, home, event) }
64
+ end
65
+
66
+ def silent_message(policy, home, event)
67
+ "policy #{policy.name} (#{home}) answers #{event[:name]}, which was emitted, yet logged no reaction"
68
+ end
69
+
70
+ def reacted_to?(reactions, policy, event)
71
+ reactions.any? { |reaction| reaction[:policy] == policy.name && reaction[:on] == event[:name] }
72
+ end
73
+
74
+ def answers_event?(policy, event)
75
+ event[:name] == policy.event_name &&
76
+ (policy.event_qualifier.nil? || event[:aggregate].to_s.split("::").last == policy.event_qualifier)
77
+ end
78
+
79
+ # One message for a reaction no declaration of its policy accounts for; nil when one does.
80
+ #
81
+ # A policy name can repeat across domains, so a reaction passes when any declaration
82
+ # of that name agrees with it on all three of event, trigger and qualifier.
83
+ def wiring_offender(reaction, bluebooks, events)
84
+ declared = declared_policies(reaction[:policy], bluebooks)
85
+ return "reaction names policy #{reaction[:policy]}, which no loaded bluebook declares" if declared.empty?
86
+
87
+ wiring_failure(reaction, declared, events)
88
+ end
89
+
90
+ # The first stage of event, trigger and happened-event that no declaration satisfies.
91
+ def wiring_failure(reaction, declared, events)
92
+ answering = declared.select { |policy, _home| policy.event_name == reaction[:on].to_s }
93
+ return unanswered_message(reaction, declared) if answering.empty?
94
+
95
+ targeted = answering.select { |policy, home| declared_trigger(policy, home) == reaction[:trigger].to_s }
96
+ return misrouted_message(reaction, answering) if targeted.empty?
97
+
98
+ phantom_failure(reaction, targeted, events)
99
+ end
100
+
101
+ def phantom_failure(reaction, targeted, events)
102
+ return if targeted.any? { |policy, _home| event_happened?(events, policy, reaction[:on]) }
103
+
104
+ phantom_message(reaction)
105
+ end
106
+
107
+ # Every `[policy, home_domain]` pair declared under `name`, across all loaded bluebooks.
108
+ def declared_policies(name, bluebooks)
109
+ bluebooks.flat_map do |home, bluebook|
110
+ bluebook.policies.select { |policy| policy.name == name.to_s }.map { |policy| [policy, home.to_s] }
111
+ end
112
+ end
113
+
114
+ # The trigger string the runtime builds: the target domain, else the policy's own home.
115
+ def declared_trigger(policy, home)
116
+ "#{policy.target_domain || home}::#{policy.trigger_command}"
117
+ end
118
+
119
+ # Whether `events` holds an emission of `name` the policy's event qualifier admits.
120
+ def event_happened?(events, policy, name)
121
+ events.any? { |event| event[:name] == name.to_s && answers_event?(policy, event) }
122
+ end
123
+
124
+ def unanswered_message(reaction, declared)
125
+ named = declared.map { |policy, _home| policy.event_name }.uniq.join(" / ")
126
+ "policy #{reaction[:policy]} reacted to #{reaction[:on]}, but it declares #{named}"
127
+ end
128
+
129
+ def misrouted_message(reaction, answering)
130
+ named = answering.map { |policy, home| declared_trigger(policy, home) }.uniq.join(" / ")
131
+ "policy #{reaction[:policy]} triggered #{reaction[:trigger]} on #{reaction[:on]}, but it declares #{named}"
132
+ end
133
+
134
+ def phantom_message(reaction)
135
+ "policy #{reaction[:policy]} reacted to #{reaction[:on]}, but no such event was emitted in this history"
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,67 @@
1
+ module Hecks
2
+ module Fuzzing
3
+ module Properties
4
+ # Recomputes which stored rows a query's `where` clauses admit, resolving reference hops
5
+ # over the replay snapshot.
6
+ module QueryRows
7
+ # The stored instances a query is recomputed over, with the domain they are read in and
8
+ # every loaded bluebook (to resolve reference hops).
9
+ Snapshot = Struct.new(:instances, :domain, :bluebooks)
10
+
11
+ # Recomputes which of an aggregate's own stored rows a query's `wheres` admit.
12
+ #
13
+ # Rows get `id:` merged in because Ordering.apply's `identity:` and the real answer
14
+ # both use it. The snapshot's `bluebooks` are needed only to resolve a `/` hop clause.
15
+ #
16
+ # @param snapshot [Snapshot] `history[:instances]` or an `:instances_at` snapshot
17
+ # @param aggregate_name [String] the aggregate whose rows are read
18
+ # @param wheres [Array<QuerySpecification::Common::WhereClause>] clauses every row
19
+ # must satisfy
20
+ # @param args [Hash] the query's call args, for clauses whose value is a Symbol
21
+ # @return [Array<Hash>] each admitted row's state, merged with its `id:`
22
+ def query_eligible_rows(snapshot, aggregate_name, wheres, args)
23
+ aggregate = snapshot.bluebooks[snapshot.domain]&.aggregate(aggregate_name)
24
+ prefix = "#{snapshot.domain}::#{aggregate_name}#"
25
+ snapshot.instances.filter_map do |key, state|
26
+ next unless key.start_with?(prefix)
27
+
28
+ row = state.merge(id: key.split("#").last)
29
+ row if wheres.all? { |clause| clause_holds?(snapshot, aggregate, clause, args, row) }
30
+ end
31
+ end
32
+
33
+ # Whether `row` satisfies one clause, after resolving any reference hop in it.
34
+ def clause_holds?(snapshot, aggregate, clause, args, row)
35
+ resolved = resolve_hop_clause(snapshot, aggregate, clause, args)
36
+ held = Ports::Query::InMemory.comparable(QuerySpecification::FieldPath.dig(row, resolved.field))
37
+ Ports::Query::InMemory.holds?(resolved, held, args)
38
+ end
39
+
40
+ # Resolves one hop of a `/`-chained clause into a local `in` clause over the target's ids.
41
+ #
42
+ # Restates `Runtime::ReferenceHop#fold` over the replay snapshot, so the property never
43
+ # checks the runtime against its own code path. A clause with no resolvable hop head
44
+ # is returned unchanged.
45
+ #
46
+ # @param aggregate [Bluebook::Aggregate, nil] nil skips hop resolution
47
+ # @return [QuerySpecification::Common::WhereClause] `clause`, or the `in` clause
48
+ def resolve_hop_clause(snapshot, aggregate, clause, args)
49
+ return clause unless aggregate && QuerySpecification::HopPath.hop_head?(clause.field, aggregate.attributes)
50
+
51
+ hop, rest = QuerySpecification::HopPath.next_hop(clause.field, aggregate.attributes)
52
+ return clause unless hop.target
53
+
54
+ hop_in_clause(snapshot, hop, rest, clause, args)
55
+ end
56
+
57
+ # The `in` clause over the ids of the hop target's rows that satisfy the rest of the path.
58
+ def hop_in_clause(snapshot, hop, rest, clause, args)
59
+ inner = QuerySpecification::Common::WhereClause.new(field: rest, op: clause.op, value: clause.value)
60
+ ids = query_eligible_rows(snapshot, hop.target.hecks_name, [inner], args).map { |row| row[:id].to_s }.uniq
61
+
62
+ QuerySpecification::Common::WhereClause.new(field: hop.attribute.name, op: "in", value: ids)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end