hecks 1.3.0 → 1.4.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 (355) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hecks/adapters/driven/claude_code.rb +7 -7
  3. data/lib/hecks/adapters/driven/d1.rb +187 -23
  4. data/lib/hecks/adapters/driven/folder.rb +10 -10
  5. data/lib/hecks/adapters/driven/google_authentication.rb +8 -8
  6. data/lib/hecks/adapters/driven/governance_authorization.rb +31 -13
  7. data/lib/hecks/adapters/driven/heki/journal.rb +5 -4
  8. data/lib/hecks/adapters/driven/heki/saga_store.rb +5 -5
  9. data/lib/hecks/adapters/driven/heki.rb +13 -7
  10. data/lib/hecks/adapters/driven/identity_registry.rb +2 -2
  11. data/lib/hecks/adapters/driven/in_memory_ordering.rb +3 -3
  12. data/lib/hecks/adapters/driven/lambda/client.rb +34 -9
  13. data/lib/hecks/adapters/driven/lambda.rb +39 -33
  14. data/lib/hecks/adapters/driven/local_storage.rb +17 -10
  15. data/lib/hecks/adapters/driven/memory.rb +205 -9
  16. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +1 -1
  17. data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
  18. data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
  19. data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
  20. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
  21. data/lib/hecks/adapters/driven/postgres.rb +175 -28
  22. data/lib/hecks/adapters/driven/prism.rb +4 -4
  23. data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
  24. data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
  25. data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
  26. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
  27. data/lib/hecks/adapters/driven/sqlite.rb +181 -21
  28. data/lib/hecks/adapters/driven.rb +4 -4
  29. data/lib/hecks/adapters/driving/github_webhook.rb +18 -18
  30. data/lib/hecks/behaviors/dsl.rb +2 -2
  31. data/lib/hecks/behaviors/expectations.rb +23 -23
  32. data/lib/hecks/behaviors/ir.rb +1 -1
  33. data/lib/hecks/behaviors/rspec.rb +1 -1
  34. data/lib/hecks/behaviors/runner.rb +2 -2
  35. data/lib/hecks/behaviors.rb +1 -1
  36. data/lib/hecks/bluebook/aggregate.rb +13 -13
  37. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +10 -10
  38. data/lib/hecks/bluebook/assembly/build.rb +1 -1
  39. data/lib/hecks/bluebook/assembly/contract.rb +39 -16
  40. data/lib/hecks/bluebook/assembly/contracts.rb +40 -38
  41. data/lib/hecks/bluebook/assembly/marks.rb +18 -18
  42. data/lib/hecks/bluebook/assembly/specializer.rb +19 -21
  43. data/lib/hecks/bluebook/assembly.rb +9 -9
  44. data/lib/hecks/bluebook/attribute.rb +9 -9
  45. data/lib/hecks/bluebook/behaviour/aggregate.rb +11 -11
  46. data/lib/hecks/bluebook/behaviour/attribute.rb +5 -5
  47. data/lib/hecks/bluebook/behaviour/chapter.rb +23 -5
  48. data/lib/hecks/bluebook/behaviour/command.rb +23 -23
  49. data/lib/hecks/bluebook/behaviour/domain_port.rb +7 -7
  50. data/lib/hecks/bluebook/behaviour/entity.rb +8 -8
  51. data/lib/hecks/bluebook/behaviour/hexagon.rb +4 -4
  52. data/lib/hecks/bluebook/behaviour/lifecycle.rb +5 -5
  53. data/lib/hecks/bluebook/behaviour/policy.rb +12 -12
  54. data/lib/hecks/bluebook/behaviour/process_manager.rb +7 -7
  55. data/lib/hecks/bluebook/behaviour/query.rb +1 -1
  56. data/lib/hecks/bluebook/behaviour/read_model.rb +8 -8
  57. data/lib/hecks/bluebook/behaviour/traits.rb +12 -12
  58. data/lib/hecks/bluebook/behaviour/value_object.rb +6 -6
  59. data/lib/hecks/bluebook/capabilities.rb +27 -0
  60. data/lib/hecks/bluebook/chapter.rb +28 -9
  61. data/lib/hecks/bluebook/command.rb +12 -12
  62. data/lib/hecks/bluebook/domain_port.rb +9 -9
  63. data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
  64. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
  65. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +96 -96
  66. data/lib/hecks/bluebook/dsl/attribute_collector.rb +41 -41
  67. data/lib/hecks/bluebook/dsl/binding_proxy.rb +22 -2
  68. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +111 -74
  69. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +48 -30
  70. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
  71. data/lib/hecks/bluebook/dsl/command_builder.rb +103 -103
  72. data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
  73. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
  74. data/lib/hecks/bluebook/dsl/entity_builder.rb +56 -56
  75. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
  76. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +89 -30
  77. data/lib/hecks/bluebook/dsl/identity_declaration.rb +17 -17
  78. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
  79. data/lib/hecks/bluebook/dsl/policy_builder.rb +30 -21
  80. data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
  81. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
  82. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +35 -35
  83. data/lib/hecks/bluebook/dsl/query_builder.rb +5 -5
  84. data/lib/hecks/bluebook/dsl/read_model_builder.rb +34 -34
  85. data/lib/hecks/bluebook/dsl/rule_reference.rb +41 -39
  86. data/lib/hecks/bluebook/dsl/translation_builder.rb +9 -9
  87. data/lib/hecks/bluebook/dsl/value_object_builder.rb +16 -16
  88. data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
  89. data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
  90. data/lib/hecks/bluebook/entity.rb +11 -11
  91. data/lib/hecks/bluebook/expression/ast_json.rb +20 -20
  92. data/lib/hecks/bluebook/expression/ast_reader.rb +3 -3
  93. data/lib/hecks/bluebook/expression/canonical_form.rb +9 -9
  94. data/lib/hecks/bluebook/expression/evaluator.rb +18 -18
  95. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +18 -18
  96. data/lib/hecks/bluebook/expression/resolver.rb +60 -62
  97. data/lib/hecks/bluebook/hexagon.rb +1 -1
  98. data/lib/hecks/bluebook/lifecycle.rb +1 -1
  99. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -1
  100. data/lib/hecks/bluebook/meta_validator/judge.rb +101 -87
  101. data/lib/hecks/bluebook/meta_validator/plan.rb +39 -39
  102. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -2
  103. data/lib/hecks/bluebook/meta_validator/readings.rb +43 -43
  104. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +44 -37
  105. data/lib/hecks/bluebook/meta_validator/shapes.rb +25 -21
  106. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +145 -31
  107. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +6 -6
  108. data/lib/hecks/bluebook/meta_validator/world_judge.rb +5 -5
  109. data/lib/hecks/bluebook/meta_validator.rb +70 -70
  110. data/lib/hecks/bluebook/model_check.rb +170 -84
  111. data/lib/hecks/bluebook/pattern_subset.rb +9 -9
  112. data/lib/hecks/bluebook/policy.rb +15 -13
  113. data/lib/hecks/bluebook/process_manager.rb +14 -14
  114. data/lib/hecks/bluebook/project_register.rb +6 -6
  115. data/lib/hecks/bluebook/query.rb +4 -4
  116. data/lib/hecks/bluebook/read_model.rb +14 -14
  117. data/lib/hecks/bluebook/reference.rb +8 -8
  118. data/lib/hecks/bluebook/smoke_test.rb +19 -19
  119. data/lib/hecks/bluebook/synthesizer.rb +12 -12
  120. data/lib/hecks/bluebook/translation.rb +4 -4
  121. data/lib/hecks/bluebook/value_object.rb +6 -6
  122. data/lib/hecks/bluebook.rb +2 -2
  123. data/lib/hecks/codemod/legacy_dispatch_args.rb +299 -0
  124. data/lib/hecks/codemod/legacy_dispatch_recorder.rb +186 -0
  125. data/lib/hecks/codemod.rb +36 -35
  126. data/lib/hecks/construct.rb +6 -6
  127. data/lib/hecks/corpus.rb +317 -0
  128. data/lib/hecks/deprecation.rb +95 -0
  129. data/lib/hecks/doc/reference.rb +19 -19
  130. data/lib/hecks/embryonaut_bluebook.rb +11 -11
  131. data/lib/hecks/facade/cli_door.rb +69 -10
  132. data/lib/hecks/facade/cli_runner.rb +105 -24
  133. data/lib/hecks/facade/command_request.rb +23 -0
  134. data/lib/hecks/facade/handle.rb +79 -32
  135. data/lib/hecks/facade/json_door.rb +106 -25
  136. data/lib/hecks/facade/surface/aggregate_door.rb +42 -27
  137. data/lib/hecks/facade/surface/chapter.rb +26 -17
  138. data/lib/hecks/facade/surface.rb +16 -3
  139. data/lib/hecks/facade.rb +15 -4
  140. data/lib/hecks/forms/app.rb +46 -30
  141. data/lib/hecks/forms/command_form_renderer.rb +70 -9
  142. data/lib/hecks/forms/field_renderer.rb +142 -6
  143. data/lib/hecks/forms/field_shape.rb +180 -19
  144. data/lib/hecks/forms/html.rb +51 -7
  145. data/lib/hecks/forms/index_renderer.rb +14 -2
  146. data/lib/hecks/forms/params.rb +120 -23
  147. data/lib/hecks/forms/port_argument.rb +2 -2
  148. data/lib/hecks/forms/query_form_renderer.rb +2 -2
  149. data/lib/hecks/forms/record_renderer.rb +2 -2
  150. data/lib/hecks/forms/record_table.rb +1 -1
  151. data/lib/hecks/forms/value_object_shape.rb +3 -3
  152. data/lib/hecks/forms.rb +24 -4
  153. data/lib/hecks/fqn.rb +1 -1
  154. data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
  155. data/lib/hecks/framework.rb +48 -17
  156. data/lib/hecks/freezer.rb +11 -11
  157. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +90 -90
  158. data/lib/hecks/fuzzing/combination_miner.rb +119 -0
  159. data/lib/hecks/fuzzing/concurrent_dispatch.rb +140 -45
  160. data/lib/hecks/fuzzing/coverage_campaign.rb +118 -0
  161. data/lib/hecks/fuzzing/differential.rb +158 -0
  162. data/lib/hecks/fuzzing/domain_generator.rb +694 -0
  163. data/lib/hecks/fuzzing/era_boundary.rb +37 -18
  164. data/lib/hecks/fuzzing/form_census.rb +35 -20
  165. data/lib/hecks/fuzzing/generated_domain_check.rb +95 -0
  166. data/lib/hecks/fuzzing/invalid_value_generator.rb +6 -6
  167. data/lib/hecks/fuzzing/isolated_boot.rb +62 -62
  168. data/lib/hecks/fuzzing/nondeterministic.rb +67 -0
  169. data/lib/hecks/fuzzing/persistence_parity.rb +19 -21
  170. data/lib/hecks/fuzzing/properties/corrections.rb +9 -9
  171. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +154 -49
  172. data/lib/hecks/fuzzing/properties/guards.rb +42 -42
  173. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +32 -32
  174. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +22 -35
  175. data/lib/hecks/fuzzing/properties/outbox.rb +24 -24
  176. data/lib/hecks/fuzzing/properties/querying.rb +17 -17
  177. data/lib/hecks/fuzzing/properties.rb +64 -40
  178. data/lib/hecks/fuzzing/qa_settings.rb +152 -0
  179. data/lib/hecks/fuzzing/replay.rb +114 -114
  180. data/lib/hecks/fuzzing/rotation_priority.rb +10 -10
  181. data/lib/hecks/fuzzing/rust_gap_manifest.rb +113 -0
  182. data/lib/hecks/fuzzing/self_consistency.rb +141 -112
  183. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +35 -35
  184. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +18 -11
  185. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +13 -12
  186. data/lib/hecks/fuzzing/sequence_generator/picker.rb +21 -12
  187. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +58 -31
  188. data/lib/hecks/fuzzing/sequence_generator.rb +111 -23
  189. data/lib/hecks/fuzzing/shrinker.rb +197 -0
  190. data/lib/hecks/fuzzing/structural_skips.rb +23 -130
  191. data/lib/hecks/fuzzing/sweep_depth.rb +4 -4
  192. data/lib/hecks/fuzzing/target_capabilities.rb +49 -18
  193. data/lib/hecks/fuzzing/value_generator.rb +14 -14
  194. data/lib/hecks/fuzzing.rb +5 -0
  195. data/lib/hecks/grammar/evolve.rb +10 -10
  196. data/lib/hecks/grammar.rb +7 -7
  197. data/lib/hecks/ir.rb +13 -13
  198. data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
  199. data/lib/hecks/language/bluebook/policy.bluebook +11 -1
  200. data/lib/hecks/language/bluebook/vocabulary.bluebook +348 -13
  201. data/lib/hecks/language/oidc.json +5 -0
  202. data/lib/hecks/literal.rb +9 -9
  203. data/lib/hecks/naming.rb +25 -25
  204. data/lib/hecks/ports/access_control.rb +58 -2
  205. data/lib/hecks/ports/agent/answers.rb +83 -6
  206. data/lib/hecks/ports/agent.rb +119 -35
  207. data/lib/hecks/ports/authentication.rb +44 -4
  208. data/lib/hecks/ports/authorization.rb +53 -11
  209. data/lib/hecks/ports/clock.rb +42 -23
  210. data/lib/hecks/ports/extraction.rb +16 -0
  211. data/lib/hecks/ports/identity_assignment.rb +24 -2
  212. data/lib/hecks/ports/identity_generation.rb +17 -3
  213. data/lib/hecks/ports/identity_resolution.rb +18 -1
  214. data/lib/hecks/ports/loading.rb +4 -0
  215. data/lib/hecks/ports/persistence/append_only.rb +172 -8
  216. data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
  217. data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
  218. data/lib/hecks/ports/persistence/execution.rb +4 -0
  219. data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
  220. data/lib/hecks/ports/persistence/plugin.rb +42 -4
  221. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
  222. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
  223. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
  224. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
  225. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
  226. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
  227. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
  228. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
  229. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
  230. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +118 -66
  231. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
  232. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +28 -5
  233. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
  234. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
  235. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
  236. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +33 -9
  237. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
  238. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +57 -4
  239. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +314 -90
  241. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
  242. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
  243. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
  244. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +42 -8
  245. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
  246. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
  247. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
  248. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -19
  249. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +5 -5
  250. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +1 -1
  251. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
  252. data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
  253. data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
  254. data/lib/hecks/ports/persistence/repository_factory.rb +23 -3
  255. data/lib/hecks/ports/persistence/state_codec.rb +319 -0
  256. data/lib/hecks/ports/persistence.rb +36 -1
  257. data/lib/hecks/ports/projection.rb +61 -7
  258. data/lib/hecks/ports/query/in_memory.rb +3 -3
  259. data/lib/hecks/ports/query/ordering.rb +6 -6
  260. data/lib/hecks/ports/query.rb +35 -0
  261. data/lib/hecks/projections/bootstrap_table.rb +112 -0
  262. data/lib/hecks/projections/diagrams.rb +75 -75
  263. data/lib/hecks/projections/glossary/html.rb +3 -3
  264. data/lib/hecks/projections/glossary/markdown.rb +3 -3
  265. data/lib/hecks/projections/glossary/mermaid.rb +1 -1
  266. data/lib/hecks/projections/glossary/sections.rb +1 -1
  267. data/lib/hecks/projections/glossary/sentences.rb +5 -5
  268. data/lib/hecks/projections/glossary.rb +15 -15
  269. data/lib/hecks/projections/ir.rb +1 -1
  270. data/lib/hecks/projections/model/deviations.rb +18 -17
  271. data/lib/hecks/projections/model.rb +25 -21
  272. data/lib/hecks/projections/oidc.rb +7 -7
  273. data/lib/hecks/projections/parser_table.rb +5 -5
  274. data/lib/hecks/projections/reference.rb +3 -3
  275. data/lib/hecks/projections/rust_vocabulary.rb +443 -0
  276. data/lib/hecks/projections/shape.rb +2 -2
  277. data/lib/hecks/projections/statements.rb +11 -11
  278. data/lib/hecks/projections/vocabulary.rb +9 -9
  279. data/lib/hecks/projections.rb +5 -3
  280. data/lib/hecks/projector/cli_projector.rb +29 -29
  281. data/lib/hecks/projector/docs_projector.rb +13 -13
  282. data/lib/hecks/projector/exporter.rb +42 -21
  283. data/lib/hecks/projector/ir_projector.rb +1 -1
  284. data/lib/hecks/projector/narrate_projector.rb +11 -11
  285. data/lib/hecks/projector/target.rb +13 -13
  286. data/lib/hecks/projector.rb +15 -15
  287. data/lib/hecks/query_ir.rb +47 -47
  288. data/lib/hecks/query_specification/common/comparators.rb +19 -3
  289. data/lib/hecks/query_specification/common/comparison.rb +109 -27
  290. data/lib/hecks/query_specification/common/dsl.rb +65 -9
  291. data/lib/hecks/query_specification/common/null_policy.rb +57 -13
  292. data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
  293. data/lib/hecks/query_specification/common/options.rb +25 -0
  294. data/lib/hecks/query_specification/field_path.rb +69 -15
  295. data/lib/hecks/query_specification/hop_path.rb +57 -20
  296. data/lib/hecks/query_specification/read_model/specification.rb +4 -0
  297. data/lib/hecks/rendering.rb +3 -3
  298. data/lib/hecks/router/namespace_installer.rb +3 -3
  299. data/lib/hecks/router.rb +1 -1
  300. data/lib/hecks/runtime/aggregate_lock.rb +11 -11
  301. data/lib/hecks/runtime/boot_gates.rb +3 -3
  302. data/lib/hecks/runtime/caller.rb +8 -8
  303. data/lib/hecks/runtime/capability_graph.rb +2 -2
  304. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +22 -25
  305. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +42 -63
  306. data/lib/hecks/runtime/command_interpreter.rb +159 -102
  307. data/lib/hecks/runtime/command_rules/admissibility.rb +69 -69
  308. data/lib/hecks/runtime/command_rules/arithmetic.rb +137 -91
  309. data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
  310. data/lib/hecks/runtime/command_rules/emission.rb +18 -1
  311. data/lib/hecks/runtime/command_rules/references.rb +35 -35
  312. data/lib/hecks/runtime/command_rules.rb +3 -0
  313. data/lib/hecks/runtime/dependency_planning.rb +11 -11
  314. data/lib/hecks/runtime/dispatcher.rb +283 -90
  315. data/lib/hecks/runtime/entity_element.rb +151 -67
  316. data/lib/hecks/runtime/entity_interpreter.rb +108 -82
  317. data/lib/hecks/runtime/errors.rb +19 -19
  318. data/lib/hecks/runtime/event.rb +6 -6
  319. data/lib/hecks/runtime/identity.rb +22 -22
  320. data/lib/hecks/runtime/instance.rb +39 -14
  321. data/lib/hecks/runtime/interpreting.rb +12 -12
  322. data/lib/hecks/runtime/invocation.rb +276 -0
  323. data/lib/hecks/runtime/loader.rb +14 -14
  324. data/lib/hecks/runtime/outbox.rb +23 -23
  325. data/lib/hecks/runtime/policy_interpreter.rb +54 -54
  326. data/lib/hecks/runtime/port_operation_interpreter.rb +22 -19
  327. data/lib/hecks/runtime/query_interpreter.rb +55 -64
  328. data/lib/hecks/runtime/reaction_invocation.rb +20 -20
  329. data/lib/hecks/runtime/read_model_interpreter.rb +40 -40
  330. data/lib/hecks/runtime/rebuild_sweep.rb +4 -4
  331. data/lib/hecks/runtime/reference_hop.rb +6 -6
  332. data/lib/hecks/runtime/refusal_wording.rb +92 -115
  333. data/lib/hecks/runtime/registry/saga_persistence.rb +21 -21
  334. data/lib/hecks/runtime/registry/verification.rb +36 -26
  335. data/lib/hecks/runtime/registry.rb +45 -28
  336. data/lib/hecks/runtime/remote_dispatcher.rb +38 -23
  337. data/lib/hecks/runtime/routing.rb +10 -153
  338. data/lib/hecks/runtime/saga_interpreter/correlation.rb +17 -17
  339. data/lib/hecks/runtime/saga_interpreter.rb +64 -64
  340. data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
  341. data/lib/hecks/runtime/tenant_check.rb +9 -9
  342. data/lib/hecks/runtime/tenant_scope.rb +5 -5
  343. data/lib/hecks/runtime/value/admission.rb +75 -30
  344. data/lib/hecks/runtime/value/coercion.rb +318 -127
  345. data/lib/hecks/runtime/value/entity_list_coercion.rb +34 -34
  346. data/lib/hecks/runtime/value.rb +21 -21
  347. data/lib/hecks/runtime.rb +7 -7
  348. data/lib/hecks/storehouse.rb +64 -64
  349. data/lib/hecks/version.rb +3 -3
  350. data/lib/hecks/vocabulary.rb +205 -4
  351. data/lib/hecks.rb +13 -11
  352. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +11 -11
  353. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +14 -12
  354. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +11 -11
  355. metadata +22 -2
