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,25 +1,28 @@
1
+ require "digest"
2
+ require "fileutils"
3
+
1
4
  module Hecks
2
5
  module Bluebook
3
6
  module MetaValidator
4
- # S14, ADR 0026 — DISPATCHES THE LANGUAGE'S OWN GRAMMAR TABLE INTO
5
- # ITSELF, once, so `Keyword`/`Argument`'s own `status` genuinely IS a
7
+ # S14, ADR 0026 — dispatches the language's own grammar table into
8
+ # itself, once, so `Keyword`/`Argument`'s own `status` genuinely is a
6
9
  # lifecycle — checked at real dispatch time (the same admission/
7
10
  # coercion/lifecycle-guard door every other command goes through),
8
11
  # not merely declared and never exercised.
9
12
  #
10
- # THE SOURCE STAYS STATIC. Aggregate-local `KeywordSeed`/
13
+ # **The source stays static**. Aggregate-local `KeywordSeed`/
11
14
  # `ArgumentSeed` value objects (still hand-written `member` rows —
12
- # now beside the concepts they spell) are what gets WRITTEN ; this
13
- # is what turns them into what gets READ. `Judge`/`Reconstruction`
15
+ # now beside the concepts they spell) are what gets written ; this
16
+ # is what turns them into what gets read. `Judge`/`Reconstruction`
14
17
  # already draw exactly this line everywhere else in the meta-domain
15
- # (a chapter's own DECLARATIONS versus what gets DISPATCHED from
18
+ # (a chapter's own declarations versus what gets dispatched from
16
19
  # them) — this runs the same distinction one level further out, for
17
20
  # the language's own grammar table.
18
21
  #
19
- # A DEDICATED RUNTIME, not `MetaValidator.fresh_runtime`. That one
20
- # is reserved for `Judge`'s own bootstrap (dispatching a CHAPTER's
21
- # declarations INTO the meta-domain's grammar) — a different act
22
- # from this one (dispatching the meta-domain's OWN grammar table
22
+ # A dedicated runtime, not `MetaValidator.fresh_runtime`. That one
23
+ # is reserved for `Judge`'s own bootstrap (dispatching a chapter's
24
+ # declarations into the meta-domain's grammar) — a different act
25
+ # from this one (dispatching the meta-domain's own grammar table
23
26
  # data into a live "Bluebook" domain instance). Sharing the runtime
24
27
  # would let one boot's own repository state leak into the other's.
25
28
  #
@@ -29,7 +32,7 @@ module Hecks
29
32
  #
30
33
  # each row a plain Hash, string values, `status` included — the
31
34
  # exact shape `ParserTable`/`syntax_conformance_spec` already read
32
- # off the OLD closed-set members, so neither consumer had to change
35
+ # off the old closed-set members, so neither consumer had to change
33
36
  # what it does with a row, only where the row comes from.
34
37
  module SyntaxBoot
35
38
  module_function
@@ -40,21 +43,21 @@ module Hecks
40
43
  # conformance_spec, bin/reference) should each pay for on every
41
44
  # call.
42
45
  #
43
- # KEYED BY THE GRAMMAR REGISTRY'S OWN CHAPTER SET, not by a
46
+ # Keyed by the grammar registry's own chapter set, not by a
44
47
  # "ready" flag. `boot` reads exactly two things: the registry's
45
48
  # "Bluebook" chapter (the core seed rows) and every chapter in the
46
49
  # registry that `attaches_to` a core context (Paging's rows). So
47
- # the table is a pure function of which chapter OBJECTS the
50
+ # the table is a pure function of which chapter objects the
48
51
  # registry holds — and that is the cache key: the same chapters,
49
52
  # by identity, mean the same table; a chapter replaced (the
50
53
  # fixpoint judge swapping a raw chapter for its assembled self)
51
54
  # or added (`load_attached_grammar_into`) means a fresh boot.
52
55
  #
53
- # WHY NOT THE EARLIER `grammar_registry_ready?` GUARD. That guard
56
+ # Why not the earlier `grammar_registry_ready?` guard. That guard
54
57
  # was right about the hazard — a snapshot taken mid-build, before
