hecks 1.3.0 → 1.5.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 (373) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hecks/adapters/driven/claude_code.rb +72 -7
  3. data/lib/hecks/adapters/driven/d1.rb +187 -23
  4. data/lib/hecks/adapters/driven/folder.rb +83 -10
  5. data/lib/hecks/adapters/driven/google_authentication.rb +33 -12
  6. data/lib/hecks/adapters/driven/governance_authorization.rb +87 -18
  7. data/lib/hecks/adapters/driven/heki/journal.rb +13 -4
  8. data/lib/hecks/adapters/driven/heki/saga_store.rb +56 -10
  9. data/lib/hecks/adapters/driven/heki/snapshot.rb +1 -1
  10. data/lib/hecks/adapters/driven/heki.rb +106 -9
  11. data/lib/hecks/adapters/driven/identity_registry.rb +12 -2
  12. data/lib/hecks/adapters/driven/in_memory_ordering.rb +25 -3
  13. data/lib/hecks/adapters/driven/in_process_key_vault.adapter +3 -0
  14. data/lib/hecks/adapters/driven/in_process_key_vault.rb +53 -0
  15. data/lib/hecks/adapters/driven/lambda/client.rb +67 -14
  16. data/lib/hecks/adapters/driven/lambda.rb +82 -35
  17. data/lib/hecks/adapters/driven/local_storage.rb +83 -10
  18. data/lib/hecks/adapters/driven/memory.rb +205 -9
  19. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +21 -1
  20. data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
  21. data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
  22. data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
  23. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
  24. data/lib/hecks/adapters/driven/postgres.rb +175 -28
  25. data/lib/hecks/adapters/driven/prism.rb +50 -11
  26. data/lib/hecks/adapters/driven/secure_random_identity.rb +3 -0
  27. data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
  28. data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
  29. data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
  30. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
  31. data/lib/hecks/adapters/driven/sqlite.rb +181 -21
  32. data/lib/hecks/adapters/driven/system_clock.rb +3 -0
  33. data/lib/hecks/adapters/driven/tenant_provisioner.adapter +3 -0
  34. data/lib/hecks/adapters/driven/tenant_provisioner.rb +66 -0
  35. data/lib/hecks/adapters/driven.rb +6 -4
  36. data/lib/hecks/adapters/driving/github_webhook.rb +31 -18
  37. data/lib/hecks/behaviors/dsl.rb +60 -2
  38. data/lib/hecks/behaviors/expectations.rb +190 -29
  39. data/lib/hecks/behaviors/ir.rb +12 -1
  40. data/lib/hecks/behaviors/rspec.rb +9 -1
  41. data/lib/hecks/behaviors/runner.rb +21 -2
  42. data/lib/hecks/behaviors.rb +9 -1
  43. data/lib/hecks/bluebook/aggregate.rb +43 -13
  44. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +17 -10
  45. data/lib/hecks/bluebook/assembly/build.rb +26 -5
  46. data/lib/hecks/bluebook/assembly/contract.rb +98 -23
  47. data/lib/hecks/bluebook/assembly/contracts.rb +59 -52
  48. data/lib/hecks/bluebook/assembly/marks.rb +159 -30
  49. data/lib/hecks/bluebook/assembly/specializer.rb +38 -21
  50. data/lib/hecks/bluebook/assembly.rb +32 -14
  51. data/lib/hecks/bluebook/attribute.rb +26 -12
  52. data/lib/hecks/bluebook/behaviour/aggregate.rb +43 -11
  53. data/lib/hecks/bluebook/behaviour/attribute.rb +18 -5
  54. data/lib/hecks/bluebook/behaviour/chapter.rb +76 -5
  55. data/lib/hecks/bluebook/behaviour/command.rb +55 -25
  56. data/lib/hecks/bluebook/behaviour/domain_port.rb +27 -7
  57. data/lib/hecks/bluebook/behaviour/entity.rb +20 -8
  58. data/lib/hecks/bluebook/behaviour/hexagon.rb +30 -4
  59. data/lib/hecks/bluebook/behaviour/lifecycle.rb +27 -6
  60. data/lib/hecks/bluebook/behaviour/policy.rb +42 -17
  61. data/lib/hecks/bluebook/behaviour/process_manager.rb +39 -8
  62. data/lib/hecks/bluebook/behaviour/query.rb +6 -1
  63. data/lib/hecks/bluebook/behaviour/read_model.rb +29 -8
  64. data/lib/hecks/bluebook/behaviour/traits.rb +48 -12
  65. data/lib/hecks/bluebook/behaviour/value_object.rb +21 -9
  66. data/lib/hecks/bluebook/capabilities.rb +27 -0
  67. data/lib/hecks/bluebook/chapter.rb +51 -9
  68. data/lib/hecks/bluebook/command.rb +62 -17
  69. data/lib/hecks/bluebook/domain_port.rb +34 -9
  70. data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
  71. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
  72. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +282 -123
  73. data/lib/hecks/bluebook/dsl/attribute_collector.rb +112 -75
  74. data/lib/hecks/bluebook/dsl/binding_proxy.rb +81 -2
  75. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +486 -117
  76. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +179 -47
  77. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
  78. data/lib/hecks/bluebook/dsl/command_builder.rb +284 -122
  79. data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
  80. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
  81. data/lib/hecks/bluebook/dsl/entity_builder.rb +191 -61
  82. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
  83. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +130 -30
  84. data/lib/hecks/bluebook/dsl/identity_declaration.rb +38 -21
  85. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
  86. data/lib/hecks/bluebook/dsl/policy_builder.rb +86 -36
  87. data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
  88. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
  89. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +111 -47
  90. data/lib/hecks/bluebook/dsl/query_builder.rb +37 -8
  91. data/lib/hecks/bluebook/dsl/read_model_builder.rb +127 -52
  92. data/lib/hecks/bluebook/dsl/rule_reference.rb +97 -43
  93. data/lib/hecks/bluebook/dsl/translation_builder.rb +150 -44
  94. data/lib/hecks/bluebook/dsl/value_object_builder.rb +68 -20
  95. data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
  96. data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
  97. data/lib/hecks/bluebook/entity.rb +40 -11
  98. data/lib/hecks/bluebook/expression/ast_json.rb +128 -36
  99. data/lib/hecks/bluebook/expression/ast_reader.rb +32 -3
  100. data/lib/hecks/bluebook/expression/canonical_form.rb +55 -16
  101. data/lib/hecks/bluebook/expression/evaluator.rb +221 -43
  102. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +54 -18
  103. data/lib/hecks/bluebook/expression/resolver.rb +369 -128
  104. data/lib/hecks/bluebook/hexagon.rb +35 -1
  105. data/lib/hecks/bluebook/lifecycle.rb +12 -1
  106. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +2 -1
  107. data/lib/hecks/bluebook/meta_validator/judge.rb +126 -108
  108. data/lib/hecks/bluebook/meta_validator/plan.rb +81 -46
  109. data/lib/hecks/bluebook/meta_validator/port_judge.rb +3 -2
  110. data/lib/hecks/bluebook/meta_validator/readings.rb +200 -50
  111. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +68 -41
  112. data/lib/hecks/bluebook/meta_validator/shapes.rb +166 -21
  113. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +286 -46
  114. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +11 -10
  115. data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -5
  116. data/lib/hecks/bluebook/meta_validator.rb +235 -139
  117. data/lib/hecks/bluebook/model_check.rb +434 -104
  118. data/lib/hecks/bluebook/pattern_subset.rb +32 -10
  119. data/lib/hecks/bluebook/policy.rb +15 -13
  120. data/lib/hecks/bluebook/process_manager.rb +27 -14
  121. data/lib/hecks/bluebook/project_discovery.rb +5 -0
  122. data/lib/hecks/bluebook/project_loader.rb +40 -0
  123. data/lib/hecks/bluebook/project_register.rb +50 -6
  124. data/lib/hecks/bluebook/query.rb +31 -4
  125. data/lib/hecks/bluebook/read_model.rb +35 -15
  126. data/lib/hecks/bluebook/reference.rb +26 -13
  127. data/lib/hecks/bluebook/smoke_test.rb +46 -23
  128. data/lib/hecks/bluebook/synthesizer.rb +46 -12
  129. data/lib/hecks/bluebook/translation.rb +34 -5
  130. data/lib/hecks/bluebook/value_object.rb +29 -11
  131. data/lib/hecks/bluebook.rb +5 -6
  132. data/lib/hecks/codemod.rb +138 -50
  133. data/lib/hecks/construct.rb +21 -7
  134. data/lib/hecks/corpus.rb +438 -0
  135. data/lib/hecks/deploy/bluebook/deploy.hecksagon +19 -0
  136. data/lib/hecks/doc/reference.rb +200 -31
  137. data/lib/hecks/embryonaut_bluebook.rb +38 -15
  138. data/lib/hecks/facade/cli_door.rb +69 -10
  139. data/lib/hecks/facade/cli_runner.rb +105 -24
  140. data/lib/hecks/facade/command_request.rb +23 -0
  141. data/lib/hecks/facade/handle.rb +155 -35
  142. data/lib/hecks/facade/json_door.rb +106 -25
  143. data/lib/hecks/facade/surface/aggregate_door.rb +50 -27
  144. data/lib/hecks/facade/surface/chapter.rb +26 -17
  145. data/lib/hecks/facade/surface.rb +16 -3
  146. data/lib/hecks/facade.rb +15 -4
  147. data/lib/hecks/forms/app.rb +46 -30
  148. data/lib/hecks/forms/command_form_renderer.rb +70 -9
  149. data/lib/hecks/forms/field_renderer.rb +142 -6
  150. data/lib/hecks/forms/field_shape.rb +183 -19
  151. data/lib/hecks/forms/html.rb +51 -7
  152. data/lib/hecks/forms/index_renderer.rb +14 -2
  153. data/lib/hecks/forms/page.rb +14 -0
  154. data/lib/hecks/forms/params.rb +120 -23
  155. data/lib/hecks/forms/port_argument.rb +14 -2
  156. data/lib/hecks/forms/query_form_renderer.rb +65 -2
  157. data/lib/hecks/forms/record_renderer.rb +60 -2
  158. data/lib/hecks/forms/record_table.rb +28 -1
  159. data/lib/hecks/forms/reference_options.rb +24 -0
  160. data/lib/hecks/forms/value_object_shape.rb +13 -3
  161. data/lib/hecks/forms.rb +24 -4
  162. data/lib/hecks/fqn.rb +59 -1
  163. data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
  164. data/lib/hecks/framework/bluebook/privacy.bluebook +155 -0
  165. data/lib/hecks/framework/oidc.json +15 -0
  166. data/lib/hecks/framework.rb +79 -25
  167. data/lib/hecks/freezer.rb +27 -11
  168. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +241 -106
  169. data/lib/hecks/fuzzing/combination_miner.rb +178 -0
  170. data/lib/hecks/fuzzing/concurrent_dispatch.rb +241 -45
  171. data/lib/hecks/fuzzing/coverage_campaign.rb +161 -0
  172. data/lib/hecks/fuzzing/differential.rb +192 -0
  173. data/lib/hecks/fuzzing/domain_generator.rb +871 -0
  174. data/lib/hecks/fuzzing/era_boundary.rb +68 -19
  175. data/lib/hecks/fuzzing/form_census.rb +121 -20
  176. data/lib/hecks/fuzzing/generated_domain_check.rb +171 -0
  177. data/lib/hecks/fuzzing/invalid_value_generator.rb +45 -6
  178. data/lib/hecks/fuzzing/isolated_boot.rb +137 -80
  179. data/lib/hecks/fuzzing/nondeterministic.rb +79 -0
  180. data/lib/hecks/fuzzing/persistence_parity.rb +111 -21
  181. data/lib/hecks/fuzzing/properties/corrections.rb +34 -9
  182. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +300 -51
  183. data/lib/hecks/fuzzing/properties/guards.rb +86 -42
  184. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +80 -32
  185. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +40 -35
  186. data/lib/hecks/fuzzing/properties/outbox.rb +70 -32
  187. data/lib/hecks/fuzzing/properties/querying.rb +82 -28
  188. data/lib/hecks/fuzzing/properties.rb +84 -51
  189. data/lib/hecks/fuzzing/qa_settings.rb +164 -0
  190. data/lib/hecks/fuzzing/replay.rb +241 -133
  191. data/lib/hecks/fuzzing/rotation_priority.rb +48 -28
  192. data/lib/hecks/fuzzing/rust_gap_manifest.rb +139 -0
  193. data/lib/hecks/fuzzing/self_consistency.rb +315 -137
  194. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +46 -40
  195. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +18 -11
  196. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +13 -12
  197. data/lib/hecks/fuzzing/sequence_generator/picker.rb +21 -12
  198. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +59 -32
  199. data/lib/hecks/fuzzing/sequence_generator.rb +158 -23
  200. data/lib/hecks/fuzzing/shrinker.rb +309 -0
  201. data/lib/hecks/fuzzing/structural_skips.rb +37 -130
  202. data/lib/hecks/fuzzing/sweep_depth.rb +12 -4
  203. data/lib/hecks/fuzzing/target_capabilities.rb +107 -29
  204. data/lib/hecks/fuzzing/value_generator.rb +110 -22
  205. data/lib/hecks/fuzzing.rb +5 -0
  206. data/lib/hecks/grammar/evolve.rb +188 -12
  207. data/lib/hecks/grammar.rb +53 -7
  208. data/lib/hecks/ir.rb +51 -20
  209. data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
  210. data/lib/hecks/language/bluebook/policy.bluebook +11 -1
  211. data/lib/hecks/language/bluebook/vocabulary.bluebook +348 -13
  212. data/lib/hecks/language/hecksagon/hecksagon.bluebook +11 -0
  213. data/lib/hecks/language/oidc.json +5 -0
  214. data/lib/hecks/literal.rb +41 -9
  215. data/lib/hecks/naming.rb +112 -31
  216. data/lib/hecks/ports/access_control.rb +53 -2
  217. data/lib/hecks/ports/agent/answers.rb +83 -6
  218. data/lib/hecks/ports/agent.rb +119 -35
  219. data/lib/hecks/ports/authentication.rb +44 -4
  220. data/lib/hecks/ports/authorization.rb +50 -11
  221. data/lib/hecks/ports/clock.rb +42 -23
  222. data/lib/hecks/ports/extraction.rb +16 -0
  223. data/lib/hecks/ports/identity_assignment.rb +23 -2
  224. data/lib/hecks/ports/identity_generation.rb +17 -3
  225. data/lib/hecks/ports/identity_resolution.rb +17 -1
  226. data/lib/hecks/ports/key_vault.port +6 -0
  227. data/lib/hecks/ports/key_vault.rb +58 -0
  228. data/lib/hecks/ports/loading.rb +4 -0
  229. data/lib/hecks/ports/persistence/append_only.rb +172 -8
  230. data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
  231. data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
  232. data/lib/hecks/ports/persistence/execution.rb +4 -0
  233. data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
  234. data/lib/hecks/ports/persistence/plugin.rb +42 -4
  235. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
  236. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
  237. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
  238. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
  239. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
  241. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
  242. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
  243. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
  244. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +118 -66
  245. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
  246. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +34 -5
  247. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
  248. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
  249. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
  250. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +33 -9
  251. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
  252. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +95 -6
  253. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
  254. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +314 -90
  255. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
  256. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
  257. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
  258. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +48 -8
  259. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
  260. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
  261. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
  262. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +58 -19
  263. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +96 -5
  264. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +15 -0
  265. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +9 -1
  266. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
  267. data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
  268. data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
  269. data/lib/hecks/ports/persistence/repository_factory.rb +23 -3
  270. data/lib/hecks/ports/persistence/state_codec.rb +319 -0
  271. data/lib/hecks/ports/persistence.rb +36 -1
  272. data/lib/hecks/ports/projection.rb +61 -7
  273. data/lib/hecks/ports/query/in_memory.rb +41 -8
  274. data/lib/hecks/ports/query/ordering.rb +21 -6
  275. data/lib/hecks/ports/query.rb +35 -0
  276. data/lib/hecks/ports.rb +1 -0
  277. data/lib/hecks/projections/bootstrap_table.rb +147 -0
  278. data/lib/hecks/projections/diagrams.rb +315 -79
  279. data/lib/hecks/projections/glossary/html.rb +91 -3
  280. data/lib/hecks/projections/glossary/markdown.rb +50 -3
  281. data/lib/hecks/projections/glossary/mermaid.rb +49 -1
  282. data/lib/hecks/projections/glossary/sections.rb +1 -1
  283. data/lib/hecks/projections/glossary/sentences.rb +110 -5
  284. data/lib/hecks/projections/glossary.rb +173 -31
  285. data/lib/hecks/projections/ir.rb +1 -1
  286. data/lib/hecks/projections/model/deviations.rb +62 -17
  287. data/lib/hecks/projections/model.rb +75 -21
  288. data/lib/hecks/projections/oidc.rb +45 -8
  289. data/lib/hecks/projections/parser_table.rb +53 -12
  290. data/lib/hecks/projections/reference.rb +15 -3
  291. data/lib/hecks/projections/rust_vocabulary.rb +646 -0
  292. data/lib/hecks/projections/shape.rb +10 -2
  293. data/lib/hecks/projections/statements.rb +69 -22
  294. data/lib/hecks/projections/vocabulary.rb +26 -9
  295. data/lib/hecks/projections.rb +5 -3
  296. data/lib/hecks/projector/cli_projector.rb +245 -37
  297. data/lib/hecks/projector/docs_projector.rb +154 -28
  298. data/lib/hecks/projector/exporter.rb +104 -29
  299. data/lib/hecks/projector/ir_projector.rb +7 -1
  300. data/lib/hecks/projector/narrate_projector.rb +144 -23
  301. data/lib/hecks/projector/target.rb +42 -18
  302. data/lib/hecks/projector.rb +86 -18
  303. data/lib/hecks/query_ir.rb +94 -47
  304. data/lib/hecks/query_specification/common/comparators.rb +19 -3
  305. data/lib/hecks/query_specification/common/comparison.rb +109 -27
  306. data/lib/hecks/query_specification/common/dsl.rb +65 -9
  307. data/lib/hecks/query_specification/common/null_policy.rb +61 -15
  308. data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
  309. data/lib/hecks/query_specification/common/options.rb +25 -0
  310. data/lib/hecks/query_specification/field_path.rb +69 -15
  311. data/lib/hecks/query_specification/hop_path.rb +57 -20
  312. data/lib/hecks/query_specification/read_model/specification.rb +4 -0
  313. data/lib/hecks/rendering.rb +9 -3
  314. data/lib/hecks/router/namespace_installer.rb +16 -3
  315. data/lib/hecks/router.rb +56 -1
  316. data/lib/hecks/runtime/aggregate_lock.rb +20 -11
  317. data/lib/hecks/runtime/boot_gates.rb +21 -3
  318. data/lib/hecks/runtime/caller.rb +40 -8
  319. data/lib/hecks/runtime/capability_graph.rb +13 -2
  320. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +40 -41
  321. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +45 -67
  322. data/lib/hecks/runtime/command_interpreter.rb +195 -113
  323. data/lib/hecks/runtime/command_rules/admissibility.rb +231 -80
  324. data/lib/hecks/runtime/command_rules/arithmetic.rb +154 -96
  325. data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
  326. data/lib/hecks/runtime/command_rules/emission.rb +18 -1
  327. data/lib/hecks/runtime/command_rules/references.rb +145 -55
  328. data/lib/hecks/runtime/command_rules.rb +3 -0
  329. data/lib/hecks/runtime/dependency_planning.rb +56 -11
  330. data/lib/hecks/runtime/dispatcher.rb +263 -92
  331. data/lib/hecks/runtime/entity_element.rb +304 -67
  332. data/lib/hecks/runtime/entity_interpreter.rb +149 -88
  333. data/lib/hecks/runtime/errors.rb +37 -23
  334. data/lib/hecks/runtime/event.rb +15 -10
  335. data/lib/hecks/runtime/identity.rb +91 -23
  336. data/lib/hecks/runtime/instance.rb +103 -18
  337. data/lib/hecks/runtime/interpreting.rb +24 -16
  338. data/lib/hecks/runtime/invocation.rb +358 -0
  339. data/lib/hecks/runtime/loader.rb +105 -19
  340. data/lib/hecks/runtime/outbox.rb +164 -26
  341. data/lib/hecks/runtime/policy_interpreter.rb +73 -60
  342. data/lib/hecks/runtime/port_operation_interpreter.rb +42 -19
  343. data/lib/hecks/runtime/query_interpreter.rb +93 -74
  344. data/lib/hecks/runtime/reaction_invocation.rb +73 -28
  345. data/lib/hecks/runtime/read_model_interpreter.rb +60 -44
  346. data/lib/hecks/runtime/rebuild_sweep.rb +32 -4
  347. data/lib/hecks/runtime/reference_hop.rb +48 -6
  348. data/lib/hecks/runtime/refusal_wording.rb +142 -115
  349. data/lib/hecks/runtime/registry/saga_persistence.rb +32 -21
  350. data/lib/hecks/runtime/registry/verification.rb +153 -28
  351. data/lib/hecks/runtime/registry.rb +202 -32
  352. data/lib/hecks/runtime/remote_dispatcher.rb +125 -24
  353. data/lib/hecks/runtime/routing.rb +36 -154
  354. data/lib/hecks/runtime/saga_interpreter/correlation.rb +25 -27
  355. data/lib/hecks/runtime/saga_interpreter.rb +90 -76
  356. data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
  357. data/lib/hecks/runtime/tenant_check.rb +33 -13
  358. data/lib/hecks/runtime/tenant_scope.rb +23 -5
  359. data/lib/hecks/runtime/value/admission.rb +75 -30
  360. data/lib/hecks/runtime/value/coercion.rb +555 -142
  361. data/lib/hecks/runtime/value/entity_list_coercion.rb +132 -60
  362. data/lib/hecks/runtime/value.rb +71 -21
  363. data/lib/hecks/runtime.rb +39 -7
  364. data/lib/hecks/storehouse.rb +368 -72
  365. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +130 -0
  366. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +32 -0
  367. data/lib/hecks/version.rb +3 -3
  368. data/lib/hecks/vocabulary.rb +205 -4
  369. data/lib/hecks.rb +91 -11
  370. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +19 -11
  371. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +24 -12
  372. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +38 -14
  373. metadata +28 -2
