hecks 2.8.0 → 3.0.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 (886) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +50 -7
  3. data/lib/hecks/adapters/driven/claude_code.rb +4 -104
  4. data/lib/hecks/adapters/driven/d1.rb +44 -237
  5. data/lib/hecks/adapters/driven/folder.rb +17 -76
  6. data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
  7. data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
  8. data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
  9. data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
  10. data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
  11. data/lib/hecks/adapters/driven/heki.rb +13 -42
  12. data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
  13. data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
  14. data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
  15. data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
  16. data/lib/hecks/adapters/driven/lambda.rb +10 -84
  17. data/lib/hecks/adapters/driven/local_storage.rb +5 -40
  18. data/lib/hecks/adapters/driven/memory.rb +32 -100
  19. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
  20. data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
  21. data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
  22. data/lib/hecks/adapters/driven/postgres/reconnect.rb +10 -32
  23. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
  24. data/lib/hecks/adapters/driven/postgres/shared_connection.rb +180 -0
  25. data/lib/hecks/adapters/driven/postgres.rb +149 -136
  26. data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
  27. data/lib/hecks/adapters/driven/prism.rb +48 -38
  28. data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
  29. data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
  30. data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
  31. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
  32. data/lib/hecks/adapters/driven/sqlite.rb +128 -65
  33. data/lib/hecks/adapters/driven/tenant_provisioner.rb +76 -62
  34. data/lib/hecks/adapters/driven.rb +5 -36
  35. data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
  36. data/lib/hecks/behaviors/dsl.rb +7 -25
  37. data/lib/hecks/behaviors/expectations.rb +32 -142
  38. data/lib/hecks/behaviors/ir.rb +7 -20
  39. data/lib/hecks/behaviors/rspec.rb +6 -17
  40. data/lib/hecks/behaviors/runner.rb +10 -34
  41. data/lib/hecks/behaviors.rb +4 -8
  42. data/lib/hecks/bench/cli.rb +62 -0
  43. data/lib/hecks/bench/environment.rb +71 -0
  44. data/lib/hecks/bench/postgres_probe.rb +30 -0
  45. data/lib/hecks/bench/report.rb +76 -0
  46. data/lib/hecks/bench/ruby_runner.rb +93 -0
  47. data/lib/hecks/bench/run.rb +55 -0
  48. data/lib/hecks/bench/rust_runner.rb +101 -0
  49. data/lib/hecks/bench/stats.rb +46 -0
  50. data/lib/hecks/bench/suite.rb +98 -0
  51. data/lib/hecks/bench/workload.rb +89 -0
  52. data/lib/hecks/bench.rb +17 -0
  53. data/lib/hecks/bluebook/aggregate.rb +9 -75
  54. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
  55. data/lib/hecks/bluebook/assembly/build.rb +4 -15
  56. data/lib/hecks/bluebook/assembly/contract.rb +15 -136
  57. data/lib/hecks/bluebook/assembly/contracts.rb +56 -174
  58. data/lib/hecks/bluebook/assembly/marks.rb +31 -223
  59. data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
  60. data/lib/hecks/bluebook/assembly.rb +6 -45
  61. data/lib/hecks/bluebook/attribute.rb +12 -61
  62. data/lib/hecks/bluebook/behaviour/aggregate.rb +39 -39
  63. data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
  64. data/lib/hecks/bluebook/behaviour/chapter.rb +14 -42
  65. data/lib/hecks/bluebook/behaviour/command.rb +14 -66
  66. data/lib/hecks/bluebook/behaviour/domain_port.rb +11 -20
  67. data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
  68. data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
  69. data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
  70. data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
  71. data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
  72. data/lib/hecks/bluebook/behaviour/read_model.rb +25 -31
  73. data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
  74. data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
  75. data/lib/hecks/bluebook/capabilities.rb +17 -49
  76. data/lib/hecks/bluebook/chapter.rb +16 -50
  77. data/lib/hecks/bluebook/command.rb +23 -81
  78. data/lib/hecks/bluebook/domain_port.rb +49 -67
  79. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
  80. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
  81. data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
  82. data/lib/hecks/bluebook/dsl/binding_proxy.rb +16 -69
  83. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +96 -708
  84. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +63 -169
  85. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +3 -1
  86. data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
  87. data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
  88. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +42 -89
  89. data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
  90. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
  91. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +148 -197
  92. data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
  93. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
  94. data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
  95. data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
  96. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
  97. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
  98. data/lib/hecks/bluebook/dsl/query_builder.rb +38 -43
  99. data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
  100. data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
  101. data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
  102. data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
  103. data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
  104. data/lib/hecks/bluebook/dsl/world_builder.rb +46 -111
  105. data/lib/hecks/bluebook/entity.rb +13 -71
  106. data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
  107. data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
  108. data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
  109. data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
  110. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
  111. data/lib/hecks/bluebook/expression/resolver.rb +39 -661
  112. data/lib/hecks/bluebook/hexagon.rb +18 -33
  113. data/lib/hecks/bluebook/lifecycle.rb +5 -16
  114. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
  115. data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
  116. data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
  117. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
  118. data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
  119. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +25 -176
  120. data/lib/hecks/bluebook/meta_validator/shapes.rb +53 -267
  121. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -306
  122. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
  123. data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +246 -0
  124. data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
  125. data/lib/hecks/bluebook/meta_validator.rb +87 -352
  126. data/lib/hecks/bluebook/model_check/client_profile.rb +6 -21
  127. data/lib/hecks/bluebook/model_check.rb +122 -596
  128. data/lib/hecks/bluebook/pattern_subset.rb +49 -69
  129. data/lib/hecks/bluebook/process_manager.rb +13 -83
  130. data/lib/hecks/bluebook/project_loader.rb +3 -39
  131. data/lib/hecks/bluebook/project_register.rb +12 -60
  132. data/lib/hecks/bluebook/query.rb +27 -51
  133. data/lib/hecks/bluebook/read_model.rb +57 -81
  134. data/lib/hecks/bluebook/reference.rb +7 -41
  135. data/lib/hecks/bluebook/smoke_test.rb +9 -99
  136. data/lib/hecks/bluebook/synthesizer.rb +13 -62
  137. data/lib/hecks/bluebook/translation.rb +26 -62
  138. data/lib/hecks/bluebook/value_object.rb +11 -36
  139. data/lib/hecks/bluebook.rb +5 -22
  140. data/lib/hecks/cache_dir.rb +4 -23
  141. data/lib/hecks/canonical_json.rb +30 -0
  142. data/lib/hecks/chapters.rb +102 -0
  143. data/lib/hecks/cli/behaviors.rb +61 -0
  144. data/lib/hecks/cli/canonicalise.rb +25 -0
  145. data/lib/hecks/cli/check_engine_agreement.rb +32 -0
  146. data/lib/hecks/cli/check_era.rb +88 -0
  147. data/lib/hecks/cli/console.rb +66 -0
  148. data/lib/hecks/cli/deploy_template_diff.rb +40 -0
  149. data/lib/hecks/cli/doc_coverage.rb +32 -0
  150. data/lib/hecks/cli/document.rb +5 -23
  151. data/lib/hecks/cli/expression_projection.rb +41 -0
  152. data/lib/hecks/cli/follow.rb +88 -0
  153. data/lib/hecks/cli/history.rb +44 -0
  154. data/lib/hecks/cli/ir.rb +4 -6
  155. data/lib/hecks/cli/mcp.rb +5 -6
  156. data/lib/hecks/cli/model_check.rb +24 -88
  157. data/lib/hecks/cli/pattern_cases.rb +47 -0
  158. data/lib/hecks/cli/present.rb +39 -0
  159. data/lib/hecks/cli/project_cli.rb +223 -64
  160. data/lib/hecks/cli/project_diagrams.rb +4 -10
  161. data/lib/hecks/cli/project_glossary.rb +44 -0
  162. data/lib/hecks/cli/reference.rb +46 -0
  163. data/lib/hecks/cli/refresh_projections.rb +44 -0
  164. data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +150 -0
  165. data/lib/hecks/cli/release.rb +70 -0
  166. data/lib/hecks/cli/release_gem.rb +59 -0
  167. data/lib/hecks/cli/rspec_io_parallel_files.rb +137 -0
  168. data/lib/hecks/cli/rspec_shard_files.rb +66 -0
  169. data/lib/hecks/cli/run.rb +15 -61
  170. data/lib/hecks/cli/seed_semantics_corpus.rb +71 -0
  171. data/lib/hecks/cli/serve_query_ir_mcp.rb +30 -0
  172. data/lib/hecks/cli/shape.rb +70 -0
  173. data/lib/hecks/cli/smoke_http.rb +230 -0
  174. data/lib/hecks/cli/smoke_test.rb +7 -19
  175. data/lib/hecks/cli/spec_example.rb +27 -0
  176. data/lib/hecks/cli/statements.rb +32 -0
  177. data/lib/hecks/cli/stores.rb +4 -6
  178. data/lib/hecks/cli/stress_concurrency_specs.rb +177 -0
  179. data/lib/hecks/cli.rb +216 -73
  180. data/lib/hecks/codemod.rb +324 -0
  181. data/lib/hecks/construct.rb +8 -34
  182. data/lib/hecks/corpus.rb +423 -0
  183. data/lib/hecks/deploy/bluebook/deploy.bluebook +617 -158
  184. data/lib/hecks/deploy/bluebook/deploy.hecksagon +41 -11
  185. data/lib/hecks/deploy/oidc.json +82 -2
  186. data/lib/hecks/doc/reference.rb +351 -0
  187. data/lib/hecks/doors/cli_door.rb +196 -0
  188. data/lib/hecks/doors/cli_runner.rb +297 -0
  189. data/lib/hecks/{facade → doors}/command_request.rb +14 -34
  190. data/lib/hecks/doors/handle.rb +206 -0
  191. data/lib/hecks/doors/json_door.rb +132 -0
  192. data/lib/hecks/doors/launcher_options.rb +129 -0
  193. data/lib/hecks/{cli → doors}/mcp_door.rb +25 -120
  194. data/lib/hecks/doors/mcp_door_scope.rb +97 -0
  195. data/lib/hecks/doors/ruby_door/aggregate_door.rb +162 -0
  196. data/lib/hecks/doors/ruby_door/chapter.rb +72 -0
  197. data/lib/hecks/doors/ruby_door.rb +77 -0
  198. data/lib/hecks/doors.rb +61 -0
  199. data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
  200. data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
  201. data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
  202. data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
  203. data/lib/hecks/embryonaut_bluebook.rb +5 -72
  204. data/lib/hecks/engine_agreement.rb +156 -0
  205. data/lib/hecks/facade.rb +23 -51
  206. data/lib/hecks/forms/app.rb +21 -76
  207. data/lib/hecks/forms/banking_presentation.rb +50 -0
  208. data/lib/hecks/forms/command_form_renderer.rb +10 -29
  209. data/lib/hecks/forms/field_renderer.rb +17 -156
  210. data/lib/hecks/forms/field_shape.rb +31 -222
  211. data/lib/hecks/forms/html.rb +12 -47
  212. data/lib/hecks/forms/index_renderer.rb +1 -4
  213. data/lib/hecks/forms/page.rb +3 -9
  214. data/lib/hecks/forms/params.rb +14 -60
  215. data/lib/hecks/forms/port_argument.rb +2 -19
  216. data/lib/hecks/forms/query_form_renderer.rb +4 -79
  217. data/lib/hecks/forms/record_renderer.rb +8 -75
  218. data/lib/hecks/forms/record_table.rb +7 -50
  219. data/lib/hecks/forms/reference_options.rb +3 -30
  220. data/lib/hecks/forms/value_object_shape.rb +8 -35
  221. data/lib/hecks/forms.rb +5 -33
  222. data/lib/hecks/fqn.rb +5 -12
  223. data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
  224. data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
  225. data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
  226. data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
  227. data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
  228. data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
  229. data/lib/hecks/framework.rb +11 -80
  230. data/lib/hecks/freezer.rb +5 -39
  231. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +393 -0
  232. data/lib/hecks/fuzzing/combination_miner.rb +86 -0
  233. data/lib/hecks/fuzzing/concurrent_dispatch.rb +214 -0
  234. data/lib/hecks/fuzzing/coverage_campaign.rb +143 -0
  235. data/lib/hecks/fuzzing/differential.rb +156 -0
  236. data/lib/hecks/fuzzing/domain_generator.rb +615 -0
  237. data/lib/hecks/fuzzing/era_boundary.rb +71 -0
  238. data/lib/hecks/fuzzing/form_census.rb +136 -0
  239. data/lib/hecks/fuzzing/generated_domain_check.rb +93 -0
  240. data/lib/hecks/fuzzing/invalid_value_generator.rb +64 -0
  241. data/lib/hecks/fuzzing/isolated_boot.rb +301 -0
  242. data/lib/hecks/fuzzing/nondeterministic.rb +51 -0
  243. data/lib/hecks/fuzzing/outside_world.rb +45 -0
  244. data/lib/hecks/fuzzing/persistence_parity.rb +102 -0
  245. data/lib/hecks/fuzzing/properties/corrections.rb +88 -0
  246. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +314 -0
  247. data/lib/hecks/fuzzing/properties/guards.rb +190 -0
  248. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +300 -0
  249. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +93 -0
  250. data/lib/hecks/fuzzing/properties/outbox.rb +89 -0
  251. data/lib/hecks/fuzzing/properties/querying.rb +175 -0
  252. data/lib/hecks/fuzzing/properties.rb +162 -0
  253. data/lib/hecks/fuzzing/qa_settings.rb +123 -0
  254. data/lib/hecks/fuzzing/replay.rb +505 -0
  255. data/lib/hecks/fuzzing/rotation_priority.rb +48 -0
  256. data/lib/hecks/fuzzing/rust_gap_manifest.rb +108 -0
  257. data/lib/hecks/fuzzing/self_consistency.rb +339 -0
  258. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +385 -0
  259. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +132 -0
  260. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +95 -0
  261. data/lib/hecks/fuzzing/sequence_generator/picker.rb +77 -0
  262. data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +109 -0
  263. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +237 -0
  264. data/lib/hecks/fuzzing/sequence_generator.rb +189 -0
  265. data/lib/hecks/fuzzing/shrinker.rb +166 -0
  266. data/lib/hecks/fuzzing/structural_skips.rb +33 -0
  267. data/lib/hecks/fuzzing/sweep_depth.rb +43 -0
  268. data/lib/hecks/fuzzing/target_capabilities.rb +163 -0
  269. data/lib/hecks/fuzzing/value_generator.rb +216 -0
  270. data/lib/hecks/fuzzing.rb +23 -0
  271. data/lib/hecks/grammar/evolve.rb +336 -0
  272. data/lib/hecks/grammar/expression.bluebook +15 -40
  273. data/lib/hecks/grammar/translation.bluebook +3 -6
  274. data/lib/hecks/grammar.rb +16 -41
  275. data/lib/hecks/hecks/adapters/codebase/codemods.rb +45 -0
  276. data/lib/hecks/hecks/adapters/codebase/conformance.rb +71 -0
  277. data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +202 -0
  278. data/lib/hecks/hecks/adapters/codebase/gem_registry.rb +80 -0
  279. data/lib/hecks/hecks/adapters/codebase/kernel_tables.rb +54 -0
  280. data/lib/hecks/hecks/adapters/codebase/language.rb +240 -0
  281. data/lib/hecks/hecks/adapters/codebase/npm_registry.rb +102 -0
  282. data/lib/hecks/hecks/adapters/codebase/publishing.rb +142 -0
  283. data/lib/hecks/hecks/adapters/codebase/regeneration.rb +67 -0
  284. data/lib/hecks/hecks/adapters/codebase/release_facts.rb +90 -0
  285. data/lib/hecks/hecks/adapters/codebase/ruby_child.rb +83 -0
  286. data/lib/hecks/hecks/adapters/codebase/secret_vault.rb +36 -0
  287. data/lib/hecks/hecks/adapters/codebase/source_tree.adapter +7 -0
  288. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +189 -0
  289. data/lib/hecks/hecks/adapters/codebase/sqlite_fixture.rb +71 -0
  290. data/lib/hecks/hecks/adapters/codebase/style.rb +171 -0
  291. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +55 -0
  292. data/lib/hecks/hecks/adapters/codebase/test_suite.rb +165 -0
  293. data/lib/hecks/hecks/adapters/codebase/tree.rb +111 -0
  294. data/lib/hecks/hecks/adapters/console_capture.rb +79 -0
  295. data/lib/hecks/hecks/adapters/deploy_toolchain.adapter +7 -0
  296. data/lib/hecks/hecks/adapters/deploy_toolchain.rb +108 -0
  297. data/lib/hecks/hecks/adapters/git.adapter +7 -0
  298. data/lib/hecks/hecks/adapters/git.rb +102 -0
  299. data/lib/hecks/hecks/adapters/host_http.adapter +7 -0
  300. data/lib/hecks/hecks/adapters/host_http.rb +65 -0
  301. data/lib/hecks/hecks/adapters/in_process_boot.adapter +7 -0
  302. data/lib/hecks/hecks/adapters/in_process_boot.rb +197 -0
  303. data/lib/hecks/hecks/adapters/in_process_operations.rb +202 -0
  304. data/lib/hecks/hecks/adapters/journal_store/changes.rb +143 -0
  305. data/lib/hecks/hecks/adapters/journal_store/compaction.rb +145 -0
  306. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +132 -0
  307. data/lib/hecks/hecks/adapters/journal_store/examination.rb +135 -0
  308. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +163 -0
  309. data/lib/hecks/hecks/adapters/journal_store/readings.rb +187 -0
  310. data/lib/hecks/hecks/adapters/journal_store.adapter +7 -0
  311. data/lib/hecks/hecks/adapters/journal_store.rb +64 -0
  312. data/lib/hecks/hecks/adapters/local_files.adapter +7 -0
  313. data/lib/hecks/hecks/adapters/local_files.rb +46 -0
  314. data/lib/hecks/hecks/adapters/pg_admin.adapter +7 -0
  315. data/lib/hecks/hecks/adapters/pg_admin.rb +245 -0
  316. data/lib/hecks/hecks/adapters/process_pool.adapter +7 -0
  317. data/lib/hecks/hecks/adapters/process_pool.rb +119 -0
  318. data/lib/hecks/hecks/adapters/rust_toolchain.adapter +7 -0
  319. data/lib/hecks/hecks/adapters/rust_toolchain.rb +179 -0
  320. data/lib/hecks/hecks/adapters/rust_workspace.rb +150 -0
  321. data/lib/hecks/hecks/adapters/shell.adapter +7 -0
  322. data/lib/hecks/hecks/adapters/shell.rb +49 -0
  323. data/lib/hecks/hecks/adapters/terminal.adapter +7 -0
  324. data/lib/hecks/hecks/adapters/terminal.rb +74 -0
  325. data/lib/hecks/hecks/codebase.behaviors +172 -0
  326. data/lib/hecks/hecks/codebase.bluebook +2453 -0
  327. data/lib/hecks/hecks/context_map.hecksagon +13 -0
  328. data/lib/hecks/hecks/custodian.behaviors +179 -0
  329. data/lib/hecks/hecks/custodian.bluebook +1847 -0
  330. data/lib/hecks/hecks/deploy.behaviors +74 -0
  331. data/lib/hecks/hecks/deploy.world +12 -0
  332. data/lib/hecks/hecks/environments/memory.world +10 -0
  333. data/lib/hecks/hecks/governance.world +7 -0
  334. data/lib/hecks/hecks/hecks.behaviors +62 -0
  335. data/lib/hecks/hecks/hecks.bluebook +124 -0
  336. data/lib/hecks/hecks/hecks.hecksagon +390 -0
  337. data/lib/hecks/hecks/hecks.world +42 -0
  338. data/lib/hecks/ir.rb +14 -83
  339. data/lib/hecks/kernel_capabilities.rb +194 -0
  340. data/lib/hecks/language/adapter.bluebook +2 -7
  341. data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
  342. data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
  343. data/lib/hecks/language/bluebook/bluebook.bluebook +26 -83
  344. data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
  345. data/lib/hecks/language/bluebook/command.bluebook +27 -144
  346. data/lib/hecks/language/bluebook/entity.bluebook +24 -97
  347. data/lib/hecks/language/bluebook/policy.bluebook +16 -67
  348. data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
  349. data/lib/hecks/language/bluebook/projection.bluebook +126 -60
  350. data/lib/hecks/language/bluebook/query.bluebook +19 -43
  351. data/lib/hecks/language/bluebook/shape.bluebook +23 -73
  352. data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
  353. data/lib/hecks/language/bluebook/vocabulary.bluebook +83 -198
  354. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
  355. data/lib/hecks/language/hecksagon/domain_port.bluebook +14 -19
  356. data/lib/hecks/language/hecksagon/hecksagon.bluebook +26 -25
  357. data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
  358. data/lib/hecks/language/oidc.json +35 -0
  359. data/lib/hecks/language/port.bluebook +4 -17
  360. data/lib/hecks/language/translation/translation.bluebook +3 -9
  361. data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
  362. data/lib/hecks/language/world/wiring.bluebook +1 -3
  363. data/lib/hecks/language/world/world.bluebook +5 -7
  364. data/lib/hecks/literal.rb +8 -50
  365. data/lib/hecks/mcp_stdio_guard.rb +4 -41
  366. data/lib/hecks/naming.rb +29 -137
  367. data/lib/hecks/persistence_legacy_fixture/regenerate.rb +161 -0
  368. data/lib/hecks/persistence_legacy_fixture.rb +113 -0
  369. data/lib/hecks/ports/access_control.rb +7 -23
  370. data/lib/hecks/ports/agent/answers.rb +5 -23
  371. data/lib/hecks/ports/agent.rb +47 -172
  372. data/lib/hecks/ports/authentication.rb +12 -39
  373. data/lib/hecks/ports/authorization.rb +16 -43
  374. data/lib/hecks/ports/clock.rb +5 -45
  375. data/lib/hecks/ports/extraction.rb +7 -12
  376. data/lib/hecks/ports/identity_assignment.rb +8 -29
  377. data/lib/hecks/ports/identity_generation.rb +6 -29
  378. data/lib/hecks/ports/identity_resolution.rb +2 -10
  379. data/lib/hecks/ports/key_vault.rb +9 -45
  380. data/lib/hecks/ports/persistence/append_only.rb +61 -64
  381. data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
  382. data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
  383. data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
  384. data/lib/hecks/ports/persistence/plugin.rb +13 -42
  385. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +44 -144
  386. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
  387. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +20 -85
  388. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +6 -25
  389. data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +18 -24
  390. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
  391. data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
  392. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
  393. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
  394. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
  395. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
  396. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
  397. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
  398. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +19 -76
  399. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
  400. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
  401. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
  402. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
  403. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
  404. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +43 -127
  405. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
  406. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +131 -555
  407. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
  408. data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +227 -0
  409. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
  410. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
  411. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
  412. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
  413. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
  414. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +50 -47
  415. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -124
  416. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
  417. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
  418. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
  419. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
  420. data/lib/hecks/ports/persistence/plugins/era/translation.rb +1 -0
  421. data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
  422. data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
  423. data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
  424. data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
  425. data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
  426. data/lib/hecks/ports/persistence/state_codec.rb +47 -108
  427. data/lib/hecks/ports/persistence.rb +7 -14
  428. data/lib/hecks/ports/projection.rb +42 -84
  429. data/lib/hecks/ports/query/in_memory.rb +10 -58
  430. data/lib/hecks/ports/query/ordering.rb +11 -32
  431. data/lib/hecks/ports/query.rb +14 -37
  432. data/lib/hecks/ports.rb +2 -8
  433. data/lib/hecks/projection_files.rb +285 -0
  434. data/lib/hecks/projections/bootstrap_table.rb +12 -44
  435. data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
  436. data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
  437. data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
  438. data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
  439. data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
  440. data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
  441. data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
  442. data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
  443. data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
  444. data/lib/hecks/projections/deploy/fargate.rb +40 -207
  445. data/lib/hecks/projections/deploy/lambda.rb +191 -708
  446. data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
  447. data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
  448. data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
  449. data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
  450. data/lib/hecks/projections/deploy/preview/script.rb +2 -14
  451. data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
  452. data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
  453. data/lib/hecks/projections/deploy/preview/template.rb +3 -59
  454. data/lib/hecks/projections/deploy/preview.rb +2 -67
  455. data/lib/hecks/projections/deploy/scripts/deploy-service.sh.tmpl +1 -1
  456. data/lib/hecks/projections/deploy/scripts/expected-era.header +1 -1
  457. data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +3 -3
  458. data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
  459. data/lib/hecks/projections/deploy/scripts/smoke-after-deploy.sh.tmpl +1 -1
  460. data/lib/hecks/projections/deploy/scripts.rb +4 -57
  461. data/lib/hecks/projections/deploy/shared.rb +48 -147
  462. data/lib/hecks/projections/deploy/smoke.rb +4 -61
  463. data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
  464. data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
  465. data/lib/hecks/projections/deploy/template_diff.rb +5 -57
  466. data/lib/hecks/projections/diagrams.rb +22 -584
  467. data/lib/hecks/projections/glossary/html.rb +14 -130
  468. data/lib/hecks/projections/glossary/markdown.rb +8 -69
  469. data/lib/hecks/projections/glossary/mermaid.rb +9 -66
  470. data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
  471. data/lib/hecks/projections/glossary/sentences.rb +14 -159
  472. data/lib/hecks/projections/glossary.rb +30 -222
  473. data/lib/hecks/projections/ir.rb +3 -10
  474. data/lib/hecks/projections/model/deviations.rb +16 -43
  475. data/lib/hecks/projections/model.rb +12 -51
  476. data/lib/hecks/projections/oidc.rb +12 -56
  477. data/lib/hecks/projections/parser_table.rb +13 -32
  478. data/lib/hecks/projections/reference.rb +4 -18
  479. data/lib/hecks/projections/rust_vocabulary.rb +13 -251
  480. data/lib/hecks/projections/shape.rb +3 -29
  481. data/lib/hecks/projections/statements.rb +7 -86
  482. data/lib/hecks/projections/vocabulary.rb +6 -22
  483. data/lib/hecks/projections.rb +2 -16
  484. data/lib/hecks/projector/cli_projector.rb +154 -400
  485. data/lib/hecks/projector/docs_projector.rb +10 -201
  486. data/lib/hecks/projector/exporter.rb +42 -134
  487. data/lib/hecks/projector/ir_projector.rb +2 -9
  488. data/lib/hecks/projector/narrate_projector.rb +15 -189
  489. data/lib/hecks/projector/target.rb +13 -76
  490. data/lib/hecks/projector.rb +30 -121
  491. data/lib/hecks/quality_control/adapters/agent.adapter +7 -0
  492. data/lib/hecks/quality_control/adapters/agent.rb +58 -0
  493. data/lib/hecks/quality_control/adapters/angle_tools.adapter +7 -0
  494. data/lib/hecks/quality_control/adapters/angle_tools.rb +15 -0
  495. data/lib/hecks/quality_control/adapters/clearance_recorder.rb +36 -0
  496. data/lib/hecks/quality_control/adapters/clearance_tools.adapter +7 -0
  497. data/lib/hecks/quality_control/adapters/clearance_tools.rb +17 -0
  498. data/lib/hecks/quality_control/adapters/git_pr.adapter +7 -0
  499. data/lib/hecks/quality_control/adapters/git_pr.rb +226 -0
  500. data/lib/hecks/quality_control/adapters/github_checks.adapter +9 -0
  501. data/lib/hecks/quality_control/adapters/github_checks.rb +83 -0
  502. data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +56 -0
  503. data/lib/hecks/quality_control/adapters/github_issues.adapter +7 -0
  504. data/lib/hecks/quality_control/adapters/github_issues.rb +49 -0
  505. data/lib/hecks/quality_control/adapters/qa_tool.rb +59 -0
  506. data/lib/hecks/quality_control/adapters/sweep_tools.adapter +7 -0
  507. data/lib/hecks/quality_control/adapters/sweep_tools.rb +51 -0
  508. data/lib/hecks/quality_control/adapters/target_tools.adapter +7 -0
  509. data/lib/hecks/quality_control/adapters/target_tools.rb +43 -0
  510. data/lib/hecks/quality_control/cli/child.rb +45 -0
  511. data/lib/hecks/quality_control/cli/qa_concurrency_racer.rb +45 -0
  512. data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +248 -0
  513. data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +163 -0
  514. data/lib/hecks/quality_control/cli/qa_generated_domains.rb +450 -0
  515. data/lib/hecks/quality_control/cli/qa_log_bug.rb +195 -0
  516. data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +220 -0
  517. data/lib/hecks/quality_control/cli/qa_open_pr.rb +305 -0
  518. data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +154 -0
  519. data/lib/hecks/quality_control/cli/qa_postgres_role.rb +159 -0
  520. data/lib/hecks/quality_control/cli/qa_pr_check.rb +232 -0
  521. data/lib/hecks/quality_control/cli/qa_seed_angles.rb +142 -0
  522. data/lib/hecks/quality_control/cli/qa_seed_targets.rb +69 -0
  523. data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +280 -0
  524. data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +329 -0
  525. data/lib/hecks/quality_control/cli/qa_sweep/dials.rb +92 -0
  526. data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +117 -0
  527. data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +175 -0
  528. data/lib/hecks/quality_control/cli/qa_sweep/release_mode.rb +60 -0
  529. data/lib/hecks/quality_control/cli/qa_sweep.rb +611 -0
  530. data/lib/hecks/quality_control/cli/qa_tick.rb +274 -0
  531. data/lib/hecks/quality_control/quality_control.bluebook +2224 -0
  532. data/lib/hecks/quality_control/quality_control.hecksagon +13 -0
  533. data/lib/hecks/quality_control/quality_control.ports.hecksagon +54 -0
  534. data/lib/hecks/query_ir.rb +346 -0
  535. data/lib/hecks/query_ir_mcp.rb +198 -0
  536. data/lib/hecks/query_specification/common/comparators.rb +5 -26
  537. data/lib/hecks/query_specification/common/comparison.rb +35 -143
  538. data/lib/hecks/query_specification/common/dsl.rb +8 -24
  539. data/lib/hecks/query_specification/common/null_policy.rb +20 -70
  540. data/lib/hecks/query_specification/common/options.rb +2 -6
  541. data/lib/hecks/query_specification/common/where_clause.rb +2 -10
  542. data/lib/hecks/query_specification/field_path.rb +37 -77
  543. data/lib/hecks/query_specification/hop_path.rb +12 -76
  544. data/lib/hecks/release/gem_pin.rb +2 -26
  545. data/lib/hecks/release/runner/ci_publisher.rb +5 -8
  546. data/lib/hecks/release/runner/clean_tree.rb +42 -0
  547. data/lib/hecks/release/runner/commands.rb +2 -4
  548. data/lib/hecks/release/runner/console.rb +6 -0
  549. data/lib/hecks/release/runner/gem_publisher.rb +15 -9
  550. data/lib/hecks/release/runner/npm_publisher.rb +9 -53
  551. data/lib/hecks/release/runner/preflight.rb +29 -20
  552. data/lib/hecks/release/runner/published.rb +8 -26
  553. data/lib/hecks/release/runner/tagger.rb +31 -23
  554. data/lib/hecks/release/runner.rb +60 -38
  555. data/lib/hecks/rendering.rb +4 -26
  556. data/lib/hecks/router/namespace_installer.rb +15 -39
  557. data/lib/hecks/router.rb +4 -8
  558. data/lib/hecks/runtime/adapter_lookup.rb +124 -0
  559. data/lib/hecks/runtime/aggregate_lock.rb +8 -33
  560. data/lib/hecks/runtime/boot_gates.rb +3 -18
  561. data/lib/hecks/runtime/caller.rb +19 -59
  562. data/lib/hecks/runtime/capability_graph.rb +5 -21
  563. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
  564. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +27 -160
  565. data/lib/hecks/runtime/command_interpreter.rb +124 -306
  566. data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
  567. data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
  568. data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
  569. data/lib/hecks/runtime/command_rules/emission.rb +8 -21
  570. data/lib/hecks/runtime/command_rules/references.rb +23 -202
  571. data/lib/hecks/runtime/dependency_planning.rb +50 -104
  572. data/lib/hecks/runtime/dispatcher.rb +134 -243
  573. data/lib/hecks/runtime/entity_element.rb +40 -462
  574. data/lib/hecks/runtime/entity_interpreter.rb +64 -219
  575. data/lib/hecks/runtime/errors.rb +32 -115
  576. data/lib/hecks/runtime/event.rb +3 -25
  577. data/lib/hecks/runtime/identity.rb +18 -154
  578. data/lib/hecks/runtime/instance.rb +18 -150
  579. data/lib/hecks/runtime/interpreting.rb +14 -70
  580. data/lib/hecks/runtime/invocation.rb +28 -164
  581. data/lib/hecks/runtime/loader.rb +109 -194
  582. data/lib/hecks/runtime/outbox.rb +39 -262
  583. data/lib/hecks/runtime/policy_interpreter.rb +43 -202
  584. data/lib/hecks/runtime/port_operation_interpreter.rb +28 -97
  585. data/lib/hecks/runtime/query_interpreter.rb +122 -187
  586. data/lib/hecks/runtime/reaction_invocation.rb +36 -138
  587. data/lib/hecks/runtime/reaction_outcome.rb +89 -0
  588. data/lib/hecks/runtime/read_model_interpreter.rb +117 -208
  589. data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
  590. data/lib/hecks/runtime/reference_hop.rb +8 -81
  591. data/lib/hecks/runtime/refusal_wording.rb +28 -87
  592. data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
  593. data/lib/hecks/runtime/registry/verification.rb +213 -227
  594. data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
  595. data/lib/hecks/runtime/registry.rb +156 -247
  596. data/lib/hecks/runtime/remote_dispatcher.rb +68 -154
  597. data/lib/hecks/runtime/routing.rb +4 -15
  598. data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
  599. data/lib/hecks/runtime/saga_interpreter.rb +79 -263
  600. data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
  601. data/lib/hecks/runtime/tenant_check.rb +6 -68
  602. data/lib/hecks/runtime/tenant_scope.rb +3 -28
  603. data/lib/hecks/runtime/value/admission.rb +16 -67
  604. data/lib/hecks/runtime/value/coercion.rb +162 -760
  605. data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
  606. data/lib/hecks/runtime/value/field_checks.rb +172 -0
  607. data/lib/hecks/runtime/value.rb +15 -84
  608. data/lib/hecks/runtime.rb +35 -69
  609. data/lib/hecks/rust_build/conformance.rb +158 -0
  610. data/lib/hecks/rust_build/conformance_fuzz.rb +71 -0
  611. data/lib/hecks/rust_build/coverage.rb +218 -0
  612. data/lib/hecks/rust_build/native_build.rb +124 -0
  613. data/lib/hecks/rust_build/project_rust/root_mod.rb +120 -0
  614. data/lib/hecks/rust_build/project_rust.rb +332 -0
  615. data/lib/hecks/rust_build/wasm.rb +105 -0
  616. data/lib/hecks/rust_build/wasm_browser.rb +113 -0
  617. data/lib/hecks/rust_build.rb +144 -0
  618. data/lib/hecks/storehouse.rb +155 -582
  619. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +10 -34
  620. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
  621. data/lib/hecks/three_zero/forms.yml +127 -0
  622. data/lib/hecks/three_zero.rb +12 -0
  623. data/lib/hecks/tools/argument_gate_matrix.rb +316 -0
  624. data/lib/hecks/tools/comment_style.rb +1070 -0
  625. data/lib/hecks/tools/corpus_report.rb +87 -0
  626. data/lib/hecks/tools/deploy_recipe.rb +255 -0
  627. data/lib/hecks/tools/deploy_recipe_lint.rb +282 -0
  628. data/lib/hecks/tools/drop_implicit_append_fields.rb +95 -0
  629. data/lib/hecks/tools/era_projection_backfill.rb +94 -0
  630. data/lib/hecks/tools/era_reattest.rb +146 -0
  631. data/lib/hecks/tools/evolve_run.rb +189 -0
  632. data/lib/hecks/tools/fuzz_sweep.rb +373 -0
  633. data/lib/hecks/tools/heki_compaction.rb +100 -0
  634. data/lib/hecks/tools/hoist_local_givens.rb +246 -0
  635. data/lib/hecks/tools/journal_compaction.rb +89 -0
  636. data/lib/hecks/tools/oidc_manifests.rb +70 -0
  637. data/lib/hecks/tools/query_ir_run.rb +81 -0
  638. data/lib/hecks/tools/regeneration_run.rb +166 -0
  639. data/lib/hecks/tools/rust_comment_style.rb +642 -0
  640. data/lib/hecks/tools/sequence_script.rb +62 -0
  641. data/lib/hecks/tools/tail_merge.rb +117 -0
  642. data/lib/hecks/tools/tenant_provisioning.rb +142 -0
  643. data/lib/hecks/tools/translation_audit.rb +208 -0
  644. data/lib/hecks/tools/translation_scaffold.rb +131 -0
  645. data/lib/hecks/tools.rb +86 -0
  646. data/lib/hecks/vendoring/git_environment.rb +2 -8
  647. data/lib/hecks/vendoring/git_source.rb +4 -10
  648. data/lib/hecks/vendoring.rb +7 -46
  649. data/lib/hecks/version.rb +3 -14
  650. data/lib/hecks.rb +52 -90
  651. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
  652. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
  653. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
  654. data/qa/settings.yml +66 -0
  655. data/rust/.cargo/config.toml +6 -0
  656. data/rust/.gitignore +2 -0
  657. data/rust/Cargo.lock +54 -0
  658. data/rust/Cargo.toml +61 -0
  659. data/rust/build/.cargo/config.toml +3 -0
  660. data/rust/build/.gitignore +1 -0
  661. data/rust/build/Cargo.lock +7 -0
  662. data/rust/build/Cargo.toml +19 -0
  663. data/rust/build/src/build_artifact.rs +47 -0
  664. data/rust/build/src/cargo_sync.rs +248 -0
  665. data/rust/build/src/json.rs +421 -0
  666. data/rust/build/src/lineage_pass.rs +285 -0
  667. data/rust/build/src/main.rs +51 -0
  668. data/rust/build/src/optional_pass.rs +150 -0
  669. data/rust/build/src/pipeline.rs +264 -0
  670. data/rust/build/src/reserved_names.rs +76 -0
  671. data/rust/build/src/resolve.rs +124 -0
  672. data/rust/build/src/root.rs +25 -0
  673. data/rust/build/src/sidecars.rs +73 -0
  674. data/rust/build/src/subprocess.rs +51 -0
  675. data/rust/build/src/tmp.rs +31 -0
  676. data/rust/codegen/.cargo/config.toml +3 -0
  677. data/rust/codegen/.gitignore +1 -0
  678. data/rust/codegen/Cargo.lock +7 -0
  679. data/rust/codegen/Cargo.toml +20 -0
  680. data/rust/codegen/src/attr.rs +32 -0
  681. data/rust/codegen/src/bridging.rs +481 -0
  682. data/rust/codegen/src/commands.rs +1226 -0
  683. data/rust/codegen/src/constraints.rs +109 -0
  684. data/rust/codegen/src/dependency_planning.rs +209 -0
  685. data/rust/codegen/src/domain_generator.rs +1288 -0
  686. data/rust/codegen/src/exemplar.rs +230 -0
  687. data/rust/codegen/src/expr_emitter.rs +87 -0
  688. data/rust/codegen/src/fielded.rs +192 -0
  689. data/rust/codegen/src/hecks_naming.rs +33 -0
  690. data/rust/codegen/src/json.rs +335 -0
  691. data/rust/codegen/src/json_codec.rs +697 -0
  692. data/rust/codegen/src/literal.rs +207 -0
  693. data/rust/codegen/src/main.rs +290 -0
  694. data/rust/codegen/src/manifest.rs +227 -0
  695. data/rust/codegen/src/mutations.rs +784 -0
  696. data/rust/codegen/src/naming.rs +286 -0
  697. data/rust/codegen/src/ports.rs +208 -0
  698. data/rust/codegen/src/prelude.rs +116 -0
  699. data/rust/codegen/src/queries.rs +786 -0
  700. data/rust/codegen/src/reactions.rs +532 -0
  701. data/rust/codegen/src/read_models.rs +697 -0
  702. data/rust/codegen/src/reference_specs.rs +40 -0
  703. data/rust/codegen/src/registry.rs +966 -0
  704. data/rust/codegen/src/reserved_names.rs +76 -0
  705. data/rust/codegen/src/shared.rs +93 -0
  706. data/rust/codegen/src/skip_reason.rs +25 -0
  707. data/rust/codegen/src/types.rs +362 -0
  708. data/rust/host/.cargo/config.toml +3 -0
  709. data/rust/host/.gitignore +1 -0
  710. data/rust/host/Cargo.lock +4297 -0
  711. data/rust/host/Cargo.toml +61 -0
  712. data/rust/host/HECKS_RELEASE +1 -0
  713. data/rust/host/rds-ca-bundle.pem +2736 -0
  714. data/rust/host/src/api.rs +1596 -0
  715. data/rust/host/src/approval.rs +652 -0
  716. data/rust/host/src/auth.rs +1287 -0
  717. data/rust/host/src/bin/expr_harness.rs +46 -0
  718. data/rust/host/src/bin/lineage_harness.rs +119 -0
  719. data/rust/host/src/bin/mint_harness.rs +135 -0
  720. data/rust/host/src/checkout.rs +265 -0
  721. data/rust/host/src/dispatch.rs +1443 -0
  722. data/rust/host/src/expr_json.rs +1117 -0
  723. data/rust/host/src/field_hints.rs +52 -0
  724. data/rust/host/src/ir.rs +733 -0
  725. data/rust/host/src/journal.rs +874 -0
  726. data/rust/host/src/lambda_client.rs +378 -0
  727. data/rust/host/src/log.rs +147 -0
  728. data/rust/host/src/main.rs +474 -0
  729. data/rust/host/src/mint.rs +1865 -0
  730. data/rust/host/src/payments/keystore.rs +330 -0
  731. data/rust/host/src/payments/tests.rs +1400 -0
  732. data/rust/host/src/payments.rs +767 -0
  733. data/rust/host/src/presentation.rs +698 -0
  734. data/rust/host/src/presentation_write.rs +1431 -0
  735. data/rust/host/src/query_step.rs +149 -0
  736. data/rust/host/src/rate_limit.rs +904 -0
  737. data/rust/host/src/reference_transform.rs +241 -0
  738. data/rust/host/src/reference_validate.rs +338 -0
  739. data/rust/host/src/resend.rs +296 -0
  740. data/rust/host/src/secrets.rs +106 -0
  741. data/rust/host/src/server.rs +663 -0
  742. data/rust/host/src/storage_shape.rs +175 -0
  743. data/rust/host/src/test_pg.rs +40 -0
  744. data/rust/host/src/ui_schema.rs +1351 -0
  745. data/rust/host/src/wasm_runner.rs +191 -0
  746. data/rust/host/src/web/newsletter/cooldown.rs +126 -0
  747. data/rust/host/src/web/newsletter/tests.rs +104 -0
  748. data/rust/host/src/web/newsletter.rs +310 -0
  749. data/rust/host/src/web/newsletter_send.rs +357 -0
  750. data/rust/host/src/web/registrations.rs +1505 -0
  751. data/rust/host/src/web.rs +2937 -0
  752. data/rust/lsp/.gitignore +1 -0
  753. data/rust/lsp/Cargo.lock +7 -0
  754. data/rust/lsp/Cargo.toml +16 -0
  755. data/rust/lsp/README.md +133 -0
  756. data/rust/lsp/src/diagnostics.rs +165 -0
  757. data/rust/lsp/src/json.rs +385 -0
  758. data/rust/lsp/src/main.rs +399 -0
  759. data/rust/lsp/src/outline.rs +177 -0
  760. data/rust/lsp/src/rpc.rs +67 -0
  761. data/rust/parser/.cargo/config.toml +5 -0
  762. data/rust/parser/.gitignore +1 -0
  763. data/rust/parser/Cargo.lock +7 -0
  764. data/rust/parser/Cargo.toml +21 -0
  765. data/rust/parser/src/build/closed_sets.rs +27 -0
  766. data/rust/parser/src/build/identity.rs +276 -0
  767. data/rust/parser/src/build/mod.rs +12 -0
  768. data/rust/parser/src/build/naming.rs +141 -0
  769. data/rust/parser/src/build/pattern_subset.rs +161 -0
  770. data/rust/parser/src/build/query_derive.rs +72 -0
  771. data/rust/parser/src/build/query_inference.rs +269 -0
  772. data/rust/parser/src/build/query_options.rs +100 -0
  773. data/rust/parser/src/build/read_model.rs +94 -0
  774. data/rust/parser/src/build/references.rs +32 -0
  775. data/rust/parser/src/canonical.rs +114 -0
  776. data/rust/parser/src/diag.rs +55 -0
  777. data/rust/parser/src/emit.rs +953 -0
  778. data/rust/parser/src/expr/ast_json.rs +147 -0
  779. data/rust/parser/src/expr/evaluator.rs +81 -0
  780. data/rust/parser/src/expr/mod.rs +84 -0
  781. data/rust/parser/src/expr/resolver.rs +497 -0
  782. data/rust/parser/src/ir.rs +387 -0
  783. data/rust/parser/src/keywords.rs +585 -0
  784. data/rust/parser/src/lex.rs +662 -0
  785. data/rust/parser/src/main.rs +252 -0
  786. data/rust/parser/src/parse/aggregate.rs +612 -0
  787. data/rust/parser/src/parse/chapter.rs +517 -0
  788. data/rust/parser/src/parse/command.rs +637 -0
  789. data/rust/parser/src/parse/domain_port.rs +127 -0
  790. data/rust/parser/src/parse/entity.rs +527 -0
  791. data/rust/parser/src/parse/file.rs +67 -0
  792. data/rust/parser/src/parse/hecksagon.rs +231 -0
  793. data/rust/parser/src/parse/lifecycle.rs +162 -0
  794. data/rust/parser/src/parse/mod.rs +1262 -0
  795. data/rust/parser/src/parse/policy.rs +87 -0
  796. data/rust/parser/src/parse/process_manager.rs +305 -0
  797. data/rust/parser/src/parse/query.rs +100 -0
  798. data/rust/parser/src/parse/read_model.rs +214 -0
  799. data/rust/parser/src/parse/value_object.rs +250 -0
  800. data/rust/parser/src/ruby_value.rs +422 -0
  801. data/rust/project/bridging.rb +257 -0
  802. data/rust/project/commands.rb +877 -0
  803. data/rust/project/constraints.rb +86 -0
  804. data/rust/project/dependency_planning.rb +178 -0
  805. data/rust/project/domain_generator.rb +980 -0
  806. data/rust/project/exemplar.rb +148 -0
  807. data/rust/project/expr_emitter.rb +72 -0
  808. data/rust/project/fielded.rb +141 -0
  809. data/rust/project/json_codec.rb +641 -0
  810. data/rust/project/mutations.rb +721 -0
  811. data/rust/project/naming.rb +205 -0
  812. data/rust/project/ports.rb +65 -0
  813. data/rust/project/queries.rb +493 -0
  814. data/rust/project/reactions.rb +317 -0
  815. data/rust/project/read_models.rb +690 -0
  816. data/rust/project/reference_specs.rb +27 -0
  817. data/rust/project/registry.rb +396 -0
  818. data/rust/project/skip_reason.rb +29 -0
  819. data/rust/project/types.rb +225 -0
  820. data/rust/project/write_if_changed.rb +83 -0
  821. data/rust/project.rb +30 -0
  822. data/rust/project_rust_pipeline.rb +383 -0
  823. data/rust/src/exemplar/commands.rs +279 -0
  824. data/rust/src/exemplar/constraints.rs +18 -0
  825. data/rust/src/exemplar/fielded.rs +280 -0
  826. data/rust/src/exemplar/json.rs +277 -0
  827. data/rust/src/exemplar/mod.rs +17 -0
  828. data/rust/src/exemplar/mutations.rs +80 -0
  829. data/rust/src/exemplar/queries.rs +33 -0
  830. data/rust/src/exemplar/reactions.rs +88 -0
  831. data/rust/src/exemplar/read_models.rs +48 -0
  832. data/rust/src/exemplar/registry.rs +166 -0
  833. data/rust/src/exemplar/types.rs +44 -0
  834. data/rust/src/kernel/attribute_shapes/composite.rs +88 -0
  835. data/rust/src/kernel/attribute_shapes/list.rs +18 -0
  836. data/rust/src/kernel/attribute_shapes/mod.rs +44 -0
  837. data/rust/src/kernel/attribute_shapes/optional.rs +9 -0
  838. data/rust/src/kernel/attribute_shapes/scalar.rs +39 -0
  839. data/rust/src/kernel/cli.rs +585 -0
  840. data/rust/src/kernel/dispatch.rs +1090 -0
  841. data/rust/src/kernel/expr.rs +458 -0
  842. data/rust/src/kernel/expression_operators/arithmetic.rs +128 -0
  843. data/rust/src/kernel/expression_operators/comparison.rs +48 -0
  844. data/rust/src/kernel/expression_operators/enumeration.rs +232 -0
  845. data/rust/src/kernel/expression_operators/logical.rs +13 -0
  846. data/rust/src/kernel/expression_operators/membership.rs +18 -0
  847. data/rust/src/kernel/expression_operators/mod.rs +68 -0
  848. data/rust/src/kernel/expression_operators/pattern_match.rs +73 -0
  849. data/rust/src/kernel/expression_operators/positional.rs +126 -0
  850. data/rust/src/kernel/expression_operators/presence.rs +101 -0
  851. data/rust/src/kernel/expression_operators/sign_test.rs +16 -0
  852. data/rust/src/kernel/expression_operators/sized.rs +35 -0
  853. data/rust/src/kernel/expression_operators/text.rs +79 -0
  854. data/rust/src/kernel/expression_operators/to_string.rs +18 -0
  855. data/rust/src/kernel/json.rs +779 -0
  856. data/rust/src/kernel/mod.rs +133 -0
  857. data/rust/src/kernel/named_query.rs +219 -0
  858. data/rust/src/kernel/orchestrate.rs +1810 -0
  859. data/rust/src/kernel/pattern.rs +307 -0
  860. data/rust/src/kernel/query_comparators.rs +206 -0
  861. data/rust/src/kernel/query_ordering.rs +103 -0
  862. data/rust/src/kernel/read_model.rs +914 -0
  863. data/rust/src/kernel/reference_lookup.rs +149 -0
  864. data/rust/src/kernel/repository.rs +468 -0
  865. data/rust/src/kernel/routing.rs +612 -0
  866. data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +118 -0
  867. data/rust/src/kernel/vocab/entity_dispatch_order.rs +114 -0
  868. data/rust/src/kernel/vocab/field_hint.rs +70 -0
  869. data/rust/src/kernel/vocab/mod.rs +20 -0
  870. data/rust/src/kernel/vocab/query_comparator.rs +65 -0
  871. data/rust/src/kernel/vocab/refusal_template.rs +1592 -0
  872. data/rust/src/lib.rs +8 -0
  873. data/rust/src/main.rs +16 -0
  874. data/rust/web/.gitignore +1 -0
  875. data/rust/web/Cargo.lock +119 -0
  876. data/rust/web/Cargo.toml +18 -0
  877. data/rust/web/src/lib.rs +8 -0
  878. metadata +478 -12
  879. data/lib/hecks/facade/cli_door.rb +0 -178
  880. data/lib/hecks/facade/cli_runner.rb +0 -271
  881. data/lib/hecks/facade/handle.rb +0 -293
  882. data/lib/hecks/facade/json_door.rb +0 -247
  883. data/lib/hecks/facade/surface/aggregate_door.rb +0 -222
  884. data/lib/hecks/facade/surface/chapter.rb +0 -116
  885. data/lib/hecks/facade/surface.rb +0 -61
  886. data/lib/hecks/mcp_door_scope.rb +0 -176