@@ -1,146 +1,39 @@
1
1
  module Hecks
2
2
  module Fuzzing
3
- # WHAT A "NOT GENERATED FOR THIS DOMAIN" REFUSAL IS HIDING, PER VERB.
3
+ # What each query verb the differential comparison skipped was hiding.
4
4
  #
5
- # `RustConformanceHelpers#structurally_refused_verbs` drops every named
6
- # query/read model the compiled Rust kernel answers "is not generated
7
- # for this domain" from BOTH sides of the differential comparison —
8
- # correct (the refusal is codegen's own honest "I cannot execute this
9
- # construct at all", `rust/project/queries.rb`'s and `read_models.rb`'s
10
- # documented boundary), but SILENT: a sweep over a domain whose every
11
- # `offset`/`cursor`/`group_by`/`count`/`median` ask was dropped reads
12
- # as "agreed across all steps" with nothing on the record saying how
13
- # much of the domain was never compared at all. Worse, the drop keys
14
- # on Rust's wording alone, so a codegen regression that started
15
- # refusing a plain wheres-only query the same way would ALSO vanish
16
- # into "agreed" — the exact quiet divergence the practice hunts.
5
+ # `Differential.manifest_partition` drops a named query or read model
6
+ # from both sides of the Ruby/Rust comparison only when the binary's own
7
+ # manifest.json declares it `generated: false`. The drop is correct, but
8
+ # a sweep that dropped every `offset`/`cursor` ask would still read as
9
+ # "agreed across all steps". `bin/qa_sweep` therefore logs one Check per
10
+ # sweep naming every skipped verb and the construct family that caused
11
+ # it, and marks it Surprised when a family is outside
12
+ # `QualityControlDials::STRUCTURAL_REFUSAL_BOUNDARY`.
17
13
  #