@@ -1,51 +1,61 @@
1
1
  module Hecks
2
2
  module Fuzzing
3
- # THE WEIGHTED HALF OF `QualityControl::Target.Rotation`
3
+ # The weighted half of `QualityControl::Target.Rotation`
4
4
  # (qa/bluebook/quality_control.bluebook) — see that query's own
5
5
  # comment for why the ledger itself still only offers
6
6
  # least-recently-swept order: `order_by` sorts by exactly one stored
7
7
  # field, and a target's actual rotation priority wants two blended
8
- # together (time since last swept, AND recent yield), which nothing
8
+ # together (time since last swept, and recent yield), which nothing
9
9
  # in the query sublanguage can express. `Rotation` stays the raw
10
10
  # view; this module is where the blend actually happens, against the
11
11
  # rows that query already returns.
12
12
  #
13
- # PURE, DELIBERATELY. Every method here is a function of its own
14
- # arguments only — no clock read, no query dispatched, nothing
15
- # random — so this is unit-testable with plain hashes and no ledger
16
- # boot at all, and reruns identically given the same rotation, the
17
- # same `now` and the same dials. `now` arrives as an argument for
18
- # the exact reason `Target.Claim`'s own comment already gives: a
19
- # pure function cannot ask the time, so whoever calls this supplies
20
- # it, exactly as it supplies an id.
13
+ # ## Pure, deliberately
21
14
  #
