hecks 1.2.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 (358) 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 +60 -2
  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/postgres_era.adapter +5 -0
  23. data/lib/hecks/adapters/driven/prism.rb +4 -4
  24. data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
  25. data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
  26. data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
  27. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
  28. data/lib/hecks/adapters/driven/sqlite.rb +181 -21
  29. data/lib/hecks/adapters/driven.rb +4 -4
  30. data/lib/hecks/adapters/driving/github_webhook.rb +145 -0
  31. data/lib/hecks/behaviors/dsl.rb +2 -2
  32. data/lib/hecks/behaviors/expectations.rb +51 -23
  33. data/lib/hecks/behaviors/ir.rb +1 -1
  34. data/lib/hecks/behaviors/rspec.rb +1 -1
  35. data/lib/hecks/behaviors/runner.rb +2 -2
  36. data/lib/hecks/behaviors.rb +1 -1
  37. data/lib/hecks/bluebook/aggregate.rb +13 -13
  38. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +10 -10
  39. data/lib/hecks/bluebook/assembly/build.rb +1 -1
  40. data/lib/hecks/bluebook/assembly/contract.rb +39 -16
  41. data/lib/hecks/bluebook/assembly/contracts.rb +40 -38
  42. data/lib/hecks/bluebook/assembly/marks.rb +18 -18
  43. data/lib/hecks/bluebook/assembly/specializer.rb +19 -21
  44. data/lib/hecks/bluebook/assembly.rb +9 -9
  45. data/lib/hecks/bluebook/attribute.rb +9 -9
  46. data/lib/hecks/bluebook/behaviour/aggregate.rb +11 -11
  47. data/lib/hecks/bluebook/behaviour/attribute.rb +5 -5
  48. data/lib/hecks/bluebook/behaviour/chapter.rb +23 -5
  49. data/lib/hecks/bluebook/behaviour/command.rb +23 -23
  50. data/lib/hecks/bluebook/behaviour/domain_port.rb +27 -3
  51. data/lib/hecks/bluebook/behaviour/entity.rb +8 -8
  52. data/lib/hecks/bluebook/behaviour/hexagon.rb +4 -4
  53. data/lib/hecks/bluebook/behaviour/lifecycle.rb +5 -5
  54. data/lib/hecks/bluebook/behaviour/policy.rb +12 -12
  55. data/lib/hecks/bluebook/behaviour/process_manager.rb +7 -7
  56. data/lib/hecks/bluebook/behaviour/query.rb +1 -1
  57. data/lib/hecks/bluebook/behaviour/read_model.rb +8 -8
  58. data/lib/hecks/bluebook/behaviour/traits.rb +12 -12
  59. data/lib/hecks/bluebook/behaviour/value_object.rb +6 -6
  60. data/lib/hecks/bluebook/capabilities.rb +27 -0
  61. data/lib/hecks/bluebook/chapter.rb +28 -9
  62. data/lib/hecks/bluebook/command.rb +12 -12
  63. data/lib/hecks/bluebook/domain_port.rb +9 -9
  64. data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
  65. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
  66. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +96 -96
  67. data/lib/hecks/bluebook/dsl/attribute_collector.rb +41 -41
  68. data/lib/hecks/bluebook/dsl/binding_proxy.rb +22 -2
  69. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +111 -74
  70. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +48 -30
  71. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
  72. data/lib/hecks/bluebook/dsl/command_builder.rb +103 -103
  73. data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
  74. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
  75. data/lib/hecks/bluebook/dsl/entity_builder.rb +56 -56
  76. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
  77. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +89 -30
  78. data/lib/hecks/bluebook/dsl/identity_declaration.rb +17 -17
  79. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
  80. data/lib/hecks/bluebook/dsl/policy_builder.rb +30 -21
  81. data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
  82. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
  83. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +35 -35
  84. data/lib/hecks/bluebook/dsl/query_builder.rb +5 -5
  85. data/lib/hecks/bluebook/dsl/read_model_builder.rb +34 -34
  86. data/lib/hecks/bluebook/dsl/rule_reference.rb +41 -39
  87. data/lib/hecks/bluebook/dsl/translation_builder.rb +9 -9
  88. data/lib/hecks/bluebook/dsl/value_object_builder.rb +16 -16
  89. data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
  90. data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
  91. data/lib/hecks/bluebook/entity.rb +11 -11
  92. data/lib/hecks/bluebook/expression/ast_json.rb +20 -20
  93. data/lib/hecks/bluebook/expression/ast_reader.rb +3 -3
  94. data/lib/hecks/bluebook/expression/canonical_form.rb +9 -9
  95. data/lib/hecks/bluebook/expression/evaluator.rb +18 -18
  96. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +18 -18
  97. data/lib/hecks/bluebook/expression/resolver.rb +60 -62
  98. data/lib/hecks/bluebook/hexagon.rb +1 -1
  99. data/lib/hecks/bluebook/lifecycle.rb +1 -1
  100. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -1
  101. data/lib/hecks/bluebook/meta_validator/judge.rb +122 -86
  102. data/lib/hecks/bluebook/meta_validator/plan.rb +39 -39
  103. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -2
  104. data/lib/hecks/bluebook/meta_validator/readings.rb +43 -43
  105. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +44 -37
  106. data/lib/hecks/bluebook/meta_validator/shapes.rb +25 -21
  107. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +145 -31
  108. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +6 -6
  109. data/lib/hecks/bluebook/meta_validator/world_judge.rb +5 -5
  110. data/lib/hecks/bluebook/meta_validator.rb +70 -70
  111. data/lib/hecks/bluebook/model_check.rb +301 -84
  112. data/lib/hecks/bluebook/pattern_subset.rb +9 -9
  113. data/lib/hecks/bluebook/policy.rb +15 -13
  114. data/lib/hecks/bluebook/process_manager.rb +14 -14
  115. data/lib/hecks/bluebook/project_register.rb +6 -6
  116. data/lib/hecks/bluebook/query.rb +4 -4
  117. data/lib/hecks/bluebook/read_model.rb +14 -14
  118. data/lib/hecks/bluebook/reference.rb +8 -8
  119. data/lib/hecks/bluebook/smoke_test.rb +19 -19
  120. data/lib/hecks/bluebook/synthesizer.rb +12 -12
  121. data/lib/hecks/bluebook/translation.rb +4 -4
  122. data/lib/hecks/bluebook/value_object.rb +6 -6
  123. data/lib/hecks/bluebook.rb +2 -2
  124. data/lib/hecks/codemod/legacy_dispatch_args.rb +299 -0
  125. data/lib/hecks/codemod/legacy_dispatch_recorder.rb +186 -0
  126. data/lib/hecks/codemod.rb +36 -35
  127. data/lib/hecks/construct.rb +6 -6
  128. data/lib/hecks/corpus.rb +317 -0
  129. data/lib/hecks/deprecation.rb +95 -0
  130. data/lib/hecks/doc/reference.rb +19 -19
  131. data/lib/hecks/embryonaut_bluebook.rb +11 -11
  132. data/lib/hecks/facade/cli_door.rb +69 -10
  133. data/lib/hecks/facade/cli_runner.rb +105 -24
  134. data/lib/hecks/facade/command_request.rb +23 -0
  135. data/lib/hecks/facade/handle.rb +79 -32
  136. data/lib/hecks/facade/json_door.rb +106 -25
  137. data/lib/hecks/facade/surface/aggregate_door.rb +42 -27
  138. data/lib/hecks/facade/surface/chapter.rb +26 -17
  139. data/lib/hecks/facade/surface.rb +16 -3
  140. data/lib/hecks/facade.rb +15 -4
  141. data/lib/hecks/forms/app.rb +46 -30
  142. data/lib/hecks/forms/command_form_renderer.rb +70 -9
  143. data/lib/hecks/forms/field_renderer.rb +142 -6
  144. data/lib/hecks/forms/field_shape.rb +183 -20
  145. data/lib/hecks/forms/html.rb +51 -7
  146. data/lib/hecks/forms/index_renderer.rb +14 -2
  147. data/lib/hecks/forms/params.rb +120 -23
  148. data/lib/hecks/forms/port_argument.rb +2 -2
  149. data/lib/hecks/forms/query_form_renderer.rb +2 -2
  150. data/lib/hecks/forms/record_renderer.rb +2 -2
  151. data/lib/hecks/forms/record_table.rb +1 -1
  152. data/lib/hecks/forms/value_object_shape.rb +3 -3
  153. data/lib/hecks/forms.rb +24 -4
  154. data/lib/hecks/fqn.rb +1 -1
  155. data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
  156. data/lib/hecks/framework.rb +48 -17
  157. data/lib/hecks/freezer.rb +11 -11
  158. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +90 -90
  159. data/lib/hecks/fuzzing/combination_miner.rb +119 -0
  160. data/lib/hecks/fuzzing/concurrent_dispatch.rb +361 -0
  161. data/lib/hecks/fuzzing/coverage_campaign.rb +118 -0
  162. data/lib/hecks/fuzzing/differential.rb +158 -0
  163. data/lib/hecks/fuzzing/domain_generator.rb +694 -0
  164. data/lib/hecks/fuzzing/era_boundary.rb +124 -0
  165. data/lib/hecks/fuzzing/form_census.rb +199 -0
  166. data/lib/hecks/fuzzing/generated_domain_check.rb +95 -0
  167. data/lib/hecks/fuzzing/invalid_value_generator.rb +6 -6
  168. data/lib/hecks/fuzzing/isolated_boot.rb +226 -38
  169. data/lib/hecks/fuzzing/nondeterministic.rb +67 -0
  170. data/lib/hecks/fuzzing/persistence_parity.rb +161 -0
  171. data/lib/hecks/fuzzing/properties/corrections.rb +100 -0
  172. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +321 -41
  173. data/lib/hecks/fuzzing/properties/guards.rb +129 -26
  174. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +32 -32
  175. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +31 -11
  176. data/lib/hecks/fuzzing/properties/outbox.rb +142 -0
  177. data/lib/hecks/fuzzing/properties/querying.rb +17 -17
  178. data/lib/hecks/fuzzing/properties.rb +84 -39
  179. data/lib/hecks/fuzzing/qa_settings.rb +152 -0
  180. data/lib/hecks/fuzzing/replay.rb +224 -114
  181. data/lib/hecks/fuzzing/rotation_priority.rb +94 -0
  182. data/lib/hecks/fuzzing/rust_gap_manifest.rb +113 -0
  183. data/lib/hecks/fuzzing/self_consistency.rb +676 -0
  184. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +526 -0
  185. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +101 -30
  186. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +55 -8
  187. data/lib/hecks/fuzzing/sequence_generator/picker.rb +31 -11
  188. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +123 -32
  189. data/lib/hecks/fuzzing/sequence_generator.rb +152 -31
  190. data/lib/hecks/fuzzing/shrinker.rb +197 -0
  191. data/lib/hecks/fuzzing/structural_skips.rb +39 -0
  192. data/lib/hecks/fuzzing/sweep_depth.rb +53 -0
  193. data/lib/hecks/fuzzing/target_capabilities.rb +180 -0
  194. data/lib/hecks/fuzzing/value_generator.rb +66 -14
  195. data/lib/hecks/fuzzing.rb +11 -0
  196. data/lib/hecks/grammar/evolve.rb +10 -10
  197. data/lib/hecks/grammar.rb +7 -7
  198. data/lib/hecks/ir.rb +13 -13
  199. data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
  200. data/lib/hecks/language/bluebook/policy.bluebook +11 -1
  201. data/lib/hecks/language/bluebook/vocabulary.bluebook +365 -15
  202. data/lib/hecks/language/oidc.json +5 -0
  203. data/lib/hecks/literal.rb +9 -9
  204. data/lib/hecks/naming.rb +89 -21
  205. data/lib/hecks/ports/access_control.rb +58 -2
  206. data/lib/hecks/ports/agent/answers.rb +83 -6
  207. data/lib/hecks/ports/agent.rb +119 -35
  208. data/lib/hecks/ports/authentication.rb +44 -4
  209. data/lib/hecks/ports/authorization.rb +53 -11
  210. data/lib/hecks/ports/clock.rb +42 -23
  211. data/lib/hecks/ports/extraction.rb +16 -0
  212. data/lib/hecks/ports/identity_assignment.rb +24 -2
  213. data/lib/hecks/ports/identity_generation.rb +17 -3
  214. data/lib/hecks/ports/identity_resolution.rb +18 -1
  215. data/lib/hecks/ports/loading.rb +4 -0
  216. data/lib/hecks/ports/persistence/append_only.rb +172 -8
  217. data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
  218. data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
  219. data/lib/hecks/ports/persistence/execution.rb +4 -0
  220. data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
  221. data/lib/hecks/ports/persistence/plugin.rb +42 -4
  222. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
  223. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
  224. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
  225. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
  226. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
  227. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
  228. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
  229. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
  230. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
  231. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +160 -58
  232. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
  233. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +28 -5
  234. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
  235. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
  236. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
  237. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +44 -6
  238. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
  239. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +57 -4
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
  241. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +338 -83
  242. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
  243. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
  244. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
  245. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +42 -8
  246. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
  247. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
  248. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
  249. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -19
  250. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +5 -5
  251. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +1 -1
  252. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
  253. data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
  254. data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
  255. data/lib/hecks/ports/persistence/repository_factory.rb +29 -6
  256. data/lib/hecks/ports/persistence/state_codec.rb +319 -0
  257. data/lib/hecks/ports/persistence.rb +36 -1
  258. data/lib/hecks/ports/projection.rb +61 -7
  259. data/lib/hecks/ports/query/in_memory.rb +3 -3
  260. data/lib/hecks/ports/query/ordering.rb +6 -6
  261. data/lib/hecks/ports/query.rb +35 -0
  262. data/lib/hecks/projections/bootstrap_table.rb +112 -0
  263. data/lib/hecks/projections/diagrams.rb +75 -75
  264. data/lib/hecks/projections/glossary/html.rb +250 -0
  265. data/lib/hecks/projections/glossary/markdown.rb +105 -0
  266. data/lib/hecks/projections/glossary/mermaid.rb +110 -0
  267. data/lib/hecks/projections/glossary/page.css +271 -0
  268. data/lib/hecks/projections/glossary/page.js +72 -0
  269. data/lib/hecks/projections/glossary/sections.rb +17 -0
  270. data/lib/hecks/projections/glossary/sentences.rb +205 -0
  271. data/lib/hecks/projections/glossary.rb +214 -286
  272. data/lib/hecks/projections/ir.rb +1 -1
  273. data/lib/hecks/projections/model/deviations.rb +18 -17
  274. data/lib/hecks/projections/model.rb +25 -21
  275. data/lib/hecks/projections/oidc.rb +7 -7
  276. data/lib/hecks/projections/parser_table.rb +5 -5
  277. data/lib/hecks/projections/reference.rb +3 -3
  278. data/lib/hecks/projections/rust_vocabulary.rb +443 -0
  279. data/lib/hecks/projections/shape.rb +2 -2
  280. data/lib/hecks/projections/statements.rb +11 -11
  281. data/lib/hecks/projections/vocabulary.rb +9 -9
  282. data/lib/hecks/projections.rb +5 -3
  283. data/lib/hecks/projector/cli_projector.rb +29 -29
  284. data/lib/hecks/projector/docs_projector.rb +13 -13
  285. data/lib/hecks/projector/exporter.rb +42 -21
  286. data/lib/hecks/projector/ir_projector.rb +1 -1
  287. data/lib/hecks/projector/narrate_projector.rb +15 -22
  288. data/lib/hecks/projector/target.rb +13 -13
  289. data/lib/hecks/projector.rb +15 -15
  290. data/lib/hecks/query_ir.rb +47 -47
  291. data/lib/hecks/query_specification/common/comparators.rb +19 -3
  292. data/lib/hecks/query_specification/common/comparison.rb +132 -24
  293. data/lib/hecks/query_specification/common/dsl.rb +65 -9
  294. data/lib/hecks/query_specification/common/null_policy.rb +57 -13
  295. data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
  296. data/lib/hecks/query_specification/common/options.rb +25 -0
  297. data/lib/hecks/query_specification/field_path.rb +69 -15
  298. data/lib/hecks/query_specification/hop_path.rb +57 -20
  299. data/lib/hecks/query_specification/read_model/specification.rb +4 -0
  300. data/lib/hecks/rendering.rb +3 -3
  301. data/lib/hecks/router/namespace_installer.rb +3 -3
  302. data/lib/hecks/router.rb +1 -1
  303. data/lib/hecks/runtime/aggregate_lock.rb +11 -11
  304. data/lib/hecks/runtime/boot_gates.rb +3 -3
  305. data/lib/hecks/runtime/caller.rb +8 -8
  306. data/lib/hecks/runtime/capability_graph.rb +2 -2
  307. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +22 -25
  308. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +64 -67
  309. data/lib/hecks/runtime/command_interpreter.rb +159 -102
  310. data/lib/hecks/runtime/command_rules/admissibility.rb +69 -69
  311. data/lib/hecks/runtime/command_rules/arithmetic.rb +137 -91
  312. data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
  313. data/lib/hecks/runtime/command_rules/emission.rb +18 -1
  314. data/lib/hecks/runtime/command_rules/references.rb +94 -19
  315. data/lib/hecks/runtime/command_rules.rb +3 -0
  316. data/lib/hecks/runtime/dependency_planning.rb +11 -11
  317. data/lib/hecks/runtime/dispatcher.rb +283 -90
  318. data/lib/hecks/runtime/entity_element.rb +282 -46
  319. data/lib/hecks/runtime/entity_interpreter.rb +160 -69
  320. data/lib/hecks/runtime/errors.rb +19 -19
  321. data/lib/hecks/runtime/event.rb +6 -6
  322. data/lib/hecks/runtime/identity.rb +22 -22
  323. data/lib/hecks/runtime/instance.rb +39 -14
  324. data/lib/hecks/runtime/interpreting.rb +12 -12
  325. data/lib/hecks/runtime/invocation.rb +276 -0
  326. data/lib/hecks/runtime/loader.rb +14 -14
  327. data/lib/hecks/runtime/outbox.rb +23 -23
  328. data/lib/hecks/runtime/policy_interpreter.rb +54 -54
  329. data/lib/hecks/runtime/port_operation_interpreter.rb +22 -19
  330. data/lib/hecks/runtime/query_interpreter.rb +111 -56
  331. data/lib/hecks/runtime/reaction_invocation.rb +76 -9
  332. data/lib/hecks/runtime/read_model_interpreter.rb +40 -40
  333. data/lib/hecks/runtime/rebuild_sweep.rb +4 -4
  334. data/lib/hecks/runtime/reference_hop.rb +6 -6
  335. data/lib/hecks/runtime/refusal_wording.rb +92 -112
  336. data/lib/hecks/runtime/registry/saga_persistence.rb +21 -21
  337. data/lib/hecks/runtime/registry/verification.rb +36 -26
  338. data/lib/hecks/runtime/registry.rb +56 -27
  339. data/lib/hecks/runtime/remote_dispatcher.rb +38 -23
  340. data/lib/hecks/runtime/routing.rb +10 -88
  341. data/lib/hecks/runtime/saga_interpreter/correlation.rb +17 -17
  342. data/lib/hecks/runtime/saga_interpreter.rb +93 -56
  343. data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
  344. data/lib/hecks/runtime/tenant_check.rb +9 -9
  345. data/lib/hecks/runtime/tenant_scope.rb +5 -5
  346. data/lib/hecks/runtime/value/admission.rb +75 -30
  347. data/lib/hecks/runtime/value/coercion.rb +379 -226
  348. data/lib/hecks/runtime/value/entity_list_coercion.rb +248 -0
  349. data/lib/hecks/runtime/value.rb +28 -23
  350. data/lib/hecks/runtime.rb +7 -7
  351. data/lib/hecks/storehouse.rb +64 -64
  352. data/lib/hecks/version.rb +3 -3
  353. data/lib/hecks/vocabulary.rb +207 -5
  354. data/lib/hecks.rb +13 -11
  355. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +11 -11
  356. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +14 -12
  357. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +11 -11
  358. metadata +43 -2