18
- # This module attributes each dropped verb to the constructs its OWN
19
- # Ruby declaration carries, in the vocabulary `queries.rb`/
20
- # `read_models.rb`'s skip reasons already use, so `bin/qa_sweep` can
21
- # log one Check per sweep saying exactly which verbs were skipped and
22
- # WHY — and mark it Surprised whenever a skipped verb declares nothing
23
- # the dial `QualityControlDials::STRUCTURAL_REFUSAL_BOUNDARY` admits as
24
- # a reason to skip (a wheres-only query on plain fields, a rooted
25
- # read model with nothing but heads, a verb Ruby doesn't even declare).
26
- #
27
- # COARSER THAN CODEGEN'S OWN PREDICATE, ON PURPOSE. `query_where_skip_
28
- # reason` decides per where clause from the field's resolved KIND
29
- # (number/string/multi-member value object) — reproducing that here
30
- # would be a second copy of codegen's typing rules, drifting on its
31
- # own. Instead a literal-valued where is reported as `where_literal`,
32
- # a family the dial admits, and only shapes with NO admitted family at
33
- # all surprise. That trades some sensitivity for zero false surprises
34
- # on today's corpus; the Check's observation still names every skipped
35
- # verb with its constructs, so a human reading the sweep sees what was
36
- # accepted and can narrow the dial when codegen grows.
14
+ # The construct comes straight from the manifest entry, written by the
15
+ # generator branch that made the skip (`Projector::SkipReason`). This
16
+ # module used to guess it from the Ruby declaration's `to_h` keys, which
17
+ # was coarser than codegen's own decision and could drift from it.
37
18
  module StructuralSkips