22
- # WHERE THIS ACTUALLY MATTERS, AND WHERE IT DOES NOT — checked
23
- # against `bin/qa_sweep`'s own code, not assumed. `bin/qa_sweep
24
- # --all` sweeps every currently-waiting target in one pass,
25
- # regardless of order (`run_all_mode`'s own `waiting.map { spawn_
26
- # sweep_child }` — every element the query returned, never
27
- # `.first`), so nothing about this module's own ordering changes
28
- # what `--all` does; it already sweeps everything the ledger has to
29
- # offer. What it changes is `bin/qa_sweep` invoked with NO target
30
- # argument, which today picks exactly one target via `Target.
31
- # Rotation.first` — wiring `.pick` in there instead is this module's
32
- # one real caller, and (per the same investigation) its only one:
33
- # there is no separate scheduling or concurrency-limit mechanism
34
- # elsewhere in this repository for it to feed instead.
15
+ # Every method here is a function of its own arguments only — no clock
16
+ # read, no query dispatched, nothing random — so this is unit-testable
17
+ # with plain hashes and no ledger boot at all, and reruns identically
18
+ # given the same rotation, the same `now` and the same dials. `now`
19
+ # arrives as an argument for the exact reason `Target.Claim`'s own
20
+ # comment already gives: a pure function cannot ask the time, so
21
+ # whoever calls this supplies it, exactly as it supplies an id.
22
+ #
23
+ # ## Where this actually matters, and where it does not
24
+ #
25
+ # Checked against `bin/qa_sweep`'s own code, not assumed. `bin/qa_sweep
26
+ # --all` sweeps every currently-waiting target in one pass, regardless
27
+ # of order (`run_all_mode`'s own `waiting.map { spawn_sweep_child }` —
28
+ # every element the query returned, never `.first`), so nothing about
29
+ # this module's own ordering changes what `--all` does; it already
30
+ # sweeps everything the ledger has to offer. What it changes is
31
+ # `bin/qa_sweep` invoked with no target argument, which today picks
32
+ # exactly one target via `Target.Rotation.first` — wiring `.pick` in
33
+ # there instead is this module's one real caller, and (per the same
34
+ # investigation) its only one: there is no separate scheduling or
35
+ # concurrency-limit mechanism elsewhere in this repository for it to
36
+ # feed instead.
35
37
  module RotationPriority