@@ -21,6 +21,13 @@ Hecks.bluebook "Bluebook" do
21
21
  attribute :on_event, PolicyText
22
22
  attribute :trigger_command, PolicyText
23
23
  attribute :target_domain, PolicyText
24
+ # AN `across` TARGET THIS DOMAIN EXPECTS NEVER TO REACH — declared on
25
+ # the policy that owns the expectation, not held in a core allowlist
26
+ # keyed by domain name. `ModelCheck` honours it both ways: the
27
+ # unknown-target and unacknowledged-relationship findings it would
28
+ # otherwise raise are expected, and a declaration whose target turns
29
+ # out to be known or acknowledged after all is STALE and fails.
30
+ attribute :expect_undelivered, PolicyText
24
31
  # THE GUARD, CARRIED AS TEXT — same discipline `Command.givens`
25
32
  # already holds: the block that wrote it is never called at
26
33
  # runtime, only its EXTRACTED SOURCE is (Ports::Extraction), so
@@ -92,6 +99,7 @@ Hecks.bluebook "Bluebook" do
92
99
  attribute :on_event, PolicyText
93
100
  attribute :trigger_command, PolicyText
94
101
  attribute :target_domain, PolicyText, optional: true
102
+ attribute :expect_undelivered, PolicyText, optional: true
95
103
  attribute :where, PolicyText, optional: true