38
19
  module_function
39
20
 
40
- # `Query#to_h`/`ReadModel#to_h` keys that, when present and
41
- # non-empty, are constructs codegen documents as (conditionally or
42
- # wholly) ungenerated — the same names as the dial's own vocabulary.
43
- QUERY_OPTION_KEYS = %i[order_by limit offset cursor consistency freshness authorization inspection
44
- index_hints scope_to].freeze
45
- READ_MODEL_OPTION_KEYS = %i[wheres order_by limit offset cursor consistency freshness authorization inspection
46
- index_hints group_by count median_field].freeze
47
-
48
- # One entry per skipped verb: `{ verb:, constructs: [...] }`, the
49
- # constructs sorted so the printed observation is stable across
50
- # seeds and runs.
51
- def attribute(bluebooks, verbs)
52
- verbs.sort.map { |verb| { verb: verb, constructs: constructs_of(bluebooks, verb) } }
21
+ # One entry per skipped verb: `{ verb:, constructs: [...] }`, sorted by
22
+ # verb so the printed observation is stable across seeds and runs. A
23
+ # verb the manifest doesn't declare answers `unknown`, which no
24
+ # boundary admits.
25
+ def attribute(gaps, verbs)
26
+ verbs.sort.map do |verb|
27
+ entry = gaps.not_generated(verb)
28
+ { verb: verb, constructs: entry ? [entry.fetch("construct")] : %w[unknown] }
29
+ end
53
30
  end
54
31
 
55
- # Every skipped verb whose constructs are NOT all inside `boundary`
56
- # — including a verb with no constructs at all (nothing explains the
57
- # skip) and a verb Ruby never declared (`unknown`).
32
+ # Every skipped verb whose constructs are not all inside `boundary`.
58
33
  def outside_boundary(attributed, boundary)
59
34
  admitted = boundary.map(&:to_s)
60
35
  attributed.select { |entry| entry[:constructs].empty? || (entry[:constructs] - admitted).any? }
61
36
  end
62
-
63
- def constructs_of(bluebooks, verb)
64
- if verb.include?("::")
65
- query = find_query(bluebooks, verb)
66
- return %w[unknown] unless query
67
-
68
- query_constructs(query)
69
- else
70
- model = find_read_model(bluebooks, verb)
71
- return %w[unknown] unless model
72
-
73
- read_model_constructs(model)
74
- end
75
- end
76
-
77
- # "Domain::Aggregate.Query" or "Domain::Aggregate.Entity.Query" — the
78
- # two named-query spellings `Fuzzing::SequenceGenerator`'s catalog
79
- # generates (entity queries stay one hop deep there).
80
- def find_query(bluebooks, verb)
81
- domain, rest = verb.split("::", 2)
82
- aggregate_name, *path = rest.to_s.split(".")
83
- aggregate = bluebooks[domain]&.aggregate(aggregate_name)
84
- return nil unless aggregate && path.any?
85
-
86
- owner = aggregate
87
- path[0...-1].each do |entity_name|
88
- owner = owner.entities.find { |entity| entity.hecks_name == entity_name }
89
- return nil unless owner
90
- end
91
- owner.query(path.last)
92
- end
93
-
94
- # "Domain.report_name" — the bare read-model form `Dispatcher#query`
95
- # routes by the absence of "::".
96
- def find_read_model(bluebooks, verb)
97
- domain, name = verb.split(".", 2)
98
- bluebooks[domain]&.read_models&.find { |model| model.query_name.to_s == name.to_s }
99
- end
100
-
101
- def query_constructs(query)
102
- spec = query.to_h
103
- constructs = QUERY_OPTION_KEYS.select { |key| present?(spec[key]) }.map(&:to_s)
104
- constructs << "null_semantics" if spec[:null_semantics] && spec[:null_semantics] != { mode: "native" }
105
- constructs << "no_wheres" if Array(spec[:wheres]).empty?
106
- constructs.concat(where_constructs(Array(spec[:wheres])))
107
- constructs.uniq.sort
108
- end
109
-
110
- def read_model_constructs(model)
111
- spec = model.to_h
112
- constructs = READ_MODEL_OPTION_KEYS.select { |key| present?(spec[key]) }.map(&:to_s)
113
- constructs << "null_semantics" if spec[:null_semantics] && spec[:null_semantics] != { mode: "native" }
114
- constructs << "rootless" if model.reference_target.nil?
115
- constructs.concat(where_constructs(Array(spec[:wheres])))
116
- constructs.uniq.sort
117
- end
118
-
119
- # The where-clause families `query_where_skip_reason` refuses by:
120
- # a `/` hop through a reference, a `.` walk into a nested field
121
- # (an entity-scoped or value-object path codegen may not resolve),
122
- # `none_in_state` (admitted by the vocabulary, deliberately not
123
- # generated), and any literal (non-Symbol) value, whose true wire
124
- # type codegen may not recover from the IR.
125
- def where_constructs(wheres)
126
- wheres.flat_map do |where|
127
- field = where[:field].to_s
128
- value = where[:value].to_s
129
- families = []
130
- families << "reference_hop_where" if field.include?("/")
131
- families << "where_nested_field" if field.include?(".")
132
- families << "where_none_in_state" if where[:op].to_s == "none_in_state"
133
- families << "where_literal" unless value.start_with?(":")
134
- families
135
- end
136
- end
137
-
138
- def present?(value)
139
- return false if value.nil? || value == false
140
- return value.any? if value.respond_to?(:empty?)
141
-
142
- true
143
- end
144
37
  end