36
38
  module_function
37
39
 
38
- # THE NEXT STORED `Target.yield_score` — decay what survives from
40
+ # The next stored `Target.yield_score` — decay what survives from
39
41
  # before, then add whatever this just-concluded period actually
40
42
  # found. Integer division, like every other count in this ledger
41
43
  # (`Sweep.CheckCount`, `Bug.BugOrder`): a yield score is a
42
44
  # priority signal, not a precise statistic, and a fractional score
43
45
  # would need a value object this ledger does not have.
44
46
  #
45
- # `decay_percent` DEFAULTS TO THE DIAL, NOT A LITERAL, so a caller
47
+ # `decay_percent` defaults to the dial, not a literal, so a caller
46
48
  # that does not care still gets the practice's own current answer
47
49
  # to "how much of this is 'recent'" rather than a second, silently
48
50
  # drifting copy of the same number.
51
+ #
52
+ # @param old_score [Integer] the target's `Target.yield_score` before this period
53
+ # @param surprises_this_period [Integer] how many Surprised checks this period found
54
+ # @param decay_percent [Integer] percent of `old_score` that survives into the new
55
+ # score; defaults to `QualityControlDials::YIELD_DECAY_PERCENT`
56
+ # @return [Integer] the next `Target.yield_score` to store
57
+ # @raise [ArgumentError] if `old_score` is negative
58
+ # @raise [ArgumentError] if `surprises_this_period` is negative
49
59
  def next_yield_score(old_score:, surprises_this_period:,
50
60
  decay_percent: QualityControlDials::YIELD_DECAY_PERCENT)