96
104
  attribute :for_each, PolicyText, optional: true
97
105
 
@@ -102,6 +110,7 @@ Hecks.bluebook "Bluebook" do
102
110
  sets :on_event
103
111
  sets :trigger_command
104
112
  sets :target_domain
113
+ sets :expect_undelivered
105
114
  sets :where
106
115
  sets :for_each
107
116
  sets :position
@@ -153,7 +162,7 @@ Hecks.bluebook "Bluebook" do
153
162
 
154
163
  member word: "on", context: "Policy", body: "none", inner: "", opens: "", fills: "on_event", calls: "on_impl"
155
164
  member word: "trigger", context: "Policy", body: "none", inner: "", opens: "", fills: "trigger_command", calls: "trigger_impl"
156
- member word: "across", context: "Policy", body: "none", inner: "", opens: "", fills: "target_domain"
165
+ member word: "across", context: "Policy", body: "none", inner: "", opens: "", fills: "target_domain", calls: "across_impl"
157
166
  member word: "where", context: "Policy", body: "source", inner: "", opens: "", fills: "where"
158
167
  member word: "for_each", context: "Policy", body: "none", inner: "", opens: "", fills: "for_each"
159
168
 
@@ -181,6 +190,7 @@ Hecks.bluebook "Bluebook" do
181
190
  member keyword: "trigger", context: "Policy", at: "1", named: "", kind: "constant", required: "true", fills: "trigger_command"