145
38
  end
146
39
  end
@@ -1,13 +1,13 @@
1
1
  module Hecks
2
2
  module Fuzzing
3
- # HOW HARD ONE SWEEP FUZZES, AS A FUNCTION OF `Target.clean_streak`
3
+ # How hard one sweep fuzzes, as a function of `Target.clean_streak`
4
4
  # (qa/bluebook/quality_control.bluebook — that attribute's own comment
5
5
  # says what the streak means). The sibling of `RotationPriority`: the
6
6
  # ledger holds the number, `QualityControlDials::WIDENING_TIERS` holds
7
7
  # the policy, and this module is where the two meet — a pure function
8
8
  # of both, nothing else read.
9
9
  #
10
- # WHY THIS IS NOT IN `bin/qa_sweep` ANY MORE. It was — `WIDENING_TIERS`
10
+ # Why this is not in `bin/qa_sweep` any more. It was — `WIDENING_TIERS`
11
11
  # and `widen_for_streak` lived at the top of that script, which meant
12
12
  # policy data lived in a script (unlike every other dial, which lives
13
13
  # in the bluebook a human edits and reviews) and duplicated itself as
@@ -15,7 +15,7 @@ module Hecks
15
15
  # and `bin/qa_sweep` calls it the way it already calls
16
16
  # `RotationPriority.pick`.
17
17
  #
18
- # PURE, DELIBERATELY — the same discipline `RotationPriority` keeps:
18
+ # **Pure, deliberately** — the same discipline `RotationPriority` keeps:
19
19
  # same streak in, same `[seeds, steps]` out, every time, which is what
20
20
  # lets a human predict what a given sweep is about to do before it
21
21
  # runs one. `tiers:` defaults to the dial but is a plain argument, so
@@ -26,7 +26,7 @@ module Hecks
26
26
  module SweepDepth
27
27
  module_function
28
28
 
29
- # THE FALLBACK TABLE, for a boot with no `QualityControlDials` at all
29
+ # The fallback table, for a boot with no `QualityControlDials` at all
30
30
  # — the same shape and the same three rows the dial ships with, so a
31
31
  # dial-less ledger fuzzes exactly as a dialled one does by default.
32
32
  # Never read when the dial exists; `bin/qa_sweep` passes the dial in.
@@ -1,30 +1,30 @@
1
1
  module Hecks
2
2
  module Fuzzing
3
- # WHAT A SWEEP TARGET CAN ACTUALLY BE CHECKED FOR, read off the
3
+ # What a sweep target can actually be checked for, read off the
4
4
  # filesystem — never off a stored list.
5
5
  #
6
- # `bin/qa_sweep` used to decide its ONE comparison mode inline: "is
6
+ # `bin/qa_sweep` used to decide its one comparison mode inline: "is
7
7
  # there a Cargo feature named after this directory? then
8
8
  # `:differential`, else `:ruby_only`", and a separate hand-typed abort
9
9
  # for `--persistence-parity` ("does any .hecksagon bind PostgresEra?").
10
10
  # Every further mode the practice adds (era boundary, concurrency, a
11
11
  # WASM front) would have grown one more inline `if`, each one a
12
12
  # policy decision hiding in a script. This module is those decisions
13
- # as DATA: `MODE_REQUIREMENTS` says which capabilities each mode
13
+ # as data: `MODE_REQUIREMENTS` says which capabilities each mode
14
14
  # needs, `infer` says which capabilities a target's own directory
15
15
  # actually has, and `resolve` is the one rule that joins them —
16
16
  # `modes_to_run = enabled ∩ eligible`.
17
17
  #
18
- # INFERENCE DECIDES; A STORED LIST ONLY RECORDS. `Target.capabilities`
18
+ # Inference decides; a stored list only records. `Target.capabilities`
19
19
  # (qa/bluebook/quality_control.bluebook, once PR-1's era lands) is
20
20
  # written by the runner from exactly this inference at release time
21
- # so `Target.EligibleFor(mode)` can AUDIT the rotation from the
21
+ # so `Target.EligibleFor(mode)` can audit the rotation from the
22
22
  # ledger alone — but the runner re-infers every sweep, because a
23
23
  # stored list that lags yesterday's Cargo feature is precisely the
24
24
  # "quiet divergence" (the chapter's own opening comment) this whole
25
25
  # practice exists to hunt. Nothing here ever reads the ledger.
26
26
  #
27
- # EVERY REGEX IS ONE THE HARNESS ALREADY OWNED, moved here rather than
27
+ # Every regex is one the harness already owned, moved here rather than
28
28
  # re-derived, and each one's provenance is named beside it so a
29
29
  # future edit to the original site is a visible drift, not a silent
30
30
  # one: the Cargo feature line (`RustConformanceHelpers#build_rust_for`),
@@ -45,10 +45,13 @@ module Hecks
45
45
  # domain-level default (`persisted_by "PostgresEra"`).
