hecks 2.9.0 → 3.0.1

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 (600) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +51 -6
  3. data/lib/hecks/adapters/driven/heki/journal.rb +1 -1
  4. data/lib/hecks/adapters/driven/lambda/client.rb +1 -1
  5. data/lib/hecks/adapters/driven/lambda.rb +1 -1
  6. data/lib/hecks/adapters/driven/memory.rb +16 -3
  7. data/lib/hecks/adapters/driven/postgres/reconnect.rb +6 -2
  8. data/lib/hecks/adapters/driven/postgres/shared_connection.rb +180 -0
  9. data/lib/hecks/adapters/driven/postgres.rb +13 -4
  10. data/lib/hecks/adapters/driven/prism.rb +41 -8
  11. data/lib/hecks/adapters/driven/tenant_provisioner.rb +73 -16
  12. data/lib/hecks/behaviors/expectations.rb +1 -1
  13. data/lib/hecks/behaviors.rb +1 -1
  14. data/lib/hecks/bench/cli.rb +62 -0
  15. data/lib/hecks/bench/environment.rb +71 -0
  16. data/lib/hecks/bench/postgres_probe.rb +30 -0
  17. data/lib/hecks/bench/report.rb +76 -0
  18. data/lib/hecks/bench/ruby_runner.rb +93 -0
  19. data/lib/hecks/bench/run.rb +55 -0
  20. data/lib/hecks/bench/rust_runner.rb +101 -0
  21. data/lib/hecks/bench/stats.rb +46 -0
  22. data/lib/hecks/bench/suite.rb +98 -0
  23. data/lib/hecks/bench/workload.rb +89 -0
  24. data/lib/hecks/bench.rb +17 -0
  25. data/lib/hecks/bluebook/assembly/contracts.rb +2 -0
  26. data/lib/hecks/bluebook/attribute.rb +1 -1
  27. data/lib/hecks/bluebook/behaviour/aggregate.rb +30 -1
  28. data/lib/hecks/bluebook/behaviour/domain_port.rb +7 -0
  29. data/lib/hecks/bluebook/chapter.rb +6 -2
  30. data/lib/hecks/bluebook/domain_port.rb +36 -5
  31. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +10 -0
  32. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +8 -0
  33. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -1
  34. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +31 -3
  35. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +122 -3
  36. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +1 -1
  37. data/lib/hecks/bluebook/dsl/query_builder.rb +27 -1
  38. data/lib/hecks/bluebook/dsl/rule_reference.rb +1 -1
  39. data/lib/hecks/bluebook/dsl/world_builder.rb +29 -2
  40. data/lib/hecks/bluebook/expression/canonical_form.rb +1 -1
  41. data/lib/hecks/bluebook/expression/resolver.rb +3 -2
  42. data/lib/hecks/bluebook/hexagon.rb +13 -5
  43. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +1 -0
  44. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +4 -1
  45. data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +246 -0
  46. data/lib/hecks/bluebook/meta_validator.rb +9 -4
  47. data/lib/hecks/bluebook/model_check.rb +23 -0
  48. data/lib/hecks/bluebook/pattern_subset.rb +38 -0
  49. data/lib/hecks/bluebook/query.rb +20 -5
  50. data/lib/hecks/bluebook/smoke_test.rb +1 -1
  51. data/lib/hecks/canonical_json.rb +30 -0
  52. data/lib/hecks/chapters.rb +102 -0
  53. data/lib/hecks/cli/behaviors.rb +61 -0
  54. data/lib/hecks/cli/canonicalise.rb +25 -0
  55. data/lib/hecks/cli/check_engine_agreement.rb +32 -0
  56. data/lib/hecks/cli/check_era.rb +88 -0
  57. data/lib/hecks/cli/console.rb +66 -0
  58. data/lib/hecks/cli/deploy_template_diff.rb +40 -0
  59. data/lib/hecks/cli/doc_coverage.rb +32 -0
  60. data/lib/hecks/cli/document.rb +2 -2
  61. data/lib/hecks/cli/expression_projection.rb +41 -0
  62. data/lib/hecks/cli/follow.rb +88 -0
  63. data/lib/hecks/cli/history.rb +44 -0
  64. data/lib/hecks/cli/ir.rb +1 -1
  65. data/lib/hecks/cli/mcp.rb +3 -3
  66. data/lib/hecks/cli/model_check.rb +15 -8
  67. data/lib/hecks/cli/pattern_cases.rb +47 -0
  68. data/lib/hecks/cli/present.rb +39 -0
  69. data/lib/hecks/cli/project_cli.rb +224 -32
  70. data/lib/hecks/cli/project_diagrams.rb +4 -3
  71. data/lib/hecks/cli/project_glossary.rb +44 -0
  72. data/lib/hecks/cli/reference.rb +46 -0
  73. data/lib/hecks/cli/refresh_projections.rb +44 -0
  74. data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +150 -0
  75. data/lib/hecks/cli/release.rb +70 -0
  76. data/lib/hecks/cli/release_gem.rb +59 -0
  77. data/lib/hecks/cli/rspec_io_parallel_files.rb +137 -0
  78. data/lib/hecks/cli/rspec_shard_files.rb +66 -0
  79. data/lib/hecks/cli/run.rb +3 -3
  80. data/lib/hecks/cli/seed_semantics_corpus.rb +71 -0
  81. data/lib/hecks/cli/serve_query_ir_mcp.rb +30 -0
  82. data/lib/hecks/cli/shape.rb +70 -0
  83. data/lib/hecks/cli/smoke_http.rb +230 -0
  84. data/lib/hecks/cli/smoke_test.rb +5 -3
  85. data/lib/hecks/cli/spec_example.rb +27 -0
  86. data/lib/hecks/cli/statements.rb +32 -0
  87. data/lib/hecks/cli/stores.rb +4 -5
  88. data/lib/hecks/cli/stress_concurrency_specs.rb +177 -0
  89. data/lib/hecks/cli.rb +201 -52
  90. data/lib/hecks/codemod.rb +324 -0
  91. data/lib/hecks/corpus.rb +423 -0
  92. data/lib/hecks/deploy/bluebook/deploy.bluebook +591 -23
  93. data/lib/hecks/deploy/bluebook/deploy.hecksagon +41 -4
  94. data/lib/hecks/deploy/oidc.json +82 -2
  95. data/lib/hecks/doc/reference.rb +351 -0
  96. data/lib/hecks/doors/cli_door.rb +196 -0
  97. data/lib/hecks/doors/cli_runner.rb +297 -0
  98. data/lib/hecks/{facade → doors}/command_request.rb +1 -1
  99. data/lib/hecks/{facade → doors}/handle.rb +2 -2
  100. data/lib/hecks/{facade → doors}/json_door.rb +4 -4
  101. data/lib/hecks/doors/launcher_options.rb +129 -0
  102. data/lib/hecks/{cli → doors}/mcp_door.rb +7 -7
  103. data/lib/hecks/doors/mcp_door_scope.rb +97 -0
  104. data/lib/hecks/{facade/surface → doors/ruby_door}/aggregate_door.rb +8 -3
  105. data/lib/hecks/{facade/surface → doors/ruby_door}/chapter.rb +3 -3
  106. data/lib/hecks/{facade/surface.rb → doors/ruby_door.rb} +36 -5
  107. data/lib/hecks/doors.rb +61 -0
  108. data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +1 -1
  109. data/lib/hecks/embryonaut_bluebook.rb +1 -1
  110. data/lib/hecks/engine_agreement.rb +156 -0
  111. data/lib/hecks/facade.rb +24 -37
  112. data/lib/hecks/forms/app.rb +6 -6
  113. data/lib/hecks/forms/banking_presentation.rb +50 -0
  114. data/lib/hecks/forms/field_shape.rb +2 -1
  115. data/lib/hecks/forms/port_argument.rb +1 -1
  116. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +393 -0
  117. data/lib/hecks/fuzzing/combination_miner.rb +86 -0
  118. data/lib/hecks/fuzzing/concurrent_dispatch.rb +214 -0
  119. data/lib/hecks/fuzzing/coverage_campaign.rb +143 -0
  120. data/lib/hecks/fuzzing/differential.rb +156 -0
  121. data/lib/hecks/fuzzing/domain_generator.rb +615 -0
  122. data/lib/hecks/fuzzing/era_boundary.rb +71 -0
  123. data/lib/hecks/fuzzing/form_census.rb +136 -0
  124. data/lib/hecks/fuzzing/generated_domain_check.rb +93 -0
  125. data/lib/hecks/fuzzing/invalid_value_generator.rb +64 -0
  126. data/lib/hecks/fuzzing/isolated_boot.rb +301 -0
  127. data/lib/hecks/fuzzing/nondeterministic.rb +51 -0
  128. data/lib/hecks/fuzzing/outside_world.rb +45 -0
  129. data/lib/hecks/fuzzing/persistence_parity.rb +102 -0
  130. data/lib/hecks/fuzzing/properties/corrections.rb +88 -0
  131. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +314 -0
  132. data/lib/hecks/fuzzing/properties/guards.rb +190 -0
  133. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +300 -0
  134. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +93 -0
  135. data/lib/hecks/fuzzing/properties/outbox.rb +89 -0
  136. data/lib/hecks/fuzzing/properties/querying.rb +175 -0
  137. data/lib/hecks/fuzzing/properties.rb +162 -0
  138. data/lib/hecks/fuzzing/qa_settings.rb +123 -0
  139. data/lib/hecks/fuzzing/replay.rb +505 -0
  140. data/lib/hecks/fuzzing/rotation_priority.rb +48 -0
  141. data/lib/hecks/fuzzing/rust_gap_manifest.rb +108 -0
  142. data/lib/hecks/fuzzing/self_consistency.rb +339 -0
  143. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +385 -0
  144. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +132 -0
  145. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +95 -0
  146. data/lib/hecks/fuzzing/sequence_generator/picker.rb +77 -0
  147. data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +109 -0
  148. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +237 -0
  149. data/lib/hecks/fuzzing/sequence_generator.rb +189 -0
  150. data/lib/hecks/fuzzing/shrinker.rb +166 -0
  151. data/lib/hecks/fuzzing/structural_skips.rb +33 -0
  152. data/lib/hecks/fuzzing/sweep_depth.rb +43 -0
  153. data/lib/hecks/fuzzing/target_capabilities.rb +163 -0
  154. data/lib/hecks/fuzzing/value_generator.rb +216 -0
  155. data/lib/hecks/fuzzing.rb +23 -0
  156. data/lib/hecks/grammar/evolve.rb +336 -0
  157. data/lib/hecks/hecks/adapters/codebase/codemods.rb +45 -0
  158. data/lib/hecks/hecks/adapters/codebase/conformance.rb +71 -0
  159. data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +202 -0
  160. data/lib/hecks/hecks/adapters/codebase/gem_registry.rb +80 -0
  161. data/lib/hecks/hecks/adapters/codebase/kernel_tables.rb +54 -0
  162. data/lib/hecks/hecks/adapters/codebase/language.rb +240 -0
  163. data/lib/hecks/hecks/adapters/codebase/npm_registry.rb +102 -0
  164. data/lib/hecks/hecks/adapters/codebase/publishing.rb +142 -0
  165. data/lib/hecks/hecks/adapters/codebase/regeneration.rb +67 -0
  166. data/lib/hecks/hecks/adapters/codebase/release_facts.rb +90 -0
  167. data/lib/hecks/hecks/adapters/codebase/ruby_child.rb +83 -0
  168. data/lib/hecks/hecks/adapters/codebase/secret_vault.rb +36 -0
  169. data/lib/hecks/hecks/adapters/codebase/source_tree.adapter +7 -0
  170. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +189 -0
  171. data/lib/hecks/hecks/adapters/codebase/sqlite_fixture.rb +71 -0
  172. data/lib/hecks/hecks/adapters/codebase/style.rb +171 -0
  173. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +55 -0
  174. data/lib/hecks/hecks/adapters/codebase/test_suite.rb +165 -0
  175. data/lib/hecks/hecks/adapters/codebase/tree.rb +111 -0
  176. data/lib/hecks/hecks/adapters/console_capture.rb +79 -0
  177. data/lib/hecks/hecks/adapters/deploy_toolchain.adapter +7 -0
  178. data/lib/hecks/hecks/adapters/deploy_toolchain.rb +108 -0
  179. data/lib/hecks/hecks/adapters/git.adapter +7 -0
  180. data/lib/hecks/hecks/adapters/git.rb +102 -0
  181. data/lib/hecks/hecks/adapters/host_http.adapter +7 -0
  182. data/lib/hecks/hecks/adapters/host_http.rb +65 -0
  183. data/lib/hecks/hecks/adapters/in_process_boot.adapter +7 -0
  184. data/lib/hecks/hecks/adapters/in_process_boot.rb +197 -0
  185. data/lib/hecks/hecks/adapters/in_process_operations.rb +202 -0
  186. data/lib/hecks/hecks/adapters/journal_store/changes.rb +143 -0
  187. data/lib/hecks/hecks/adapters/journal_store/compaction.rb +145 -0
  188. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +132 -0
  189. data/lib/hecks/hecks/adapters/journal_store/examination.rb +135 -0
  190. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +163 -0
  191. data/lib/hecks/hecks/adapters/journal_store/readings.rb +187 -0
  192. data/lib/hecks/hecks/adapters/journal_store.adapter +7 -0
  193. data/lib/hecks/hecks/adapters/journal_store.rb +64 -0
  194. data/lib/hecks/hecks/adapters/local_files.adapter +7 -0
  195. data/lib/hecks/hecks/adapters/local_files.rb +46 -0
  196. data/lib/hecks/hecks/adapters/pg_admin.adapter +7 -0
  197. data/lib/hecks/hecks/adapters/pg_admin.rb +245 -0
  198. data/lib/hecks/hecks/adapters/process_pool.adapter +7 -0
  199. data/lib/hecks/hecks/adapters/process_pool.rb +119 -0
  200. data/lib/hecks/hecks/adapters/rust_toolchain.adapter +7 -0
  201. data/lib/hecks/hecks/adapters/rust_toolchain.rb +179 -0
  202. data/lib/hecks/hecks/adapters/rust_workspace.rb +150 -0
  203. data/lib/hecks/hecks/adapters/shell.adapter +7 -0
  204. data/lib/hecks/hecks/adapters/shell.rb +49 -0
  205. data/lib/hecks/hecks/adapters/terminal.adapter +7 -0
  206. data/lib/hecks/hecks/adapters/terminal.rb +74 -0
  207. data/lib/hecks/hecks/codebase.behaviors +172 -0
  208. data/lib/hecks/hecks/codebase.bluebook +2453 -0
  209. data/lib/hecks/hecks/context_map.hecksagon +13 -0
  210. data/lib/hecks/hecks/custodian.behaviors +179 -0
  211. data/lib/hecks/hecks/custodian.bluebook +1847 -0
  212. data/lib/hecks/hecks/deploy.behaviors +74 -0
  213. data/lib/hecks/hecks/deploy.world +12 -0
  214. data/lib/hecks/hecks/environments/memory.world +10 -0
  215. data/lib/hecks/hecks/governance.world +7 -0
  216. data/lib/hecks/hecks/hecks.behaviors +62 -0
  217. data/lib/hecks/hecks/hecks.bluebook +124 -0
  218. data/lib/hecks/hecks/hecks.hecksagon +390 -0
  219. data/lib/hecks/hecks/hecks.world +42 -0
  220. data/lib/hecks/kernel_capabilities.rb +194 -0
  221. data/lib/hecks/language/bluebook/bluebook.bluebook +11 -0
  222. data/lib/hecks/language/bluebook/query.bluebook +7 -0
  223. data/lib/hecks/language/bluebook/vocabulary.bluebook +4 -4
  224. data/lib/hecks/language/hecksagon/domain_port.bluebook +10 -0
  225. data/lib/hecks/language/hecksagon/hecksagon.bluebook +20 -0
  226. data/lib/hecks/mcp_stdio_guard.rb +2 -2
  227. data/lib/hecks/persistence_legacy_fixture/regenerate.rb +161 -0
  228. data/lib/hecks/persistence_legacy_fixture.rb +113 -0
  229. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +8 -5
  230. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +4 -1
  231. data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +15 -2
  232. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +1 -1
  233. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +1 -1
  234. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +1 -1
  235. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +32 -15
  236. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +15 -5
  237. data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +227 -0
  238. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +1 -1
  239. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +43 -24
  240. data/lib/hecks/ports/persistence/plugins/era/translation.rb +1 -0
  241. data/lib/hecks/ports/persistence/state_codec.rb +24 -5
  242. data/lib/hecks/projection_files.rb +285 -0
  243. data/lib/hecks/projections/bootstrap_table.rb +1 -1
  244. data/lib/hecks/projections/deploy/fargate.rb +5 -5
  245. data/lib/hecks/projections/deploy/lambda.rb +43 -32
  246. data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
  247. data/lib/hecks/projections/deploy/preview/template.rb +1 -1
  248. data/lib/hecks/projections/deploy/scripts/deploy-service.sh.tmpl +1 -1
  249. data/lib/hecks/projections/deploy/scripts/expected-era.header +1 -1
  250. data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +3 -3
  251. data/lib/hecks/projections/deploy/scripts/smoke-after-deploy.sh.tmpl +1 -1
  252. data/lib/hecks/projections/deploy/shared.rb +1 -1
  253. data/lib/hecks/projections/diagrams.rb +3 -3
  254. data/lib/hecks/projections/model/deviations.rb +1 -1
  255. data/lib/hecks/projections/parser_table.rb +4 -4
  256. data/lib/hecks/projections/reference.rb +2 -3
  257. data/lib/hecks/projections/rust_vocabulary.rb +1 -1
  258. data/lib/hecks/projector/cli_projector.rb +106 -37
  259. data/lib/hecks/projector.rb +1 -1
  260. data/lib/hecks/quality_control/adapters/agent.adapter +7 -0
  261. data/lib/hecks/quality_control/adapters/agent.rb +58 -0
  262. data/lib/hecks/quality_control/adapters/angle_tools.adapter +7 -0
  263. data/lib/hecks/quality_control/adapters/angle_tools.rb +15 -0
  264. data/lib/hecks/quality_control/adapters/clearance_recorder.rb +36 -0
  265. data/lib/hecks/quality_control/adapters/clearance_tools.adapter +7 -0
  266. data/lib/hecks/quality_control/adapters/clearance_tools.rb +17 -0
  267. data/lib/hecks/quality_control/adapters/git_pr.adapter +7 -0
  268. data/lib/hecks/quality_control/adapters/git_pr.rb +226 -0
  269. data/lib/hecks/quality_control/adapters/github_checks.adapter +9 -0
  270. data/lib/hecks/quality_control/adapters/github_checks.rb +83 -0
  271. data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +56 -0
  272. data/lib/hecks/quality_control/adapters/github_issues.adapter +7 -0
  273. data/lib/hecks/quality_control/adapters/github_issues.rb +49 -0
  274. data/lib/hecks/quality_control/adapters/qa_tool.rb +59 -0
  275. data/lib/hecks/quality_control/adapters/sweep_tools.adapter +7 -0
  276. data/lib/hecks/quality_control/adapters/sweep_tools.rb +51 -0
  277. data/lib/hecks/quality_control/adapters/target_tools.adapter +7 -0
  278. data/lib/hecks/quality_control/adapters/target_tools.rb +43 -0
  279. data/lib/hecks/quality_control/cli/child.rb +45 -0
  280. data/lib/hecks/quality_control/cli/qa_concurrency_racer.rb +45 -0
  281. data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +248 -0
  282. data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +163 -0
  283. data/lib/hecks/quality_control/cli/qa_generated_domains.rb +450 -0
  284. data/lib/hecks/quality_control/cli/qa_log_bug.rb +195 -0
  285. data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +220 -0
  286. data/lib/hecks/quality_control/cli/qa_open_pr.rb +305 -0
  287. data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +154 -0
  288. data/lib/hecks/quality_control/cli/qa_postgres_role.rb +159 -0
  289. data/lib/hecks/quality_control/cli/qa_pr_check.rb +232 -0
  290. data/lib/hecks/quality_control/cli/qa_seed_angles.rb +142 -0
  291. data/lib/hecks/quality_control/cli/qa_seed_targets.rb +69 -0
  292. data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +280 -0
  293. data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +329 -0
  294. data/lib/hecks/quality_control/cli/qa_sweep/dials.rb +92 -0
  295. data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +117 -0
  296. data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +175 -0
  297. data/lib/hecks/quality_control/cli/qa_sweep/release_mode.rb +60 -0
  298. data/lib/hecks/quality_control/cli/qa_sweep.rb +611 -0
  299. data/lib/hecks/quality_control/cli/qa_tick.rb +274 -0
  300. data/lib/hecks/quality_control/quality_control.bluebook +2224 -0
  301. data/lib/hecks/quality_control/quality_control.hecksagon +13 -0
  302. data/lib/hecks/quality_control/quality_control.ports.hecksagon +54 -0
  303. data/lib/hecks/query_ir.rb +346 -0
  304. data/lib/hecks/query_ir_mcp.rb +198 -0
  305. data/lib/hecks/release/runner/ci_publisher.rb +2 -2
  306. data/lib/hecks/release/runner/clean_tree.rb +42 -0
  307. data/lib/hecks/release/runner/console.rb +6 -0
  308. data/lib/hecks/release/runner/gem_publisher.rb +14 -7
  309. data/lib/hecks/release/runner/npm_publisher.rb +6 -36
  310. data/lib/hecks/release/runner/preflight.rb +26 -2
  311. data/lib/hecks/release/runner/published.rb +8 -26
  312. data/lib/hecks/release/runner/tagger.rb +30 -15
  313. data/lib/hecks/release/runner.rb +57 -6
  314. data/lib/hecks/router/namespace_installer.rb +3 -3
  315. data/lib/hecks/runtime/adapter_lookup.rb +124 -0
  316. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +4 -0
  317. data/lib/hecks/runtime/dependency_planning.rb +20 -2
  318. data/lib/hecks/runtime/dispatcher.rb +53 -3
  319. data/lib/hecks/runtime/interpreting.rb +3 -0
  320. data/lib/hecks/runtime/loader.rb +65 -12
  321. data/lib/hecks/runtime/outbox.rb +1 -1
  322. data/lib/hecks/runtime/policy_interpreter.rb +5 -2
  323. data/lib/hecks/runtime/port_operation_interpreter.rb +2 -10
  324. data/lib/hecks/runtime/query_interpreter.rb +77 -0
  325. data/lib/hecks/runtime/reaction_outcome.rb +89 -0
  326. data/lib/hecks/runtime/refusal_wording.rb +23 -1
  327. data/lib/hecks/runtime/registry/verification.rb +163 -4
  328. data/lib/hecks/runtime/registry.rb +57 -3
  329. data/lib/hecks/runtime/remote_dispatcher.rb +31 -2
  330. data/lib/hecks/runtime/value/coercion.rb +23 -135
  331. data/lib/hecks/runtime/value/field_checks.rb +172 -0
  332. data/lib/hecks/runtime/value.rb +4 -1
  333. data/lib/hecks/runtime.rb +20 -6
  334. data/lib/hecks/rust_build/conformance.rb +158 -0
  335. data/lib/hecks/rust_build/conformance_fuzz.rb +71 -0
  336. data/lib/hecks/rust_build/coverage.rb +218 -0
  337. data/lib/hecks/rust_build/native_build.rb +124 -0
  338. data/lib/hecks/rust_build/project_rust/root_mod.rb +120 -0
  339. data/lib/hecks/rust_build/project_rust.rb +332 -0
  340. data/lib/hecks/rust_build/wasm.rb +105 -0
  341. data/lib/hecks/rust_build/wasm_browser.rb +113 -0
  342. data/lib/hecks/rust_build.rb +144 -0
  343. data/lib/hecks/storehouse.rb +16 -16
  344. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +2 -2
  345. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +1 -1
  346. data/lib/hecks/three_zero/forms.yml +127 -0
  347. data/lib/hecks/three_zero.rb +12 -0
  348. data/lib/hecks/tools/argument_gate_matrix.rb +316 -0
  349. data/lib/hecks/tools/comment_style.rb +1070 -0
  350. data/lib/hecks/tools/corpus_report.rb +87 -0
  351. data/lib/hecks/tools/deploy_recipe.rb +255 -0
  352. data/lib/hecks/tools/deploy_recipe_lint.rb +282 -0
  353. data/lib/hecks/tools/drop_implicit_append_fields.rb +95 -0
  354. data/lib/hecks/tools/era_projection_backfill.rb +94 -0
  355. data/lib/hecks/tools/era_reattest.rb +146 -0
  356. data/lib/hecks/tools/evolve_run.rb +189 -0
  357. data/lib/hecks/tools/fuzz_sweep.rb +373 -0
  358. data/lib/hecks/tools/heki_compaction.rb +100 -0
  359. data/lib/hecks/tools/hoist_local_givens.rb +246 -0
  360. data/lib/hecks/tools/journal_compaction.rb +89 -0
  361. data/lib/hecks/tools/oidc_manifests.rb +70 -0
  362. data/lib/hecks/tools/query_ir_run.rb +81 -0
  363. data/lib/hecks/tools/regeneration_run.rb +166 -0
  364. data/lib/hecks/tools/rust_comment_style.rb +642 -0
  365. data/lib/hecks/tools/sequence_script.rb +62 -0
  366. data/lib/hecks/tools/tail_merge.rb +117 -0
  367. data/lib/hecks/tools/tenant_provisioning.rb +142 -0
  368. data/lib/hecks/tools/translation_audit.rb +208 -0
  369. data/lib/hecks/tools/translation_scaffold.rb +131 -0
  370. data/lib/hecks/tools.rb +86 -0
  371. data/lib/hecks/version.rb +1 -1
  372. data/lib/hecks.rb +32 -15
  373. data/qa/settings.yml +66 -0
  374. data/rust/.cargo/config.toml +6 -0
  375. data/rust/.gitignore +2 -0
  376. data/rust/Cargo.lock +54 -0
  377. data/rust/Cargo.toml +61 -0
  378. data/rust/build/.cargo/config.toml +3 -0
  379. data/rust/build/.gitignore +1 -0
  380. data/rust/build/Cargo.lock +7 -0
  381. data/rust/build/Cargo.toml +19 -0
  382. data/rust/build/src/build_artifact.rs +47 -0
  383. data/rust/build/src/cargo_sync.rs +248 -0
  384. data/rust/build/src/json.rs +421 -0
  385. data/rust/build/src/lineage_pass.rs +285 -0
  386. data/rust/build/src/main.rs +51 -0
  387. data/rust/build/src/optional_pass.rs +150 -0
  388. data/rust/build/src/pipeline.rs +264 -0
  389. data/rust/build/src/reserved_names.rs +76 -0
  390. data/rust/build/src/resolve.rs +124 -0
  391. data/rust/build/src/root.rs +25 -0
  392. data/rust/build/src/sidecars.rs +73 -0
  393. data/rust/build/src/subprocess.rs +51 -0
  394. data/rust/build/src/tmp.rs +31 -0
  395. data/rust/codegen/.cargo/config.toml +3 -0
  396. data/rust/codegen/.gitignore +1 -0
  397. data/rust/codegen/Cargo.lock +7 -0
  398. data/rust/codegen/Cargo.toml +20 -0
  399. data/rust/codegen/src/attr.rs +32 -0
  400. data/rust/codegen/src/bridging.rs +481 -0
  401. data/rust/codegen/src/commands.rs +1226 -0
  402. data/rust/codegen/src/constraints.rs +109 -0
  403. data/rust/codegen/src/dependency_planning.rs +209 -0
  404. data/rust/codegen/src/domain_generator.rs +1288 -0
  405. data/rust/codegen/src/exemplar.rs +230 -0
  406. data/rust/codegen/src/expr_emitter.rs +87 -0
  407. data/rust/codegen/src/fielded.rs +192 -0
  408. data/rust/codegen/src/hecks_naming.rs +33 -0
  409. data/rust/codegen/src/json.rs +335 -0
  410. data/rust/codegen/src/json_codec.rs +697 -0
  411. data/rust/codegen/src/literal.rs +207 -0
  412. data/rust/codegen/src/main.rs +290 -0
  413. data/rust/codegen/src/manifest.rs +227 -0
  414. data/rust/codegen/src/mutations.rs +784 -0
  415. data/rust/codegen/src/naming.rs +286 -0
  416. data/rust/codegen/src/ports.rs +208 -0
  417. data/rust/codegen/src/prelude.rs +116 -0
  418. data/rust/codegen/src/queries.rs +786 -0
  419. data/rust/codegen/src/reactions.rs +532 -0
  420. data/rust/codegen/src/read_models.rs +697 -0
  421. data/rust/codegen/src/reference_specs.rs +40 -0
  422. data/rust/codegen/src/registry.rs +966 -0
  423. data/rust/codegen/src/reserved_names.rs +76 -0
  424. data/rust/codegen/src/shared.rs +93 -0
  425. data/rust/codegen/src/skip_reason.rs +25 -0
  426. data/rust/codegen/src/types.rs +362 -0
  427. data/rust/host/.cargo/config.toml +3 -0
  428. data/rust/host/.gitignore +1 -0
  429. data/rust/host/Cargo.lock +4297 -0
  430. data/rust/host/Cargo.toml +61 -0
  431. data/rust/host/HECKS_RELEASE +1 -0
  432. data/rust/host/rds-ca-bundle.pem +2736 -0
  433. data/rust/host/src/api.rs +1596 -0
  434. data/rust/host/src/approval.rs +652 -0
  435. data/rust/host/src/auth.rs +1287 -0
  436. data/rust/host/src/bin/expr_harness.rs +46 -0
  437. data/rust/host/src/bin/lineage_harness.rs +119 -0
  438. data/rust/host/src/bin/mint_harness.rs +135 -0
  439. data/rust/host/src/checkout.rs +265 -0
  440. data/rust/host/src/dispatch.rs +1443 -0
  441. data/rust/host/src/expr_json.rs +1117 -0
  442. data/rust/host/src/field_hints.rs +52 -0
  443. data/rust/host/src/ir.rs +733 -0
  444. data/rust/host/src/journal.rs +874 -0
  445. data/rust/host/src/lambda_client.rs +378 -0
  446. data/rust/host/src/log.rs +147 -0
  447. data/rust/host/src/main.rs +474 -0
  448. data/rust/host/src/mint.rs +1865 -0
  449. data/rust/host/src/payments/keystore.rs +330 -0
  450. data/rust/host/src/payments/tests.rs +1400 -0
  451. data/rust/host/src/payments.rs +767 -0
  452. data/rust/host/src/presentation.rs +698 -0
  453. data/rust/host/src/presentation_write.rs +1431 -0
  454. data/rust/host/src/query_step.rs +149 -0
  455. data/rust/host/src/rate_limit.rs +904 -0
  456. data/rust/host/src/reference_transform.rs +241 -0
  457. data/rust/host/src/reference_validate.rs +338 -0
  458. data/rust/host/src/resend.rs +296 -0
  459. data/rust/host/src/secrets.rs +106 -0
  460. data/rust/host/src/server.rs +663 -0
  461. data/rust/host/src/storage_shape.rs +175 -0
  462. data/rust/host/src/test_pg.rs +40 -0
  463. data/rust/host/src/ui_schema.rs +1351 -0
  464. data/rust/host/src/wasm_runner.rs +191 -0
  465. data/rust/host/src/web/newsletter/cooldown.rs +126 -0
  466. data/rust/host/src/web/newsletter/tests.rs +104 -0
  467. data/rust/host/src/web/newsletter.rs +310 -0
  468. data/rust/host/src/web/newsletter_send.rs +357 -0
  469. data/rust/host/src/web/registrations.rs +1505 -0
  470. data/rust/host/src/web.rs +2937 -0
  471. data/rust/lsp/.gitignore +1 -0
  472. data/rust/lsp/Cargo.lock +7 -0
  473. data/rust/lsp/Cargo.toml +16 -0
  474. data/rust/lsp/README.md +133 -0
  475. data/rust/lsp/src/diagnostics.rs +165 -0
  476. data/rust/lsp/src/json.rs +385 -0
  477. data/rust/lsp/src/main.rs +399 -0
  478. data/rust/lsp/src/outline.rs +177 -0
  479. data/rust/lsp/src/rpc.rs +67 -0
  480. data/rust/parser/.cargo/config.toml +5 -0
  481. data/rust/parser/.gitignore +1 -0
  482. data/rust/parser/Cargo.lock +7 -0
  483. data/rust/parser/Cargo.toml +21 -0
  484. data/rust/parser/src/build/closed_sets.rs +27 -0
  485. data/rust/parser/src/build/identity.rs +276 -0
  486. data/rust/parser/src/build/mod.rs +12 -0
  487. data/rust/parser/src/build/naming.rs +141 -0
  488. data/rust/parser/src/build/pattern_subset.rs +161 -0
  489. data/rust/parser/src/build/query_derive.rs +72 -0
  490. data/rust/parser/src/build/query_inference.rs +269 -0
  491. data/rust/parser/src/build/query_options.rs +100 -0
  492. data/rust/parser/src/build/read_model.rs +94 -0
  493. data/rust/parser/src/build/references.rs +32 -0
  494. data/rust/parser/src/canonical.rs +114 -0
  495. data/rust/parser/src/diag.rs +55 -0
  496. data/rust/parser/src/emit.rs +953 -0
  497. data/rust/parser/src/expr/ast_json.rs +147 -0
  498. data/rust/parser/src/expr/evaluator.rs +81 -0
  499. data/rust/parser/src/expr/mod.rs +84 -0
  500. data/rust/parser/src/expr/resolver.rs +497 -0
  501. data/rust/parser/src/ir.rs +387 -0
  502. data/rust/parser/src/keywords.rs +585 -0
  503. data/rust/parser/src/lex.rs +662 -0
  504. data/rust/parser/src/main.rs +252 -0
  505. data/rust/parser/src/parse/aggregate.rs +612 -0
  506. data/rust/parser/src/parse/chapter.rs +517 -0
  507. data/rust/parser/src/parse/command.rs +637 -0
  508. data/rust/parser/src/parse/domain_port.rs +127 -0
  509. data/rust/parser/src/parse/entity.rs +527 -0
  510. data/rust/parser/src/parse/file.rs +67 -0
  511. data/rust/parser/src/parse/hecksagon.rs +231 -0
  512. data/rust/parser/src/parse/lifecycle.rs +162 -0
  513. data/rust/parser/src/parse/mod.rs +1262 -0
  514. data/rust/parser/src/parse/policy.rs +87 -0
  515. data/rust/parser/src/parse/process_manager.rs +305 -0
  516. data/rust/parser/src/parse/query.rs +100 -0
  517. data/rust/parser/src/parse/read_model.rs +214 -0
  518. data/rust/parser/src/parse/value_object.rs +250 -0
  519. data/rust/parser/src/ruby_value.rs +422 -0
  520. data/rust/project/bridging.rb +257 -0
  521. data/rust/project/commands.rb +877 -0
  522. data/rust/project/constraints.rb +86 -0
  523. data/rust/project/dependency_planning.rb +178 -0
  524. data/rust/project/domain_generator.rb +980 -0
  525. data/rust/project/exemplar.rb +148 -0
  526. data/rust/project/expr_emitter.rb +72 -0
  527. data/rust/project/fielded.rb +141 -0
  528. data/rust/project/json_codec.rb +641 -0
  529. data/rust/project/mutations.rb +721 -0
  530. data/rust/project/naming.rb +205 -0
  531. data/rust/project/ports.rb +65 -0
  532. data/rust/project/queries.rb +493 -0
  533. data/rust/project/reactions.rb +317 -0
  534. data/rust/project/read_models.rb +690 -0
  535. data/rust/project/reference_specs.rb +27 -0
  536. data/rust/project/registry.rb +396 -0
  537. data/rust/project/skip_reason.rb +29 -0
  538. data/rust/project/types.rb +225 -0
  539. data/rust/project/write_if_changed.rb +83 -0
  540. data/rust/project.rb +30 -0
  541. data/rust/project_rust_pipeline.rb +383 -0
  542. data/rust/src/exemplar/commands.rs +279 -0
  543. data/rust/src/exemplar/constraints.rs +18 -0
  544. data/rust/src/exemplar/fielded.rs +280 -0
  545. data/rust/src/exemplar/json.rs +277 -0
  546. data/rust/src/exemplar/mod.rs +17 -0
  547. data/rust/src/exemplar/mutations.rs +80 -0
  548. data/rust/src/exemplar/queries.rs +33 -0
  549. data/rust/src/exemplar/reactions.rs +88 -0
  550. data/rust/src/exemplar/read_models.rs +48 -0
  551. data/rust/src/exemplar/registry.rs +166 -0
  552. data/rust/src/exemplar/types.rs +44 -0
  553. data/rust/src/kernel/attribute_shapes/composite.rs +88 -0
  554. data/rust/src/kernel/attribute_shapes/list.rs +18 -0
  555. data/rust/src/kernel/attribute_shapes/mod.rs +44 -0
  556. data/rust/src/kernel/attribute_shapes/optional.rs +9 -0
  557. data/rust/src/kernel/attribute_shapes/scalar.rs +39 -0
  558. data/rust/src/kernel/cli.rs +585 -0
  559. data/rust/src/kernel/dispatch.rs +1090 -0
  560. data/rust/src/kernel/expr.rs +458 -0
  561. data/rust/src/kernel/expression_operators/arithmetic.rs +128 -0
  562. data/rust/src/kernel/expression_operators/comparison.rs +48 -0
  563. data/rust/src/kernel/expression_operators/enumeration.rs +232 -0
  564. data/rust/src/kernel/expression_operators/logical.rs +13 -0
  565. data/rust/src/kernel/expression_operators/membership.rs +18 -0
  566. data/rust/src/kernel/expression_operators/mod.rs +68 -0
  567. data/rust/src/kernel/expression_operators/pattern_match.rs +73 -0
  568. data/rust/src/kernel/expression_operators/positional.rs +126 -0
  569. data/rust/src/kernel/expression_operators/presence.rs +101 -0
  570. data/rust/src/kernel/expression_operators/sign_test.rs +16 -0
  571. data/rust/src/kernel/expression_operators/sized.rs +35 -0
  572. data/rust/src/kernel/expression_operators/text.rs +79 -0
  573. data/rust/src/kernel/expression_operators/to_string.rs +18 -0
  574. data/rust/src/kernel/json.rs +779 -0
  575. data/rust/src/kernel/mod.rs +133 -0
  576. data/rust/src/kernel/named_query.rs +219 -0
  577. data/rust/src/kernel/orchestrate.rs +1810 -0
  578. data/rust/src/kernel/pattern.rs +307 -0
  579. data/rust/src/kernel/query_comparators.rs +206 -0
  580. data/rust/src/kernel/query_ordering.rs +103 -0
  581. data/rust/src/kernel/read_model.rs +914 -0
  582. data/rust/src/kernel/reference_lookup.rs +149 -0
  583. data/rust/src/kernel/repository.rs +468 -0
  584. data/rust/src/kernel/routing.rs +612 -0
  585. data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +118 -0
  586. data/rust/src/kernel/vocab/entity_dispatch_order.rs +114 -0
  587. data/rust/src/kernel/vocab/field_hint.rs +70 -0
  588. data/rust/src/kernel/vocab/mod.rs +20 -0
  589. data/rust/src/kernel/vocab/query_comparator.rs +65 -0
  590. data/rust/src/kernel/vocab/refusal_template.rs +1592 -0
  591. data/rust/src/lib.rs +8 -0
  592. data/rust/src/main.rs +16 -0
  593. data/rust/web/.gitignore +1 -0
  594. data/rust/web/Cargo.lock +119 -0
  595. data/rust/web/Cargo.toml +18 -0
  596. data/rust/web/src/lib.rs +8 -0
  597. metadata +477 -12
  598. data/lib/hecks/facade/cli_door.rb +0 -96
  599. data/lib/hecks/facade/cli_runner.rb +0 -127
  600. data/lib/hecks/mcp_door_scope.rb +0 -95
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hecks
4
+ module QualityControlCli
5
+ class QaSweep
6
+ # The dials a sweep reads once the ledger has booted, and the modes they enable. A dial-less
7
+ # fixture ledger falls back to a sweep with the adversarial layer off and self-consistency on.
8
+ module Dials
9
+ private
10
+
11
+ def dial(name, fallback)
12
+ ::QualityControlDials.const_defined?(name, false) ? ::QualityControlDials.const_get(name) : fallback
13
+ rescue NameError
14
+ fallback
15
+ end
16
+
17
+ # Dials are read after boot because the bluebook defines them; a dial-less fixture ledger
18
+ # runs the adversarial layer off and self-consistency on.
19
+ def read_dials
20
+ @adversarial ||= dial(:ADVERSARIAL_FRACTION, 0.0).to_f
21
+ # Remembered before defaulting: the alias below applies only when the flag was typed, so
22
+ # an explicit `--modes ruby_only` stays exclusive.
23
+ @self_consistency_explicit = !@self_consistency.nil?
24
+ @self_consistency = dial(:SELF_CONSISTENCY_CHECKS, true) if @self_consistency.nil?
25
+ # Same off-without-a-dial default as the adversarial layer.
26
+ @role_draw ||= dial(:ROLE_DRAW_PROBABILITY, 0.0).to_f
27
+ @dry_run ||= dial(:DRY_RUN_FRACTION, 0.0).to_f
28
+ # The loop's identity: `held_by` on claims, `engineer` on sweeps, and the literal
29
+ # `WaivedBy` refuses.
30
+ @engineer = dial(:AUTOMATED_ENGINEER, "qa_sweep")
31
+ @widening_tiers = dial(:WIDENING_TIERS, Hecks::Fuzzing::SweepDepth::DEFAULT_TIERS)
32
+ @guided_generation = dial(:GUIDED_GENERATION, false)
33
+ @corpus_splice_probability = dial(:CORPUS_SPLICE_PROBABILITY, 0.5)
34
+ @favor_rare_verbs = dial(:FAVOR_RARE_VERBS, 3)
35
+ @max_parallel = dial(:SWEEP_MAX_PARALLEL, 4)
36
+ @shrink_budget = dial(:SHRINK_BUDGET, 200)
37
+ @structural_boundary = dial(:STRUCTURAL_REFUSAL_BOUNDARY, [])
38
+ # The adapter pair each parity mode compares; a new pairing is a data change here, not a
39
+ # new diff.
40
+ @adapter_parity_pairs = dial(:ADAPTER_PARITY_PAIRS,
41
+ { persistence_parity: { left: :memory, right: :postgres_era },
42
+ adapter_parity_sqlite: { left: :memory, right: :sqlite } }.freeze)
43
+ end
44
+
45
+ # `--modes` wins outright; otherwise the dial's enabled modes. `--self-consistency` adjusts
46
+ # the set only when typed or when `--modes` was not given, so an explicit `--modes a,b`
47
+ # stays exact.
48
+ def resolve_enabled_modes
49
+ @enabled_modes = @explicit_modes || dial_modes
50
+ if @self_consistency_explicit || @explicit_modes.nil?
51
+ @enabled_modes = if @self_consistency
52
+ @enabled_modes | [:self_consistency]
53
+ else
54
+ @enabled_modes - [:self_consistency]
55
+ end
56
+ end
57
+ # `--all --persistence-parity` forces the wave on regardless of the dial.
58
+ @enabled_modes |= [:persistence_parity] if @force_parity_wave
59
+
60
+ # Refuse modes with no implementation before claiming, so `resolved modes:` never
61
+ # advertises coverage nobody wrote.
62
+ unrunnable = @enabled_modes - Hecks::Fuzzing::TargetCapabilities::RUNNABLE_MODES
63
+ return if unrunnable.empty?
64
+
65
+ abort "enabled mode(s) #{unrunnable.join(',')} have no implementation in hecks quality_control ask run " \
66
+ "(Hecks::Fuzzing::TargetCapabilities::RUNNABLE_MODES is what exists). Set them false in " \
67
+ "qa/settings.yml, or drop them from --modes, until the code lands."
68
+ end
69
+
70
+ def dial_modes
71
+ return DEFAULT_MODES unless ::QualityControlDials.const_defined?(:MODES, false)
72
+
73
+ ::QualityControlDials::MODES.select { |_, on| on }.keys
74
+ rescue NameError
75
+ DEFAULT_MODES
76
+ end
77
+
78
+ # `--no-parity` skips every later wave. A mode gets a wave only when the dial enabled it and
79
+ # `--modes` did not narrow the run.
80
+ def deferred_waves
81
+ %i[era_boundary concurrency].select do |mode|
82
+ !@skip_parity_wave && @explicit_modes.nil? && @enabled_modes.include?(mode)
83
+ end
84
+ end
85
+
86
+ def parity_wave?
87
+ !@skip_parity_wave && @explicit_modes.nil? && @enabled_modes.include?(:persistence_parity)
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hecks
4
+ module QualityControlCli
5
+ class QaSweep
6
+ # What a sweep prints when a check surprised: the header, the reproduction, every divergence
7
+ # and the generated and shrunk steps, so an agent can decide from the report alone.
8
+ module FindingReport
9
+ private
10
+
11
+ # @param surprise [Hash] the surprising seed's result: `seed`, `steps`, `checks`, `plan` and
12
+ # optionally `shrunk`
13
+ # @return [void]
14
+ def print_finding(surprise)
15
+ print_finding_header
16
+ print_finding_facts(surprise)
17
+ # One block per surprised check, so a seed that surprised on two axes prints both.
18
+ surprise[:checks].each { |check| print_surprised_check(check) }
19
+ print_generated_steps(surprise[:steps])
20
+ # One shrunk demonstration per shrinkable check, written to a file so the replay line
21
+ # works as printed.
22
+ Array(surprise[:shrunk]).each { |shrunk| print_shrunk(shrunk, surprise[:seed]) }
23
+ end
24
+
25
+ def print_finding_header
26
+ puts
27
+ puts "=" * 72
28
+ puts "FOUND SOMETHING — sweep #{@sweep_reference} left OPEN, target #{@target_reference} SUSPENDED."
29
+ puts "No Bug was logged (that needs a real failing-test demonstration, which"
30
+ puts "needs judgment this script does not have — hecks quality_control log is the door)"
31
+ puts "and the sweep was not concluded. The ledger's own SuspendOnSurprise"
32
+ puts "policy took the target out of the rotation; it stays out until a PERSON"
33
+ puts "runs: hecks quality_control ask run target=#{@target_reference} " \
34
+ "arguments=\"--release --notes …\""
35
+ puts "An agent decides from here: self-contained fix with a regression test"
36
+ puts "and a PR (hecks quality_control patch.open), or a Bug left open for something bigger."
37
+ puts "Never waived here, never filed upstream from here."
38
+ puts "=" * 72
39
+ puts
40
+ end
41
+
42
+ def print_finding_facts(surprise)
43
+ puts "domain: #{@target_path} (#{@domain_path})"
44
+ puts "target: #{@target_reference}"
45
+ puts "sweep: #{@sweep_reference} (id #{@sweep.id})"
46
+ puts "mode: #{@mode} (active modes: #{@active_modes.join(', ')}; " \
47
+ "capabilities: #{@capabilities.join(', ')})"
48
+ puts "seed: #{surprise[:seed] || 'n/a (once-per-sweep check)'}"
49
+ puts "steps: #{@steps_per_sequence}"
50
+ puts "adversarial: #{@adversarial}"
51
+ puts "role-draw: #{@role_draw}"
52
+ puts "dry-run: #{@dry_run}"
53
+ puts "streak: clean_streak was #{@current_streak} going into this pass"
54
+ if surprise[:seed]
55
+ puts "reproduce: Hecks::Fuzzing::SequenceGenerator.generate(#{@domain_path.inspect}, " \
56
+ "seed: #{surprise[:seed]}, steps: #{@steps_per_sequence}, adversarial: #{@adversarial}, " \
57
+ "role_draw: #{@role_draw}, dry_run: #{@dry_run}#{plan_arguments(surprise[:plan])})"
58
+ end
59
+ puts "surprised: #{surprise[:checks].map { |c| c[:mode] }.join(', ')}"
60
+ puts
61
+ end
62
+
63
+ def print_surprised_check(check)
64
+ puts "subject: #{check[:subject]}"
65
+ puts "expectation: #{check[:expectation]}"
66
+ puts "observation: #{check[:observation]}"
67
+ puts
68
+
69
+ # One generic printer for every divergence shape (ruby/rust, memory/postgres_era,
70
+ # live/rehydrated): print every key except the field and the redundant
71
+ # domain/aggregate/type.
72
+ check[:divergences].each do |divergence|
73
+ label = [divergence[:field], divergence[:domain], divergence[:aggregate], divergence[:type]]
74
+ .compact.join(" ")
75
+ puts "-- #{label} --"
76
+ divergence.except(:field, :domain, :aggregate, :type).each { |key, value| puts "#{key}: #{value.inspect}" }
77
+ puts
78
+ end
79
+ end
80
+
81
+ # Lists every step in order with its `adversarial` metadata, so a divergence's verb matches
82
+ # back to its step and the Bug can name the mutation.
83
+ def print_generated_steps(steps)
84
+ puts "-- generated steps (index: verb, adversarial mutation if any) --"
85
+ steps.each_with_index do |step, index|
86
+ label = %w[verb query dry_run].filter_map { |key| step[key] if step.key?(key) }.first
87
+ mutation = step["adversarial"] ? JSON.generate(step["adversarial"]) : "(not mutated)"
88
+ puts "#{index}: #{label} #{mutation}"
89
+ puts " args: #{JSON.generate(step['args'])}" if step["adversarial"]
90
+ end
91
+ puts
92
+ end
93
+
94
+ def print_shrunk(shrunk, seed)
95
+ path = write_shrunk!(shrunk, seed)
96
+ budget = shrunk[:exhausted] ? ", budget exhausted — may shrink further" : ""
97
+ puts "shrunk: [#{shrunk[:mode]}] #{shrunk[:original_size]} -> #{shrunk[:steps].size} step(s) " \
98
+ "(#{shrunk[:attempts]} candidate checks#{budget})"
99
+ puts "file: #{path.delete_prefix("#{@root}/")}"
100
+ replay =
101
+ if %i[differential self_consistency].include?(shrunk[:mode]) && @binary
102
+ "hecks check_conformance domain=#{@domain_path} script=#{path} artifact=#{@binary}"
103
+ else
104
+ "hecks run #{@domain_path} #{path}"
105
+ end
106
+ puts "replay: #{replay}"
107
+ puts "-- shrunk steps [#{shrunk[:mode]}] --"
108
+ shrunk[:steps].each_with_index do |step, index|
109
+ kind = %w[verb query dry_run].find { |key| step.key?(key) }
110
+ puts "#{index}: #{"#{kind} " unless kind == 'verb'}#{step[kind]} args: #{JSON.generate(step['args'])}"
111
+ end
112
+ puts
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hecks
4
+ module QualityControlCli
5
+ class QaSweep
6
+ # The command line of `QaSweep`: every flag, and the rules for which combinations are refused.
7
+ #
8
+ # `seeds_override` and `steps_override` stay nil rather than a default, so an explicit
9
+ # `--seeds 10` can be told apart from the streak-derived depth. The dials are read after the
10
+ # ledger boots, so `adversarial`, `self_consistency`, `role_draw` and `dry_run` stay nil
11
+ # until then.
12
+ module Parsing
13
+ # Each flag that reads a value, and the setting it fills.
14
+ VALUE_SETTINGS = { "--role-draw" => :role_draw, "--dry-run" => :dry_run, "--adversarial" => :adversarial,
15
+ "--seeds" => :seeds_override, "--steps" => :steps_override }.freeze
16
+
17
+ # Each flag that stands alone, and the setting it turns on.
18
+ SWITCH_SETTINGS = { "--all" => :all_mode, "--no-parity" => :skip_parity_wave,
19
+ "--release" => :release_mode }.freeze
20
+
21
+ private
22
+
23
+ # Parses the flags into the instance's settings.
24
+ #
25
+ # @param argv [Array<String>] the command line's arguments, consumed
26
+ # @return [Symbol, nil] `:help` once the usage is printed, else nil
27
+ # @raise [SystemExit] with the usage when a flag or combination is refused
28
+ def parse_arguments(argv)
29
+ @target_ref = @seeds_override = @steps_override = nil
30
+ @all_mode = @persistence_parity_mode = @skip_parity_wave = @release_mode = false
31
+ @adversarial = @self_consistency = @role_draw = @dry_run = nil
32
+ # `--modes` (or its alias `--persistence-parity`); nil means the dial decides.
33
+ @explicit_modes = nil
34
+ @release_notes = nil
35
+ until argv.empty?
36
+ arg = argv.shift
37
+ if %w[-h --help].include?(arg)
38
+ puts USAGE
39
+ return :help
40
+ end
41
+ parse_flag(arg, argv)
42
+ end
43
+ validate_arguments
44
+ nil
45
+ end
46
+
47
+ def parse_flag(arg, argv)
48
+ if SWITCH_SETTINGS.key?(arg)
49
+ instance_variable_set(:"@#{SWITCH_SETTINGS.fetch(arg)}", true)
50
+ elsif VALUE_SETTINGS.key?(arg)
51
+ parse_value_flag(arg, argv.shift)
52
+ else
53
+ parse_other_flag(arg, argv)
54
+ end
55
+ end
56
+
57
+ def parse_value_flag(arg, value)
58
+ setting = VALUE_SETTINGS.fetch(arg)
59
+ parsed = %w[--seeds --steps].include?(arg) ? parse_integer(arg, value) : parse_fraction(arg, value)
60
+ instance_variable_set(:"@#{setting}", parsed)
61
+ end
62
+
63
+ def parse_other_flag(arg, argv)
64
+ case arg
65
+ when "--persistence-parity"
66
+ @persistence_parity_mode = true
67
+ @explicit_modes = %i[persistence_parity]
68
+ when "--modes"
69
+ @explicit_modes = parse_modes(argv.shift)
70
+ @persistence_parity_mode = @explicit_modes == %i[persistence_parity]
71
+ when "--notes"
72
+ @release_notes = argv.shift
73
+ abort "#{USAGE}\n--notes needs the text a person concluded" unless @release_notes
74
+ when "--self-consistency" then @self_consistency = parse_boolean(arg, argv.shift)
75
+ else record_target(arg)
76
+ end
77
+ end
78
+
79
+ def record_target(arg)
80
+ abort "#{USAGE}\nunexpected argument: #{arg.inspect} (target already given: #{@target_ref.inspect})" if @target_ref
81
+
82
+ @target_ref = arg
83
+ end
84
+
85
+ def parse_modes(value)
86
+ names = value.to_s.split(",").map(&:strip).reject(&:empty?).map(&:to_sym)
87
+ abort "#{USAGE}\n--modes needs at least one mode name" if names.empty?
88
+
89
+ known = Hecks::Fuzzing::TargetCapabilities::MODE_REQUIREMENTS.keys
90
+ unknown = names - known
91
+ abort "#{USAGE}\n--modes names no such mode: #{unknown.join(', ')} (known: #{known.join(', ')})" unless unknown.empty?
92
+
93
+ names
94
+ end
95
+
96
+ def parse_fraction(flag, value)
97
+ abort "#{USAGE}\n#{flag} needs a fraction between 0 and 1" unless value
98
+
99
+ fraction = begin
100
+ Float(value)
101
+ rescue ArgumentError
102
+ abort "#{USAGE}\n#{flag} must be a number, got #{value.inspect}"
103
+ end
104
+ abort "#{USAGE}\n#{flag} must be between 0 and 1, got #{value}" unless fraction.between?(0, 1)
105
+ fraction
106
+ end
107
+
108
+ def parse_integer(flag, value)
109
+ abort "#{USAGE}\n#{flag} needs a number" unless value
110
+
111
+ begin
112
+ Integer(value)
113
+ rescue ArgumentError
114
+ abort "#{USAGE}\n#{flag} must be an integer, got #{value.inspect}"
115
+ end
116
+ end
117
+
118
+ def parse_boolean(flag, value)
119
+ abort "#{USAGE}\n#{flag} needs true or false" unless value
120
+
121
+ case value
122
+ when "true" then true
123
+ when "false" then false
124
+ else abort "#{USAGE}\n#{flag} must be true or false, got #{value.inspect}"
125
+ end
126
+ end
127
+
128
+ def validate_arguments
129
+ if @seeds_override && @seeds_override < 1
130
+ abort "#{USAGE}\n--seeds must be at least 1 — Sweep.Conclude refuses a sweep that checked nothing"
131
+ end
132
+ abort "#{USAGE}\n--steps must be at least 1" if @steps_override && @steps_override < 1
133
+ if @all_mode && @target_ref
134
+ abort "#{USAGE}\n--all sweeps every waiting target itself — it does not take a target-reference " \
135
+ "(got #{@target_ref.inspect})"
136
+ end
137
+
138
+ # `--all --persistence-parity` forces the parity wave on; narrowing every child to that
139
+ # one mode would abort each ineligible target. A single named target still narrows to that
140
+ # mode.
141
+ @force_parity_wave = @all_mode && @persistence_parity_mode
142
+ if @force_parity_wave
143
+ @persistence_parity_mode = false
144
+ @explicit_modes = nil
145
+ end
146
+ validate_parity_and_release
147
+ end
148
+
149
+ def validate_parity_and_release
150
+ if @persistence_parity_mode && !@target_ref
151
+ abort "#{USAGE}\n--persistence-parity needs an explicit target-reference — it never auto-picks " \
152
+ "from the rotation, since only a PostgresEra-bound domain gains anything from this " \
153
+ "comparison at all (`resolved modes:` on any single-target run says whether a target qualifies)"
154
+ end
155
+ validate_release if @release_mode
156
+ abort "#{USAGE}\n--notes only means something with --release" if @release_notes && !@release_mode
157
+ end
158
+
159
+ def validate_release
160
+ unless @target_ref
161
+ abort "#{USAGE}\n--release needs an explicit target-reference — the suspended target a person is " \
162
+ "putting back"
163
+ end
164
+ unless @release_notes
165
+ abort "#{USAGE}\n--release needs --notes — what a person concluded is the one thing this script " \
166
+ "cannot supply"
167
+ end
168
+ return unless @all_mode || @persistence_parity_mode
169
+
170
+ abort "#{USAGE}\n--release is its own mode — it does not combine with --all or --persistence-parity"
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hecks
4
+ module QualityControlCli
5
+ class QaSweep
6
+ # `--release`: a person puts a suspended target back. It concludes or abandons what was open
7
+ # against the target, then releases it with the streak moved by what was found.
8
+ module ReleaseMode
9
+ private
10
+
11
+ # `--release`: a person puts a suspended target back, concluding what was open against it.
12
+ def release_suspended_target
13
+ target = ::QualityControl::Target.find(@target_reference)
14
+ abort "target #{@target_reference.inspect} vanished between being queried and being released" unless target
15
+ unless %w[suspended held].include?(target.status)
16
+ abort "target #{@target_reference.inspect} is #{target.status.inspect}, not suspended (or held) — " \
17
+ "nothing to release"
18
+ end
19
+
20
+ open_sweeps = query("Sweep.Sweeping").select { |row| row[:target] == target.id }
21
+ .map { |row| ::QualityControl::Sweep.find(row[:reference][:value]) }
22
+ surprises = 0
23
+ clean = !open_sweeps.empty?
24
+ open_sweeps.each do |sweep|
25
+ surprises += query("Bug.FoundIn", sweep_id: { value: sweep.id }).size
26
+ clean &&= sweep_was_clean?(sweep)
27
+ close_open_sweep(sweep, surprises)
28
+ end
29
+
30
+ # No open sweep (a crash between claim and open): nothing was watched, so the streak
31
+ # resets rather than incrementing.
32
+ puts "no open sweep against #{@target_reference} — releasing with the streak reset" if open_sweeps.empty?
33
+
34
+ capabilities = Hecks::Fuzzing::TargetCapabilities.infer(@domain_path, rust_dir: @rust_dir)
35
+ was = target.status
36
+ target = release_target!(target, capabilities, target.clean_streak.value, surprises: surprises, clean: clean)
37
+ puts "released #{@target_reference} (was #{was}) — status #{target.status}, " \
38
+ "clean_streak #{target.clean_streak.value}, yield_score #{target.yield_score.value}, " \
39
+ "capabilities #{target.capabilities.value.inspect}"
40
+ EXIT_OK
41
+ end
42
+
43
+ def close_open_sweep(sweep, surprises)
44
+ if sweep.made.value.positive? || sweep.waived.value.positive?
45
+ begin
46
+ sweep.conclude!(notes: { value: @release_notes })
47
+ rescue Hecks::Runtime::InvariantViolation => e
48
+ abort "--notes was refused by Sweep.Conclude — #{e.message}"
49
+ end
50
+ puts "concluded #{sweep.id} (#{sweep.made.value} check(s), #{surprises} bug(s) logged against it so far)"
51
+ else
52
+ # Never made a check: `Sweep.Conclude` refuses it, so abandon it to leave `Sweeping`.
53
+ sweep.abandon!
54
+ puts "abandoned #{sweep.id} (it never made a check)"
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end