hecks 2.7.0 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +11 -0
  3. data/lib/hecks/adapters/driven/claude_code.rb +4 -104
  4. data/lib/hecks/adapters/driven/d1.rb +44 -237
  5. data/lib/hecks/adapters/driven/folder.rb +17 -76
  6. data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
  7. data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
  8. data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
  9. data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
  10. data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
  11. data/lib/hecks/adapters/driven/heki.rb +13 -42
  12. data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
  13. data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
  14. data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
  15. data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
  16. data/lib/hecks/adapters/driven/lambda.rb +10 -84
  17. data/lib/hecks/adapters/driven/local_storage.rb +5 -40
  18. data/lib/hecks/adapters/driven/memory.rb +18 -99
  19. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
  20. data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
  21. data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
  22. data/lib/hecks/adapters/driven/postgres/reconnect.rb +4 -30
  23. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
  24. data/lib/hecks/adapters/driven/postgres.rb +145 -134
  25. data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
  26. data/lib/hecks/adapters/driven/prism.rb +7 -30
  27. data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
  28. data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
  29. data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
  30. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
  31. data/lib/hecks/adapters/driven/sqlite.rb +128 -65
  32. data/lib/hecks/adapters/driven/tenant_provisioner.rb +15 -37
  33. data/lib/hecks/adapters/driven.rb +5 -36
  34. data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
  35. data/lib/hecks/behaviors/dsl.rb +7 -25
  36. data/lib/hecks/behaviors/expectations.rb +32 -142
  37. data/lib/hecks/behaviors/ir.rb +7 -20
  38. data/lib/hecks/behaviors/rspec.rb +6 -17
  39. data/lib/hecks/behaviors/runner.rb +10 -34
  40. data/lib/hecks/behaviors.rb +4 -8
  41. data/lib/hecks/bluebook/aggregate.rb +9 -75
  42. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
  43. data/lib/hecks/bluebook/assembly/build.rb +4 -15
  44. data/lib/hecks/bluebook/assembly/contract.rb +15 -136
  45. data/lib/hecks/bluebook/assembly/contracts.rb +54 -174
  46. data/lib/hecks/bluebook/assembly/marks.rb +31 -223
  47. data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
  48. data/lib/hecks/bluebook/assembly.rb +6 -45
  49. data/lib/hecks/bluebook/attribute.rb +12 -61
  50. data/lib/hecks/bluebook/behaviour/aggregate.rb +10 -39
  51. data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
  52. data/lib/hecks/bluebook/behaviour/chapter.rb +17 -42
  53. data/lib/hecks/bluebook/behaviour/command.rb +14 -66
  54. data/lib/hecks/bluebook/behaviour/domain_port.rb +4 -20
  55. data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
  56. data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
  57. data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
  58. data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
  59. data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
  60. data/lib/hecks/bluebook/behaviour/read_model.rb +38 -26
  61. data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
  62. data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
  63. data/lib/hecks/bluebook/capabilities.rb +17 -49
  64. data/lib/hecks/bluebook/chapter.rb +10 -48
  65. data/lib/hecks/bluebook/command.rb +23 -81
  66. data/lib/hecks/bluebook/domain_port.rb +14 -63
  67. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
  68. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
  69. data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
  70. data/lib/hecks/bluebook/dsl/binding_proxy.rb +17 -65
  71. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +86 -708
  72. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +56 -170
  73. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +1 -0
  74. data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
  75. data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
  76. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +12 -87
  77. data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
  78. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
  79. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +26 -189
  80. data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
  81. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
  82. data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
  83. data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
  84. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
  85. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
  86. data/lib/hecks/bluebook/dsl/query_builder.rb +11 -42
  87. data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
  88. data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
  89. data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
  90. data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
  91. data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
  92. data/lib/hecks/bluebook/dsl/world_builder.rb +19 -106
  93. data/lib/hecks/bluebook/entity.rb +13 -71
  94. data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
  95. data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
  96. data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
  97. data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
  98. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
  99. data/lib/hecks/bluebook/expression/resolver.rb +37 -660
  100. data/lib/hecks/bluebook/hexagon.rb +5 -28
  101. data/lib/hecks/bluebook/lifecycle.rb +5 -16
  102. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
  103. data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
  104. data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
  105. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
  106. data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
  107. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +24 -176
  108. data/lib/hecks/bluebook/meta_validator/shapes.rb +54 -268
  109. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -308
  110. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
  111. data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
  112. data/lib/hecks/bluebook/meta_validator.rb +79 -349
  113. data/lib/hecks/bluebook/model_check/client_profile.rb +10 -91
  114. data/lib/hecks/bluebook/model_check.rb +102 -600
  115. data/lib/hecks/bluebook/pattern_subset.rb +11 -69
  116. data/lib/hecks/bluebook/process_manager.rb +13 -83
  117. data/lib/hecks/bluebook/project_loader.rb +3 -39
  118. data/lib/hecks/bluebook/project_register.rb +12 -60
  119. data/lib/hecks/bluebook/query.rb +9 -48
  120. data/lib/hecks/bluebook/read_model.rb +57 -81
  121. data/lib/hecks/bluebook/reference.rb +7 -41
  122. data/lib/hecks/bluebook/smoke_test.rb +8 -98
  123. data/lib/hecks/bluebook/synthesizer.rb +13 -62
  124. data/lib/hecks/bluebook/translation.rb +26 -62
  125. data/lib/hecks/bluebook/value_object.rb +11 -36
  126. data/lib/hecks/bluebook.rb +5 -22
  127. data/lib/hecks/cache_dir.rb +84 -0
  128. data/lib/hecks/cli/document.rb +86 -0
  129. data/lib/hecks/cli/ir.rb +45 -0
  130. data/lib/hecks/cli/mcp.rb +31 -0
  131. data/lib/hecks/cli/mcp_door.rb +366 -0
  132. data/lib/hecks/cli/model_check.rb +203 -0
  133. data/lib/hecks/cli/project_cli.rb +90 -0
  134. data/lib/hecks/cli/project_diagrams.rb +36 -0
  135. data/lib/hecks/cli/run.rb +173 -0
  136. data/lib/hecks/cli/smoke_test.rb +45 -0
  137. data/lib/hecks/cli/stores.rb +53 -0
  138. data/lib/hecks/cli.rb +160 -0
  139. data/lib/hecks/construct.rb +8 -34
  140. data/lib/hecks/deploy/bluebook/deploy.bluebook +33 -142
  141. data/lib/hecks/deploy/bluebook/deploy.hecksagon +2 -9
  142. data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
  143. data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
  144. data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
  145. data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
  146. data/lib/hecks/embryonaut_bluebook.rb +4 -71
  147. data/lib/hecks/facade/cli_door.rb +24 -106
  148. data/lib/hecks/facade/cli_runner.rb +28 -172
  149. data/lib/hecks/facade/command_request.rb +13 -33
  150. data/lib/hecks/facade/handle.rb +34 -121
  151. data/lib/hecks/facade/json_door.rb +31 -146
  152. data/lib/hecks/facade/surface/aggregate_door.rb +39 -104
  153. data/lib/hecks/facade/surface/chapter.rb +10 -54
  154. data/lib/hecks/facade/surface.rb +8 -23
  155. data/lib/hecks/facade.rb +10 -25
  156. data/lib/hecks/forms/app.rb +15 -70
  157. data/lib/hecks/forms/command_form_renderer.rb +10 -29
  158. data/lib/hecks/forms/field_renderer.rb +17 -156
  159. data/lib/hecks/forms/field_shape.rb +30 -222
  160. data/lib/hecks/forms/html.rb +12 -47
  161. data/lib/hecks/forms/index_renderer.rb +1 -4
  162. data/lib/hecks/forms/page.rb +3 -9
  163. data/lib/hecks/forms/params.rb +14 -60
  164. data/lib/hecks/forms/port_argument.rb +2 -19
  165. data/lib/hecks/forms/query_form_renderer.rb +4 -79
  166. data/lib/hecks/forms/record_renderer.rb +8 -75
  167. data/lib/hecks/forms/record_table.rb +7 -50
  168. data/lib/hecks/forms/reference_options.rb +3 -30
  169. data/lib/hecks/forms/value_object_shape.rb +8 -35
  170. data/lib/hecks/forms.rb +5 -33
  171. data/lib/hecks/fqn.rb +5 -12
  172. data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
  173. data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
  174. data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
  175. data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
  176. data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
  177. data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
  178. data/lib/hecks/framework.rb +11 -80
  179. data/lib/hecks/freezer.rb +5 -39
  180. data/lib/hecks/grammar/expression.bluebook +15 -40
  181. data/lib/hecks/grammar/translation.bluebook +3 -6
  182. data/lib/hecks/grammar.rb +16 -41
  183. data/lib/hecks/ir.rb +14 -83
  184. data/lib/hecks/language/adapter.bluebook +2 -7
  185. data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
  186. data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
  187. data/lib/hecks/language/bluebook/bluebook.bluebook +15 -83
  188. data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
  189. data/lib/hecks/language/bluebook/command.bluebook +27 -144
  190. data/lib/hecks/language/bluebook/entity.bluebook +24 -97
  191. data/lib/hecks/language/bluebook/policy.bluebook +16 -67
  192. data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
  193. data/lib/hecks/language/bluebook/projection.bluebook +126 -60
  194. data/lib/hecks/language/bluebook/query.bluebook +12 -43
  195. data/lib/hecks/language/bluebook/shape.bluebook +23 -73
  196. data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
  197. data/lib/hecks/language/bluebook/vocabulary.bluebook +98 -197
  198. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
  199. data/lib/hecks/language/hecksagon/domain_port.bluebook +4 -19
  200. data/lib/hecks/language/hecksagon/hecksagon.bluebook +6 -25
  201. data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
  202. data/lib/hecks/language/oidc.json +35 -0
  203. data/lib/hecks/language/port.bluebook +4 -17
  204. data/lib/hecks/language/translation/translation.bluebook +3 -9
  205. data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
  206. data/lib/hecks/language/world/wiring.bluebook +1 -3
  207. data/lib/hecks/language/world/world.bluebook +5 -7
  208. data/lib/hecks/literal.rb +8 -50
  209. data/lib/hecks/mcp_door_scope.rb +95 -0
  210. data/lib/hecks/mcp_stdio_guard.rb +4 -41
  211. data/lib/hecks/naming.rb +29 -137
  212. data/lib/hecks/ports/access_control.rb +7 -23
  213. data/lib/hecks/ports/agent/answers.rb +5 -23
  214. data/lib/hecks/ports/agent.rb +47 -172
  215. data/lib/hecks/ports/authentication.rb +12 -39
  216. data/lib/hecks/ports/authorization.rb +16 -43
  217. data/lib/hecks/ports/clock.rb +5 -45
  218. data/lib/hecks/ports/extraction.rb +7 -12
  219. data/lib/hecks/ports/identity_assignment.rb +8 -29
  220. data/lib/hecks/ports/identity_generation.rb +6 -29
  221. data/lib/hecks/ports/identity_resolution.rb +2 -10
  222. data/lib/hecks/ports/key_vault.rb +9 -45
  223. data/lib/hecks/ports/persistence/append_only.rb +62 -65
  224. data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
  225. data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
  226. data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
  227. data/lib/hecks/ports/persistence/plugin.rb +13 -42
  228. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +38 -141
  229. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
  230. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +16 -84
  231. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +7 -26
  232. data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +3 -22
  233. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
  234. data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
  235. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
  236. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
  237. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
  238. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
  239. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
  241. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +18 -75
  242. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
  243. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
  244. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
  245. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
  246. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
  247. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +14 -115
  248. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
  249. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +127 -554
  250. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
  251. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
  252. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
  253. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
  254. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
  255. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
  256. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +9 -25
  257. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +22 -122
  258. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
  259. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
  260. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
  261. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
  262. data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
  263. data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
  264. data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
  265. data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
  266. data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
  267. data/lib/hecks/ports/persistence/state_codec.rb +23 -103
  268. data/lib/hecks/ports/persistence.rb +7 -14
  269. data/lib/hecks/ports/projection.rb +42 -84
  270. data/lib/hecks/ports/query/in_memory.rb +10 -58
  271. data/lib/hecks/ports/query/ordering.rb +11 -32
  272. data/lib/hecks/ports/query.rb +14 -37
  273. data/lib/hecks/ports.rb +2 -8
  274. data/lib/hecks/projections/bootstrap_table.rb +11 -43
  275. data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
  276. data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
  277. data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
  278. data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
  279. data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
  280. data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
  281. data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
  282. data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
  283. data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
  284. data/lib/hecks/projections/deploy/fargate.rb +35 -202
  285. data/lib/hecks/projections/deploy/lambda.rb +151 -679
  286. data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
  287. data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
  288. data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
  289. data/lib/hecks/projections/deploy/preview/script.rb +2 -14
  290. data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
  291. data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
  292. data/lib/hecks/projections/deploy/preview/template.rb +2 -58
  293. data/lib/hecks/projections/deploy/preview.rb +2 -67
  294. data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
  295. data/lib/hecks/projections/deploy/scripts.rb +4 -57
  296. data/lib/hecks/projections/deploy/shared.rb +47 -146
  297. data/lib/hecks/projections/deploy/smoke.rb +4 -61
  298. data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
  299. data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
  300. data/lib/hecks/projections/deploy/template_diff.rb +5 -57
  301. data/lib/hecks/projections/diagrams.rb +20 -582
  302. data/lib/hecks/projections/glossary/html.rb +14 -130
  303. data/lib/hecks/projections/glossary/markdown.rb +8 -69
  304. data/lib/hecks/projections/glossary/mermaid.rb +9 -66
  305. data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
  306. data/lib/hecks/projections/glossary/sentences.rb +14 -159
  307. data/lib/hecks/projections/glossary.rb +30 -222
  308. data/lib/hecks/projections/ir.rb +3 -10
  309. data/lib/hecks/projections/model/deviations.rb +15 -42
  310. data/lib/hecks/projections/model.rb +12 -51
  311. data/lib/hecks/projections/oidc.rb +12 -56
  312. data/lib/hecks/projections/parser_table.rb +9 -28
  313. data/lib/hecks/projections/reference.rb +9 -16
  314. data/lib/hecks/projections/rust_vocabulary.rb +12 -250
  315. data/lib/hecks/projections/shape.rb +3 -29
  316. data/lib/hecks/projections/statements.rb +7 -86
  317. data/lib/hecks/projections/vocabulary.rb +6 -22
  318. data/lib/hecks/projections.rb +2 -16
  319. data/lib/hecks/projector/cli_projector.rb +60 -375
  320. data/lib/hecks/projector/docs_projector.rb +10 -201
  321. data/lib/hecks/projector/exporter.rb +46 -138
  322. data/lib/hecks/projector/ir_projector.rb +2 -9
  323. data/lib/hecks/projector/narrate_projector.rb +15 -189
  324. data/lib/hecks/projector/target.rb +13 -76
  325. data/lib/hecks/projector.rb +30 -121
  326. data/lib/hecks/query_specification/common/comparators.rb +5 -26
  327. data/lib/hecks/query_specification/common/comparison.rb +35 -143
  328. data/lib/hecks/query_specification/common/dsl.rb +8 -24
  329. data/lib/hecks/query_specification/common/null_policy.rb +20 -70
  330. data/lib/hecks/query_specification/common/options.rb +2 -6
  331. data/lib/hecks/query_specification/common/where_clause.rb +2 -10
  332. data/lib/hecks/query_specification/field_path.rb +37 -77
  333. data/lib/hecks/query_specification/hop_path.rb +12 -76
  334. data/lib/hecks/release/gem_pin.rb +2 -26
  335. data/lib/hecks/release/runner/ci_publisher.rb +93 -0
  336. data/lib/hecks/release/runner/commands.rb +66 -0
  337. data/lib/hecks/release/runner/console.rb +52 -0
  338. data/lib/hecks/release/runner/gem_publisher.rb +43 -0
  339. data/lib/hecks/release/runner/git.rb +48 -0
  340. data/lib/hecks/release/runner/npm_publisher.rb +75 -0
  341. data/lib/hecks/release/runner/preflight.rb +104 -0
  342. data/lib/hecks/release/runner/published.rb +55 -0
  343. data/lib/hecks/release/runner/tagger.rb +80 -0
  344. data/lib/hecks/release/runner.rb +215 -0
  345. data/lib/hecks/rendering.rb +4 -26
  346. data/lib/hecks/router/namespace_installer.rb +12 -36
  347. data/lib/hecks/router.rb +4 -8
  348. data/lib/hecks/runtime/aggregate_lock.rb +8 -33
  349. data/lib/hecks/runtime/boot_gates.rb +3 -18
  350. data/lib/hecks/runtime/caller.rb +19 -59
  351. data/lib/hecks/runtime/capability_graph.rb +5 -21
  352. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
  353. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +23 -160
  354. data/lib/hecks/runtime/command_interpreter.rb +125 -307
  355. data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
  356. data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
  357. data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
  358. data/lib/hecks/runtime/command_rules/emission.rb +8 -21
  359. data/lib/hecks/runtime/command_rules/references.rb +23 -202
  360. data/lib/hecks/runtime/dependency_planning.rb +30 -102
  361. data/lib/hecks/runtime/dispatcher.rb +82 -241
  362. data/lib/hecks/runtime/entity_element.rb +40 -462
  363. data/lib/hecks/runtime/entity_interpreter.rb +65 -220
  364. data/lib/hecks/runtime/errors.rb +32 -115
  365. data/lib/hecks/runtime/event.rb +3 -25
  366. data/lib/hecks/runtime/identity.rb +18 -154
  367. data/lib/hecks/runtime/instance.rb +18 -150
  368. data/lib/hecks/runtime/interpreting.rb +11 -70
  369. data/lib/hecks/runtime/invocation.rb +28 -164
  370. data/lib/hecks/runtime/loader.rb +48 -186
  371. data/lib/hecks/runtime/outbox.rb +38 -261
  372. data/lib/hecks/runtime/policy_interpreter.rb +38 -200
  373. data/lib/hecks/runtime/port_operation_interpreter.rb +26 -87
  374. data/lib/hecks/runtime/query_interpreter.rb +45 -187
  375. data/lib/hecks/runtime/reaction_invocation.rb +36 -138
  376. data/lib/hecks/runtime/read_model_interpreter.rb +139 -208
  377. data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
  378. data/lib/hecks/runtime/reference_hop.rb +8 -81
  379. data/lib/hecks/runtime/refusal_wording.rb +8 -89
  380. data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
  381. data/lib/hecks/runtime/registry/verification.rb +52 -225
  382. data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
  383. data/lib/hecks/runtime/registry.rb +103 -244
  384. data/lib/hecks/runtime/remote_dispatcher.rb +37 -152
  385. data/lib/hecks/runtime/routing.rb +4 -15
  386. data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
  387. data/lib/hecks/runtime/saga_interpreter.rb +79 -263
  388. data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
  389. data/lib/hecks/runtime/tenant_check.rb +6 -68
  390. data/lib/hecks/runtime/tenant_scope.rb +3 -28
  391. data/lib/hecks/runtime/value/admission.rb +16 -67
  392. data/lib/hecks/runtime/value/coercion.rb +155 -641
  393. data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
  394. data/lib/hecks/runtime/value.rb +12 -84
  395. data/lib/hecks/runtime.rb +17 -65
  396. data/lib/hecks/storehouse.rb +146 -567
  397. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +8 -32
  398. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
  399. data/lib/hecks/vendoring/git_environment.rb +2 -8
  400. data/lib/hecks/vendoring/git_source.rb +4 -10
  401. data/lib/hecks/vendoring.rb +7 -46
  402. data/lib/hecks/version.rb +3 -14
  403. data/lib/hecks/vocabulary.rb +5 -0
  404. data/lib/hecks.rb +32 -82
  405. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
  406. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
  407. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
  408. metadata +30 -59
  409. data/lib/hecks/bench/cli.rb +0 -74
  410. data/lib/hecks/bench/environment.rb +0 -100
  411. data/lib/hecks/bench/postgres_probe.rb +0 -41
  412. data/lib/hecks/bench/report.rb +0 -116
  413. data/lib/hecks/bench/ruby_runner.rb +0 -151
  414. data/lib/hecks/bench/run.rb +0 -55
  415. data/lib/hecks/bench/rust_runner.rb +0 -165
  416. data/lib/hecks/bench/stats.rb +0 -75
  417. data/lib/hecks/bench/suite.rb +0 -172
  418. data/lib/hecks/bench/workload.rb +0 -137
  419. data/lib/hecks/bench.rb +0 -28
  420. data/lib/hecks/codemod.rb +0 -443
  421. data/lib/hecks/corpus.rb +0 -479
  422. data/lib/hecks/doc/reference.rb +0 -585
  423. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -684
  424. data/lib/hecks/fuzzing/combination_miner.rb +0 -178
  425. data/lib/hecks/fuzzing/concurrent_dispatch.rb +0 -469
  426. data/lib/hecks/fuzzing/coverage_campaign.rb +0 -161
  427. data/lib/hecks/fuzzing/differential.rb +0 -192
  428. data/lib/hecks/fuzzing/domain_generator.rb +0 -871
  429. data/lib/hecks/fuzzing/era_boundary.rb +0 -154
  430. data/lib/hecks/fuzzing/form_census.rb +0 -285
  431. data/lib/hecks/fuzzing/generated_domain_check.rb +0 -171
  432. data/lib/hecks/fuzzing/invalid_value_generator.rb +0 -125
  433. data/lib/hecks/fuzzing/isolated_boot.rb +0 -658
  434. data/lib/hecks/fuzzing/nondeterministic.rb +0 -79
  435. data/lib/hecks/fuzzing/persistence_parity.rb +0 -253
  436. data/lib/hecks/fuzzing/properties/corrections.rb +0 -125
  437. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +0 -688
  438. data/lib/hecks/fuzzing/properties/guards.rb +0 -398
  439. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +0 -399
  440. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +0 -137
  441. data/lib/hecks/fuzzing/properties/outbox.rb +0 -180
  442. data/lib/hecks/fuzzing/properties/querying.rb +0 -260
  443. data/lib/hecks/fuzzing/properties.rb +0 -267
  444. data/lib/hecks/fuzzing/qa_settings.rb +0 -164
  445. data/lib/hecks/fuzzing/replay.rb +0 -930
  446. data/lib/hecks/fuzzing/rotation_priority.rb +0 -114
  447. data/lib/hecks/fuzzing/rust_gap_manifest.rb +0 -139
  448. data/lib/hecks/fuzzing/self_consistency.rb +0 -825
  449. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +0 -532
  450. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +0 -171
  451. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +0 -127
  452. data/lib/hecks/fuzzing/sequence_generator/picker.rb +0 -116
  453. data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +0 -138
  454. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +0 -344
  455. data/lib/hecks/fuzzing/sequence_generator.rb +0 -311
  456. data/lib/hecks/fuzzing/shrinker.rb +0 -309
  457. data/lib/hecks/fuzzing/structural_skips.rb +0 -53
  458. data/lib/hecks/fuzzing/sweep_depth.rb +0 -61
  459. data/lib/hecks/fuzzing/target_capabilities.rb +0 -255
  460. data/lib/hecks/fuzzing/value_generator.rb +0 -340
  461. data/lib/hecks/fuzzing.rb +0 -23
  462. data/lib/hecks/grammar/evolve.rb +0 -524
  463. data/lib/hecks/query_ir.rb +0 -482