55
58
  # Paging attached, would be missing limit/offset/cursor/nulls
56
59
  # forever — and wrong about the cost of its cure. It refused to
57
- # cache ANYTHING until the whole grammar registry had finished
60
+ # cache anything until the whole grammar registry had finished
58
61
  # building, calling that window "narrow" and recomputing in it
59
62
  # "cheap". Measured (hecks_ai_training, a six-entity chess domain,
60
63
  # 2026-08-22): every `word_gate_dispatch` landing in that window
@@ -69,7 +72,7 @@ module Hecks
69
72
  # chapter objects, so it invalidates this the same way it always
70
73
  # invalidated `grammar_registry_ready?`.
71
74
  #
72
- # `equal?`, NOT `==`, on the chapters — identity is the fact being
75
+ # `equal?`, not `==`, on the chapters — identity is the fact being
73
76
  # tracked. Holding the chapter objects themselves (not their ids)
74
77
  # in the key also means a collected chapter can never hand its id
75
78
  # to a newcomer behind this cache's back.
@@ -77,7 +80,12 @@ module Hecks
77
80
  chapters = MetaValidator.grammar_registry.bluebooks.to_a
78
81
  return @call if @call && same_chapters?(@call_chapters, chapters)
79
82
 
80
- result = boot
83
+ result = read_disk_cache(chapters) || begin
84
+ fresh = boot
85
+ write_disk_cache(chapters, fresh)
86
+ fresh
87
+ end
88
+
81
89
  @call = result
82
90
  @call_chapters = chapters
83
91
  result
@@ -90,14 +98,118 @@ module Hecks
90
98
  end
91
99
  end
92
100
 