182
191
  member keyword: "trigger", context: "Policy", at: "1", named: "", kind: "text", required: "true", fills: "trigger_command"
183
192
  member keyword: "across", context: "Policy", at: "1", named: "", kind: "text", required: "true", fills: "target_domain"
193
+ member keyword: "across", context: "Policy", at: "", named: "expect_undelivered", kind: "flag", required: "false", fills: "expect_undelivered"
184
194
  member keyword: "for_each", context: "Policy", at: "1", named: "", kind: "text", required: "true", fills: "for_each"
185
195
  member keyword: "trigger", context: "Policy", at: "", named: "with", kind: "pairs", required: "false", fills: "with_spec", pairs_shape: "verbatim"
186
196
 
@@ -2,8 +2,11 @@ Hecks.bluebook "Bluebook" do
2
2
  aggregate "Vocabulary" do
3
3
  # These are DECLARATIONS, not runtime state — a language's admitted sets are
4
4
  # fixed when the language is defined, which is what one_of means. They carry
5
- # no commands on purpose : nothing dispatches a vocabulary, the conformance
6
- # check READS them from the IR and holds the runtime's hand-typed tables to them.
5
+ # no commands on purpose : nothing dispatches a vocabulary. They are READ
6
+ # from the IR and projected bin/project_vocabulary writes the Ruby tables
7
+ # (lib/hecks/vocabulary.rb) the runtime's constants read, and
8
+ # bin/project_rust_vocabulary writes rust/src/kernel/vocab/ — so the
9
+ # runtimes carry no hand-typed copies to drift.
7
10
  #
8
11
  # Every one of these is a set the runtime must agree with, and every one has
9
12
  # already drifted or leaked at least once :
@@ -171,9 +174,17 @@ Hecks.bluebook "Bluebook" do
171
174
  # fires for a creating command, advance_lifecycle only when a transition
172
175
  # applies — so this is the order a command that does both follows,
173
176
  # confirmed by tracing a real dispatch, not read off the source.
177
+ #
178
+ # decode_arguments leads both dispatch orders: turning the caller's raw
179
+ # facts into a command's declared arguments, before any argument gate
180
+ # judges them. A no-op in Ruby today (routing already hands the
181
+ # interpreter a decoded hash) and in the Rust kernel's dispatch loop
182
+ # (generated `from_json` still decodes and gates in one pass) — declared
183
+ # now so the Rust kernel's step enum has a place for a generated decoder
184
+ # to move into, rather than the order being implied by generated code.
174
185
  value_object "AggregateDispatchOrder" do
175
186
  attribute :step, String,