@@ -0,0 +1,166 @@
1
+ module Hecks
2
+ module Fuzzing
3
+ # Shrinks a failing step list to a small one that still reproduces the finding.
4
+ # The caller's block decides "same finding"; this module never replays anything.
5
+ #
6
+ # Pass 1 removes step chunks (delta debugging) until the list is 1-minimal.
7
+ # Pass 2 drops argument keys one at a time inside each surviving step.
8
+ # `budget:` caps candidate checks; when spent, the best candidate so far is returned.
9
+ module Shrinker
10
+ Result = Struct.new(:steps, :attempts, :exhausted, keyword_init: true)
11
+
12
+ module_function
13
+
14
+ # Shrinks `steps` to the smallest list the block still accepts as reproducing.
15
+ #
16
+ # @param steps [Array<Hash>] the step list to shrink
17
+ # @param budget [Integer, nil] maximum candidate checks to spend; nil for unbounded
18
+ # @yieldparam candidate [Array<Hash>] a step-dropped or argument-trimmed copy of `steps`
19
+ # @yieldreturn [Boolean] true if `candidate` still reproduces the finding
20
+ # @return [Fuzzing::Shrinker::Result] `steps:` the shrunk list, `attempts:` checks
21
+ # spent, `exhausted:` whether the budget ran out
22
+ # @raise [ArgumentError] if no block is given
23
+ def call(steps, budget: nil, &reproduces)
24
+ raise ArgumentError, "Shrinker.call needs a block answering whether a candidate reproduces" unless reproduces
25
+
26
+ meter = Meter.new(budget)
27
+ current = drop_steps(steps.dup, meter, &reproduces)
28
+ current = drop_arguments(current, meter, &reproduces)
29
+ Result.new(steps: current, attempts: meter.used, exhausted: meter.exhausted?)
30
+ end
31
+
32
+ def drop_steps(steps, meter, &reproduces)
33
+ current = steps
34
+ chunk = [current.length / 2, 1].max
35
+ loop do
36
+ changed = false
37
+ index = 0
38
+ while index < current.length
39
+ return current if meter.exhausted?
40
+
41
+ candidate = current[0...index] + (current[(index + chunk)..] || [])
42
+ if candidate.empty?
43
+ index += chunk
44
+ next
45
+ end
46
+
47
+ if meter.try { reproduces.call(candidate) }
48
+ current = candidate
49
+ changed = true
50
+ else
51
+ index += chunk
52
+ end
53
+ end
54
+
55
+ if chunk > 1
56
+ chunk = [chunk / 2, 1].max
57
+ elsif !changed
58
+ break
59
+ end
60
+ end
61
+ current
62
+ end
63
+
64
+ def drop_arguments(steps, meter, &reproduces)
65
+ steps.each_index do |position|
66
+ original = args_of(steps[position])
67
+ next unless original.is_a?(Hash)
68
+
69
+ original.each_key do |key|
70
+ return steps if meter.exhausted?
71
+
72
+ step = steps[position]
73
+ trimmed = args_of(step).reject { |name, _| name == key }
74
+ candidate = steps.map(&:dup)
75
+ candidate[position] = step.merge("args" => trimmed)
76
+ steps = candidate if meter.try { reproduces.call(candidate) }
77
+ end
78
+ end
79
+ steps
80
+ end
81
+
82
+ # `key?` first, never `||`, which cannot tell a stored `false` from an absent key.
83
+ def args_of(step)
84
+ step.key?("args") ? step["args"] : step[:args]
85
+ end
86
+
87
+ LIST_FIELDS = %w[refusals queries dry_runs reactions].freeze
88
+
89
+ CRASH_FIELDS = %w[crash process generator_crash].freeze
90
+
91
+ # The identity a shrink candidate has to keep, as a set of stable strings.
92
+ #
93
+ # `field` alone is too loose for list comparisons: a candidate could show a different
94
+ # refusal split and the shrinker would hand back the wrong bug. So list fields add the
95
+ # verbs in the symmetric difference, `instances` adds the differing aggregates, and
96
+ # crash fields add the exception class.
97
+ #
98
+ # @param divergences [Array<Hash>] entries carrying at least `{field:, detail:}`
99
+ # @return [Set<String>] identity strings
100
+ def signature(divergences)
101
+ divergences.each_with_object(Set.new) do |divergence, keys|
102
+ field = divergence[:field].to_s
103
+ keys << field
104
+ keys.merge(detail_keys(field, divergence))
105
+ end
106
+ end
107
+
108
+ def detail_keys(field, divergence)
109
+ left, right = divergence.except(:field, :detail).values.select { |v| v.is_a?(Array) || v.is_a?(Hash) }
110
+ if LIST_FIELDS.include?(field) then list_keys(field, left, right)
111
+ elsif field == "instances" then instance_keys(left, right)
112
+ elsif CRASH_FIELDS.include?(field) && divergence[:detail]
113
+ ["#{field}:#{divergence[:detail].to_s[/\A\w+(?:::\w+)*/]}"]
114
+ else []
115
+ end
116
+ end
117
+
118
+ def list_keys(field, left, right)
119
+ return [] unless left.is_a?(Array) && right.is_a?(Array)
120
+
121
+ ((left - right) + (right - left)).map { |row| "#{field}:#{named(row)}" }
122
+ end
123
+
124
+ # The `#id` suffix is dropped: the generator mints ids, so they name the record,
125
+ # not the finding, and keeping them would pin every creating step.
126
+ def instance_keys(left, right)
127
+ return [] unless left.is_a?(Hash) && right.is_a?(Hash)
128
+
129
+ (left.keys | right.keys).reject { |key| left[key] == right[key] }
130
+ .map { |key| "instances:#{key.to_s.split('#').first}" }
131
+ end
132
+
133
+ # True when the candidate's signature contains the original's.
134
+ # Removing steps may add a second divergence but must never lose the one being shrunk.
135
+ def reproduces?(original_signature, divergences)
136
+ !divergences.empty? && original_signature.subset?(signature(divergences))
137
+ end
138
+
139
+ def named(row)
140
+ return row.to_s unless row.is_a?(Hash)
141
+
142
+ key = [%w[verb query policy], %i[verb query policy]].flatten.find { |name| row.key?(name) }
143
+ (key ? row[key] : row).to_s
144
+ end
145
+
146
+ # Counts candidate checks against the budget.
147
+ class Meter
148
+ attr_reader :used
149
+
150
+ # @param budget [Integer, nil] maximum candidate checks to allow; nil for unbounded
151
+ def initialize(budget)
152
+ @budget = budget
153
+ @used = 0
154
+ end
155
+
156
+ def exhausted? = !@budget.nil? && @used >= @budget
157
+
158
+ # Spends one check against the budget and yields.
159
+ def try
160
+ @used += 1
161
+ yield
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,33 @@
1
+ module Hecks
2
+ module Fuzzing
3
+ # Names the construct family behind each query verb the Ruby/Rust comparison skipped.
4
+ # The construct is read from the binary's manifest entry, not guessed from the declaration.
5
+ module StructuralSkips
6
+ module_function
7
+
8
+ # Attributes each skipped verb to the construct family its manifest entry names.
9
+ # A verb the manifest does not declare answers `unknown`, which no boundary admits.
10
+ #
11
+ # @param gaps [Fuzzing::RustGapManifest] the binary's not-generated manifest entries
12
+ # @param verbs [Array<String>] the skipped query/read-model verbs to attribute
13
+ # @return [Array<Hash{Symbol => Object}>] one `{ verb:, constructs: }` per verb,
14
+ # sorted by verb
15
+ def attribute(gaps, verbs)
16
+ verbs.sort.map do |verb|
17
+ entry = gaps.not_generated(verb)
18
+ { verb: verb, constructs: entry ? [entry.fetch("construct")] : %w[unknown] }
19
+ end
20
+ end
21
+
22
+ # Selects the attributed entries whose constructs are not all inside `boundary`.
23
+ #
24
+ # @param attributed [Array<Hash{Symbol => Object}>] entries as returned by `attribute`
25
+ # @param boundary [Array<String, Symbol>] the construct families the codegen boundary admits
26
+ # @return [Array<Hash{Symbol => Object}>] the entries naming an unadmitted construct
27
+ def outside_boundary(attributed, boundary)
28
+ admitted = boundary.map(&:to_s)
29
+ attributed.select { |entry| entry[:constructs].empty? || (entry[:constructs] - admitted).any? }
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,43 @@
1
+ module Hecks
2
+ module Fuzzing
3
+ # Maps a QA target's clean streak to how hard the next sweep fuzzes.
4
+ module SweepDepth
5
+ module_function
6
+
7
+ # Fallback tiers for a ledger with no QualityControlDials configured.
8
+ DEFAULT_TIERS = [
9
+ { upto: 4, seeds: 10, steps: 25 },
10
+ { upto: 19, seeds: 25, steps: 50 },
11
+ { upto: Float::INFINITY, seeds: 50, steps: 100 }
12
+ ].freeze
13
+
14
+ # Rows are read in order; the last row must keep upto: Float::INFINITY.
15
+ def for_streak(streak, tiers: DEFAULT_TIERS)
16
+ raise ArgumentError, "streak must not be negative" if streak.negative?
17
+
18
+ tier = tiers.find { |row| streak <= row[:upto] }
19
+ raise ArgumentError, "no tier covers a streak of #{streak} — the last row must be upto: Float::INFINITY" unless tier
20
+
21
+ [tier[:seeds], tier[:steps]]
22
+ end
23
+
24
+ # The first seed a streak-widened sweep counts from. Once a target's streak has widened past
25
+ # the ceiling tier, `for_streak` keeps returning the same seed count forever; sweeping
26
+ # `1..seeds` every time would regenerate the identical sequences on every tick. Advancing
27
+ # this with the streak keeps the swept range moving into seed integers no earlier tick of
28
+ # this streak ever reached, without a new persisted field: `streak` already ties consecutive
29
+ # tiers' ranges back to back (each tier's width times its own streak count), and a streak
30
+ # reset (back to 0) lands this back at 0 too, so a fresh or just-released target still sweeps
31
+ # the familiar `1..seeds`.
32
+ #
33
+ # @param streak [Integer] `Target#clean_streak`, non-negative
34
+ # @param seeds [Integer] the seed count `for_streak` resolved for this same streak
35
+ # @return [Integer] the offset; the sweep should cover `(offset + 1)..(offset + seeds)`
36
+ def seed_offset(streak, seeds)
37
+ raise ArgumentError, "streak must not be negative" if streak.negative?
38
+
39
+ streak * seeds
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,163 @@
1
+ module Hecks
2
+ module Fuzzing
3
+ # Infers what a sweep target can be checked for from its directory, not a stored list.
4
+ # `modes_to_run = enabled ∩ eligible`: `infer` finds capabilities, `resolve` applies it.
5
+ module TargetCapabilities
6
+ module_function
7
+
8
+ # Matches the `[features]` table only, so `[package] name = "rust"` never reads as a feature.
9
+ FEATURES_TABLE = /^\[features\](?:\n(?!\[).*)*$/
10
+
11
+ # Both spellings: aggregate-scoped `.persisted_by("PostgresEra")` and the bare
12
+ # domain-level `persisted_by "PostgresEra"`.
13
+ POSTGRES_ERA_BINDING = /persisted_by\s*\(?\s*"PostgresEra"/
14
+
15
+ # A local assigned the bare literal on its own line; any other right-hand side is not one.
16
+ POSTGRES_ERA_VARIABLE = /^\s*([a-z_]\w*)\s*=\s*"PostgresEra"\s*(?:#.*)?$/
17
+
18
+ # Captures the member a hecksagon attaches; authorization is read off its declaration.
19
+ FRAMEWORK_ATTACHED = /uses_framework\s*\(?\s*"([^"]+)"/
20
+
21
+ # A command-level `role "..."`, the only construct a role check can compare a caller against.
22
+ ROLE_GATED = /^\s*role\s+"/
23
+
24
+ TENANT_SCOPED = /\btenant:/
25
+
26
+ PROCESS_MANAGER = /^\s*process_manager\s+"/
27
+
28
+ # Capabilities each mode needs; an empty list means any target.
29
+ # `resolve` drops `ruby_only` when `differential` resolves too: same seat, Rust is better.
30
+ MODE_REQUIREMENTS = {
31
+ differential: %w[rust],
32
+ ruby_only: [],
33
+ self_consistency: [],
34
+ properties_in_differential: %w[rust],
35
+ structural_skip_report: %w[rust],
36
+ adapter_parity_sqlite: %w[sqlite],
37
+ persistence_parity: %w[postgres_era],
38
+ adapter_parity_postgres: %w[postgres_era],
39
+ era_boundary: %w[translations postgres_era],
40
+ concurrency: %w[postgres_era],
41
+ wasm_front: %w[rust]
42
+ }.freeze
43
+
44
+ # The modes `hecks quality_control ask run` can run; one absent here is refused at start, not
45
+ # resolved.
46
+ RUNNABLE_MODES = %i[differential ruby_only self_consistency properties_in_differential
47
+ structural_skip_report adapter_parity_sqlite persistence_parity
48
+ era_boundary concurrency].freeze
49
+
50
+ # Expensive passes run only when named (`--modes`) or as `--all`'s second wave.
51
+ DEFERRED_MODES = %i[persistence_parity adapter_parity_postgres era_boundary concurrency].freeze
52
+
53
+ # Reads a target directory to find out which capabilities it actually has.
54
+ #
55
+ # @param domain_path [String] filesystem path to the target domain's directory
56
+ # @param rust_dir [String] path to the Rust project root, checked for a matching
57
+ # Cargo feature; defaults to this repo's own `rust/` directory
58
+ # @return [Array<String>] the target's capabilities, sorted; a subset of
59
+ # `sqlite`, `rust`, `postgres_era`, `translations`, `governance`, `role_gated`,
60
+ # `tenant`, `sagas`
61
+ def infer(domain_path, rust_dir: File.expand_path("../../../rust", __dir__))
62
+ capabilities = %w[sqlite]
63
+ capabilities << "rust" if rust_feature?(domain_path, rust_dir)
64
+ capabilities << "postgres_era" if postgres_era_bound?(domain_path)
65
+ capabilities << "translations" if Dir.glob(File.join(domain_path, "**", "translations", "*.bluebook")).any?
66
+ capabilities << "governance" if authorization_attached?(domain_path)
67
+ capabilities << "role_gated" if any_file?(domain_path, "*.bluebook", ROLE_GATED)
68
+ capabilities << "tenant" if any_file?(domain_path, "*.bluebook", TENANT_SCOPED)
69
+ capabilities << "sagas" if any_file?(domain_path, "*.bluebook", PROCESS_MANAGER)
70
+ capabilities.sort
71
+ end
72
+
73
+ # Answers whether `mode` can run against a target with `capabilities`.
74
+ #
75
+ # @param mode [Symbol, String] a key of `MODE_REQUIREMENTS`, such as `:differential`
76
+ # @param capabilities [Array<String>] the target's capabilities, as `infer` returns
77
+ # @return [Boolean] whether `capabilities` covers every capability `mode` requires
78
+ # @raise [ArgumentError] if `mode` names no entry in `MODE_REQUIREMENTS`
79
+ def eligible?(mode, capabilities)
80
+ required = MODE_REQUIREMENTS.fetch(mode.to_sym) { raise ArgumentError, "unknown sweep mode #{mode.inspect}" }
81
+ (required - capabilities).empty?
82
+ end
83
+
84
+ # Filters the enabled modes down to those the target is eligible for, keeping their order.
85
+ #
86
+ # @param enabled [Array<Symbol, String>] modes turned on, in the dial's own
87
+ # declaration order
88
+ # @param capabilities [Array<String>] the target's capabilities, as `infer` returns
89
+ # @return [Array<Symbol>] `enabled`'s eligible modes, in `enabled`'s order, with
90
+ # `:ruby_only` dropped whenever `:differential` is also eligible
91
+ def resolve(enabled, capabilities)
92
+ resolved = enabled.map(&:to_sym).select { |mode| eligible?(mode, capabilities) }
93
+ resolved.delete(:ruby_only) if resolved.include?(:differential)
94
+ resolved
95
+ end
96
+
97
+ # Answers whether `rust_dir`'s Cargo.toml declares a feature named after
98
+ # `domain_path`'s own directory.
99
+ #
100
+ # @param domain_path [String] filesystem path to the target domain's directory;
101
+ # its basename, lowercased, is the feature name looked up
102
+ # @param rust_dir [String] path to the Rust project root (holds `Cargo.toml`)
103
+ # @return [Boolean] whether a matching Cargo feature is declared; false if
104
+ # `rust_dir` has no `Cargo.toml`
105
+ def rust_feature?(domain_path, rust_dir)
106
+ cargo_toml = File.join(rust_dir, "Cargo.toml")
107
+ return false unless File.file?(cargo_toml)
108
+
109
+ feature = File.basename(domain_path).downcase
110
+ features = File.read(cargo_toml)[FEATURES_TABLE] || ""
111
+ features.match?(/^#{Regexp.escape(feature)}\s*=\s*\[\]/)
112
+ end
113
+
114
+ # Answers whether any `.hecksagon` under `domain_path` binds PostgresEra,
115
+ # by literal name or through a local variable assigned `"PostgresEra"`.
116
+ #
117
+ # @param domain_path [String] filesystem path to the target domain's directory
118
+ # @return [Boolean] whether a PostgresEra `persisted_by` binding is found
119
+ def postgres_era_bound?(domain_path)
120
+ Dir.glob(File.join(domain_path, "**", "*.hecksagon")).any? do |path|
121
+ text = File.read(path)
122
+ text.match?(POSTGRES_ERA_BINDING) || postgres_era_variable_bound?(text)
123
+ end
124
+ end
125
+
126
+ # Answers whether `text` passes a variable assigned `"PostgresEra"` to `persisted_by`.
127
+ #
128
+ # @param text [String] the contents of one `.hecksagon` file
129
+ # @return [Boolean] whether some `persisted_by` call names such a variable
130
+ def postgres_era_variable_bound?(text)
131
+ text.scan(POSTGRES_ERA_VARIABLE).flatten.any? do |name|
132
+ text.match?(/persisted_by\s*\(?\s*#{Regexp.escape(name)}(?!\w)/)
133
+ end
134
+ end
135
+
136
+ # Answers whether any `.hecksagon` under `domain_path` attaches a member
137
+ # that provides authorization.
138
+ #
139
+ # The capability label stays "governance" because it is the value stored in the ledger.
140
+ #
141
+ # @param domain_path [String] filesystem path to the target domain's directory
142
+ # @return [Boolean] whether the domain attaches a member that provides the
143
+ # `Bluebook::Capabilities::AUTHORIZATION` capability
144
+ def authorization_attached?(domain_path)
145
+ attached = Dir.glob(File.join(domain_path, "**", "*.hecksagon"))
146
+ .flat_map { |path| File.read(path).scan(FRAMEWORK_ATTACHED).flatten }.uniq
147
+ providers = Framework.providers_of(Bluebook::Capabilities::AUTHORIZATION)
148
+ attached.intersect?(providers)
149
+ end
150
+
151
+ # Answers whether any file under `domain_path` matching `glob` contains `pattern`.
152
+ #
153
+ # @param domain_path [String] filesystem path to the target domain's directory
154
+ # @param glob [String] a `Dir.glob` pattern relative to `domain_path`, such as
155
+ # `"*.bluebook"`
156
+ # @param pattern [Regexp] the pattern each matching file's contents is tested against
157
+ # @return [Boolean] whether any matching file's contents match `pattern`
158
+ def any_file?(domain_path, glob, pattern)
159
+ Dir.glob(File.join(domain_path, "**", glob)).any? { |path| File.read(path).match?(pattern) }
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,216 @@
1
+ require_relative "../runtime/value"
2
+
3
+ module Hecks
4
+ module Fuzzing
5
+ # Generates one JSON-safe value per attribute, in the shape the hand-written corpus uses.
6
+ # Edge cases are frequent but not dominant; name-aware shapes reach deep state.
7
+ module ValueGenerator
8
+ module_function
9
+
10
+ EDGE_CASE_PROBABILITY = 0.2
11
+ INVALID_MEMBER_PROBABILITY = 0.1
12
+ INVALID_REFERENCE_PROBABILITY = 0.2
13
+ # Exercises the bare-scalar form a single-field value object accepts.
14
+ BARE_SCALAR_PROBABILITY = 0.2
15
+
16
+ STRING_EDGE_CASES = [
17
+ "", "x", "with \"quotes\"", "with, a comma", "with a \\backslash",
18
+ "unicode héllo wörld 🎉", "x" * 200, " leading and trailing "
19
+ ].freeze
20
+ # Includes Bignums past i64, which a Rust kernel value cannot represent (`kernel/json.rs`).
21
+ INTEGER_EDGE_CASES = [0, -1, 2_147_483_647, -2_147_483_648, 2**100, -(2**100)].freeze
22
+ # Clock- and count-shaped fields stay under f64's exact-integer ceiling: `Json::Num` is an
23
+ # f64, so a Bignum there only re-hits the known precision-loss class.
24
+ SAFE_INTEGER_EDGE_CASES = [0, -1, 2_147_483_647, -2_147_483_648].freeze
25
+ # Tested against the value object's name plus the attribute's name; deliberately narrow, so
26
+ # "amount"/"cents"/"sequence" keep the full Bignum pool.
27
+ CLOCK_OR_COUNT_NAME_PATTERN = /clock|instant|expir|ttl|\bnow\b|timestamp|epoch|count/i
28
+ # NaN and infinities are safe to generate; -0.0 covers signed zero.
29
+ FLOAT_EDGE_CASES = [0.0, -0.0, -0.5, -100.25, Float::NAN, Float::INFINITY, -Float::INFINITY].freeze
30
+ WORDS = %w[alpha bravo charlie delta echo foxtrot golf hotel india juliet].freeze
31
+ CURRENCY_CODES = %w[USD EUR GBP JPY].freeze
32
+
33
+ # The value for one command/query/value-object attribute.
34
+ #
35
+ # `context` carries the enclosing value object's name, since `EmailAddress`'s `address` field
36
+ # only looks email-shaped through the name of the object around it.
37
+ #
38
+ # @param attribute [Bluebook::Attribute] the attribute to generate a value for
39
+ # @param aggregate [Bluebook::Aggregate] the aggregate `attribute` belongs to
40
+ # @param random [Random] the RNG driving every draw this call makes
41
+ # @param known_ids [Hash{String => Array<String>}] real ids by aggregate or entity name
42
+ # @param context [String, nil] the enclosing value object's name; nil at the top level
43
+ # @return [String, Integer, Float, Boolean, Hash] a JSON-safe value: a nested Hash for a
44
+ # value-object type, a bare id String for a reference, a primitive otherwise
45
+ def value_for(attribute, aggregate, random:, known_ids: {}, context: nil)
46
+ return reference_value(attribute, random: random, known_ids: known_ids) if attribute.reference?
47
+
48
+ # Same lookup the runtime uses: an identity value object may live on a sibling aggregate.
49
+ value_object = Runtime::Value.value_object_for(aggregate, attribute.type.to_s)
50
+ return object_for(value_object, aggregate, random: random, known_ids: known_ids) if value_object
51
+
52
+ primitive(attribute.type.to_s, random: random, name: "#{context} #{attribute.name}")
53
+ end
54
+
55
+ # Generates a nested value for a whole value object: a random admitted
56
+ # row for a closed set, or a value per declared attribute otherwise —
57
+ # occasionally unwrapped to a bare scalar for a genuinely single-field
58
+ # value object.
59
+ #
60
+ # @param value_object [Bluebook::ValueObject] the value object to generate a value for
61
+ # @param aggregate [Bluebook::Aggregate] the aggregate `value_object` is reached from
62
+ # @param random [Random] the RNG driving every draw this call makes
63
+ # @param known_ids [Hash{String => Array<String>}] real ids by aggregate or entity name
64
+ # @return [Hash, Object] `{field name => value, ...}`, or the lone value when the
65
+ # value object has one field and the bare-scalar draw hits
66
+ def object_for(value_object, aggregate, random:, known_ids:)
67
+ fields =
68
+ if value_object.closed_set? && !value_object.members.empty?
69
+ return invalid_member(value_object, random: random) if random.rand < INVALID_MEMBER_PROBABILITY
70
+
71
+ member = value_object.members.sample(random: random)
72
+ member.to_h { |field, value| [field.to_s, value] }
73
+ else
74
+ value_object.attributes.to_h do |field|
75
+ [field.name.to_s,
76
+ value_for(field, aggregate, random: random, known_ids: known_ids, context: value_object.hecks_name)]
77
+ end
78
+ end
79
+
80
+ # Unwrap only a genuinely single-field value object, never `invalid_member`: a wrong
81
+ # combination stays a Hash so its wrongness is what gets exercised.
82
+ return fields.values.first if fields.size == 1 && random.rand < BARE_SCALAR_PROBABILITY
83
+
84
+ fields
85
+ end
86
+
87
+ # A combination that (almost certainly) isn't one of the closed set's admitted rows,
88
+ # to exercise the refusal a `one_of` exists to enforce.
89
+ #
90
+ # @param value_object [Bluebook::ValueObject] the closed-set value object to
91
+ # generate a non-admitted combination for
92
+ # @param random [Random] the RNG driving every draw this call makes
93
+ # @return [Hash] `{field name => value, ...}` for every declared attribute, each
94
+ # drawn independently rather than sampled from an admitted row
95
+ def invalid_member(value_object, random:)
96
+ value_object.attributes.to_h do |field|
97
+ [field.name.to_s, primitive(field.type.to_s, random: random, name: field.name.to_s)]
98
+ end
99
+ end
100
+
101
+ # The ID itself, unwrapped: the payload gate refuses `{"value" => id}` for a reference.
102
+ #
103
+ # @param attribute [Bluebook::Attribute] the reference-typed attribute to
104
+ # generate a value for
105
+ # @param random [Random] the RNG driving every draw this call makes
106
+ # @param known_ids [Hash{String => Array<String>}] known real ids, keyed by
107
+ # aggregate or entity name; looked up under `attribute.type.target_name`
108
+ # @return [String] a real id drawn from the matching pool most of the time; a
109
+ # fabricated `"missing-..."` id when the pool is empty or the invalid-reference
110
+ # draw hits
111
+ def reference_value(attribute, random:, known_ids:)
112
+ pool = known_ids[attribute.type.target_name.to_s] || []
113
+ return "missing-#{random.bytes(4).unpack1('H*')}" if pool.empty? || random.rand < INVALID_REFERENCE_PROBABILITY
114
+
115
+ pool.sample(random: random)
116
+ end
117
+
118
+ # Generates a value for one Ruby-primitive-typed attribute.
119
+ #
120
+ # @param type_name [String] the primitive type name: `"String"`, `"Integer"`,
121
+ # `"Float"`, `"Boolean"`, `"TrueClass"`, or `"FalseClass"`
122
+ # @param random [Random] the RNG driving every draw this call makes
123
+ # @param name [String, nil] a name hint (attribute name, optionally
124
+ # context-prefixed) that draws an email-/currency-shaped string or a
125
+ # clock/count-shaped integer
126
+ # @return [String, Integer, Float, Boolean] a value of the type `type_name` names
127
+ # @raise [ArgumentError] if `type_name` names anything else
128
+ def primitive(type_name, random:, name: nil)
129
+ case type_name
130
+ when "String" then string_value(random, name: name)
131
+ when "Integer" then integer_value(random, name: name)
132
+ when "Float" then float_value(random)
133
+ when "TrueClass", "FalseClass", "Boolean" then random.rand(2).zero?
134
+ else raise ArgumentError, "ValueGenerator does not know primitive type #{type_name.inspect}"
135
+ end
136
+ end
137
+
138
+ # Generates a String value, name-aware for shapes an invariant needs (email, currency).
139
+ #
140
+ # @param random [Random] the RNG driving every draw this call makes
141
+ # @param name [String, nil] a name hint; an `"email"` or `"currency"` match
142
+ # draws a shaped value instead of random words
143
+ # @return [String] an edge-case string, an email address, a currency code, or
144
+ # 1-3 random words joined by spaces
145
+ def string_value(random, name: nil)
146
+ return STRING_EDGE_CASES.sample(random: random) if random.rand < EDGE_CASE_PROBABILITY
147
+ return email_value(random) if name&.match?(/email/i)
148
+ return CURRENCY_CODES.sample(random: random) if name&.match?(/currency/i)
149
+
150
+ Array.new(random.rand(1..3)) { WORDS.sample(random: random) }.join(" ")
151
+ end
152
+
153
+ # Generates a fabricated, syntactically valid email address.
154
+ #
155
+ # @param random [Random] the RNG driving every draw this call makes
156
+ # @return [String] a `"word@word.example"` address
157
+ def email_value(random)
158
+ "#{WORDS.sample(random: random)}@#{WORDS.sample(random: random)}.example"
159
+ end
160
+
161
+ # Generates an Integer value, skewed positive so `positive?`-style invariants are reachable.
162
+ # Zero and negatives still come through the edge-case pool.
163
+ #
164
+ # @param random [Random] the RNG driving every draw this call makes
165
+ # @param name [String, nil] a name hint; a clock/count-shaped match narrows
166
+ # the edge-case pool to `SAFE_INTEGER_EDGE_CASES`
167
+ # @return [Integer] an edge-case integer sometimes, else a random count in 1..1000
168
+ def integer_value(random, name: nil)
169
+ if random.rand < EDGE_CASE_PROBABILITY
170
+ pool = clock_or_count_shaped?(name) ? SAFE_INTEGER_EDGE_CASES : INTEGER_EDGE_CASES
171
+ return pool.sample(random: random)
172
+ end
173
+
174
+ random.rand(1..1000)
175
+ end
176
+
177
+ # Reports whether a field name reads as a clock reading or a policy-capped count.
178
+ #
179
+ # @param name [String, nil] the name to test
180
+ # @return [Boolean] true if `name` matches the clock/count name pattern
181
+ def clock_or_count_shaped?(name)
182
+ name.to_s.match?(CLOCK_OR_COUNT_NAME_PATTERN)
183
+ end
184
+
185
+ # Generates a Float value.
186
+ #
187
+ # @param random [Random] the RNG driving every draw this call makes
188
+ # @return [Float] an edge-case float sometimes, else a random value in
189
+ # 0.01..1000.0, rounded to 2 decimal places
190
+ def float_value(random)
191
+ return FLOAT_EDGE_CASES.sample(random: random) if random.rand < EDGE_CASE_PROBABILITY
192
+
193
+ random.rand(0.01..1000.0).round(2)
194
+ end
195
+
196
+ # The bare scalar a generated identity value stands for, for recording into `known_ids`.
197
+ # A reference to this record is already that scalar; the two are not interchangeable.
198
+ #
199
+ # @param identity_value [Hash, Object] a generated identity value, as `value_for`
200
+ # produced it — a Hash for a multi-field value object, or the bare scalar already
201
+ # for a single-field one
202
+ # @return [String] the identity's bare scalar, stringified
203
+ def scalar_of(identity_value)
204
+ identity_value.is_a?(Hash) ? identity_value.values.first.to_s : identity_value.to_s
205
+ end
206
+
207
+ # Generates a fabricated id unrelated to anything `known_ids` tracks.
208
+ #
209
+ # @param random [Random] the RNG driving every draw this call makes
210
+ # @return [String] a `"gen-"`-prefixed id with 8 random hex characters
211
+ def random_id(random)
212
+ "gen-#{random.bytes(4).unpack1('H*')}"
213
+ end
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,23 @@
1
+ module Hecks
2
+ # The fuzzing toolkit hecks fuzz and hecks generate_sequence drive. Not required by
3
+ # lib/hecks.rb on purpose — a booted domain never needs it.
4
+ module Fuzzing
5
+ end
6
+ end
7
+
8
+ require_relative "fuzzing/value_generator"
9
+ require_relative "fuzzing/invalid_value_generator"
10
+ require_relative "fuzzing/sequence_generator"
11
+ require_relative "fuzzing/nondeterministic"
12
+ require_relative "fuzzing/replay"
13
+ require_relative "fuzzing/shrinker"
14
+ require_relative "fuzzing/properties"
15
+ require_relative "fuzzing/qa_settings"
16
+ require_relative "fuzzing/rotation_priority"
17
+ require_relative "fuzzing/sweep_depth"
18
+ require_relative "fuzzing/persistence_parity"
19
+ require_relative "fuzzing/form_census"
20
+ require_relative "fuzzing/target_capabilities"
21
+ require_relative "fuzzing/rust_gap_manifest"
22
+ require_relative "fuzzing/structural_skips"
23
+ require_relative "fuzzing/coverage_campaign"