@@ -1,65 +1,15 @@
1
1
  module RuboCop
2
2
  module Cop
3
3
  module Hecks
4
- # Flags plain `@ivar` mutation inside a class this codebase already
5
- # knows is a thread-shared singleton — one `Dispatcher`/`Registry`
6
- # instance lives for the life of a boot and is dispatched through
7
- # from every thread of a Puma worker pool (or any other multi-
8
- # threaded host), so a plain instance variable on either class is
9
- # shared, mutable state with no per-thread or mutex-guarded
10
- # isolation at all.
11
- #
12
- # ## The bug this follows up on
13
- #
14
- # This is the mechanical follow-up to a real bug already fixed here
15
- # (see `dispatcher.rb`'s own `#reenter` comment, and
16
- # `spec/runtime/dispatcher_spec.rb`): a plain `@reaction_depth` ivar on
17
- # `Dispatcher` let two threads' concurrent top-level
18
- # dispatches corrupt each other's view of "how deep into a
19
- # reaction cascade am I". The fix moved that one ivar to
20
- # `Thread.current[:hecks_reaction_depth]`. This cop exists so the
21
- # next plain ivar someone adds to either class gets flagged before
22
- # it becomes the next instance of the same bug, rather than after.
23
- #
24
- # ## Scoped narrowly on purpose
25
- #
26
- # By class name
27
- # (`Hecks::Runtime::Dispatcher`/`Hecks::Runtime::Registry`), not by
28
- # blanket-flagging every ivar mutation in the codebase. Most classes
29
- # in this codebase are not shared across threads (a fresh value
30
- # object per call, a builder used once at boot) and ivar mutation
31
- # there is completely ordinary Ruby with no hazard behind it at
32
- # all — flagging it everywhere would be noise nobody trusts, the
33
- # same reasoning `.rubocop.yml`'s own header gives for every other
34
- # cop in this repo.
35
- #
36
- # ## What counts as "plain"
37
- #
38
- # `@ivar = ...`, `@ivar ||= ...`, `@ivar +=
39
- # ...`, `@ivar << ...`, `@ivar[k] = v`. `initialize` is exempt — an
40
- # ivar being set up for the first time, before any other thread can
41
- # possibly hold a reference to this object, is not the hazard (see
42
- # `Registry#initialize`'s own `@saga_mutex = Mutex.new`, which this
43
- # cop must not flag). `Thread.current[...]`-backed state and a
44
- # `Mutex`-guarded critical section are exactly the two idioms this
45
- # codebase has already established for this — see `Dispatcher
46
- # #reenter` and `Registry#saga_mutex` respectively — so the message
47
- # points at both rather than inventing a third.
4
+ # Flags plain `@ivar` mutation inside the thread-shared `Dispatcher` and `Registry` classes.
5
+ # `initialize` is exempt; use `Thread.current[...]` or a `Mutex` elsewhere.
48
6
  #