51
61
  raise ArgumentError, "old_score must not be negative" if old_score.negative?
@@ -54,14 +64,14 @@ module Hecks
54
64
  ((old_score * decay_percent) / 100) + surprises_this_period
55
65
  end
56
66
 
57
- # THE PICK ITSELF. `rows` is whatever `Target.Rotation` returned —
67
+ # The pick itself. `rows` is whatever `Target.Rotation` returned —
58
68
  # each row a hash carrying at least `:last_swept` and
59
69
  # `:yield_score`, both `{ value: Integer }`, the shape every
60
70
  # VO-typed field in this ledger already comes back as. Returns
61
71
  # `nil` for an empty rotation, the same "nothing waiting" case
62
72
  # `bin/qa_sweep` already handles by seeding the default targets.
63
73
  #
64
- # THE FLOOR WINS OUTRIGHT — no starvation, on purpose (see
74
+ # The floor wins outright — no starvation, on purpose (see
65
75
  # `QualityControlDials::ROTATION_STALE_FLOOR_SECONDS`'s own
66
76
  # comment for why a floor and not a total exclusion). A row stale
67
77
  # past `floor_seconds` is picked ahead of every row that is not,
@@ -70,13 +80,23 @@ module Hecks
70
80
  # keeps the floor from becoming a new source of starvation between