101
+ # Cross-process persistence for the same ~1s-per-build work `call`
102
+ # above already memoizes in-process — this file's own chapter-
103
+ # identity keying only ever helps callers sharing one process (the
104
+ # in-memory fixpoint window, or `bin/reference`'s single run); every
105
+ # fresh process (a `qa_sweep --all` child, a `parallel_rspec`
106
+ # worker, `bin/qa_sweep` itself) pays both real builds again from
107
+ # scratch even when the grammar source hasn't changed at all since
108
+ # the last process that built it.
109
+ #
110
+ # Not a fix for the two-builds-per-process shape — investigated and
111
+ # confirmed genuine, not waste (see this module's own header
112
+ # history: the previous "wait for the whole registry" design cost
113
+ # 42 rebuilds/32s per process precisely because real callers need a
114
+ # correct table mid-bootstrap, before Paging attaches). Both builds
115
+ # still happen once each per process; this only makes each of them
116
+ # a cheap disk read instead of a real ~1s dispatch, once some
117
+ # earlier process has already paid for that exact chapter-set +
118
+ # grammar-content combination.
119
+ #
120
+ # Keyed the same way `same_chapters?` is, translated across process
121
+ # boundaries — chapter *object identity* (what the in-memory cache
122
+ # keys on) means nothing to a different process; chapter *names*,
123
+ # in the same order, do. Combined with a content hash of every
124
+ # grammar file `boot` can read from (`seed_chapters` walks every
125
+ # bluebook the registry holds, so this must cover the core chapters
126
+ # and every attached one, not just "Bluebook" + "Paging") — a
127
+ # source edit anywhere in that set correctly misses the old cache
128
+ # entry rather than silently serving a stale table.
129
+ #
130
+ # Fails toward a real boot, never toward a wrong table — same
131
+ # loud-not-silent discipline this codebase already holds CI to
132
+ # (`postgres_io_relevant_changed`'s own header). A missing file, a
133
+ # corrupt Marshal blob, a permission error, an unwritable `tmp/` —
134
+ # every one of these degrades to "no disk cache today", never to a
135
+ # crash or a served-but-wrong table. `tmp/` is already gitignored
136
+ # for exactly this kind of local, disposable-but-useful-while-it-
137
+ # lasts artifact (`Storehouse::LOG_ROOT`'s own header names the
138
+ # same convention).
139
+ #
140
+ # **Atomic write, not a lock** — `qa_sweep --all` spawns up to 4
141
+ # children at once, any of which could reach a cold cache
142
+ # simultaneously and each compute the identical real boot result
143
+ # for the identical key. Writing to a PID-suffixed temp file and
144
+ # `File.rename`ing it into place (a single atomic syscall on the
145
+ # same filesystem) means a concurrent second writer's rename just
146
+ # overwrites the first with byte-identical content — never a torn
147
+ # or partially-written file a concurrent reader could observe.
148
+ #
149
+ # `HECKS_SYNTAX_BOOT_CACHE=off` — an escape hatch needing no code
150
+ # change, the same shape `Storehouse::BOOT_ROOT`'s own
151
+ # `HECKS_STOREHOUSE_ROOT` override uses, for the day this needs to
152
+ # be ruled out while debugging something else entirely.
153
+ CACHE_DIR = File.expand_path("../../../../tmp/hecks_syntax_boot_cache", __dir__).freeze
154
+
155
+ def disk_cache_enabled? = ENV["HECKS_SYNTAX_BOOT_CACHE"] != "off"
156
+
157
+ def read_disk_cache(chapters)
158
+ return nil unless disk_cache_enabled?
159
+
160
+ path = disk_cache_path(chapters)
161
+ return nil unless File.exist?(path)
162
+
163
+ Marshal.load(File.binread(path)) # rubocop:disable Security/MarshalLoad -- own process-local cache, never external input
164
+ rescue StandardError
165
+ nil
166
+ end
167
+
168
+ def write_disk_cache(chapters, result)
169
+ return unless disk_cache_enabled?
170
+
171
+ path = disk_cache_path(chapters)
172
+ FileUtils.mkdir_p(CACHE_DIR)
173
+ tmp_path = "#{path}.#{Process.pid}.tmp"
174
+ File.binwrite(tmp_path, Marshal.dump(result))
175
+ File.rename(tmp_path, path)
176
+ rescue StandardError
177
+ nil
178
+ end
179
+
180
+ def disk_cache_path(chapters)
181
+ File.join(CACHE_DIR, "#{disk_cache_key(chapters)}.marshal")
182
+ end
183
+
184
+ def disk_cache_key(chapters)
185
+ names = chapters.map { |name, _chapter| name }
186
+ Digest::SHA256.hexdigest("#{names.join(',')}:#{grammar_content_digest}")
187
+ end
188
+
189
+ # Every file `boot` can possibly read from, via `seed_chapters`
190
+ # walking every bluebook the registry holds — not just "Bluebook"
191
+ # and "Paging" (the two chapters this module's own comments name
192
+ # most often), because World/Hecksagon/any future attached chapter
193
+ # are equally eligible to carry their own `KeywordSeed`/
194
+ # `ArgumentSeed` value object. Coarser than strictly necessary (any
195
+ # one file changing invalidates every cached key, not just the
196
+ # chapter it belongs to) — deliberately, since under-covering this
197
+ # set is a correctness bug (a stale table survives a real grammar
198
+ # edit) and over-covering it is only ever a wasted cache miss.
199
+ def grammar_content_digest
200
+ files = (MetaValidator::GRAMMAR_FILES + MetaValidator::WORLD_GRAMMAR + MetaValidator::HECKSAGON_GRAMMAR +
201
+ Dir.glob(File.join(MetaValidator::ATTACHED_GRAMMAR_DIR, "*.bluebook"))).sort
202
+ Digest::SHA256.hexdigest(files.map { |file| File.read(file) }.join("\0"))
203
+ end
204
+
93
205
  def boot
94
206
  bluebook = MetaValidator.grammar_registry.bluebook("Bluebook")
95
207
  # `MetaValidator.fresh_runtime`, not a brand-new `Runtime::
96
208
  # Registry` — the grammar registry's own copy already has
97
209
  # "Bluebook" registered (`grammar_registry`'s own boot already
98
- # ran `registry.add_bluebook`) AND its adapter ports already
210
+ # ran `registry.add_bluebook`) and its adapter ports already
99
211
  # loaded ; a standalone registry would need both wired by hand.
100
- # `fresh_runtime` resets `@repositories` on the SAME registry —
212
+ # `fresh_runtime` resets `@repositories` on the same registry —
101
213
  # the identical isolation `Judge.new` already relies on for