49
7
  # @example
50
8
  # # bad
51
- # class Dispatcher
52
- # def reenter(verb)
53
- # @reaction_depth = @reaction_depth.to_i + 1
54
- # end
55
- # end
9
+ # @reaction_depth = @reaction_depth.to_i + 1
56
10
  #
57
11
  # # good
58
- # class Dispatcher
59
- # def reenter(verb)
60
- # Thread.current[:hecks_reaction_depth] = Thread.current[:hecks_reaction_depth].to_i + 1
61
- # end
62
- # end
12
+ # Thread.current[:hecks_reaction_depth] = Thread.current[:hecks_reaction_depth].to_i + 1
63
13
  class ThreadSharedIvarMutation < Base
64
14
  MSG = "`%<ivar>s` is a plain instance variable mutated outside `initialize` on " \
65
15
  "%<klass>s, which is shared across every thread dispatching through it " \
@@ -73,59 +23,33 @@ module RuboCop
73
23
 
74
24
  RESTRICT_ON_SEND = [:<<, :[]=].freeze
75
25
 
76
- # Flags a plain `@ivar = ...` assignment inside a thread-shared class.
77
- #
78
- # @param node [RuboCop::AST::IvasgnNode] the ivar-assignment node being visited
79
- # @return [void]
80
26
  def on_ivasgn(node)