71
81
  # two long-neglected targets.
72
82
  #
73
- # BELOW THE FLOOR, HIGHEST COMBINED SCORE WINS. `staleness +
83
+ # Below the floor, highest combined score wins. `staleness +
74
84
  # (yield_score * weight_seconds)` — plain addition, never a ratio
75
85
  # or anything that could divide by zero, and the units are
76
86
  # deliberately the same (seconds) so `weight_seconds` reads as
77
87
  # "how many seconds of extra staleness one point of yield is
78
88
  # worth" rather than an opaque multiplier nobody could sanity
79
89
  # check by eye.
90
+ #
91
+ # @param rows [Array<Hash>] rows from `Target.Rotation`, each carrying at least
92
+ # `:last_swept` and `:yield_score` as `{ value: Integer }`
93
+ # @param now [Integer] the current time, Unix epoch seconds
94
+ # @param weight_seconds [Integer] seconds of extra staleness one point of yield is
95
+ # worth; defaults to `QualityControlDials::YIELD_WEIGHT_SECONDS`
96
+ # @param floor_seconds [Integer] staleness, in seconds, past which a row is picked
97
+ # ahead of every row not yet that stale; defaults to
98
+ # `QualityControlDials::ROTATION_STALE_FLOOR_SECONDS`
99
+ # @return [Hash, nil] the picked row, or `nil` if `rows` is empty
80
100
  def pick(rows, now:, weight_seconds: QualityControlDials::YIELD_WEIGHT_SECONDS,
81
101
  floor_seconds: QualityControlDials::ROTATION_STALE_FLOOR_SECONDS)