102
214
  # every real domain it judges, proven safe by every dispatch
103
215
  # this session has ever made.
@@ -119,7 +231,7 @@ module Hecks
119
231
  { value: text.to_s }
120
232
  end
121
233
 
122
- # ABSENT STAYS ABSENT. A seed row's own optional columns ("was",
234
+ # Absent stays absent. A seed row's own optional columns ("was",
123
235
  # "at", "named", ...) are empty strings, not nil — `Literal`/CSV-
124
236
  # shaped grammar data has no `nil` to write — so this is the one
125
237
  # place that decides "" means "not given" for the purpose of an
@@ -131,7 +243,7 @@ module Hecks
131
243
  v(text)
132
244
  end
133
245
 
134
- # `Syntax.Declare`'s own `reference_to Bluebook` names the CHAPTER
246
+ # `Syntax.Declare`'s own `reference_to Bluebook` names the chapter
135
247
  # it belongs to — the same fact every other top-level aggregate's
136
248
  # own creating command carries (`ProcessManager.Declare`,
137
249
  # `Policy.Declare`, ...). This fresh runtime holds no chapter
@@ -141,15 +253,17 @@ module Hecks
141
253
  # by anything this boot does.
142
254
  def declare_syntax(runtime, bluebook)
143
255
  syntax = bluebook.aggregate("Syntax")
144
- runtime.dispatch("Bluebook::Bluebook.Declare", name: v(bluebook.hecks_name),
145
- vision: v("the language's own grammar table, " \
146
- "dispatched into itself"),
147
- classification: v("core"))
148
- runtime.dispatch("Bluebook::Syntax.Declare", bluebook: bluebook.hecks_name, name: v(syntax.hecks_name))
256
+ runtime.dispatch("Bluebook::Bluebook.Declare",
257
+ with: { name: v(bluebook.hecks_name),
258
+ vision: v("the language's own grammar table, " \
259
+ "dispatched into itself"),
260
+ classification: v("core") })
261
+ runtime.dispatch("Bluebook::Syntax.Declare",
262
+ with: { bluebook: bluebook.hecks_name, name: v(syntax.hecks_name) })
149
263
  end
150
264
 
151
- # `to: "Syntax"` NAMES THE RECORD ALREADY OPENED BY `declare_syntax`
152
- # ABOVE — an append onto an existing aggregate, not a second creation
265
+ # `to: "Syntax"` names the record already opened by `declare_syntax`
266
+ # above — an append onto an existing aggregate, not a second creation
153
267
  # of it. This used to smuggle `name: v("Syntax")` into the payload
154
268
  # instead, the pre-routing convention `Judge#appends` (the same
155
269
  # append shape, for `ValueObject.Member`/`ProcessManager.Handler`)
@@ -194,12 +308,12 @@ module Hecks
194
308
  end
195
309
  end
196
310
 
197
- # EVERY AGGREGATE-LOCAL TABLE IN EVERY LOADED LANGUAGE CHAPTER.
311
+ # Every aggregate-local table in every loaded language chapter.
198
312
  # The table's presence is the registration: no chapter, aggregate,
199
313
  # filename, or context catalog is maintained here. This finds the core
200
314
  # Bluebook concepts, the sibling artifact languages (World, Hecksagon,
201
315
  # Port, Adapter, Translation), and attached sub-languages alike.
202
- # Concatenated into ONE sequence because `position` is minted from the
316
+ # Concatenated into one sequence because `position` is minted from the
203
317
  # walk index and must not collide across concepts.
204
318
  def all_rows(bluebook, name)
205
319
  seed_chapters(bluebook).flat_map { |chapter| rows(chapter, name) }
@@ -226,7 +340,7 @@ module Hecks
226
340
  end
227
341
  end
228
342
 
229
- # Reads the dispatched result back into the SAME shape `rows`
343
+ # Reads the dispatched result back into the same shape `rows`
230
344
  # above hands the seed data in as — plain hashes, string values,
231
345
  # `status` included — so `ParserTable`/`syntax_conformance_spec`
232
346
  # need not know or care that a real dispatch happened in between.