81
- # A plain `@x = 1` parses as `(ivasgn :@x (int 1))` — two
82
- # children. The commissioner also visits the bare `(ivasgn :@x)`
83
- # node nested one level inside an `op_asgn`/`or_asgn` (`@x += 1`,
84
- # `@x ||= 1`) as its own `ivasgn` node with only one child — that
85
- # one is handled by `on_op_asgn`/`on_or_asgn` below instead, so
86
- # it's skipped here to avoid double-reporting the same mutation.
27
+ # Skips the bare one-child `ivasgn` nested in `op_asgn`/`or_asgn`; those handlers
28
+ # report it, so this avoids a double offense.
87
29
  return unless node.children.size == 2
88
30
 
89
31
  check(node, node.children.first)
90
32
  end
91
33
 
92
- # Flags a plain `@ivar += ...` (or similar) compound assignment inside a
93
- # thread-shared class.
94
- #
95
- # @param node [RuboCop::AST::OpAsgnNode] the compound-assignment node being visited
96
- # @return [void]
97
34
  def on_op_asgn(node)
98
- # `@x += 1` parses as `(op_asgn (ivasgn :@x) :+ (int 1))` — the
99
- # target is an `ivasgn` node carrying just the name (no value
100
- # child, unlike a plain `@x = 1`), not an `ivar` node.
35
+ # The target of `@x += 1` is a value-less `ivasgn` node, not an `ivar`.
101
36
  ivar_node = node.children.first