176
- one_of: ["refuse_unknown_arguments", "refuse_absent_arguments", "normalize_args",
187
+ one_of: ["decode_arguments", "refuse_unknown_arguments", "refuse_absent_arguments", "normalize_args",
177
188
  "refuse_role_mismatch", "resolve_references", "hydrate", "enforce_givens",
178
189
  "admissible_transition", "assign_creation_attributes", "apply_mutations",
179
190
  "advance_lifecycle", "delegate_to_entity", "enforce_ensures", "enforce_invariants",
@@ -197,7 +208,7 @@ Hecks.bluebook "Bluebook" do
197
208
  # both interpreters), even though nothing in the real corpus does yet.
198
209
  value_object "EntityDispatchOrder" do
199
210
  attribute :step, String,
200
- one_of: ["refuse_unknown_arguments", "refuse_absent_arguments", "normalize_args",
211
+ one_of: ["decode_arguments", "refuse_unknown_arguments", "refuse_absent_arguments", "normalize_args",
201
212
  "refuse_role_mismatch", "resolve_references", "hydrate_parent",
202
213
  "locate_element", "enforce_givens", "admissible_transition", "apply_mutations",
203
214
  "advance_lifecycle", "enforce_ensures", "enforce_invariants", "save", "emit"]
@@ -219,11 +230,10 @@ Hecks.bluebook "Bluebook" do
219
230
  # declared them. Everything here is different in kind: a LANGUAGE-LEVEL
220
231
  # refusal, the same wording for every domain, not authored per-bluebook —
221
232
  # closer to Comparison/SignTest beside it than to a given. So it follows
222
- # THEIR pattern, not given's: declared here for a human to read and a
223
- # conformance spec to hold equal, and a hand-typed table
224
- # (RefusalWording) is what a dispatch
225
- # actually reads the same reason Evaluator::SIGN_TEST_OPERATORS is
226
- # hand-typed rather than read live off this very chapter at every call.
233
+ # THEIR pattern, not given's: declared here, and projected into the
234
+ # generated tables a dispatch actually reads (Runtime::RefusalWording in
235
+ # Ruby, kernel::vocab::RefusalSite in Rust) rather than read live off
236
+ # this very chapter at every call.
227
237
  #
228
238
  # `{name}` markers are placeholders — plain text substitution, not
229
239
  # expression syntax ; a template is read, never evaluated. Two call
@@ -284,8 +294,20 @@ Hecks.bluebook "Bluebook" do
284
294
  template: "{command} refused — {field} is {current}, and {command} moves it only from {allowed}"
285
295
  member refusal: "TypeMismatch", site: "value_object_shape",
286
296
  template: "{name} is a {type} — pass its fields as an object, not {offered}"
287
- member refusal: "TypeMismatch", site: "reference_as_object",
288
- template: "{command} refused a reference is an id, and {attribute} arrived as an object{known_by}"
297
+ # RENAMED FROM `reference_as_object` (BUG#27, QualityControl ledger) —
298
+ # a reference command argument that is an object was never the only
299
+ # wrong shape, only the first one anyone noticed: a bare Boolean,
300
+ # Array, or `null` used to sail past this refusal entirely, get
301
+ # `.to_s`'d into a lookup key by `CommandRules::References#
302
+ # reference_key` ("true", "false", "[8, 8]"), and answer NotFound (or,
303
+ # for `null`, skip the lookup outright and answer whatever the
304
+ # command's own `given` said instead) — a shape error misreading as a
305
+ # missing record. `{offered}` now names what actually arrived; the
306
+ # Hash/Value case still renders "an object" (Value::Coercion's own
307
+ # `reference_shape_description`), so the wording already pinned byte
308
+ # for byte in spec/runtime/reference_shape_spec.rb is unchanged.
309
+ member refusal: "TypeMismatch", site: "reference_wrong_shape",
310
+ template: "{command} refused — a reference is an id, and {attribute} arrived as {offered}{known_by}"
289
311
  member refusal: "TypeMismatch", site: "multi_field_scalar",
290
312
  template: "{type} has multiple fields and cannot stand in for a scalar"
291
313
  member refusal: "TypeMismatch", site: "composite_identity",
@@ -322,6 +344,9 @@ Hecks.bluebook "Bluebook" do
322
344
  "{field} this ask is scoped to"
323
345
  member refusal: "Unauthorized", site: "role_mismatch",
324
346
  template: "{command} refused — role: {role}, and the caller stated {caller_role}"
347
+ member refusal: "Unauthorized", site: "cross_tenant_reference",
348
+ template: "{aggregate} {field} is {tenant}, but {attribute} names a {target} whose own " \
349
+ "{target_field} is {other} — a cross-tenant reference"
325
350
  member refusal: "AttributeAbsent", site: "absent_read",
326
351
  template: "{aggregate} {field} is absent on this record — declared, not optional, and " \
327
352
  "added since it was written. Backfill it in a translation (backfill :{field}, " \
@@ -336,6 +361,303 @@ Hecks.bluebook "Bluebook" do
336
361
  "or read {reference}.{remote_field} directly if this rule cannot wait"
337
362
  end
338
363
 
364
+ # THE ARGUMENTS EACH RefusalTemplate TAKES, AND HOW EACH ONE IS WRITTEN.
365
+ # A template says WHERE a value goes; this says WHICH values a site
366
+ # takes (in the order its placeholders first appear) and how each is
367
+ # rendered before it goes there — so a caller hands over the raw value
368
+ # (a list of names, a name) rather than a string it formatted itself.
369
+ # BUG#134 was exactly the hand-formatted kind: Ruby's `declared_reading`
370
+ # fell back to "none" for an empty list, the Rust generators joined
371
+ # the list themselves and never did.
372
+ #
373
+ # Read by Runtime::RefusalWording.render_site (a missing or extra
374
+ # argument refuses to render at all) and projected into
375
+ # rust/src/kernel/vocab/refusal_template.rs as one typed args struct
376
+ # per site (`render_args` — a missing argument does not compile).
377
+ #
378
+ # shape — "scalar" (one value) or "list" (a collection of them)
379
+ # quoting — "none" (the value's own text) or "inspect" (Ruby's
380
+ # `#inspect`; Rust's `{:?}`), per value or per item
381
+ # separator — what a list's items are joined with
382
+ # sorted — "true" sorts a list's items first (before quoting)
383
+ # when_empty — what an empty list renders as
384
+ #
385
+ # Recorded from what the Ruby call sites did when this table was
386
+ # introduced; no wording changed. A value whose rendering depends on
387
+ # its runtime type (`Rendering.describe`, `offered.inspect` of an
388
+ # arbitrary value) stays a caller-rendered "none" scalar, as do the
389
+ # identity readings (`identity`, `heads`, `wants`) the Rust side already
390
+ # joins once at codegen time or inside `extract_wants`.
391
+ value_object "RefusalSiteArgument" do
392
+ attribute :refusal, String, admits: "Vocabulary::DomainRefusal"
393
+ attribute :site, String
394
+ attribute :argument, String
395
+ attribute :shape, String
396
+ attribute :quoting, String
397
+ attribute :separator, String
398
+ attribute :sorted, String
399
+ attribute :when_empty, String
400
+
401
+ member refusal: "NotFound", site: "creating_no_identity", argument: "command",
402
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
403
+ member refusal: "NotFound", site: "creating_no_identity", argument: "aggregate",
404
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
405
+ member refusal: "NotFound", site: "creating_no_identity", argument: "identity",
406
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
407
+ member refusal: "AlreadyExists", site: "creating_duplicate", argument: "command",
408
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
409
+ member refusal: "AlreadyExists", site: "creating_duplicate", argument: "aggregate",
410
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
411
+ member refusal: "AlreadyExists", site: "creating_duplicate", argument: "identity",
412
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
413
+ member refusal: "AlreadyExists", site: "creating_duplicate", argument: "offered",
414
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
415
+ member refusal: "AlreadyExists", site: "entity_duplicate", argument: "entity",
416
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
417
+ member refusal: "AlreadyExists", site: "entity_duplicate", argument: "aggregate",
418
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
419
+ member refusal: "AlreadyExists", site: "entity_duplicate", argument: "identity",
420
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
421
+ # One described value per identity head (MutationApplier), or the
422
+ # one offered element identity (EntityListCoercion).
423
+ member refusal: "AlreadyExists", site: "entity_duplicate", argument: "offered",
424
+ shape: "list", quoting: "none", separator: ", ", sorted: "false", when_empty: ""
425
+ member refusal: "NotFound", site: "acting_no_identity", argument: "command",
426
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
427
+ member refusal: "NotFound", site: "acting_no_identity", argument: "aggregate",
428
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
429
+ member refusal: "NotFound", site: "acting_no_identity", argument: "identity",
430
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
431
+ member refusal: "NotFound", site: "record_missing", argument: "aggregate",
432
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
433
+ member refusal: "NotFound", site: "record_missing", argument: "identity",
434
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
435
+ member refusal: "NotFound", site: "record_missing", argument: "offered",
436
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
437
+ member refusal: "NotFound", site: "entity_parent_no_identity", argument: "command",
438
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
439
+ member refusal: "NotFound", site: "entity_parent_no_identity", argument: "aggregate",
440
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
441
+ member refusal: "NotFound", site: "entity_parent_no_identity", argument: "entity",
442
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
443
+ member refusal: "NotFound", site: "entity_parent_no_identity", argument: "identity",
444
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
445
+ member refusal: "UnknownVerb", site: "entity_unknown", argument: "aggregate",
446
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
447
+ member refusal: "UnknownVerb", site: "entity_unknown", argument: "entity",
448
+ shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
449
+ member refusal: "NotFound", site: "entity_element_no_identity", argument: "command",
450
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
451
+ member refusal: "NotFound", site: "entity_element_no_identity", argument: "entity",
452
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
453
+ member refusal: "NotFound", site: "entity_element_no_identity", argument: "identity",
454
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
455
+ member refusal: "NotFound", site: "entity_element_missing", argument: "entity",
456
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
457
+ member refusal: "NotFound", site: "entity_element_missing", argument: "identity",
458
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
459
+ member refusal: "NotFound", site: "entity_element_missing", argument: "wants",
460
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
461
+ member refusal: "NotFound", site: "entity_element_missing", argument: "aggregate",
462
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
463
+ member refusal: "NotFound", site: "entity_element_missing", argument: "parent_id",
464
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
465
+ member refusal: "NotFound", site: "reference_target_missing", argument: "target",
466
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
467
+ member refusal: "NotFound", site: "reference_target_missing", argument: "heads",
468
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
469
+ member refusal: "NotFound", site: "reference_target_missing", argument: "key",
470
+ shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
471
+ member refusal: "NotFound", site: "read_model_reference_missing", argument: "aggregate",
472
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
473
+ member refusal: "NotFound", site: "read_model_reference_missing", argument: "offered",
474
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
475
+ member refusal: "TypeMismatch", site: "read_model_object_reference", argument: "query",
476
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
477
+ member refusal: "TypeMismatch", site: "read_model_object_reference", argument: "field",
478
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
479
+ member refusal: "UnknownVerb", site: "no_query", argument: "aggregate",
480
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
481
+ member refusal: "UnknownVerb", site: "no_query", argument: "query",
482
+ shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
483
+ member refusal: "UnknownVerb", site: "entity_query_missing", argument: "entity",
484
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
485
+ member refusal: "UnknownVerb", site: "entity_query_missing", argument: "query",
486
+ shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
487
+ member refusal: "UnknownVerb", site: "entity_holds_no_list", argument: "aggregate",
488
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
489
+ member refusal: "UnknownVerb", site: "entity_holds_no_list", argument: "entity",
490
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
491
+ member refusal: "UnknownVerb", site: "entity_no_command", argument: "entity",
492
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
493
+ member refusal: "UnknownVerb", site: "entity_no_command", argument: "command",
494
+ shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
495
+ member refusal: "UnknownVerb", site: "aggregate_no_command", argument: "aggregate",
496
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
497
+ member refusal: "UnknownVerb", site: "aggregate_no_command", argument: "command",
498
+ shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
499
+ member refusal: "UnknownVerb", site: "port_no_operation", argument: "port",
500
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
501
+ member refusal: "UnknownVerb", site: "port_no_operation", argument: "operation",
502
+ shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
503
+ member refusal: "UnknownVerb", site: "no_domain", argument: "domain",
504
+ shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
505
+ member refusal: "UnknownVerb", site: "no_domain", argument: "verb",
506
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
507
+ member refusal: "UnknownVerb", site: "no_read_model", argument: "domain",
508
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
509
+ member refusal: "UnknownVerb", site: "no_read_model", argument: "query",
510
+ shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
511
+ member refusal: "UnknownVerb", site: "not_fully_qualified", argument: "verb",
512
+ shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
513
+ member refusal: "UnknownVerb", site: "no_aggregate", argument: "domain",
514
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
515
+ member refusal: "UnknownVerb", site: "no_aggregate", argument: "aggregate",
516
+ shape: "scalar", quoting: "inspect", separator: "", sorted: "false", when_empty: ""
517
+ member refusal: "LifecycleRefused", site: "transition_blocked", argument: "command",
518
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
519
+ member refusal: "LifecycleRefused", site: "transition_blocked", argument: "field",
520
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
521
+ member refusal: "LifecycleRefused", site: "transition_blocked", argument: "current",
522
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
523
+ member refusal: "LifecycleRefused", site: "transition_blocked", argument: "allowed",
524
+ shape: "list", quoting: "inspect", separator: " or ", sorted: "false", when_empty: ""
525
+ member refusal: "TypeMismatch", site: "value_object_shape", argument: "name",
526
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
527
+ member refusal: "TypeMismatch", site: "value_object_shape", argument: "type",
528
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
529
+ member refusal: "TypeMismatch", site: "value_object_shape", argument: "offered",
530
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
531
+ member refusal: "TypeMismatch", site: "reference_wrong_shape", argument: "command",
532
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
533
+ member refusal: "TypeMismatch", site: "reference_wrong_shape", argument: "attribute",
534
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
535
+ member refusal: "TypeMismatch", site: "reference_wrong_shape", argument: "offered",
536
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
537
+ member refusal: "TypeMismatch", site: "reference_wrong_shape", argument: "known_by",
538
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
539
+ member refusal: "TypeMismatch", site: "multi_field_scalar", argument: "type",
540
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
541
+ member refusal: "TypeMismatch", site: "composite_identity", argument: "type",
542
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
543
+ member refusal: "TypeMismatch", site: "numeric_field", argument: "type",
544
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
545
+ member refusal: "TypeMismatch", site: "numeric_field", argument: "field",
546
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
547
+ member refusal: "TypeMismatch", site: "numeric_field", argument: "expected",
548
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
549
+ member refusal: "TypeMismatch", site: "numeric_field", argument: "offered",
550
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
551
+ member refusal: "TypeMismatch", site: "non_finite_field", argument: "type",
552
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
553
+ member refusal: "TypeMismatch", site: "non_finite_field", argument: "field",
554
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
555
+ member refusal: "TypeMismatch", site: "non_finite_field", argument: "offered",
556
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
557
+ member refusal: "TypeMismatch", site: "integer_range", argument: "type",
558
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
559
+ member refusal: "TypeMismatch", site: "integer_range", argument: "field",
560
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
561
+ member refusal: "TypeMismatch", site: "integer_range", argument: "offered",
562
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
563
+ member refusal: "TypeMismatch", site: "pattern_mismatch", argument: "type",
564
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
565
+ member refusal: "TypeMismatch", site: "pattern_mismatch", argument: "field",
566
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
567
+ member refusal: "TypeMismatch", site: "pattern_mismatch", argument: "pattern",
568
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
569
+ member refusal: "TypeMismatch", site: "pattern_mismatch", argument: "offered",
570
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
571
+ member refusal: "TypeMismatch", site: "arithmetic_amount", argument: "op",
572
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
573
+ member refusal: "TypeMismatch", site: "arithmetic_amount", argument: "target",
574
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
575
+ member refusal: "TypeMismatch", site: "arithmetic_amount", argument: "offered",
576
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
577
+ member refusal: "TypeMismatch", site: "arithmetic_current", argument: "op",
578
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
579
+ member refusal: "TypeMismatch", site: "arithmetic_current", argument: "target",
580
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
581
+ member refusal: "TypeMismatch", site: "arithmetic_current", argument: "offered",
582
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
583
+ member refusal: "TypeMismatch", site: "arithmetic_shared_field", argument: "op",
584
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
585
+ member refusal: "TypeMismatch", site: "arithmetic_shared_field", argument: "target",
586
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
587
+ member refusal: "UnknownArgument", site: "unknown_args", argument: "command",
588
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
589
+ member refusal: "UnknownArgument", site: "unknown_args", argument: "unknown",
590
+ shape: "list", quoting: "none", separator: ", ", sorted: "true", when_empty: ""
591
+ member refusal: "UnknownArgument", site: "unknown_args", argument: "declared",
592
+ shape: "list", quoting: "none", separator: ", ", sorted: "false", when_empty: "none"
593
+ member refusal: "AbsentArgument", site: "absent_args", argument: "command",
594
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
595
+ member refusal: "AbsentArgument", site: "absent_args", argument: "absent",
596
+ shape: "list", quoting: "none", separator: ", ", sorted: "true", when_empty: ""
597
+ member refusal: "AbsentArgument", site: "absent_args", argument: "declared",
598
+ shape: "list", quoting: "none", separator: ", ", sorted: "false", when_empty: "none"
599
+ member refusal: "InvariantViolation", site: "closed_set_member", argument: "type",
600
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
601
+ member refusal: "InvariantViolation", site: "closed_set_member", argument: "admitted",
602
+ shape: "list", quoting: "inspect", separator: ", ", sorted: "false", when_empty: ""
603
+ member refusal: "InvariantViolation", site: "closed_set_member", argument: "offered",
604
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
605
+ member refusal: "InvariantViolation", site: "value_object_invariant", argument: "name",
606
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
607
+ member refusal: "InvariantViolation", site: "value_object_invariant", argument: "description",
608
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
609
+ member refusal: "InvariantViolation", site: "value_object_invariant", argument: "offered",
610
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
611
+ member refusal: "InvariantViolation", site: "admits_declared_set", argument: "name",
612
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
613
+ member refusal: "InvariantViolation", site: "admits_declared_set", argument: "admits",
614
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
615
+ member refusal: "InvariantViolation", site: "admits_declared_set", argument: "admitted",
616
+ shape: "list", quoting: "inspect", separator: ", ", sorted: "false", when_empty: ""
617
+ member refusal: "InvariantViolation", site: "admits_declared_set", argument: "offered",
618
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
619
+ member refusal: "InvariantViolation", site: "undeclared_set", argument: "name",
620
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
621
+ member refusal: "InvariantViolation", site: "undeclared_set", argument: "admits",
622
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
623
+ member refusal: "Unauthorized", site: "tenant_required", argument: "query",
624
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
625
+ member refusal: "Unauthorized", site: "tenant_required", argument: "field",
626
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
627
+ member refusal: "Unauthorized", site: "role_mismatch", argument: "command",
628
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
629
+ member refusal: "Unauthorized", site: "role_mismatch", argument: "role",
630
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
631
+ member refusal: "Unauthorized", site: "role_mismatch", argument: "caller_role",
632
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
633
+ member refusal: "Unauthorized", site: "cross_tenant_reference", argument: "aggregate",
634
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
635
+ member refusal: "Unauthorized", site: "cross_tenant_reference", argument: "field",
636
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
637
+ member refusal: "Unauthorized", site: "cross_tenant_reference", argument: "tenant",
638
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
639
+ member refusal: "Unauthorized", site: "cross_tenant_reference", argument: "attribute",
640
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
641
+ member refusal: "Unauthorized", site: "cross_tenant_reference", argument: "target",
642
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
643
+ member refusal: "Unauthorized", site: "cross_tenant_reference", argument: "target_field",
644
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
645
+ member refusal: "Unauthorized", site: "cross_tenant_reference", argument: "other",
646
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
647
+ member refusal: "AttributeAbsent", site: "absent_read", argument: "aggregate",
648
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
649
+ member refusal: "AttributeAbsent", site: "absent_read", argument: "field",
650
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
651
+ member refusal: "ProjectionAbsent", site: "absent_read", argument: "aggregate",
652
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
653
+ member refusal: "ProjectionAbsent", site: "absent_read", argument: "field",
654
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
655
+ member refusal: "ProjectionAbsent", site: "absent_read", argument: "reference",
656
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
657
+ member refusal: "ProjectionAbsent", site: "absent_read", argument: "remote_field",
658
+ shape: "scalar", quoting: "none", separator: "", sorted: "false", when_empty: ""
659
+ end
660
+
339
661
  # SagaInterpreter::REFUSED.
340
662
  #
341
663
  # A leg answers an EVENT — `on "AccountDebited"` — or it answers one of these,
@@ -358,10 +680,9 @@ Hecks.bluebook "Bluebook" do
358
680
  # rendering convention, the same guess for every domain, not
359
681
  # authored per-bluebook — closer to Comparison/SignTest than to a
360
682
  # given. `pattern` is the regex SOURCE, no delimiters or flags
361
- # (Ruby's own `Regexp#source`) — spec/field_hint_conformance_spec.rb
362
- # holds FieldShape's four hand-typed constants equal to this, both
363
- # directions, the same conformance shape refusal_wording_
364
- # conformance_spec.rb already holds RefusalTemplate to.
683
+ # (Ruby's own `Regexp#source`) — FieldShape builds its four constants
684
+ # off these rows, and bin/project_field_hints writes the Rust host's
685
+ # copy from them, so neither side is typed by hand.
365
686
  #
366
687
  # `resolves_to` names WHICH Field attribute a match sets — `html_type`
367
688
  # for email/url/tel (three candidates, only one wins, checked in that
@@ -377,5 +698,34 @@ Hecks.bluebook "Bluebook" do
377
698
  member name: "tel", pattern: 'phone|\btel(ephone)?\b', resolves_to: "html_type"
378
699
  member name: "textarea", pattern: '\b(text|body|note|notes|description|message|comment)\b', resolves_to: "kind"
379
700
  end
701
+
702
+ # The Rust keywords (strict + reserved) a generated identifier must not
703
+ # collide with — RustProjection::Projector::RUST_KEYWORDS (rust/project/
704
+ # naming.rb) reads this, and bin/project_reserved_names projects it into
705
+ # rust/codegen/src/reserved_names.rs, so the Ruby and Rust generators
706
+ # escape (a field: `r#type`) or refuse (a module name) the SAME words.
707
+ # Declared once here because the two hand-typed copies were held equal
708
+ # by nothing but a comment.
709
+ value_object "RustReservedWord" do
710
+ attribute :word, String,
711
+ one_of: ["as", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern", "false",
712
+ "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub",
713
+ "ref", "return", "self", "Self", "static", "struct", "super", "trait", "true", "type",
714
+ "unsafe", "use", "where", "while", "abstract", "become", "box", "do", "final", "macro",
715
+ "override", "priv", "typeof", "unsized", "virtual", "yield", "try"]
716
+ end
717
+
718
+ # The keys a domain's own name must not take, because that name doubles
719
+ # as a Cargo `[features]` key: every key rust/Cargo.toml already uses
720
+ # outside `[features]` (`[package]`, `[lib]`, `[[bin]]`) plus `default`,
721
+ # which Cargo reserves for the auto-enabled feature set. Read by
722
+ # RustProjection::Projector::CARGO_RESERVED_DOMAIN_NAMES and projected by
723
+ # bin/project_reserved_names, same as RustReservedWord above.
724
+ value_object "CargoReservedName" do
725
+ attribute :name, String,
726
+ one_of: ["name", "version", "edition", "path", "authors", "license", "description", "default",
727
+ "features", "package", "lib", "bin", "dependencies", "dev-dependencies",
728
+ "build-dependencies", "workspace"]
729
+ end
380
730
  end
381
731
  end
@@ -76,6 +76,11 @@
76
76
  "verb": "Bluebook::Bluebook.Normalise",
77
77
  "role": "Language"
78
78
  },
79
+ {
80
+ "scope": "bluebook:bluebook.provide",
81
+ "verb": "Bluebook::Bluebook.Provide",
82
+ "role": "Language"
83
+ },
79
84
  {
80
85
  "scope": "bluebook:command.acts_on",
81
86
  "verb": "Bluebook::Command.ActsOn",
data/lib/hecks/literal.rb CHANGED
@@ -1,31 +1,31 @@
1
1
  module Hecks
2
- # THE ONE SPELLING FOR A CAPTURED RUBY LITERAL ON THE WIRE.
2
+ # The one spelling for a captured Ruby literal on the wire.
3
3
  #
4
4
  # Several `to_h` fields hold a value the author wrote in a bluebook —
5
5
  # `where(status: { eq: "open" })`, `then_set append: { direction: { value:
6
6
  # "credit" } }`, `dispatch ... with: { number: :source }`, an attribute's
7
- # `default:` — as TEXT, because the export has to stand on its own and a
7
+ # `default:` — as text, because the export has to stand on its own and a
8
8
  # String field cannot say "this one was a Symbol". Every such field is the
9
9
  # same question and now gets the same answer.
10
10
  #
11
11
  # It was three answers before, and they disagreed on both axes that matter.
12
- # `Mutation#appended_fields` spelled a Symbol BARE and everything else
13
- # `inspect`; `QuerySpecification.render_value` spelled a Symbol with a COLON
12
+ # `Mutation#appended_fields` spelled a Symbol bare and everything else
13
+ # `inspect`; `QuerySpecification.render_value` spelled a Symbol with a colon
14
14
  # and everything else `to_s`. So `:amount` crossed as "amount" in a mutation
15
15
  # and ":amount" in a saga binding — the same value, two spellings, and each
16
16
  # reader had to know which field it was looking at. Worse, `to_s`/`inspect`
17
- # on a Hash is Ruby's OWN rendering, which moved under us: 3.3 writes
17
+ # on a Hash is Ruby's own rendering, which moved under us: 3.3 writes
18
18
  # `{:value=>"credit"}` and 3.4 writes `{value: "credit"}` for the identical
19
19
  # Hash, so the wire format was silently pinned to an interpreter version.
20
20
  #
21
- # SELF-DESCRIBING IS THE RULE, stated once here rather than inherited from
21
+ # Self-describing is the rule, stated once here rather than inherited from
22
22
  # whatever `inspect` happens to do: a symbol wears its colon, a string wears
23
23
  # its quotes, a hash wears `{key: value}` braces, a list wears its brackets,
24
24
  # and a number, a boolean and nil are bare. `read` is the exact inverse, and
25
25
  # is the only thing that should ever take one of these strings apart.
26
- # A MUTATION SOURCE THAT READS THE RECORD'S OWN STATE — `sets :positions,
26
+ # A mutation source that reads the record's own state — `sets :positions,
27
27
  # append: { knights: state(:knights) }`. A bare Symbol in a mutation
28
- # source always names a command ARGUMENT (and imports it as one when
28
+ # source always names a command argument (and imports it as one when
29
29
  # the target's own field carries the same name — `CommandBuilder
30
30
  # #resolve_append_fields!`); before this there was no way to say "the
31
31
  # value this field already holds", so a command could not snapshot its
@@ -102,7 +102,7 @@ module Hecks
102
102
 
103
103
  def read_array(raw) = split_items(raw[1..-2]).map { |item| read(item) }
104
104
 
105
- # Split on the commas that are actually SEPARATORS — never one inside a
105
+ # Split on the commas that are actually separators — never one inside a
106
106
  # quoted string or a nested brace/bracket. Scanned rather than
107
107
  # `String#split(", ")`, which tore `"a, b"` in half and lost the second
108
108
  # field of anything nested.