@@ -10,7 +10,7 @@ module Hecks
10
10
  # AdapterJudge already are — its own file, its own door, judged
11
11
  # through its own self-hosted language (translation.bluebook)
12
12
  # rather than left as plain Ruby structs nothing checks. Walks the
13
- # WHOLE built translation in one pass — the top-level Declare/
13
+ # whole built translation in one pass — the top-level Declare/
14
14
  # Retire commands, then every nested aggregate's own Declare plus
15
15
  # one Add* command per rule it carries — the same "one judge, every
16
16
  # nested record" shape WorldJudge already gives Wiring. Field names
@@ -35,9 +35,9 @@ module Hecks
35
35
 
36
36
  def args(pairs) = pairs.compact
37
37
 
38
- # `Runtime::AlreadyExists` is rescued HERE but not by World/Port/
38
+ # `Runtime::AlreadyExists` is rescued here but not by World/Port/
39
39
  # Adapter's own sibling judges — found live, not by inspection.
40
- # Those three each judge a SINGLE aggregate per build (Port/Adapter)
40
+ # Those three each judge a single aggregate per build (Port/Adapter)
41
41
  # or a Hash keyed by verb (World's own settings, deduped by
42
42
  # construction), so a duplicate-identity Declare can never reach
43
43
  # their own runtime. `TranslationBuilder#aggregate` appends every
@@ -65,13 +65,13 @@ module Hecks
65
65
  send_to("Translation::Translation.Declare", t.domain,
66
66
  with: { domain: v(t.domain), from: v(t.from), to: v(t.to) })
67
67
 
68
- # `id:`, computed the SAME way — `Naming.identity([domain, from,
69
- # to])` — Translation's own identity is COMPOSITE
68
+ # `id:`, computed the same way — `Naming.identity([domain, from,
69
+ # to])` — Translation's own identity is composite
70
70
  # (`identified_by :domain, :from, :to`), the same reason
71
71
  # `Wiring.Set`'s own self-reference dispatch (world.bluebook,
72
72
  # `WorldJudge#judge_wiring`) needs a computed `id:` rather than
73
73
  # a bare field value — a single-field identity (TranslationAggregate's
74
- # own `name`) is the ONE case where the bare value itself IS the
74
+ # own `name`) is the one case where the bare value itself is the
75
75
  # id, confirmed live via direct dispatch testing, not assumed.
76
76
  translation_id = Naming.identity([t.domain, t.from, t.to])
77
77
  Array(t.retired).each do |name|
@@ -3,7 +3,7 @@ module Hecks
3
3
  module MetaValidator
4
4
  # Offers a built .world to the language that describes worlds.
5
5
  #
6
- # A world is a SIBLING of a bluebook — the same domain runs in many of
6
+ # A world is a sibling of a bluebook — the same domain runs in many of
7
7
  # them — so it is judged through its own door, against its own language
8
8
  # file, and its settings normalise the same way a mutation's fields do:
9
9
  # an open map becomes one Wiring per verb and one Setting row per value.
@@ -51,14 +51,14 @@ module Hecks
51
51
  end
52
52
 
53
53
  def judge_wiring(domain, verb, values)
54
- # THE SAME JOIN THE LANGUAGE ITSELF DERIVES. Wiring is
54
+ # The same join the language itself derives. Wiring is
55
55
  # `identified_by do world; verb.value end` — `Wiring.Declare`
56
- # (a creating command) ignores this `id:` entirely and computes its OWN
56
+ # (a creating command) ignores this `id:` entirely and computes its own
57
57
  # from `world`/`verb`, so a locally minted "#{domain}.#{verb}" named a
58
58
  # record `Wiring.Set` could never find : the id passed here has to be
59
- # the SAME derivation, not a second guess at what it must be.
59
+ # the same derivation, not a second guess at what it must be.
60
60
  id = Naming.identity([domain, verb])
61
- # `world_ref` is the WORLD's id and goes bare, the way every reference
61
+ # `world_ref` is the world's id and goes bare, the way every reference
62
62
  # does now ; the language gives it that explicit `as:` because `world`
63
63
  # beside it is an ordinary text attribute that happens to hold the same
64
64
  # string, and stays a value object. The two look alike and are not —