102
37
  return unless ivar_node.is_a?(RuboCop::AST::Node) && ivar_node.ivasgn_type?
103
38
 
104
39
  check(node, ivar_node.children.first)
105
40
  end
106
41
 
107
- # Flags a plain `@ivar ||= ...` assignment inside a thread-shared class.
108
- #
109
- # @param node [RuboCop::AST::OrAsgnNode] the `||=` assignment node being visited
110
- # @return [void]
111
42
  def on_or_asgn(node)
112
43
  on_op_asgn(node)
113
44
  end
114
45
 
115
- # Flags a plain `@ivar << ...` or `@ivar[k] = v` mutation inside a thread-shared
116
- # class.
117
- #
118
- # @param node [RuboCop::AST::SendNode] the `<<` or `[]=` send node being visited
119
- # @return [void]
120
46
  def on_send(node)
121
47
  return unless RESTRICT_ON_SEND.include?(node.method_name)
122
48
 
123
49
  receiver = node.receiver
124
50
  return unless receiver
125
51
 
126
- # `@ivar << x` — the receiver is the ivar.
127
- # `@ivar[k] = v` — the receiver is a `send(@ivar, :[], k)`, whose
128
- # own receiver is the ivar (`node.receiver.receiver`).
52
+ # `@ivar << x` has the ivar as receiver; `@ivar[k] = v` has it one `send` deeper.
129
53
  ivar_node = if receiver.ivar_type?
130
54
  receiver
131
55
  elsif receiver.send_type? && receiver.receiver&.ivar_type?
@@ -149,14 +73,7 @@ module RuboCop
149
73
  !!enclosing_class_name(node)&.then { |name| THREAD_SHARED_CLASSES.include?(name) }
150
74
  end
151
75
 
152
- # Walks outward to the nearest enclosing `class` node and returns
153
- # its own short name (`Dispatcher`, not the fully-qualified
154
- # `Hecks::Runtime::Dispatcher`) — good enough to match this repo's
155
- # own one-class-per-file layout without needing full namespace
156
- # resolution, and avoids a false negative on `class Dispatcher`
157
- # bodies that reopen the class from inside the `Hecks::Runtime`
158
- # module (this repo's actual style) as much as one written as
159
- # `class Hecks::Runtime::Dispatcher`.
76
+ # Uses the short class name so both nested and `Hecks::Runtime::Dispatcher` styles match.
160
77
  def enclosing_class_name(node)
161
78
  klass = node.each_ancestor(:class).first
162
79
  return nil unless klass
@@ -165,13 +82,7 @@ module RuboCop
165
82
  const_node.const_name.to_s.split("::").last
166
83
  end
167
84
 
168
- # `initialize` is where an ivar is set up for the first time —
169
- # before this object has been handed to a caller at all, so no
170
- # other thread can hold a reference to mutate concurrently with
171
- # it. Also exempts `initialize` methods defined on an object
172
- # reopened via `class << self` or nested module — `each_ancestor`
173
- # naturally stops at the nearest enclosing `def`, matching Ruby's
174
- # own method-scoping.
85
+ # An ivar set in `initialize` cannot yet be shared with another thread.
175
86
  def inside_initialize?(node)
176
87
  def_node = node.each_ancestor(:def, :defs).first
177
88
  return false unless def_node
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hecks
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.0
4
+ version: 2.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Young
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2026-09-27 00:00:00.000000000 Z
11
+ date: 2026-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prism
@@ -30,10 +30,12 @@ description: |
30
30
  Nothing is scripted: no handler body, no class you write, no schema
31
31
  you migrate.
32
32
  email:
33
- executables: []
33
+ executables:
34
+ - hecks
34
35
  extensions: []
35
36
  extra_rdoc_files: []
36
37
  files:
38
+ - exe/hecks
37
39
  - lib/hecks.rb
38
40
  - lib/hecks/adapters.rb
39
41
  - lib/hecks/adapters/driven.rb
@@ -94,17 +96,6 @@ files:
94
96
  - lib/hecks/behaviors/ir.rb
95
97
  - lib/hecks/behaviors/rspec.rb
96
98
  - lib/hecks/behaviors/runner.rb
97
- - lib/hecks/bench.rb
98
- - lib/hecks/bench/cli.rb
99
- - lib/hecks/bench/environment.rb
100
- - lib/hecks/bench/postgres_probe.rb
101
- - lib/hecks/bench/report.rb
102
- - lib/hecks/bench/ruby_runner.rb
103
- - lib/hecks/bench/run.rb
104
- - lib/hecks/bench/rust_runner.rb
105
- - lib/hecks/bench/stats.rb
106
- - lib/hecks/bench/suite.rb
107
- - lib/hecks/bench/workload.rb
108
99
  - lib/hecks/bluebook.rb
109
100
  - lib/hecks/bluebook/aggregate.rb
110
101
  - lib/hecks/bluebook/assembly.rb
@@ -199,13 +190,22 @@ files:
199
190
  - lib/hecks/bluebook/synthesizer.rb
200
191
  - lib/hecks/bluebook/translation.rb
201
192
  - lib/hecks/bluebook/value_object.rb
202
- - lib/hecks/codemod.rb
193
+ - lib/hecks/cache_dir.rb
194
+ - lib/hecks/cli.rb
195
+ - lib/hecks/cli/document.rb
196
+ - lib/hecks/cli/ir.rb
197
+ - lib/hecks/cli/mcp.rb
198
+ - lib/hecks/cli/mcp_door.rb
199
+ - lib/hecks/cli/model_check.rb
200
+ - lib/hecks/cli/project_cli.rb
201
+ - lib/hecks/cli/project_diagrams.rb
202
+ - lib/hecks/cli/run.rb
203
+ - lib/hecks/cli/smoke_test.rb
204
+ - lib/hecks/cli/stores.rb
203
205
  - lib/hecks/construct.rb