46
46
  POSTGRES_ERA_BINDING = /persisted_by\s*\(?\s*"PostgresEra"/
47
47
 
48
- # `HecksagonBuilder#uses_framework` — the one line that attaches
49
- # Governance's own `RoleAssignment` lookup to a domain's `role` checks
50
- # (`CommandRules::Authorization#governance_attached?`).
51
- GOVERNANCE_ATTACHED = /uses_framework\s*\(?\s*"Governance"/
48
+ # `HecksagonBuilder#uses_framework "X"` — captures which member a
49
+ # hecksagon attaches, whatever its name. Whether that member answers
50
+ # a role check is then read off its own declaration (`provides
51
+ # "authorization"`, via `Framework.providers_of`), the same rule
52
+ # `Registry#authorization_provider_for` applies at runtime — never a
53
+ # match on the literal "Governance".
54
+ FRAMEWORK_ATTACHED = /uses_framework\s*\(?\s*"([^"]+)"/
52
55
 
53
56
  # A command-level `role "..."` — the only construct
54
57
  # `refuse_role_mismatch` ever has anything to check a caller against.
@@ -61,21 +64,21 @@ module Hecks
61
64
 
62
65
  PROCESS_MANAGER = /^\s*process_manager\s+"/
63
66
 
64
- # WHICH CAPABILITIES EACH MODE NEEDS BEFORE IT CAN SAY ANYTHING TRUE
65
- # ABOUT A TARGET. An empty list means "any target at all" — every
67
+ # Which capabilities each mode needs before it can say anything true
68
+ # about a target. An empty list means "any target at all" — every
66
69
  # domain boots under Memory, so Ruby-only properties and the
67
70
  # self-consistency pass are always answerable. `ruby_only` is listed
68
- # requirement-free on purpose and then EXCLUDED by `resolve` whenever
71
+ # requirement-free on purpose and then excluded by `resolve` whenever
69
72
  # `differential` resolved too: they are the same seat, and a compiled
70
73
  # Rust binary is strictly the better occupant (item 1 of the
71
- # detection plan folded the Ruby-only property battery INTO the
74
+ # detection plan folded the Ruby-only property battery into the
72
75
  # differential seat, so nothing is lost by the exclusion).
73
76
  #
74
77
  # The four `false`-by-default modes in `QualityControlDials::MODES`
75
78
  # (`adapter_parity_postgres`, `era_boundary`, `concurrency`,
76
79
  # `wasm_front`) are named here with their requirements even though
77
80
  # nothing runs them yet — so `resolved modes:` can already say, per
78
- # target, which of them WOULD be eligible the day a human flips the
81
+ # target, which of them would be eligible the day a human flips the
79
82
  # dial, and so flipping it is a one-line data change rather than a
80
83
  # code change plus a data change.
81
84
  MODE_REQUIREMENTS = {
@@ -92,7 +95,24 @@ module Hecks
92
95
  wasm_front: %w[rust]
93
96
  }.freeze
94
97
 
95
- # MODES THAT NAME A SEPARATE, EXPENSIVE PASS OF THEIR OWN rather than
98
+ # Which of those modes `bin/qa_sweep` can actually run today.
99
+ # `MODE_REQUIREMENTS` above says what a mode needs; this says what
100
+ # exists to do it, and the two are not the same. Conflating them is
101
+ # how `qa/settings.yml` came to enable `wasm_front` and
102
+ # `adapter_parity_postgres` with nothing behind either — no seat, no
103
+ # check folded into the seed loop, no `MODE_EXPECTATIONS` entry — while
104
+ # `resolved modes:` still printed them per target, so the sweep
105
+ # advertised coverage it never performed. A mode named in
106
+ # `MODE_REQUIREMENTS` but absent here is one this practice wants and has
107
+ # not built: `bin/qa_sweep` refuses to start when a dial or `--modes`
108
+ # enables it, rather than resolving it into a line nobody can act on.
109
+ # `spec/qa_sweep_runnable_modes_spec.rb` keeps this list honest from
110
+ # both sides by grepping the runner itself.
111
+ RUNNABLE_MODES = %i[differential ruby_only self_consistency properties_in_differential
112
+ structural_skip_report adapter_parity_sqlite persistence_parity
113
+ era_boundary concurrency].freeze
114
+
115
+ # Modes that name a separate, expensive pass of their own rather than
96
116
  # an extra check folded into the ordinary per-seed loop —
97
117
  # `bin/qa_sweep` runs these only when asked by name (`--modes
98
118
  # persistence_parity`, or its older alias `--persistence-parity`) or
@@ -110,7 +130,7 @@ module Hecks
110
130
  capabilities << "rust" if rust_feature?(domain_path, rust_dir)
111
131
  capabilities << "postgres_era" if any_file?(domain_path, "*.hecksagon", POSTGRES_ERA_BINDING)
112
132
  capabilities << "translations" if Dir.glob(File.join(domain_path, "**", "translations", "*.bluebook")).any?
113
- capabilities << "governance" if any_file?(domain_path, "*.hecksagon", GOVERNANCE_ATTACHED)
133
+ capabilities << "governance" if authorization_attached?(domain_path)
114
134
  capabilities << "role_gated" if any_file?(domain_path, "*.bluebook", ROLE_GATED)
115
135
  capabilities << "tenant" if any_file?(domain_path, "*.bluebook", TENANT_SCOPED)
116
136
  capabilities << "sagas" if any_file?(domain_path, "*.bluebook", PROCESS_MANAGER)
@@ -122,7 +142,7 @@ module Hecks
122
142
  (required - capabilities).empty?
123
143
  end
124
144
 
125
- # THE ONE RULE. `enabled` is whatever the dial (or `--modes`) turned
145
+ # The one rule. `enabled` is whatever the dial (or `--modes`) turned
126
146
  # on, in the dial's own declaration order — that order is preserved
127
147
  # so the printed line reads the same way the dial does. Then the
128
148
  # single exclusion named on `MODE_REQUIREMENTS`.
@@ -141,6 +161,17 @@ module Hecks
141
161
  features.match?(/^#{Regexp.escape(feature)}\s*=\s*\[\]/)
142
162
  end
143
163
 
164
+ # The capability label stays "governance" — it is the value
165
+ # `bin/qa_sweep` writes into the QualityControl ledger's
166
+ # `Target.capabilities`, and renaming it is a ledger change, not
167
+ # part of dropping the name check.
168
+ def authorization_attached?(domain_path)
169
+ attached = Dir.glob(File.join(domain_path, "**", "*.hecksagon"))
170
+ .flat_map { |path| File.read(path).scan(FRAMEWORK_ATTACHED).flatten }.uniq
171
+ providers = Framework.providers_of(Bluebook::Capabilities::AUTHORIZATION)
172
+ attached.intersect?(providers)
173
+ end
174
+
144
175
  def any_file?(domain_path, glob, pattern)
145
176
  Dir.glob(File.join(domain_path, "**", glob)).any? { |path| File.read(path).match?(pattern) }
146
177
  end
@@ -4,7 +4,7 @@ module Hecks
4
4
  module Fuzzing
5
5
  # One attribute, one value — in the exact JSON shape the hand-written
6
6
  # corpus already uses (a value-object-typed attribute is a nested hash keyed
7
- # by its own field names ; a reference is the BARE ID of the head it points
7
+ # by its own field names ; a reference is the bare ID of the head it points
8
8
  # at, because that is what a reference is). Everything
9
9
  # returned is a plain, JSON-safe Ruby value : String keys throughout, never
10
10
  # symbols, so a generated step can be dumped straight to JSON.
@@ -15,7 +15,7 @@ module Hecks
15
15
  # codebase," and a fixed corpus of a few dozen examples rarely happens to
16
16
  # exercise the boundary that actually breaks. But mostly not : an attribute
17
17
  # named `email`/`currency` almost always needs a specific shape just to get
18
- # PAST its own invariant (`address.include?("@")`, `currency.size == 3`) —
18
+ # past its own invariant (`address.include?("@")`, `currency.size == 3`) —
19
19
  # banking's very first fuzz run never got past Customer.Register, because
20
20
  # no plain random word ever contains "@". Reaching deep state matters more
21
21
  # than edge-casing every single field every single time, so the "normal"
@@ -31,7 +31,7 @@ module Hecks
31
31
  # (lib/hecks/runtime/value/coercion.rb) has accepted a bare
32
32
  # `"large"` in place of `{"value" => "large"}` for any single-field
33
33
  # value object since 86727afd — but until this generator actually
34
- # PRODUCES that shape, nothing exercises it: neither the adapter-
34
+ # produces that shape, nothing exercises it: neither the adapter-
35
35
  # agreement gate nor the Rust/WASM `from_json` codegen (rust/project/
36
36
  # json_codec.rb) can ever be caught drifting on a shape they're
37
37
  # never handed.
@@ -44,22 +44,22 @@ module Hecks
44
44
  # PRD 05 (numeric-boundary-coverage) — Bignum (`2**100`, past i64's
45
45
  # own ceiling, which Ruby's own `Integer` has no such ceiling for —
46
46
  # `rust/src/kernel/json.rs`'s own `integral_i64` doc comment names
47
- # exactly this: a Rust kernel value CANNOT represent it, so this
47
+ # exactly this: a Rust kernel value cannot represent it, so this
48
48
  # exercises a real cross-runtime capability gap, not a Ruby-only
49
49
  # edge) and its negative twin. Both round-trip through Ruby's own
50
50
  # arithmetic/JSON cleanly (confirmed directly: `(2**100).clamp(...)`
51
51
  # and `JSON.generate(2**100)` both just work — Integer has no
52
- # ceiling here), so nothing in THIS runtime needed a fix for these;
52
+ # ceiling here), so nothing in this runtime needed a fix for these;
53
53
  # they're included so a real generated sequence occasionally
54
54
  # produces the value at all, since nothing had, repo-wide, before.
55
55
  INTEGER_EDGE_CASES = [0, -1, 2_147_483_647, -2_147_483_648, 2**100, -(2**100)].freeze
56
56
  # BUG#35 (QualityControl QA ledger, `lease-clock-json-precision`) —
57
57
  # a Bignum edge case (`2**100`, above) landing on an Integer-typed
58
- # CLOCK or COUNT reading fires the already-catalogued `Json::Num`/
58
+ # clock or count reading fires the already-catalogued `Json::Num`/
59
59
  # f64 precision-loss class (`rust/src/kernel/json.rs`'s
60
60
  # `parse_number` parses every number through `s.parse::<f64>()`
61
61
  # before any target-type conversion runs, and `Json::Num` is a
62
- # plain `f64` end to end — see that file's own header) on a NEW
62
+ # plain `f64` end to end — see that file's own header) on a new
63
63
  # site every time a new clock/count-shaped field is authored,
64
64
  # without adding any new coverage: both engines already refuse
65
65
  # (`TypeMismatch`, out of `i64` range either way) for this shape,
@@ -83,7 +83,7 @@ module Hecks
83
83
  # as a clock or a count is capped to a narrower, still-real
84
84
  # edge-case pool below (still exercises the ordinary i32
85
85
  # boundaries, just never a value past f64's own 2**53 exact-
86
- # integer ceiling) — every OTHER Integer-typed field (a money
86
+ # integer ceiling) — every other Integer-typed field (a money
87
87
  # amount, an identity sequence, anything not clock/count-shaped)
88
88
  # still draws from the full `INTEGER_EDGE_CASES` pool above,
89
89
  # unchanged.
@@ -105,7 +105,7 @@ module Hecks
105
105
  # (raw `ArgumentError`, not a domain refusal) or `JSON.generate`
106
106
  # (`JSON::GeneratorError`, also not a domain refusal) — both fixed
107
107
  # at the source now, so these are safe to generate. -0.0 is
108
- # deliberately included too even though it was ALREADY safe
108
+ # deliberately included too even though it was already safe
109
109
  # (finite, round-trips through JSON as `-0.0` cleanly) — a signed
110
110
  # zero is exactly the kind of boundary a hand-written corpus never
111
111
  # happens to type, and the fuzzer existing to cover it is the
@@ -157,10 +157,10 @@ module Hecks
157
157
  end
158
158
  end
159
159
 
160
- # `fields.size == 1` — the SAME test `Behaviour::ValueObject#
160
+ # `fields.size == 1` — the same test `Behaviour::ValueObject#
161
161
  # sole_attribute` names: a genuinely single-field value object,
162
162
  # not merely "this particular closed-set member happened to pick
163
- # one field." Unwrapping ONLY here, not in `invalid_member`
163
+ # one field." Unwrapping only here, not in `invalid_member`
164
164
  # above — a deliberately-wrong combination stays a Hash so its
165
165
  # own wrongness is what gets exercised, not a second, unrelated
166
166
  # shape question.
@@ -178,10 +178,10 @@ module Hecks
178
178
  end
179
179
  end
180
180
 
181
- # THE ID ITSELF. This minted `{"value" => id}` back when a reference was
181
+ # The ID itself. This minted `{"value" => id}` back when a reference was
182
182
  # stored wrapped ; the payload gate refuses that shape now, so a fuzzer
183
183
  # still emitting it would have every generated reference refused and
184
- # the SILENT guard would report the fuzzer broken rather than
184
+ # the silent guard would report the fuzzer broken rather than
185
185
  # the runtime.
186
186
  def reference_value(attribute, random:, known_ids:)
187
187
  pool = known_ids[attribute.type.target_name.to_s] || []
@@ -236,7 +236,7 @@ module Hecks
236
236
  random.rand(0.01..1000.0).round(2)
237
237
  end
238
238
 
239
- # The bare scalar a generated IDENTITY value stands for, for recording into
239
+ # The bare scalar a generated identity value stands for, for recording into
240
240
  # `known_ids`. An identity is declared as a value object, so this opens one ;
241
241
  # a reference pointing at this record is already that scalar and needs no
242
242
  # opening at all. The two used to be the same reading and are not any more.
data/lib/hecks/fuzzing.rb CHANGED
@@ -8,11 +8,16 @@ end
8
8
  require_relative "fuzzing/value_generator"
9
9
  require_relative "fuzzing/invalid_value_generator"
10
10
  require_relative "fuzzing/sequence_generator"
11
+ require_relative "fuzzing/nondeterministic"
11
12
  require_relative "fuzzing/replay"
13
+ require_relative "fuzzing/shrinker"
12
14
  require_relative "fuzzing/properties"
15
+ require_relative "fuzzing/qa_settings"
13
16
  require_relative "fuzzing/rotation_priority"
14
17
  require_relative "fuzzing/sweep_depth"
15
18
  require_relative "fuzzing/persistence_parity"
16
19
  require_relative "fuzzing/form_census"
17
20
  require_relative "fuzzing/target_capabilities"
21
+ require_relative "fuzzing/rust_gap_manifest"
18
22
  require_relative "fuzzing/structural_skips"
23
+ require_relative "fuzzing/coverage_campaign"
@@ -1,7 +1,7 @@
1
1
  module Hecks
2
2
  module Grammar
3
3
  # The file surgery under bin/evolve: reading and rewriting the
4
- # aggregate-local KeywordSeed/ArgumentSeed rows as TEXT, so a
4
+ # aggregate-local KeywordSeed/ArgumentSeed rows as text, so a
5
5
  # proposed word enters the table exactly as a hand would write it
6
6
  # and an admitted one loses its ceremony (an absent status reads as
7
7
  # admitted — the grown-column convention).
@@ -18,7 +18,7 @@ module Hecks
18
18
  module_function
19
19
 
20
20
  # bin/evolve's own `--name value` flag reader. Only consumes the
21
- # NEXT argv element as the value when that element doesn't itself
21
+ # next argv element as the value when that element doesn't itself
22
22
  # look like a flag — otherwise `--foo --bar` would swallow `--bar`
23
23
  # as `--foo`'s value (and `--bar` would then never be seen at
24
24
  # all), and a value-less `--foo` at the end of argv would bypass
@@ -97,7 +97,7 @@ module Hecks
97
97
  row = %(#{indent}member word: "#{word}", context: "#{context}", body: "#{body}", ) +
98
98
  %(inner: "#{inner}", opens: "#{opens}", fills: "#{fills}", status: "proposed"\n)
99
99
 
100
- # At the END of the one_of — grouping by context is a courtesy of
100
+ # At the end of the one_of — grouping by context is a courtesy of
101
101
  # the hand; a proposed row sits at the bottom until admission,
102
102
  # when whoever admits it may move it home.
103
103
  closing = block.rindex(/^\s*end\s*$/)
@@ -119,7 +119,7 @@ module Hecks
119
119
  next line unless member_row?(line, word, context)
120
120
 
121
121
  stripped = line.sub(/,\s*status: "[^"]*"/, "")
122
- # Admitted is the default and stays UNSPELLED — only a word
122
+ # Admitted is the default and stays unspelled — only a word
123
123
  # entering or leaving the language carries its status.
124
124
  to == "admitted" ? stripped : stripped.sub(/\n\z/, %(, status: "#{to}"\n))
125
125
  end.join
@@ -219,10 +219,10 @@ module Hecks
219
219
  block
220
220
  end
221
221
 
222
- # From `value_object "KeywordSeed"` to ITS OWN closing `end` — `member`
222
+ # From `value_object "KeywordSeed"` to its own closing `end` — `member`
223
223
  # rows sit bare now (S3, ADR 0025 — the `one_of do ... end` wrapper
224
224
  # is gone), so the first bare `end` line after the opener already
225
- # IS the value object's own, the same fact the original one_of-
225
+ # is the value object's own, the same fact the original one_of-
226
226
  # nested version of this method leaned on (nothing else nested
227
227
  # inside it either, before or after).
228
228
  def keyword_blocks(source) = seed_blocks(source, "KeywordSeed")
@@ -230,7 +230,7 @@ module Hecks
230
230
 
231
231
  # ── the Argument rows — a word's own arguments, at last with tooling
232
232
  # of their own rather than the rename-only cascade above. A word may
233
- # carry SEVERAL argument rows (one per position, one per named
233
+ # carry several argument rows (one per position, one per named
234
234
  # kwarg), so identity here is the full (keyword, context, at, named)
235
235
  # tuple, not the two-field key a Keyword row answers to.
236
236
 
@@ -250,7 +250,7 @@ module Hecks
250
250
  end
251
251
  end
252
252
 
253
- # `pairs_shape` — for a `pairs` argument that fills ONE field with a
253
+ # `pairs_shape` — for a `pairs` argument that fills one field with a
254
254
  # whole key/value list rather than naming a field per pair (the
255
255
  # shape `Handler.dispatch`'s own `with:` already carries). Without
256
256
  # it, `spec/syntax_conformance_spec.rb` reads a pairs argument
@@ -315,7 +315,7 @@ module Hecks
315
315
 
316
316
  def argument_identity(row) = [row[:keyword], row[:context], row[:at], row[:named]]
317
317
 
318
- # The rename cascade, ROW-AWARE — only the rows that actually belong
318
+ # The rename cascade, row-aware — only the rows that actually belong
319
319
  # to the renamed word, spelling updated in place, rather than a
320
320
  # blind `gsub` on every `keyword: "word",` substring in the file
321
321
  # (which a coincidentally-matching row elsewhere could have
@@ -337,7 +337,7 @@ module Hecks
337
337
  end
338
338
  end
339
339
 
340
- # From `value_object "ArgumentSeed"` to ITS OWN closing `end` — see
340
+ # From `value_object "ArgumentSeed"` to its own closing `end` — see
341
341
  # `keyword_block`'s own comment for why the first bare `end` after
342
342
  # the opener is already the right one, now that `member` rows sit
343
343
  # bare (S3, ADR 0025).
data/lib/hecks/grammar.rb CHANGED
@@ -7,12 +7,12 @@ require_relative "../hecks"
7
7
 
8
8
  module Hecks
9
9
  # The sublanguage grammar domains (grammar/*.bluebook) and the one boot
10
- # path for reading them as DATA — the expression chapter replayed
10
+ # path for reading them as data — the expression chapter replayed
11
11
  # through its own admission ledger, so anything derived from it (the
12
12
  # operator projections, the conformance specs) reads the set that
13
13
  # actually survived the Admit gates, never a hand-copied list.
14
14
  #
15
- # Booted on CALL, never at require: the Prism adapter normalises every
15
+ # Booted on call, never at require: the Prism adapter normalises every
16
16
  # predicate through CanonicalForm while a bluebook loads, so the
17
17
  # expression machinery cannot boot the chapter that configures it —
18
18
  # this module exists precisely so generators and specs boot it in a
@@ -42,7 +42,7 @@ module Hecks
42
42
  JSON.parse(File.read(LEDGER)).fetch("steps").each do |step|
43
43
  args = symbolize(step.fetch("args"))
44
44
  begin
45
- dispatcher.dispatch(step.fetch("verb"), **args)
45
+ dispatcher.dispatch_flat(step.fetch("verb"), args)
46
46
  rescue *Runtime::DOMAIN_REFUSALS => e
47
47
  raise Runtime::WiringError,
48
48
  "the admission ledger refused at #{step['verb']} #{step['args']} — #{e.message}"
@@ -77,15 +77,15 @@ module Hecks
77
77
  registry.repository("Expression", aggregate).all
78
78
  end
79
79
 
80
- # THE OPERATORS THE LANGUAGE STANDS ON. Every guard and invariant in
80
+ # The operators the language stands on. Every guard and invariant in
81
81
  # the language's own chapters — the meta-domain (Bluebook, World) and
82
82
  # the grammar chapters beside this file — evaluates through the very
83
83
  # operator table the ledger admits. An operator one of those
84
- # predicates uses is SELF-BEARING: retire it and the language can no
84
+ # predicates uses is self-bearing: retire it and the language can no
85
85
  # longer read its own rules — found the hard way, as a projection
86
86
  # missing `!=` that could not boot the chapter to fix itself. This
87
87
  # derives the set, with a usage site per operator, so the generator
88
- # and the conformance spec can refuse the retirement BY NAME instead
88
+ # and the conformance spec can refuse the retirement by name instead
89
89
  # of wedging.
90
90
  def self_bearing_operators
91
91
  sites = Hash.new { |h, k| h[k] = [] }
@@ -146,7 +146,7 @@ module Hecks
146
146
  walk_operators(node, evaluator).uniq
147
147
  end
148
148
 
149
- # A recursive descent over a CLOSED, declared set of AST node types
149
+ # A recursive descent over a closed, declared set of AST node types
150
150
  # (Evaluator's boolean/compare/include nodes, Resolver's arithmetic
151
151
  # nodes, and the generic Struct fallback) — each branch does the
152
152
  # same one thing (name the node's own operator, recurse into its