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,423 @@
1
+ require_relative "fuzzing/target_capabilities"
2
+
3
+ module Hecks
4
+ # The corpus: every place in this repo that holds a real domain, named once.
5
+ # Plain Dir/File only — the tools require this before booting anything.
6
+ module Corpus
7
+ ROOT = File.expand_path("../..", __dir__).freeze
8
+
9
+ Member = Struct.new(:stem, :kind, :path)
10
+
11
+ # **One domain per directory** — its bluebooks sit in `<dir>/bluebook/`
12
+ # or directly in `<dir>` (see `bluebook_files`). Stemmed by directory.
13
+ DIRECTORY_KINDS = {
14
+ example: "examples/*",
15
+ stress: "qa/stress_domains/*",
16
+ semantics: "spec/corpus/semantics/domains/*",
17
+ # The Hecks domain (ADR 0080): its chapters share one namespace and one hecksagon, so
18
+ # they load together, as a directory, never file by file.
19
+ hecks: "lib/hecks/hecks",
20
+ # A package vendored via `uses_embryonaut_bluebook` — nested inside the
21
+ # consuming example's own checkout, not this gem's own framework/bluebook/.
22
+ vendored: "examples/*/vendor/embryonaut_bluebooks/*"
23
+ }.freeze
24
+
25
+ # **One chapter per file**. Stemmed by the path below the glob's fixed
26
+ # prefix, so a nested fixture keeps its subdirectory (`eras/base`)
27
+ # and never collides with a same-named file elsewhere in the kind.
28
+ FILE_KINDS = {
29
+ grammar: "lib/hecks/grammar/*.bluebook",
30
+ framework: "lib/hecks/framework/bluebook/*.bluebook",
31
+ qa: "lib/hecks/quality_control/*.bluebook",
32
+ language: "lib/hecks/language/**/*.bluebook",
33
+ deploy: "lib/hecks/deploy/bluebook/*.bluebook",
34
+ tenancy: "lib/hecks/tenancy/bluebook/*.bluebook",
35
+ fixture: "spec/fixtures/**/*.bluebook"
36
+ }.freeze
37
+
38
+ KINDS = (DIRECTORY_KINDS.keys + FILE_KINDS.keys).freeze
39
+
40
+ # A route sends what the sweep does not boot elsewhere; each entry's
41
+ # `check` (:named_in, :gitignored, :gap) is verified by
42
+ # spec/corpus_accounting_spec.rb, matched in order.
43
+ Route = Struct.new(:pattern, :check, :destination, :names, :why)
44
+
45
+ ROUTES = [
46
+ Route.new(%r{\Atmp/}, :gitignored, ".gitignore", "tmp/",
47
+ "scratch output — generated and mined candidate domains, fuzz failures — never committed"),
48
+ Route.new(%r{/\.aws-sam/}, :gitignored, ".gitignore", ".aws-sam/",
49
+ "SAM build output — a vendored copy of real sources, never committed"),
50
+ Route.new(%r{/data/eras/}, :gitignored, ".gitignore", "**/data/eras/",
51
+ "era snapshots a file adapter writes at runtime, never committed"),
52
+ Route.new(%r{\Arust/}, :named_in, "rust/parser/tests/gates.rs", :each_file,
53
+ "the Rust parser's own fixtures, each loaded by its gate tests"),
54
+ Route.new(%r{/translations/}, :named_in, "spec/translation/committed_edges_spec.rb", "bluebook/translations",
55
+ "translation edges, not chapters; each must load, chain era to era, and end at the storage " \
56
+ "shape its bluebook declares today"),
57
+ Route.new(%r{\Alib/hecks/forms/examples/}, :named_in, "spec/forms/app_spec.rb", :each_file,
58
+ "a Forms presentation config wearing the .bluebook extension"),
59
+ Route.new(%r{\Aspec/fixtures/eras/}, :named_in, "spec/runtime/storage_shape_spec.rb", "fixtures/eras",
60
+ "deliberately conflicting versions of one domain; each must classify as the verdict " \
61
+ "its filename declares (bump_* / same_*)"),
62
+ Route.new(%r{\Aspec/fixtures/model_check/}, :named_in, "spec/model_check_spec.rb", :each_file,
63
+ "domains broken on purpose; each must produce exactly the finding kinds it is built to trigger"),
64
+ # hecks fuzz sweeps it too, once Fuzzing::Replay coerces value-object args
65
+ # before recomputing givens — today it doesn't, so this given reads as
66
+ # wrongly admitted.
67
+ Route.new(%r{\Aspec/fixtures/rust_host/}, :named_in, "rust/host/src/web.rs", "checkout_fixture",
68
+ "the Rust host's checkout fixture, pinned by its web and /api tests")
69
+ ].freeze
70
+
71
+ module_function
72
+
73
+ # Lists corpus members of the given kinds (every kind, by default).
74
+ #
75
+ # @param kinds [Array<Symbol>] corpus kinds to include, from `KINDS`; every kind
76
+ # when empty
77
+ # @param root [String] repository root to search under
78
+ # @return [Array<Member>] matching members
79
+ # @raise [ArgumentError] if `kinds` names a kind not in `KINDS`
80
+ def members(*kinds, root: ROOT)
81
+ kinds = KINDS if kinds.empty?
82
+ kinds.flat_map do |kind|
83
+ if (glob = DIRECTORY_KINDS[kind])
84
+ Dir.glob(File.join(root, glob)).select { |path| File.directory?(path) }.sort
85
+ .map { |dir| Member.new(File.basename(dir), kind, dir) }
86
+ elsif (glob = FILE_KINDS[kind])
87
+ prefix = File.join(root, glob[/\A[^*]*/].chomp("/"))
88
+ Dir.glob(File.join(root, glob))
89
+ .map { |file| Member.new(file.delete_prefix("#{prefix}/").delete_suffix(".bluebook"), kind, file) }
90
+ else
91
+ raise ArgumentError, "unknown corpus kind #{kind.inspect} — known: #{KINDS.join(', ')}"
92
+ end
93
+ end
94
+ end
95
+
96
+ # What a boot loads for a member — a directory kind's bluebook
97
+ # directory, or a file kind's own file.
98
+ #
99
+ # @param member [Member] the corpus member
100
+ # @return [String, nil] the path to boot, or nil when a directory member holds
101
+ # no bluebook
102
+ def source_of(member)
103
+ DIRECTORY_KINDS.key?(member.kind) ? bluebook_dir(member.path) : member.path
104
+ end
105
+
106
+ # How a domain's hecksagon names a chapter the gem carries and loads by name, as the QA
107
+ # ledger's does (`Hecks::Chapters.load!("QualityControl")`).
108
+ ATTACHED_CHAPTER = /Chapters\.load!\(\s*"([^"]+)"\s*\)/
109
+
110
+ # Where a domain path keeps its bluebooks — `<domain>/bluebook/*.bluebook`, or the directory
111
+ # itself when that holds none, or the chapter files its hecksagons load by name (the QA
112
+ # ledger, `qa/bluebook`, holds only wiring: its chapter ships in `lib/hecks/quality_control/`).
113
+ #
114
+ # @param domain_path [String] path to a domain directory
115
+ # @return [Array<String>, nil] `.bluebook` file paths found, or nil when none
116
+ def bluebook_files(domain_path)
117
+ [File.join(domain_path, "bluebook"), domain_path].each do |dir|
118
+ files = Dir[File.join(dir, "*.bluebook")]
119
+ return files unless files.empty?
120
+ end
121
+ attached_chapter_files(domain_path)
122
+ end
123
+
124
+ # The bluebook files of every chapter a domain's own hecksagons load by name.
125
+ #
126
+ # @param domain_path [String] path to a domain directory
127
+ # @return [Array<String>, nil] the chapters' `.bluebook` file paths, or nil when none is named
128
+ def attached_chapter_files(domain_path)
129
+ names = Dir[File.join(domain_path, "{bluebook/,}*.hecksagon")]
130
+ .flat_map { |path| File.read(path).scan(ATTACHED_CHAPTER).flatten }.uniq
131
+ files = names.flat_map { |name| Chapters.index.fetch(name, []) }
132
+ files.empty? ? nil : files
133
+ end
134
+
135
+ # The directory holding `domain_path`'s bluebooks.
136
+ #
137
+ # @param domain_path [String] path to a domain directory
138
+ # @return [String, nil] directory of the first `.bluebook` file found, or nil
139
+ # when `domain_path` holds none
140
+ def bluebook_dir(domain_path)
141
+ files = bluebook_files(domain_path)
142
+ files && File.dirname(files.first)
143
+ end
144
+
145
+ # The route a repo-relative path takes instead of the sweep — the
146
+ # first one it matches — or `nil` when the sweep boots it.
147
+ #
148
+ # @param relative_path [String] a corpus member's path, relative to the repo root
149
+ # @return [Route, nil] the first matching route, or nil when the sweep boots it
150
+ def route_for(relative_path)
151
+ ROUTES.find { |route| route.pattern.match?(relative_path) }
152
+ end
153
+
154
+ # Every kind hecks model_check walks: excludes language/deploy (checked
155
+ # elsewhere) and anything a route already sends to its own destination.
156
+ MODEL_CHECK_KINDS = %i[example grammar framework vendored qa stress fixture hecks].freeze
157
+
158
+ # Every corpus member `hecks model_check` and `spec/model_check_spec.rb` walk.
159
+ #
160
+ # @param root [String] repository root to search under
161
+ # @return [Array<Member>] members of `MODEL_CHECK_KINDS`, less any routed elsewhere
162
+ def model_check_members(root: ROOT)
163
+ members(*MODEL_CHECK_KINDS, root: root).reject { |member| route_for(member.path.delete_prefix("#{root}/")) }
164
+ end
165
+
166
+ # **The ledger sweeps itself** — its own chapter is a domain like any
167
+ # other, and the one rotation member that is neither an example nor a
168
+ # stress domain.
169
+ ROTATION_LEDGER = { "quality_control" => "qa/bluebook" }.freeze
170
+
171
+ # What the QA rotation is made of — every example and stress domain,
172
+ # plus the ledger, as `reference => repo-relative path` — derived, not hand-kept.
173
+ #
174
+ # @param root [String] repository root to search under
175
+ # @return [Hash{String => String}] each rotation member's stem/reference mapped
176
+ # to its repo-relative path
177
+ def rotation_targets(root: ROOT)
178
+ members(:example, :stress, root: root)
179
+ .to_h { |member| [member.stem, member.path.delete_prefix("#{root}/")] }
180
+ .merge(ROTATION_LEDGER)
181
+ end
182
+
183
+ # Every bootable domain in the project — any directory holding a
184
+ # `.bluebook` no route sends elsewhere (a `bluebook/` folder stands for its parent).
185
+ #
186
+ # @param root [String] repository root to search under
187
+ # @return [Array<String>] absolute paths of every sweepable domain directory
188
+ def sweepable_domains(root = ROOT)
189
+ Dir.chdir(root) do
190
+ Dir.glob("**/*.bluebook")
191
+ .reject { |path| route_for(path) }
192
+ .map { |path| File.dirname(path) }
193
+ .map { |dir| File.basename(dir) == "bluebook" ? File.dirname(dir) : dir }
194
+ .uniq.sort
195
+ .map { |dir| File.join(root, dir) }
196
+ end
197
+ end
198
+
199
+ # Sweepable domains a fuzz cannot boot from its copy, by repo-relative directory, each with
200
+ # the reason. A fuzz boots a tmpdir copy of a domain to isolate its state.
201
+ FUZZ_UNBOOTABLE = {
202
+ "lib/hecks/hecks" => "the gem's own chapter; model_check covers it",
203
+ "spec/fixtures/qa_discover_external_domains/projects/hecks" => "declares the reserved chapter name `Hecks`"
204
+ }.freeze
205
+
206
+ # Every sweepable domain a fuzz can boot: `sweepable_domains` less `FUZZ_UNBOOTABLE`.
207
+ #
208
+ # @param root [String] repository root to search under
209
+ # @return [Array<String>] absolute paths of the domain directories `hecks fuzz` sweeps
210
+ def fuzzable_domains(root = ROOT)
211
+ sweepable_domains(root) - FUZZ_UNBOOTABLE.keys.map { |dir| File.join(root, dir) }
212
+ end
213
+
214
+ # The domain directory a member stands for, spelled the way
215
+ # `sweepable_domains` spells it: a `bluebook/` folder is its parent.
216
+ #
217
+ # @param member [Member] the corpus member
218
+ # @return [String] the member's owning domain directory path
219
+ def domain_dir_of(member)
220
+ dir = File.directory?(member.path) ? member.path : File.dirname(member.path)
221
+ File.basename(dir) == "bluebook" ? File.dirname(dir) : dir
222
+ end
223
+
224
+ # Every Rust-facing list reads `rust/Cargo.toml`'s `[features]` as its
225
+ # one source, rather than each consumer typing it out by hand.
226
+ GENERATED_DIR = "rust/src/generated".freeze
227
+ RUST_DOMAIN_KINDS = %i[example stress fixture].freeze
228
+
229
+ RustDomain = Struct.new(:feature, :dir, :kind)
230
+
231
+ # `check: :named_in` — `destination` must name `names`.
232
+ Elsewhere = Struct.new(:check, :destination, :names, :why)
233
+
234
+ RUST_ELSEWHERE = {
235
+ "meta" => Elsewhere.new(:named_in, "spec/codegen_parity_spec.rb", "bluebook_language",
236
+ "the self-hosted grammar (lib/hecks/language), not a domain directory — every " \
237
+ "hecks project_rust run rewrites it (so the drift check diffs it), codegen parity " \
238
+ "checks it as bluebook_language, and there is no directory to fuzz")
239
+ }.freeze
240
+
241
+ # Every place a Rust-facing domain's own `uses_framework`/
242
+ # `uses_embryonaut_bluebook` attachment could be declared.
243
+ #
244
+ # @param root [String] repository root to search under
245
+ # @return [String] every reachable hecksagon file's own text, joined by newlines
246
+ def rust_attachment_hecksagon_text(root: ROOT)
247
+ rust_domains(root: root).flat_map { |domain| Dir.glob(File.join(domain.dir, "**", "*.hecksagon")) }
248
+ .map { |path| File.read(path) }.join("\n")
249
+ end
250
+
251
+ # **Shrink-only**: a generated module `hecks rust_coverage` still flags.
252
+ # `hecks corpus_rust_coverage --rust-coverage` requires each entry to still fail, so a
253
+ # newly-passing module breaks the build until removed here.
254
+ RUST_COVERAGE_PENDING = {}.freeze
255
+
256
+ # The Cargo `[features]` table's raw text.
257
+ #
258
+ # @param root [String] repository root to search under
259
+ # @return [String] the table's text, or `""` when `rust/Cargo.toml` has none
260
+ def cargo_features_table(root: ROOT)
261
+ File.read(File.join(root, "rust/Cargo.toml"))[Fuzzing::TargetCapabilities::FEATURES_TABLE] || ""
262
+ end
263
+
264
+ # Every feature name Cargo declares with no dependency array of its own.
265
+ #
266
+ # @param root [String] repository root to search under
267
+ # @return [Array<String>] feature names, in file order
268
+ def cargo_features(root: ROOT)
269
+ cargo_features_table(root: root).scan(/^(\w+)\s*=\s*\[\]/).flatten
270
+ end
271
+
272
+ # The feature `hecks project_rust` last wrote as Cargo's `default`.
273
+ #
274
+ # @param root [String] repository root to search under
275
+ # @return [String, nil] the default feature's name, or nil when Cargo.toml
276
+ # declares none
277
+ def cargo_default(root: ROOT)
278
+ cargo_features_table(root: root)[/^default\s*=\s*\["(\w+)"\]/, 1]
279
+ end
280
+
281
+ # Every in-repo domain directory whose name is a Cargo feature, sorted
282
+ # by path — disambiguated by the generated module's metadata.rs stamp when one exists.
283
+ #
284
+ # @param root [String] repository root to search under
285
+ # @return [Array<RustDomain>] each Rust-facing domain, sorted by directory path
286
+ def rust_domains(root: ROOT)
287
+ features = cargo_features(root: root)
288
+ members(*RUST_DOMAIN_KINDS, root: root)
289
+ .map { |member| [domain_dir_of(member), member.kind] }
290
+ .uniq(&:first)
291
+ .select { |dir, _| rust_domain_dir?(dir, features, root) }
292
+ .sort_by(&:first)
293
+ .map { |dir, kind| RustDomain.new(File.basename(dir).downcase, dir, kind) }
294
+ end
295
+
296
+ # Tells whether `dir` is the real source directory for its Cargo feature.
297
+ #
298
+ # @param dir [String] a candidate domain directory
299
+ # @param features [Array<String>] known Cargo feature names
300
+ # @param root [String] repository root `dir` is rooted under
301
+ # @return [Boolean]
302
+ def rust_domain_dir?(dir, features, root)
303
+ feature = File.basename(dir).downcase
304
+ source = generated_source(feature, root: root)
305
+ features.include?(feature) && (source.nil? || source == dir.delete_prefix("#{root}/"))
306
+ end
307
+
308
+ # The stamp hecks project_rust writes into metadata.rs, e.g.
309
+ # `examples/pizzas` or `the self-hosted language (...)`, with any
310
+ # ` (uses_framework "X")`/` (uses_embryonaut_bluebook "X")` suffix stripped.
311
+ SOURCE_STAMP = /
312
+ GENERATED\ by\ hecks\ project_rust\ —\ (.+?)
313
+ (?:\ \((?:uses_framework|uses_embryonaut_bluebook)\ "\w+"\))?
314
+ 's\ own\ canonical\ IR,
315
+ /x
316
+
317
+ # Where a generated module came from, read off the stamp `hecks project_rust`
318
+ # writes into its metadata.rs.
319
+ #
320
+ # @param module_name [String] a generated module's name
321
+ # @param root [String] repository root to search under
322
+ # @return [String, nil] the source path the stamp names, or nil when the module
323
+ # is not generated
324
+ def generated_source(module_name, root: ROOT)
325
+ metadata = File.join(root, GENERATED_DIR, module_name, "metadata.rs")
326
+ File.file?(metadata) ? File.read(metadata)[SOURCE_STAMP, 1] : nil
327
+ end
328
+
329
+ # Every module directory under `rust/src/generated`.
330
+ #
331
+ # @param root [String] repository root to search under
332
+ # @return [Array<String>] generated module names, sorted
333
+ def generated_modules(root: ROOT)
334
+ Dir.children(File.join(root, GENERATED_DIR)).select { |name| File.directory?(File.join(root, GENERATED_DIR, name)) }.sort
335
+ end
336
+
337
+ # Tells whether `feature` has already been generated (has a merged.rs).
338
+ #
339
+ # @param feature [String] a Cargo feature / domain name
340
+ # @param root [String] repository root to search under
341
+ # @return [Boolean]
342
+ def generated?(feature, root: ROOT)
343
+ File.file?(File.join(root, GENERATED_DIR, feature, "merged.rs"))
344
+ end
345
+
346
+ # Chapters attached via `kind` that get a generated module as a side
347
+ # effect of the attaching domain's regen, with no merged.rs of their own.
348
+ #
349
+ # @param kind [Symbol] :framework or :vendored
350
+ # @param root [String] repository root to search under
351
+ # @return [Array<String>] stems with a generated module but no merged.rs
352
+ # of their own
353
+ def rust_side_chapters(kind, root: ROOT)
354
+ modules = generated_modules(root: root)
355
+ members(kind, root: root).map(&:stem)
356
+ .select do |stem|
357
+ module_name = Naming.pascal(stem).downcase
358
+ modules.include?(module_name) && !generated?(module_name, root: root)
359
+ end
360
+ end
361
+
362
+ # The generated module name a `:framework`/`:vendored` stem writes
363
+ # under — strips underscores, so it can differ from the raw stem.
364
+ #
365
+ # @param stem [String] a `:framework`/`:vendored` corpus member's stem
366
+ # @return [String] the generated module's own directory name
367
+ def rust_side_module_name(stem)
368
+ Naming.pascal(stem).downcase
369
+ end
370
+
371
+ # Names the framework chapters Rust carries as modules, beside its domains' own bluebooks.
372
+ #
373
+ # @param root [String] repository root to search under
374
+ # @return [Array<String>] generated module names for the `:framework` corpus members
375
+ def rust_framework_chapters(root: ROOT)
376
+ rust_side_chapters(:framework, root: root)
377
+ end
378
+
379
+ # Names the vendored chapters Rust carries as modules, beside its domains' own bluebooks.
380
+ #
381
+ # @param root [String] repository root to search under
382
+ # @return [Array<String>] generated module names for the `:vendored` corpus members
383
+ def rust_vendored_chapters(root: ROOT)
384
+ rust_side_chapters(:vendored, root: root)
385
+ end
386
+
387
+ # Chapters an in-repo Rust domain carries beside its own bluebook,
388
+ # written as a module by `hecks project_rust` with no merged.rs of its own.
389
+ #
390
+ # @param root [String] repository root to search under
391
+ # @return [Array<String>] generated module names with no merged.rs of their own
392
+ def rust_sibling_chapters(root: ROOT)
393
+ modules = generated_modules(root: root)
394
+ rust_domains(root: root)
395
+ .flat_map { |domain| Dir.glob(File.join(domain.dir, "bluebook", "*.bluebook")) }
396
+ .map { |path| Naming.pascal(File.basename(path, ".bluebook")).downcase }
397
+ .uniq
398
+ .select { |name| modules.include?(name) && !generated?(name, root: root) }
399
+ end
400
+
401
+ # The regeneration order the drift check runs, sorted by path — so which
402
+ # domain wins Cargo's `default` is derived, not hand-picked.
403
+ #
404
+ # @param root [String] repository root to search under
405
+ # @return [Array<RustDomain>] already-generated Rust domains, in regeneration order
406
+ def rust_regen_order(root: ROOT)
407
+ rust_domains(root: root).select { |domain| generated?(domain.feature, root: root) }
408
+ end
409
+
410
+ # The chapter a bluebook declares — `Hecks.bluebook "<Name>"` — read off
411
+ # the file rather than guessed from its name, since the two can differ.
412
+ #
413
+ # @param bluebook_path [String, Array<String>] a `.bluebook` file path, or an
414
+ # array whose first element is used
415
+ # @return [String, nil] the declared chapter name, or nil when the file never
416
+ # declares one
417
+ def chapter_name_of(bluebook_path)
418
+ bluebook_path = Array(bluebook_path).first
419
+ header = File.foreach(bluebook_path).find { |line| line =~ /\A\s*Hecks\.bluebook\s+"([^"]+)"/ }
420
+ header && Regexp.last_match(1)
421
+ end
422
+ end
423
+ end