204
- - lib/hecks/corpus.rb
205
206
  - lib/hecks/deploy/bluebook/deploy.bluebook
206
207
  - lib/hecks/deploy/bluebook/deploy.hecksagon
207
208
  - lib/hecks/deploy/oidc.json
208
- - lib/hecks/doc/reference.rb
209
209
  - lib/hecks/embryonaut_bluebook.rb
210
210
  - lib/hecks/embryonaut_bluebook/lock.rb
211
211
  - lib/hecks/embryonaut_bluebook/shape.rb
@@ -246,47 +246,7 @@ files:
246
246
  - lib/hecks/framework/bluebook/privacy.bluebook
247
247
  - lib/hecks/framework/oidc.json
248
248
  - lib/hecks/freezer.rb
249
- - lib/hecks/fuzzing.rb
250
- - lib/hecks/fuzzing/bounded_exhaustive_expressions.rb
251
- - lib/hecks/fuzzing/combination_miner.rb
252
- - lib/hecks/fuzzing/concurrent_dispatch.rb
253
- - lib/hecks/fuzzing/coverage_campaign.rb
254
- - lib/hecks/fuzzing/differential.rb
255
- - lib/hecks/fuzzing/domain_generator.rb
256
- - lib/hecks/fuzzing/era_boundary.rb
257
- - lib/hecks/fuzzing/form_census.rb
258
- - lib/hecks/fuzzing/generated_domain_check.rb
259
- - lib/hecks/fuzzing/invalid_value_generator.rb
260
- - lib/hecks/fuzzing/isolated_boot.rb
261
- - lib/hecks/fuzzing/nondeterministic.rb
262
- - lib/hecks/fuzzing/persistence_parity.rb
263
- - lib/hecks/fuzzing/properties.rb
264
- - lib/hecks/fuzzing/properties/corrections.rb
265
- - lib/hecks/fuzzing/properties/dispatch_and_mutations.rb
266
- - lib/hecks/fuzzing/properties/guards.rb
267
- - lib/hecks/fuzzing/properties/invariants_and_aggregation.rb
268
- - lib/hecks/fuzzing/properties/lifecycle_and_replay.rb
269
- - lib/hecks/fuzzing/properties/outbox.rb
270
- - lib/hecks/fuzzing/properties/querying.rb
271
- - lib/hecks/fuzzing/qa_settings.rb
272
- - lib/hecks/fuzzing/replay.rb
273
- - lib/hecks/fuzzing/rotation_priority.rb
274
- - lib/hecks/fuzzing/rust_gap_manifest.rb
275
- - lib/hecks/fuzzing/self_consistency.rb
276
- - lib/hecks/fuzzing/sequence_generator.rb
277
- - lib/hecks/fuzzing/sequence_generator/adversary.rb
278
- - lib/hecks/fuzzing/sequence_generator/catalog.rb
279
- - lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb
280
- - lib/hecks/fuzzing/sequence_generator/picker.rb
281
- - lib/hecks/fuzzing/sequence_generator/query_binding.rb
282
- - lib/hecks/fuzzing/sequence_generator/step_builder.rb
283
- - lib/hecks/fuzzing/shrinker.rb
284
- - lib/hecks/fuzzing/structural_skips.rb
285
- - lib/hecks/fuzzing/sweep_depth.rb
286
- - lib/hecks/fuzzing/target_capabilities.rb
287
- - lib/hecks/fuzzing/value_generator.rb
288
249
  - lib/hecks/grammar.rb
289
- - lib/hecks/grammar/evolve.rb
290
250
  - lib/hecks/grammar/expression.bluebook
291
251
  - lib/hecks/grammar/expression_operators.json
292
252
  - lib/hecks/grammar/grammar.hecksagon
@@ -318,6 +278,7 @@ files:
318
278
  - lib/hecks/language/world/wiring.bluebook
319
279
  - lib/hecks/language/world/world.bluebook
320
280
  - lib/hecks/literal.rb
281
+ - lib/hecks/mcp_door_scope.rb
321
282
  - lib/hecks/mcp_stdio_guard.rb
322
283
  - lib/hecks/naming.rb
323
284
  - lib/hecks/ports.rb
@@ -360,6 +321,7 @@ files:
360
321
  - lib/hecks/ports/persistence/plugins/era/expected_era.rb
361
322
  - lib/hecks/ports/persistence/plugins/era/lineage.rb
362
323
  - lib/hecks/ports/persistence/plugins/era/postgres_era.rb
324
+ - lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb
363
325
  - lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb
364
326
  - lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb
365
327
  - lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb
@@ -460,7 +422,6 @@ files:
460
422
  - lib/hecks/projector/ir_projector.rb
461
423
  - lib/hecks/projector/narrate_projector.rb
462
424
  - lib/hecks/projector/target.rb
463
- - lib/hecks/query_ir.rb
464
425
  - lib/hecks/query_specification.rb
465
426
  - lib/hecks/query_specification/common/authorization_spec.rb
466
427
  - lib/hecks/query_specification/common/comparators.rb
@@ -481,6 +442,16 @@ files:
481
442
  - lib/hecks/query_specification/read_model/specification.rb
482
443
  - lib/hecks/release/gem_pin.rb
483
444
  - lib/hecks/release/gem_pin/published_versions.rb
445
+ - lib/hecks/release/runner.rb
446
+ - lib/hecks/release/runner/ci_publisher.rb
447
+ - lib/hecks/release/runner/commands.rb
448
+ - lib/hecks/release/runner/console.rb
449
+ - lib/hecks/release/runner/gem_publisher.rb
450
+ - lib/hecks/release/runner/git.rb
451
+ - lib/hecks/release/runner/npm_publisher.rb
452
+ - lib/hecks/release/runner/preflight.rb
453
+ - lib/hecks/release/runner/published.rb
454
+ - lib/hecks/release/runner/tagger.rb
484
455
  - lib/hecks/rendering.rb
485
456
  - lib/hecks/router.rb
486
457
  - lib/hecks/router/namespace_installer.rb