82
102
  return nil if rows.empty?
@@ -0,0 +1,139 @@
1
+ require "json"
2
+ require "hecks/naming"
3
+
4
+ module Hecks
5
+ module Fuzzing
6
+ # What a compiled Rust binary declares it did not generate — read off the
7
+ # `manifest.json` files `rust/project/domain_generator.rb` writes beside
8
+ # every generated module, never inferred from Rust's refusal wording.
9
+ #
10
+ # The differential fuzzer (`Differential.diff`) drops a query or
11
+ # read-model verb from the comparison if and only if the generator's own
12
+ # manifest recorded it as `generated: false`, with the `gap_class` and
13
+ # `construct` that explain why — never by pattern-matching Rust's
14
+ # refusal wording ("is not generated for this domain"), which would
15
+ # tolerate whatever Rust happened to say, including a codegen
16
+ # regression that silently started refusing a construct it once
17
+ # generated. A refusal the manifest does not account for stays in the
18
+ # comparison and fails it.
19
+ #
20
+ # ## Which manifests describe a binary
21
+ #
22
+ # `build_and_pin` (spec/support/rust_conformance_helpers.rb) and
23
+ # `bin/qa_generated_domains` both pin a feature's binary at
24
+ # `<rust_dir>/target/debug/rust-<feature>`. That binary compiles
25
+ # `src/generated/<feature>/` plus every shared framework chapter (a
26
+ # generated directory with no `merged.rs` of its own — `governance`,
27
+ # `identity`; see the generated `mod.rs` header). Ids in those manifests
28
+ # are domain-qualified, so a chapter a domain never attaches contributes
29
+ # entries no sequence for that domain can name.
30
+ #
31
+ # ## A missing manifest tolerates nothing
32
+ #
33
+ # A hand-written fixture crate, or a tree generated before manifests
34
+ # existed, has no declaration to honour, so every refusal it produces
35
+ # is compared as-is. That is the fail-closed direction.
36
+ class RustGapManifest
37
+ # The only kinds the kernel answers as a query step. A not-generated
38
+ # command changes state, so dropping its refusal would not make the
39
+ # comparison honest; those stay compared and fail.
40
+ TOLERABLE_KINDS = %w[query read_model].freeze
41
+ PINNED_BINARY = %r{\A(?<rust_dir>.+)/target/debug/rust-(?<feature>[a-z0-9_]+)\z}
42
+
43
+ attr_reader :rust_dir, :feature, :entries
44
+
45
+ # Builds the manifest reader for the pinned conformance binary at `binary`.
46
+ #
47
+ # @param binary [String] path to a pinned binary, `<rust_dir>/target/debug/rust-<feature>`
48
+ # @return [Fuzzing::RustGapManifest] the manifest reader for that binary's feature
49
+ # @raise [ArgumentError] if `binary` does not match the pinned-binary path shape
50
+ def self.for_binary(binary)
51
+ match = PINNED_BINARY.match(File.expand_path(binary.to_s))
52
+ unless match
53
+ raise ArgumentError, "#{binary.inspect} is not a pinned conformance binary " \
54
+ "(<rust_dir>/target/debug/rust-<feature>) — cannot tell which manifest describes it"
55
+ end
56
+
57
+ new(rust_dir: match[:rust_dir], feature: match[:feature])
58
+ end
59
+
60
+ # Every committed manifest entry under `rust_dir`, each tagged with the
61
+ # generated module it came from — what the boundary ratchet and
62
+ # bin/rust_coverage's allowlist staleness check read.
63
+ #
64
+ # @param rust_dir [String] path to the Rust project root (holds `src/generated/*/`)
65
+ # @return [Array<Hash>] every `src/generated/*/manifest.json` entry, each a
66
+ # String-keyed manifest Hash plus `"module" => String` naming the directory it came from
67
+ def self.all_entries(rust_dir)
68
+ Dir.glob(File.join(rust_dir, "src/generated/*/manifest.json")).flat_map do |path|
69
+ module_name = File.basename(File.dirname(path))
70
+ JSON.parse(File.read(path)).map { |entry| entry.merge("module" => module_name) }
71
+ end
72
+ end
73
+
74
+ # @param rust_dir [String] path to the Rust project root (holds `src/generated/*/`)
75
+ # @param feature [String] the domain feature this manifest reader describes
76
+ def initialize(rust_dir:, feature:)
77
+ @rust_dir = rust_dir
78
+ @feature = feature
79
+ @entries = manifest_paths.flat_map { |path| JSON.parse(File.read(path)) }.freeze
80
+ @not_generated = index_not_generated
81
+ end
82
+
83
+ # The manifest entry that declares `verb` not generated, or nil. `verb`
84
+ # is the wire spelling a sequence step uses; an ad hoc filter (a Hash)
85
+ # is never declared and answers nil.
86
+ #
87
+ # @param verb [String, Object] the wire-spelled query or read-model verb to look up
88
+ # @return [Hash, nil] the String-keyed manifest entry declaring `verb` not generated,
89
+ # or nil if `verb` is not a String or no entry declares it
90
+ def not_generated(verb)
91
+ return nil unless verb.is_a?(String)
92
+
93
+ @not_generated[verb]
94
+ end
95
+
96
+ # Answers whether `verb` is declared not generated by this manifest.
97
+ #
98
+ # @param verb [String, Object] the wire-spelled query or read-model verb to look up
99
+ # @return [Boolean] whether the manifest declares `verb` not generated
100
+ def not_generated?(verb) = !not_generated(verb).nil?
101
+
102
+ # Lists every verb this manifest declares not generated.
103
+ #
104
+ # @return [Set<String>] every verb the manifest declares not generated
105
+ def not_generated_verbs = @not_generated.keys.to_set
106
+
107
+ private
108
+
109
+ def manifest_paths
110
+ generated = File.join(rust_dir, "src/generated")
111
+ own = File.join(generated, feature, "manifest.json")
112
+ chapters = Dir.glob(File.join(generated, "*/manifest.json")).reject do |path|
113
+ dir = File.dirname(path)
114
+ File.basename(dir) == feature || File.exist?(File.join(dir, "merged.rs"))
115
+ end
116
+ ([own] + chapters.sort).select { |path| File.exist?(path) }
117
+ end
118
+
119
+ def index_not_generated
120
+ @entries.each_with_object({}) do |entry, index|
121
+ next unless TOLERABLE_KINDS.include?(entry["kind"]) && entry["generated"] == false
122
+
123
+ wire_verbs(entry).each { |verb| index[verb] = entry }
124
+ end.freeze
125
+ end
126
+
127
+ # A query is asked by its id. A read model's id is "Domain::Name", but
128
+ # it is asked as "Domain.Name" or "Domain.name_in_snake_case" — the two
129
+ # spellings `kernel::read_model::find` accepts (`matches_snake_alias`,
130
+ # a port of `Hecks::Naming.snake`).
131
+ def wire_verbs(entry)
132
+ return [entry["id"]] if entry["kind"] == "query"
133
+
134
+ domain, name = entry["id"].split("::", 2)
135
+ ["#{domain}.#{name}", "#{domain}.#{Hecks::Naming.snake(name)}"].uniq
136
+ end
137
+ end
138
+ end
139
+ end