@@ -1,74 +0,0 @@
1
- require "optparse"
2
- require_relative "suite"
3
- require_relative "report"
4
-
5
- module Hecks
6
- module Bench
7
- # The command line behind `bin/bench`: parses flags, runs the `Suite`, prints the report.
8
- #
9
- # Kept in `lib/` so a spec can drive it with a tiny configuration and read what it
10
- # prints, rather than shelling out to a script.
11
- module CLI
12
- # The defaults `bin/bench` runs with when no flag says otherwise.
13
- DEFAULTS = { domains: %w[pizzas banking], targets: Suite::TARGETS, warmup: 200, iterations: 1000,
14
- runs: 3 }.freeze
15
-
16
- module_function
17
-
18
- # Runs the benchmark described by the command line and prints its report.
19
- #
20
- # @param argv [Array<String>] the command-line arguments
21
- # @param out [#puts] where the report goes
22
- # @param err [#puts] where progress and usage errors go
23
- # @return [Integer] the process exit status: 0 on success, 2 for a usage error
24
- def run(argv, out: $stdout, err: $stderr)
25
- options = parse(argv)
26
- result = Suite.call(options.fetch(:config), log: err)
27
- out.puts(options[:format] == "json" ? Report.json(result) : Report.markdown(result))
28
- File.write(options[:output], Report.json(result)) if options[:output]
29
- 0
30
- rescue OptionParser::ParseError, ArgumentError => e
31
- err.puts "bin/bench: #{e.message}"
32
- 2
33
- end
34
-
35
- # Turns command-line arguments into a configuration and output choices.
36
- #
37
- # @param argv [Array<String>] the command-line arguments
38
- # @return [Hash{Symbol => Object}] `:config` (a `Suite::Config`), `:format` and `:output`
39
- # @raise [OptionParser::ParseError] on an unknown or malformed flag
40
- def parse(argv)
41
- values = DEFAULTS.dup
42
- extras = { format: "markdown", output: nil, rust_binary: nil }
43
- parser(values, extras).parse(argv.dup)
44
- { config: Suite::Config.new(**values, rust_binary: extras[:rust_binary]),
45
- format: extras[:format], output: extras[:output] }
46
- end
47
-
48
- # Builds the flag parser.
49
- #
50
- # @param values [Hash{Symbol => Object}] the `Suite::Config` fields, filled in as flags parse
51
- # @param extras [Hash{Symbol => Object}] the output choices, filled in as flags parse
52
- # @return [OptionParser] the parser
53
- def parser(values, extras)
54
- OptionParser.new do |opts|
55
- opts.banner = "usage: bin/bench [options]"
56
- opts.on("--domain NAMES", Array, "pizzas, banking (default: both)") { |v| values[:domains] = v }
57
- opts.on("--targets NAMES", Array, "#{Suite::TARGETS.join(', ')} (default: all)") { |v| values[:targets] = v }
58
- opts.on("--iterations N", Integer, "timed cycles per run (default #{DEFAULTS[:iterations]})") do |v|
59
- values[:iterations] = v
60
- end
61
- opts.on("--warmup N", Integer, "discarded cycles before timing (default #{DEFAULTS[:warmup]})") do |v|
62
- values[:warmup] = v
63
- end
64
- opts.on("--runs N", Integer, "fresh boots per target, median reported (default #{DEFAULTS[:runs]})") do |v|
65
- values[:runs] = v
66
- end
67
- opts.on("--rust-binary PATH", "use this `rust` binary instead of building one") { |v| extras[:rust_binary] = v }
68
- opts.on("--format FORMAT", %w[markdown json], "markdown (default) or json") { |v| extras[:format] = v }
69
- opts.on("--output PATH", "also write the full JSON result here") { |v| extras[:output] = v }
70
- end
71
- end
72
- end
73
- end
74
- end
@@ -1,100 +0,0 @@
1
- require "etc"
2
- require "open3"
3
-
4
- module Hecks
5
- module Bench
6
- # A description of the machine and toolchain a benchmark ran on.
7
- #
8
- # A number without its hardware is not reproducible, so every report carries
9
- # this. Each probe is best effort: a missing tool becomes `"unknown"` rather
10
- # than an error, since the benchmark itself is still valid without it.
11
- module Environment
12
- module_function
13
-
14
- # Collects the machine and toolchain facts a report should carry.
15
- #
16
- # @return [Hash{Symbol => Object}] `:cpu`, `:cores`, `:memory_gib`, `:os`, `:ruby`,
17
- # `:yjit`, `:rustc`, `:cargo`, `:hecks`, `:commit` and `:load_average`
18
- def describe
19
- {
20
- cpu: cpu, cores: Etc.nprocessors, memory_gib: memory_gib, os: os,
21
- ruby: RUBY_DESCRIPTION, yjit: yjit?,
22
- rustc: capture("rustc", "-V"), cargo: capture("cargo", "-V"),
23
- hecks: Hecks::VERSION, commit: commit, load_average: load_average
24
- }
25
- end
26
-
27
- # Reads the one-minute load average, the quickest sign that something else was
28
- # busy while a benchmark ran. `Suite.call` reads it before and after and reports both.
29
- #
30
- # @return [Float, nil] the one-minute load average, or nil when it cannot be read
31
- def load_average
32
- text = RUBY_PLATFORM.include?("darwin") ? capture("sysctl", "-n", "vm.loadavg").delete("{}") : File.read("/proc/loadavg")
33
- text.split.first.to_f.round(2)
34
- rescue SystemCallError
35
- nil
36
- end
37
-
38
- # Names the processor.
39
- #
40
- # @return [String] the CPU model, or `"unknown"`
41
- def cpu
42
- return capture("sysctl", "-n", "machdep.cpu.brand_string") if RUBY_PLATFORM.include?("darwin")
43
-
44
- model = File.foreach("/proc/cpuinfo").find { |line| line.start_with?("model name") }
45
- model ? model.split(":", 2).last.strip : "unknown"
46
- rescue SystemCallError
47
- "unknown"
48
- end
49
-
50
- # Reads installed memory.
51
- #
52
- # @return [Float, String] physical memory in GiB, or `"unknown"`
53
- def memory_gib
54
- bytes =
55
- if RUBY_PLATFORM.include?("darwin")
56
- capture("sysctl", "-n", "hw.memsize").to_i
57
- else
58
- File.read("/proc/meminfo")[/MemTotal:\s+(\d+)/, 1].to_i * 1024
59
- end
60
- bytes.zero? ? "unknown" : (bytes / (1024.0**3)).round(1)
61
- rescue SystemCallError
62
- "unknown"
63
- end
64
-
65
- # Names the operating system.
66
- #
67
- # @return [String] the OS name and version, or `"unknown"`
68
- def os
69
- return "macOS #{capture('sw_vers', '-productVersion')} (#{capture('uname', '-m')})" if RUBY_PLATFORM.include?("darwin")
70
-
71
- capture("uname", "-sr")
72
- end
73
-
74
- # Says whether Ruby's `YJIT` compiler was running.
75
- #
76
- # @return [Boolean] true when `YJIT` is enabled in this process
77
- def yjit?
78
- defined?(RubyVM::YJIT) ? RubyVM::YJIT.enabled? : false
79
- end
80
-
81
- # Names the Hecks source revision under test.
82
- #
83
- # @return [String] the short commit hash, or `"unknown"` outside a git checkout
84
- def commit
85
- capture("git", "-C", File.expand_path("../../..", __dir__), "rev-parse", "--short", "HEAD")
86
- end
87
-
88
- # Runs a command and returns its first line of output.
89
- #
90
- # @param command [Array<String>] the program and its arguments
91
- # @return [String] the trimmed first line of stdout, or `"unknown"` if it cannot run
92
- def capture(*command)
93
- out, status = Open3.capture2(*command, err: File::NULL)
94
- status.success? && !out.strip.empty? ? out.lines.first.strip : "unknown"
95
- rescue SystemCallError
96
- "unknown"
97
- end
98
- end
99
- end
100
- end
@@ -1,41 +0,0 @@
1
- module Hecks
2
- module Bench
3
- # Decides whether the Postgres targets can run at all.
4
- #
5
- # Postgres is optional. A machine with no server, or without the `pg` gem, gets a
6
- # skipped target and a sentence saying why, never a stack trace. Connection
7
- # settings come from libpq's own environment (`PGHOST`, `PGPORT`, `PGUSER`,
8
- # `PGPASSWORD`), the same way the fuzzer's Postgres adapters read them.
9
- module PostgresProbe
10
- module_function
11
-
12
- # Tries to reach the server's maintenance database.
13
- #
14
- # @return [String, nil] nil when a server answered, otherwise one sentence saying why
15
- # the Postgres targets cannot run
16
- def unavailable_reason
17
- require "pg"
18
- PG.connect(dbname: "postgres", connect_timeout: 2).close
19
- nil
20
- rescue LoadError
21
- "the `pg` gem is not installed"
22
- rescue PG::Error => e
23
- "no Postgres server is reachable (#{e.message.lines.first.to_s.strip}); start one, or point " \
24
- "PGHOST, PGPORT and PGUSER at one"
25
- end
26
-
27
- # Reads the server's version for the report's environment block.
28
- #
29
- # @return [String] the `server_version` setting, or `"unknown"` if it cannot be read
30
- def server_version
31
- require "pg"
32
- connection = PG.connect(dbname: "postgres", connect_timeout: 2)
33
- connection.exec("SHOW server_version").getvalue(0, 0)
34
- rescue LoadError, PG::Error
35
- "unknown"
36
- ensure
37
- connection&.close
38
- end
39
- end
40
- end
41
- end
@@ -1,116 +0,0 @@
1
- require "json"
2
-
3
- module Hecks
4
- module Bench
5
- # Renders a `Suite.call` result as Markdown or JSON.
6
- #
7
- # The Markdown is what `docs/benchmarks.md` pastes in. It states the machine, the
8
- # counts and the skipped targets next to the table, so a copied table is never a
9
- # bare number.
10
- module Report
11
- module_function
12
-
13
- # Renders the whole report as Markdown.
14
- #
15
- # @param result [Hash] the value `Suite.call` returned
16
- # @return [String] the environment, the configuration, the table and any skipped targets
17
- def markdown(result)
18
- [environment_block(result[:environment]), configuration_block(result[:config]),
19
- table(result[:results]), floor_block(result[:results]), skipped_block(result[:skipped])]
20
- .compact.join("\n\n") << "\n"
21
- end
22
-
23
- # Renders the whole report as JSON.
24
- #
25
- # @param result [Hash] the value `Suite.call` returned
26
- # @return [String] pretty-printed JSON of `result`
27
- def json(result)
28
- JSON.pretty_generate(result)
29
- end
30
-
31
- # Renders the results table.
32
- #
33
- # @param results [Array<Hash>] the `:results` of `Suite.call`
34
- # @return [String] a Markdown table with one row per domain and target
35
- def table(results)
36
- header = ["| domain | target | commands/s | range across runs | p50 (us) | p99 (us) | drift |",
37
- "|---|---|---:|---:|---:|---:|---:|"]
38
- (header + results.map { |entry| row(entry) }).join("\n")
39
- end
40
-
41
- # Renders one table row.
42
- #
43
- # @param entry [Hash] one aggregated result
44
- # @return [String] the row as Markdown
45
- def row(entry)
46
- median = entry[:median]
47
- low, high = entry[:throughput_range]
48
- cells = [entry[:domain], entry[:target], number(median[:throughput_per_s], 0),
49
- "#{number(low, 0)} to #{number(high, 0)}", number(median[:p50_us], 1),
50
- number(median[:p99_us], 1), number(median[:drift], 2)]
51
- "| #{cells.join(' | ')} |"
52
- end
53
-
54
- # Formats a number with thousands separators.
55
- #
56
- # @param value [Numeric, nil] the number
57
- # @param places [Integer] digits after the decimal point
58
- # @return [String] the formatted number, or `"n/a"` for nil
59
- def number(value, places)
60
- return "n/a" if value.nil?
61
-
62
- whole, fraction = format("%.#{places}f", value).split(".")
63
- [whole.gsub(/(\d)(?=(\d{3})+\z)/, '\1,'), fraction].compact.join(".")
64
- end
65
-
66
- # Renders the machine and toolchain.
67
- #
68
- # @param environment [Hash] the `:environment` of `Suite.call`
69
- # @return [String] a Markdown bullet list
70
- def environment_block(environment)
71
- load = environment[:load_average]
72
- lines = [
73
- "- CPU: #{environment[:cpu]} (#{environment[:cores]} cores), #{environment[:memory_gib]} GiB",
74
- "- OS: #{environment[:os]}",
75
- "- Ruby: #{environment[:ruby]} (YJIT #{environment[:yjit] ? 'on' : 'off'})",
76
- "- Rust: #{environment[:rustc]}; #{environment[:cargo]}",
77
- "- Hecks: #{environment[:hecks]} at #{environment[:commit]}",
78
- "- Load average (1 min) before and after: #{load[:before]} and #{load[:after]}"
79
- ]
80
- lines << "- Postgres: #{environment[:postgres]}" if environment[:postgres]
81
- lines.join("\n")
82
- end
83
-
84
- # Renders how hard the run pushed.
85
- #
86
- # @param config [Hash] the `:config` of `Suite.call`
87
- # @return [String] one sentence with the warmup, iteration and run counts
88
- def configuration_block(config)
89
- "Warmup #{config[:warmup]} cycles, then #{config[:iterations]} timed cycles per run, " \
90
- "median of #{config[:runs]} run(s), domains: #{config[:domains].join(', ')}."
91
- end
92
-
93
- # Renders the Rust round-trip floor, if a Rust target ran.
94
- #
95
- # @param results [Array<Hash>] the `:results` of `Suite.call`
96
- # @return [String, nil] a sentence naming each domain's floor, or nil without a Rust result
97
- def floor_block(results)
98
- floors = results.select { |entry| entry[:target] == "rust" }
99
- .map { |entry| "#{entry[:domain]} #{number(entry[:median][:roundtrip_floor_p50_us], 1)} us" }
100
- return nil if floors.empty?
101
-
102
- "Rust pipe round-trip floor (p50, a step refused at once): #{floors.join(', ')}."
103
- end
104
-
105
- # Renders the targets that did not run.
106
- #
107
- # @param skipped [Array<Hash>] the `:skipped` of `Suite.call`
108
- # @return [String, nil] one line per skipped target, or nil when none were skipped
109
- def skipped_block(skipped)
110
- return nil if skipped.empty?
111
-
112
- (["Skipped:"] + skipped.map { |entry| "- #{entry[:target]}: #{entry[:reason]}" }).join("\n")
113
- end
114
- end
115
- end
116
- end