hecks 3.13.0 → 4.0.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 (440) hide show
  1. checksums.yaml +4 -4
  2. data/examples/pizzas/adapters/fake_processor.rb +34 -0
  3. data/examples/pizzas/adapters/payment_signature.rb +66 -0
  4. data/examples/pizzas/adapters/payment_webhook.rb +87 -0
  5. data/examples/pizzas/bluebook/pizzas.behaviors +33 -0
  6. data/examples/pizzas/bluebook/pizzas.bluebook +4 -4
  7. data/examples/pizzas/bluebook/pizzas.hecksagon +5 -3
  8. data/examples/pizzas/config.ru +22 -0
  9. data/lib/hecks/adapters/driven/prism.rb +0 -2
  10. data/lib/hecks/adapters/driven.rb +0 -2
  11. data/lib/hecks/adapters/driving/json.rb +1 -7
  12. data/lib/hecks/bluebook/dsl/attribute_collector.rb +15 -5
  13. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -2
  14. data/lib/hecks/bluebook/dsl/derivation_words.rb +58 -0
  15. data/lib/hecks/bluebook/dsl/translation_builder.rb +6 -37
  16. data/lib/hecks/bluebook/expression/ast_json.rb +0 -9
  17. data/lib/hecks/bluebook/hecksagon.rb +1 -1
  18. data/lib/hecks/bluebook/meta_validator/translation_judge/rules.rb +7 -10
  19. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +4 -8
  20. data/lib/hecks/bluebook/meta_validator.rb +0 -11
  21. data/lib/hecks/bluebook/named_pattern.rb +33 -0
  22. data/lib/hecks/bluebook/translation.rb +18 -10
  23. data/lib/hecks/bluebook/translation_expression/evaluator.rb +63 -0
  24. data/lib/hecks/bluebook/translation_expression/parser.rb +127 -0
  25. data/lib/hecks/bluebook/translation_expression.rb +39 -0
  26. data/lib/hecks/bluebook/translation_plan.rb +70 -0
  27. data/lib/hecks/bluebook.rb +3 -0
  28. data/lib/hecks/chapters.rb +3 -3
  29. data/lib/hecks/cli/domain_stub.rb +1 -1
  30. data/lib/hecks/cli/interview_aggregate.rb +4 -4
  31. data/lib/hecks/composer/adapters/claude_composer.adapter +3 -0
  32. data/lib/hecks/composer/adapters/claude_composer.rb +83 -0
  33. data/lib/hecks/composer/adapters/fake_agent.adapter +3 -0
  34. data/lib/hecks/composer/adapters/fake_agent.rb +55 -0
  35. data/lib/hecks/composer/adapters/jev.adapter +3 -0
  36. data/lib/hecks/composer/adapters/jev.rb +66 -0
  37. data/lib/hecks/composer/agent.rb +113 -0
  38. data/lib/hecks/composer/assistant.rb +110 -0
  39. data/lib/hecks/composer/behavior_run.rb +53 -0
  40. data/lib/hecks/composer/bluebook/composer.bluebook +178 -0
  41. data/lib/hecks/composer/bluebook/composer.hecksagon +16 -0
  42. data/lib/hecks/composer/board.rb +65 -0
  43. data/lib/hecks/composer/board_edit/command_text.rb +39 -0
  44. data/lib/hecks/composer/board_edit/source.rb +84 -0
  45. data/lib/hecks/composer/board_edit.rb +144 -0
  46. data/lib/hecks/composer/check.rb +89 -0
  47. data/lib/hecks/composer/domains.rb +81 -0
  48. data/lib/hecks/composer/jobs.rb +134 -0
  49. data/lib/hecks/composer/layout.rb +37 -0
  50. data/lib/hecks/composer/live.rb +150 -0
  51. data/lib/hecks/composer/outline.rb +48 -0
  52. data/lib/hecks/composer/page.html +989 -0
  53. data/lib/hecks/composer/panels.rb +142 -0
  54. data/lib/hecks/composer/parse.rb +83 -0
  55. data/lib/hecks/composer/plain.rb +28 -0
  56. data/lib/hecks/composer/ports/composer_agent.port +7 -0
  57. data/lib/hecks/composer/session.rb +141 -0
  58. data/lib/hecks/composer/toolbox.rb +166 -0
  59. data/lib/hecks/composer/web.rb +156 -0
  60. data/lib/hecks/composer/workbench.rb +51 -0
  61. data/lib/hecks/composer/workspace.rb +81 -0
  62. data/lib/hecks/composer.rb +17 -0
  63. data/lib/hecks/corpus/adapters.rb +22 -0
  64. data/lib/hecks/corpus/rust.rb +1 -1
  65. data/lib/hecks/corpus/worlds.rb +19 -0
  66. data/lib/hecks/corpus.rb +5 -0
  67. data/lib/hecks/deploy/bluebook/deploy.bluebook +34 -34
  68. data/lib/hecks/forms/app/commands.rb +2 -3
  69. data/lib/hecks/forms/app/queries.rb +2 -3
  70. data/lib/hecks/forms/app/records.rb +17 -5
  71. data/lib/hecks/forms/command_form_renderer.rb +42 -16
  72. data/lib/hecks/forms/field_controls.rb +2 -2
  73. data/lib/hecks/forms/field_renderer.rb +1 -1
  74. data/lib/hecks/forms/field_shape.rb +36 -17
  75. data/lib/hecks/forms/index_renderer.rb +2 -1
  76. data/lib/hecks/forms/page.rb +1 -1
  77. data/lib/hecks/forms/params.rb +0 -13
  78. data/lib/hecks/forms/query_form_renderer.rb +7 -6
  79. data/lib/hecks/forms/record_renderer.rb +11 -7
  80. data/lib/hecks/forms/rule_words.rb +100 -0
  81. data/lib/hecks/forms/value_object_shape.rb +2 -1
  82. data/lib/hecks/framework/bluebook/change.bluebook +2 -2
  83. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -3
  84. data/lib/hecks/fuzzing/domain_generator/block_rendering.rb +1 -1
  85. data/lib/hecks/fuzzing/isolated_boot/worlds.rb +3 -6
  86. data/lib/hecks/fuzzing/replay/filters.rb +2 -6
  87. data/lib/hecks/gate/stages.yml +25 -0
  88. data/lib/hecks/grammar/evolve/seeds.rb +0 -6
  89. data/lib/hecks/grammar/evolve.rb +0 -3
  90. data/lib/hecks/grammar/translation.bluebook +1 -1
  91. data/lib/hecks/hecks/adapters/codebase/composing.rb +56 -0
  92. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +3 -1
  93. data/lib/hecks/hecks/adapters/journal_store/changes.rb +0 -26
  94. data/lib/hecks/hecks/adapters/journal_store/examination.rb +2 -23
  95. data/lib/hecks/hecks/adapters/journal_store/readings.rb +3 -11
  96. data/lib/hecks/hecks/adapters/journal_store.rb +0 -11
  97. data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +4 -11
  98. data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +0 -9
  99. data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +0 -4
  100. data/lib/hecks/hecks/codebase.behaviors +6 -0
  101. data/lib/hecks/hecks/codebase.bluebook +58 -37
  102. data/lib/hecks/hecks/composer.behaviors +68 -0
  103. data/lib/hecks/hecks/context_map.hecksagon +1 -1
  104. data/lib/hecks/hecks/custodian.behaviors +0 -6
  105. data/lib/hecks/hecks/custodian.bluebook +15 -92
  106. data/lib/hecks/hecks/hecks.bluebook +2 -2
  107. data/lib/hecks/hecks/hecks.hecksagon +2 -2
  108. data/lib/hecks/hecks/hecks.world +1 -1
  109. data/lib/hecks/hecks/rehearsal.bluebook +10 -16
  110. data/lib/hecks/hecks/tooling.bluebook +22 -22
  111. data/lib/hecks/kernel_capabilities/templates.rb +4 -4
  112. data/lib/hecks/kernel_capabilities.rb +1 -1
  113. data/lib/hecks/language/bluebook/aggregate.bluebook +1 -0
  114. data/lib/hecks/language/bluebook/command.bluebook +1 -0
  115. data/lib/hecks/language/bluebook/entity.bluebook +1 -0
  116. data/lib/hecks/language/bluebook/query.bluebook +1 -0
  117. data/lib/hecks/language/bluebook/shape.bluebook +8 -7
  118. data/lib/hecks/language/bluebook/vocabulary.bluebook +2 -3
  119. data/lib/hecks/language/hecksagon/port_operation.bluebook +1 -0
  120. data/lib/hecks/language/translation/translation_aggregate.bluebook +21 -24
  121. data/lib/hecks/ports/access_control.rb +2 -2
  122. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +3 -41
  123. data/lib/hecks/ports/persistence/plugins/era/lineage/coverage.rb +7 -7
  124. data/lib/hecks/ports/persistence/plugins/era/lineage/rewrite.rb +25 -2
  125. data/lib/hecks/ports/persistence/plugins/era/lineage/rules.rb +4 -4
  126. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +17 -25
  127. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/base_sql.rb +0 -12
  128. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/domain_rename.rb +1 -1
  129. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +2 -22
  130. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +0 -1
  131. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +9 -3
  132. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +3 -29
  133. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/refusals.rb +2 -26
  134. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +6 -33
  135. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -3
  136. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +2 -4
  137. data/lib/hecks/ports/persistence/plugins/era/translation/expression_sql.rb +52 -0
  138. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +23 -29
  139. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +1 -1
  140. data/lib/hecks/ports/persistence/plugins/era/translation.rb +0 -1
  141. data/lib/hecks/ports/persistence/plugins/era.rb +3 -6
  142. data/lib/hecks/ports.rb +0 -1
  143. data/lib/hecks/projection_files.rb +3 -1
  144. data/lib/hecks/projections/deploy/templates/lambda/nat_comment_oauth.tmpl +1 -1
  145. data/lib/hecks/projections/glossary/entries.rb +10 -4
  146. data/lib/hecks/projections/glossary/groups.rb +42 -0
  147. data/lib/hecks/projections/glossary/html/page.rb +7 -2
  148. data/lib/hecks/projections/glossary/html/parser.rb +1 -1
  149. data/lib/hecks/projections/glossary/html/sections.rb +31 -11
  150. data/lib/hecks/projections/glossary/html.rb +1 -2
  151. data/lib/hecks/projections/glossary/markdown.rb +31 -28
  152. data/lib/hecks/projections/glossary/mermaid.rb +3 -0
  153. data/lib/hecks/projections/glossary/page.css +143 -153
  154. data/lib/hecks/projections/glossary/page.js +63 -3
  155. data/lib/hecks/projections/glossary/sentences/actions.rb +88 -0
  156. data/lib/hecks/projections/glossary/sentences/paths.rb +77 -0
  157. data/lib/hecks/projections/glossary/sentences/queries.rb +90 -0
  158. data/lib/hecks/projections/glossary/sentences/value_objects.rb +32 -5
  159. data/lib/hecks/projections/glossary/sentences.rb +13 -3
  160. data/lib/hecks/projections/glossary/slugs.rb +4 -1
  161. data/lib/hecks/projections/glossary.rb +2 -1
  162. data/lib/hecks/projections/plain_english.rb +97 -0
  163. data/lib/hecks/projections/rust_vocabulary/arguments.rb +2 -2
  164. data/lib/hecks/projections/rust_vocabulary/enum_body.rb +20 -25
  165. data/lib/hecks/projections/rust_vocabulary/tests.rb +2 -2
  166. data/lib/hecks/projections/rust_vocabulary.rb +14 -6
  167. data/lib/hecks/projections/site/cms_editor/color.rb +0 -6
  168. data/lib/hecks/projections/statements/actions.rb +99 -0
  169. data/lib/hecks/projections/statements/relationships.rb +86 -0
  170. data/lib/hecks/projections/statements.rb +15 -24
  171. data/lib/hecks/projector/exporter/adapters.rb +112 -0
  172. data/lib/hecks/projector/exporter/translations.rb +18 -35
  173. data/lib/hecks/projector/exporter/worlds.rb +103 -0
  174. data/lib/hecks/projector/exporter.rb +5 -1
  175. data/lib/hecks/quality_control/adapters/agent.rb +6 -7
  176. data/lib/hecks/quality_control/adapters/agent_profile.rb +16 -114
  177. data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +1 -1
  178. data/lib/hecks/quality_control/quality_control.bluebook +51 -51
  179. data/lib/hecks/runtime/loader/boot_steps.rb +0 -20
  180. data/lib/hecks/runtime/outbox.rb +2 -9
  181. data/lib/hecks/runtime/port_operation_interpreter.rb +1 -9
  182. data/lib/hecks/runtime/remote_dispatcher.rb +2 -2
  183. data/lib/hecks/runtime/value.rb +13 -0
  184. data/lib/hecks/rust_build/project_rust/target_ir.rb +23 -4
  185. data/lib/hecks/rust_build/wasm.rb +0 -12
  186. data/lib/hecks/rust_build/write_if_changed.rb +12 -12
  187. data/lib/hecks/rust_format.rb +77 -0
  188. data/lib/hecks/site/bluebook/site.bluebook +5 -5
  189. data/lib/hecks/sme/bluebook/sme.bluebook +12 -12
  190. data/lib/hecks/tickets/bluebook/tickets.bluebook +3 -3
  191. data/lib/hecks/tools/fuzz_sweep/findings.rb +3 -9
  192. data/lib/hecks/tools/fuzz_sweep.rb +1 -3
  193. data/lib/hecks/tools/translation_audit/verdicts.rb +3 -28
  194. data/lib/hecks/tools/translation_audit.rb +8 -10
  195. data/lib/hecks/tools/translation_scaffold/reporting.rb +1 -1
  196. data/lib/hecks/version.rb +1 -1
  197. data/lib/hecks/vocabulary.rb +2 -1
  198. data/lib/hecks.rb +3 -0
  199. data/prebuilt/{58208399bada10b0db99928c48e38789288fc58f7b71a72b21bfa386680e32ed.marshal → 02c09c73b272c1fb5a9ae6d87bb5e5e529208e00f6b4b597dc2c0fd70a9c0964.marshal} +0 -0
  200. data/prebuilt/{2b59737fbdbd5f44edda0fddce2611f45d76087b3a7c782d1f1a17ea58c77948.marshal → bb84a835cf6a15136bad5ca03aa5bf93a5b92f5f72444618d3ef2412b987fb32.marshal} +0 -0
  201. data/prebuilt/verdicts-f1f10da14c8e8f01b4c9b7e3e2d74be8cd2bf4676364ed17fa16975d2a076d75.json +1 -0
  202. data/rust/Cargo.toml +40 -0
  203. data/rust/build/Cargo.toml +36 -0
  204. data/rust/build/clippy.toml +4 -0
  205. data/rust/build/src/adapters_pass.rs +196 -0
  206. data/rust/build/src/binding_pass.rs +54 -13
  207. data/rust/build/src/build_artifact.rs +23 -5
  208. data/rust/build/src/cargo_sync.rs +69 -26
  209. data/rust/build/src/lineage_pass.rs +101 -87
  210. data/rust/build/src/main.rs +11 -2
  211. data/rust/build/src/pipeline.rs +80 -19
  212. data/rust/build/src/reserved_names.rs +6 -50
  213. data/rust/build/src/resolve.rs +82 -35
  214. data/rust/build/src/rustfmt.rs +100 -0
  215. data/rust/build/src/seams_pass.rs +85 -16
  216. data/rust/build/src/subprocess.rs +30 -6
  217. data/rust/build/src/tmp.rs +5 -2
  218. data/rust/build/src/translation_pass.rs +72 -22
  219. data/rust/build/src/world_pass.rs +109 -0
  220. data/rust/clippy.toml +4 -0
  221. data/rust/codegen/Cargo.toml +36 -0
  222. data/rust/codegen/clippy.toml +4 -0
  223. data/rust/codegen/src/asks.rs +40 -14
  224. data/rust/codegen/src/attr.rs +2 -2
  225. data/rust/codegen/src/bridging.rs +676 -117
  226. data/rust/codegen/src/commands.rs +979 -373
  227. data/rust/codegen/src/constraints.rs +88 -25
  228. data/rust/codegen/src/dependency_planning.rs +128 -34
  229. data/rust/codegen/src/domain_generator.rs +300 -170
  230. data/rust/codegen/src/exemplar.rs +87 -32
  231. data/rust/codegen/src/expr_emitter.rs +54 -6
  232. data/rust/codegen/src/fielded.rs +193 -41
  233. data/rust/codegen/src/hecks_naming.rs +124 -16
  234. data/rust/codegen/src/hecks_naming_tests.rs +81 -0
  235. data/rust/codegen/src/json.rs +80 -44
  236. data/rust/codegen/src/json_codec.rs +585 -149
  237. data/rust/codegen/src/literal.rs +104 -138
  238. data/rust/codegen/src/main.rs +145 -52
  239. data/rust/codegen/src/manifest.rs +76 -14
  240. data/rust/codegen/src/mutations.rs +1212 -239
  241. data/rust/codegen/src/naming.rs +111 -60
  242. data/rust/codegen/src/optional_pass.rs +90 -28
  243. data/rust/codegen/src/ports.rs +5 -4
  244. data/rust/codegen/src/prelude.rs +139 -49
  245. data/rust/codegen/src/queries.rs +601 -226
  246. data/rust/codegen/src/reactions.rs +268 -74
  247. data/rust/codegen/src/read_models.rs +606 -205
  248. data/rust/codegen/src/reference_specs.rs +16 -3
  249. data/rust/codegen/src/registry.rs +128 -79
  250. data/rust/codegen/src/reserved_names.rs +6 -50
  251. data/rust/codegen/src/shared.rs +71 -22
  252. data/rust/codegen/src/sidecars.rs +15 -5
  253. data/rust/codegen/src/skip_reason.rs +8 -2
  254. data/rust/codegen/src/types.rs +306 -108
  255. data/rust/host/Cargo.lock +1 -0
  256. data/rust/host/Cargo.toml +40 -4
  257. data/rust/host/HECKS_RELEASE +1 -1
  258. data/rust/host/clippy.toml +4 -0
  259. data/rust/host/src/api.rs +698 -218
  260. data/rust/host/src/auth.rs +491 -214
  261. data/rust/host/src/b64.rs +91 -0
  262. data/rust/host/src/bin/expr_harness.rs +6 -2
  263. data/rust/host/src/bin/lineage_harness.rs +47 -11
  264. data/rust/host/src/bin/mint_harness.rs +70 -37
  265. data/rust/host/src/bin/validate_harness.rs +16 -8
  266. data/rust/host/src/boot.rs +144 -68
  267. data/rust/host/src/boundary_fuzz/api.rs +130 -32
  268. data/rust/host/src/boundary_fuzz/auth.rs +108 -23
  269. data/rust/host/src/boundary_fuzz/expr_json.rs +85 -11
  270. data/rust/host/src/boundary_fuzz/ir.rs +164 -12
  271. data/rust/host/src/boundary_fuzz/server.rs +283 -36
  272. data/rust/host/src/boundary_fuzz/web.rs +56 -8
  273. data/rust/host/src/checkout.rs +78 -32
  274. data/rust/host/src/clock.rs +8 -0
  275. data/rust/host/src/commerce_ir.rs +333 -95
  276. data/rust/host/src/crypto.rs +33 -0
  277. data/rust/host/src/dispatch.rs +990 -331
  278. data/rust/host/src/expr_json.rs +1021 -273
  279. data/rust/host/src/extension.rs +24 -4
  280. data/rust/host/src/field_hints.rs +11 -7
  281. data/rust/host/src/fuzz_support.rs +85 -13
  282. data/rust/host/src/host.rs +100 -0
  283. data/rust/host/src/http.rs +22 -0
  284. data/rust/host/src/ir.rs +326 -16
  285. data/rust/host/src/journal.rs +277 -176
  286. data/rust/host/src/lambda_client.rs +219 -53
  287. data/rust/host/src/lib.rs +16 -4
  288. data/rust/host/src/log.rs +62 -11
  289. data/rust/host/src/mint.rs +1153 -326
  290. data/rust/host/src/needs.rs +185 -44
  291. data/rust/host/src/payments/keystore.rs +197 -45
  292. data/rust/host/src/payments/roles.rs +191 -0
  293. data/rust/host/src/payments/tests.rs +1445 -275
  294. data/rust/host/src/payments.rs +409 -121
  295. data/rust/host/src/platform_signin/attack_tests.rs +5 -5
  296. data/rust/host/src/platform_signin/config.rs +11 -11
  297. data/rust/host/src/platform_signin/cookie.rs +2 -2
  298. data/rust/host/src/platform_signin/extension.rs +2 -1
  299. data/rust/host/src/platform_signin/handler.rs +9 -8
  300. data/rust/host/src/platform_signin/jti.rs +4 -2
  301. data/rust/host/src/platform_signin/jwks.rs +2 -1
  302. data/rust/host/src/platform_signin/jws.rs +2 -37
  303. data/rust/host/src/platform_signin/known_answer_tests.rs +5 -1
  304. data/rust/host/src/platform_signin/mode_tests.rs +5 -3
  305. data/rust/host/src/platform_signin/pages.rs +20 -20
  306. data/rust/host/src/platform_signin/session.rs +8 -1
  307. data/rust/host/src/platform_signin/settings.rs +6 -6
  308. data/rust/host/src/platform_signin/strict_json.rs +12 -9
  309. data/rust/host/src/platform_signin/verify.rs +41 -41
  310. data/rust/host/src/platform_signin/wiring_support.rs +13 -18
  311. data/rust/host/src/presentation.rs +207 -63
  312. data/rust/host/src/presentation_write.rs +502 -187
  313. data/rust/host/src/query_step.rs +69 -18
  314. data/rust/host/src/rate_limit.rs +541 -142
  315. data/rust/host/src/reference_transform.rs +77 -25
  316. data/rust/host/src/reference_validate.rs +443 -104
  317. data/rust/host/src/resend.rs +190 -55
  318. data/rust/host/src/secrets.rs +116 -21
  319. data/rust/host/src/server.rs +483 -104
  320. data/rust/host/src/storage_shape.rs +88 -21
  321. data/rust/host/src/test_pg.rs +17 -7
  322. data/rust/host/src/ui_schema.rs +495 -207
  323. data/rust/host/src/wasm_runner.rs +21 -6
  324. data/rust/host/src/web/commerce.rs +101 -23
  325. data/rust/host/src/web/newsletter/cooldown.rs +10 -3
  326. data/rust/host/src/web/newsletter/template.rs +26 -7
  327. data/rust/host/src/web/newsletter/tests.rs +112 -23
  328. data/rust/host/src/web/newsletter.rs +209 -59
  329. data/rust/host/src/web/newsletter_send.rs +251 -79
  330. data/rust/host/src/web/registration_receipt/tests.rs +16 -4
  331. data/rust/host/src/web/registration_receipt.rs +100 -24
  332. data/rust/host/src/web/registrations.rs +1384 -332
  333. data/rust/host/src/web/resend_webhook.rs +138 -80
  334. data/rust/host/src/web.rs +2416 -508
  335. data/rust/lsp/Cargo.toml +36 -0
  336. data/rust/lsp/clippy.toml +4 -0
  337. data/rust/lsp/src/json.rs +29 -22
  338. data/rust/lsp/src/main.rs +81 -31
  339. data/rust/lsp/src/outline.rs +23 -7
  340. data/rust/lsp/src/rpc.rs +17 -4
  341. data/rust/parser/Cargo.toml +36 -0
  342. data/rust/parser/clippy.toml +4 -0
  343. data/rust/parser/src/build/closed_sets.rs +6 -1
  344. data/rust/parser/src/build/identity.rs +4 -3
  345. data/rust/parser/src/build/mod.rs +1 -0
  346. data/rust/parser/src/build/named_pattern.rs +26 -0
  347. data/rust/parser/src/build/naming.rs +2 -80
  348. data/rust/parser/src/build/pattern_subset.rs +6 -8
  349. data/rust/parser/src/build/query_derive.rs +3 -1
  350. data/rust/parser/src/build/query_inference.rs +14 -5
  351. data/rust/parser/src/build/read_model.rs +4 -1
  352. data/rust/parser/src/build/references.rs +4 -3
  353. data/rust/parser/src/canonical.rs +34 -15
  354. data/rust/parser/src/emit.rs +187 -105
  355. data/rust/parser/src/expr/ast_json.rs +134 -42
  356. data/rust/parser/src/expr/evaluator.rs +27 -9
  357. data/rust/parser/src/expr/mod.rs +54 -13
  358. data/rust/parser/src/expr/resolver.rs +299 -92
  359. data/rust/parser/src/ir.rs +35 -3
  360. data/rust/parser/src/keywords.rs +7168 -510
  361. data/rust/parser/src/lex.rs +11 -25
  362. data/rust/parser/src/lib.rs +1 -0
  363. data/rust/parser/src/main.rs +65 -6
  364. data/rust/parser/src/parse/adapter.rs +157 -0
  365. data/rust/parser/src/parse/aggregate.rs +19 -10
  366. data/rust/parser/src/parse/chapter.rs +16 -17
  367. data/rust/parser/src/parse/command.rs +35 -16
  368. data/rust/parser/src/parse/domain_port.rs +4 -7
  369. data/rust/parser/src/parse/entity.rs +21 -11
  370. data/rust/parser/src/parse/hecksagon.rs +10 -4
  371. data/rust/parser/src/parse/lifecycle.rs +9 -5
  372. data/rust/parser/src/parse/mod.rs +43 -91
  373. data/rust/parser/src/parse/needs.rs +21 -12
  374. data/rust/parser/src/parse/policy.rs +2 -2
  375. data/rust/parser/src/parse/process_manager.rs +9 -11
  376. data/rust/parser/src/parse/query.rs +8 -4
  377. data/rust/parser/src/parse/read_model.rs +57 -16
  378. data/rust/parser/src/parse/value_object.rs +7 -2
  379. data/rust/parser/src/parse/world.rs +322 -0
  380. data/rust/parser/src/ruby_value.rs +7 -6
  381. data/rust/src/exemplar/json.rs +4 -4
  382. data/rust/src/exemplar/mutations.rs +18 -0
  383. data/rust/src/exemplar/read_models.rs +1 -10
  384. data/rust/src/kernel/attribute_shapes/composite.rs +54 -14
  385. data/rust/src/kernel/attribute_shapes/list.rs +2 -2
  386. data/rust/src/kernel/attribute_shapes/mod.rs +8 -8
  387. data/rust/src/kernel/attribute_shapes/scalar.rs +2 -2
  388. data/rust/src/kernel/cli.rs +229 -112
  389. data/rust/src/kernel/dispatch.rs +323 -115
  390. data/rust/src/kernel/dispatch_guard_tests.rs +327 -65
  391. data/rust/src/kernel/expr.rs +203 -86
  392. data/rust/src/kernel/expression_operators/arithmetic.rs +138 -25
  393. data/rust/src/kernel/expression_operators/comparison.rs +87 -2
  394. data/rust/src/kernel/expression_operators/enumeration.rs +106 -22
  395. data/rust/src/kernel/expression_operators/logical.rs +9 -3
  396. data/rust/src/kernel/expression_operators/membership.rs +3 -1
  397. data/rust/src/kernel/expression_operators/mod.rs +34 -21
  398. data/rust/src/kernel/expression_operators/pattern_match.rs +46 -11
  399. data/rust/src/kernel/expression_operators/positional.rs +84 -30
  400. data/rust/src/kernel/expression_operators/presence.rs +52 -13
  401. data/rust/src/kernel/expression_operators/sign_test.rs +3 -1
  402. data/rust/src/kernel/expression_operators/sized.rs +24 -8
  403. data/rust/src/kernel/expression_operators/text.rs +120 -27
  404. data/rust/src/kernel/expression_operators/to_string.rs +10 -4
  405. data/rust/src/kernel/json.rs +230 -148
  406. data/rust/src/kernel/mod.rs +46 -33
  407. data/rust/src/kernel/named_query.rs +63 -15
  408. data/rust/src/kernel/needs.rs +112 -25
  409. data/rust/src/kernel/orchestrate.rs +980 -581
  410. data/rust/src/kernel/orchestrate_guard_tests.rs +538 -140
  411. data/rust/src/kernel/pattern.rs +107 -34
  412. data/rust/src/kernel/query_comparators.rs +118 -41
  413. data/rust/src/kernel/query_ordering.rs +13 -5
  414. data/rust/src/kernel/read_model.rs +479 -181
  415. data/rust/src/kernel/reference_lookup.rs +122 -26
  416. data/rust/src/kernel/repository.rs +293 -66
  417. data/rust/src/kernel/routing.rs +58 -42
  418. data/rust/src/kernel/ruby_float.rs +139 -0
  419. data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +57 -57
  420. data/rust/src/kernel/vocab/entity_dispatch_order.rs +54 -54
  421. data/rust/src/kernel/vocab/field_hint.rs +19 -25
  422. data/rust/src/kernel/vocab/mod.rs +6 -6
  423. data/rust/src/kernel/vocab/query_comparator.rs +23 -24
  424. data/rust/src/kernel/vocab/refusal_template.rs +501 -297
  425. data/rust/src/lib.rs +50 -0
  426. data/rust/src/main.rs +4 -1
  427. data/rust/web/Cargo.toml +36 -0
  428. data/rust/web/clippy.toml +4 -0
  429. metadata +85 -15
  430. data/examples/pizzas/bluebook/hecksagon/mock_stripe_payment_adapter.rb +0 -36
  431. data/lib/hecks/adapters/driven/google_authentication.adapter +0 -3
  432. data/lib/hecks/adapters/driven/google_authentication.rb +0 -99
  433. data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +0 -3
  434. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +0 -32
  435. data/lib/hecks/ports/authentication.port +0 -6
  436. data/lib/hecks/ports/authentication.rb +0 -67
  437. data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +0 -255
  438. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +0 -22
  439. data/prebuilt/verdicts-48318ca172edd21443b1ad02801c697fff100b746e828f09db987647641a5df2.json +0 -1
  440. data/rust/host/src/approval.rs +0 -652
@@ -0,0 +1,91 @@
1
+ //! The base64 the host reads and writes, in the two alphabets and strictness it needs.
2
+ //!
3
+ //! Both decoders refuse a second spelling of the same bytes where they can: URL-safe text must be
4
+ //! canonical (no padding, no spare non-zero bits), because a signature that verifies over one
5
+ //! spelling must not be re-spelled into a lookalike the issuer never produced.
6
+
7
+ use base64::alphabet;
8
+ use base64::engine::general_purpose::{GeneralPurpose, GeneralPurposeConfig, URL_SAFE_NO_PAD};
9
+ use base64::engine::DecodePaddingMode;
10
+ use base64::Engine;
11
+
12
+ /// Standard alphabet, accepting padding or none: what webhook secrets and signatures arrive as.
13
+ const STANDARD_ANY_PADDING: GeneralPurpose = GeneralPurpose::new(
14
+ &alphabet::STANDARD,
15
+ GeneralPurposeConfig::new().with_decode_padding_mode(DecodePaddingMode::Indifferent),
16
+ );
17
+
18
+ /// Unpadded base64url (RFC 4648 section 5).
19
+ pub fn url_encode(bytes: &[u8]) -> String {
20
+ URL_SAFE_NO_PAD.encode(bytes)
21
+ }
22
+
23
+ /// Canonical unpadded base64url; `None` for padding, a character outside the alphabet, a length
24
+ /// no byte string encodes to, or spare trailing bits that are not zero.
25
+ pub fn url_decode(text: &str) -> Option<Vec<u8>> {
26
+ URL_SAFE_NO_PAD.decode(text).ok()
27
+ }
28
+
29
+ /// Standard base64, padded or not; `None` on any other character.
30
+ pub fn standard_decode(text: &str) -> Option<Vec<u8>> {
31
+ STANDARD_ANY_PADDING.decode(text).ok()
32
+ }
33
+
34
+ #[cfg(test)]
35
+ mod tests {
36
+ use super::*;
37
+
38
+ #[test]
39
+ fn url_text_round_trips_every_length_and_is_url_safe() {
40
+ for input in [
41
+ &b""[..],
42
+ b"a",
43
+ b"ab",
44
+ b"abc",
45
+ b"abcd",
46
+ b"\x00\xff\x10hello world!",
47
+ ] {
48
+ let encoded = url_encode(input);
49
+ assert!(
50
+ !encoded.contains(['+', '/', '=']),
51
+ "must be URL-safe: {encoded}"
52
+ );
53
+ assert_eq!(url_decode(&encoded).as_deref(), Some(input));
54
+ }
55
+ }
56
+
57
+ #[test]
58
+ fn url_text_must_be_canonical() {
59
+ assert_eq!(url_decode("Zg").as_deref(), Some(&b"f"[..]));
60
+ assert_eq!(url_decode("Zg=="), None, "padding is a second spelling");
61
+ assert_eq!(url_decode("Zh"), None, "spare bits must be zero");
62
+ assert_eq!(
63
+ url_decode("a+b/"),
64
+ None,
65
+ "the standard alphabet is another spelling"
66
+ );
67
+ assert_eq!(
68
+ url_decode("Z"),
69
+ None,
70
+ "no byte string encodes to one character"
71
+ );
72
+ }
73
+
74
+ #[test]
75
+ fn standard_text_decodes_padded_or_not_and_refuses_other_characters() {
76
+ assert_eq!(
77
+ standard_decode("c2VjcmV0LWtleQ==").as_deref(),
78
+ Some(&b"secret-key"[..])
79
+ );
80
+ assert_eq!(
81
+ standard_decode("c2VjcmV0LWtleQ").as_deref(),
82
+ Some(&b"secret-key"[..])
83
+ );
84
+ assert_eq!(
85
+ standard_decode("-_"),
86
+ None,
87
+ "the URL-safe alphabet is not standard"
88
+ );
89
+ assert_eq!(standard_decode("not base64!"), None);
90
+ }
91
+ }
@@ -16,12 +16,16 @@ fn main() -> anyhow::Result<()> {
16
16
  let mut input = String::new();
17
17
  std::io::stdin().read_to_string(&mut input)?;
18
18
  let request: Json = serde_json::from_str(&input)?;
19
- let cases = request.get("cases").and_then(Json::as_array).ok_or_else(|| anyhow::anyhow!("no \"cases\" array on stdin"))?;
19
+ let cases = request
20
+ .get("cases")
21
+ .and_then(Json::as_array)
22
+ .ok_or_else(|| anyhow::anyhow!("no \"cases\" array on stdin"))?;
20
23
 
21
24
  let results: Vec<Json> = cases
22
25
  .iter()
23
26
  .map(|case| {
24
- let outcome = expr_json::parse(&case["ast"]).and_then(|expr| expr_json::interpret(&expr, &case["instance"]));
27
+ let outcome = expr_json::parse(&case["ast"])
28
+ .and_then(|expr| expr_json::interpret(&expr, &case["instance"]));
25
29
  match outcome {
26
30
  Ok(value) => json!({ "ok": to_json(&value) }),
27
31
  Err(error) => json!({ "error": error }),
@@ -8,10 +8,13 @@
8
8
  //! stdout is `{"results": [...]}`, one entry per operation in order. A per-operation Postgres
9
9
  //! error (such as an RLS refusal) lands in that entry; only a failed connection exits nonzero.
10
10
 
11
- // journal.rs has no `crate::` references, so it is shared with `bootstrap` by path, not a lib
12
- // split.
11
+ // journal.rs reaches only `crate::hecks_naming`, so it is shared with `bootstrap` by path, not a
12
+ // lib split, and carries that one file with it.
13
13
  // The flat-journal functions it also carries are unused here.
14
14
  #[allow(dead_code)]
15
+ #[path = "../../../codegen/src/hecks_naming.rs"]
16
+ mod hecks_naming;
17
+ #[allow(dead_code)]
15
18
  #[path = "../journal.rs"]
16
19
  mod journal;
17
20
 
@@ -31,7 +34,9 @@ async fn main() -> anyhow::Result<()> {
31
34
  let [_, db_name, app_role, domain, era] = args.as_slice() else {
32
35
  anyhow::bail!("usage: lineage_harness <db_name> <app_role> <domain> <era>");
33
36
  };
34
- let era: i32 = era.parse().map_err(|_| anyhow::anyhow!("era must be an integer, got {era:?}"))?;
37
+ let era: i32 = era
38
+ .parse()
39
+ .map_err(|_| anyhow::anyhow!("era must be an integer, got {era:?}"))?;
35
40
 
36
41
  let mut input = String::new();
37
42
  std::io::stdin().read_to_string(&mut input)?;
@@ -42,7 +47,11 @@ async fn main() -> anyhow::Result<()> {
42
47
  .ok_or_else(|| anyhow::anyhow!("stdin JSON missing \"operations\" array"))?;
43
48
 
44
49
  // tokio_postgres ignores libpq's `PGPASSWORD`, so pass it through when the server asks for one.
45
- let password = std::env::var("PGPASSWORD").ok().filter(|p| !p.is_empty()).map(|p| format!(" password={p}")).unwrap_or_default();
50
+ let password = std::env::var("PGPASSWORD")
51
+ .ok()
52
+ .filter(|p| !p.is_empty())
53
+ .map(|p| format!(" password={p}"))
54
+ .unwrap_or_default();
46
55
  let conn_string = format!("host=localhost dbname={db_name} user={app_role}{password}");
47
56
  let (client, connection) = tokio_postgres::connect(&conn_string, NoTls).await?;
48
57
  tokio::spawn(async move {
@@ -51,7 +60,11 @@ async fn main() -> anyhow::Result<()> {
51
60
  }
52
61
  });
53
62
 
54
- let config = journal::LineageConfig { domain: domain.clone(), era: Some(era), mirrored: None };
63
+ let config = journal::LineageConfig {
64
+ domain: domain.clone(),
65
+ era: Some(era),
66
+ mirrored: None,
67
+ };
55
68
  let mut results = Vec::with_capacity(operations.len());
56
69
 
57
70
  for operation in operations {
@@ -62,7 +75,11 @@ async fn main() -> anyhow::Result<()> {
62
75
  Ok(())
63
76
  }
64
77
 
65
- async fn run_one(client: &tokio_postgres::Client, config: &journal::LineageConfig, operation: &Value) -> Value {
78
+ async fn run_one(
79
+ client: &tokio_postgres::Client,
80
+ config: &journal::LineageConfig,
81
+ operation: &Value,
82
+ ) -> Value {
66
83
  let op = operation.get("op").and_then(|v| v.as_str()).unwrap_or("");
67
84
 
68
85
  let outcome = match op {
@@ -82,20 +99,34 @@ async fn run_one(client: &tokio_postgres::Client, config: &journal::LineageConfi
82
99
  }
83
100
  }
84
101
 
85
- async fn read_all(client: &tokio_postgres::Client, config: &journal::LineageConfig, operation: &Value) -> anyhow::Result<Value> {
102
+ async fn read_all(
103
+ client: &tokio_postgres::Client,
104
+ config: &journal::LineageConfig,
105
+ operation: &Value,
106
+ ) -> anyhow::Result<Value> {
86
107
  let storage_name = require_str(operation, "storage_name")?;
87
108
  let rows = journal::read_lineage_head_all(client, &config.domain, storage_name).await?;
88
- Ok(json!({ "rows": rows.into_iter().map(|(id, state)| json!([id, state])).collect::<Vec<_>>() }))
109
+ Ok(
110
+ json!({ "rows": rows.into_iter().map(|(id, state)| json!([id, state])).collect::<Vec<_>>() }),
111
+ )
89
112
  }
90
113
 
91
- async fn read_by_id(client: &tokio_postgres::Client, config: &journal::LineageConfig, operation: &Value) -> anyhow::Result<Value> {
114
+ async fn read_by_id(
115
+ client: &tokio_postgres::Client,
116
+ config: &journal::LineageConfig,
117
+ operation: &Value,
118
+ ) -> anyhow::Result<Value> {
92
119
  let storage_name = require_str(operation, "storage_name")?;
93
120
  let id = require_str(operation, "id")?;
94
121
  let state = journal::read_lineage_head_by_id(client, &config.domain, storage_name, id).await?;
95
122
  Ok(json!({ "state": state }))
96
123
  }
97
124
 
98
- async fn write(client: &tokio_postgres::Client, config: &journal::LineageConfig, operation: &Value) -> anyhow::Result<Value> {
125
+ async fn write(
126
+ client: &tokio_postgres::Client,
127
+ config: &journal::LineageConfig,
128
+ operation: &Value,
129
+ ) -> anyhow::Result<Value> {
99
130
  let aggregate = require_str(operation, "aggregate")?;
100
131
  let id = require_str(operation, "id")?;
101
132
  let state = operation
@@ -105,7 +136,12 @@ async fn write(client: &tokio_postgres::Client, config: &journal::LineageConfig,
105
136
  journal::append_lineage_mutation(
106
137
  client,
107
138
  config,
108
- &journal::Mutation { aggregate, id, operation: "save", state },
139
+ &journal::Mutation {
140
+ aggregate,
141
+ id,
142
+ operation: "save",
143
+ state,
144
+ },
109
145
  )
110
146
  .await?;
111
147
  Ok(json!({}))
@@ -4,29 +4,29 @@
4
4
  // Modules are shared with `bootstrap` by path, not a lib split, so `crate::` in mint.rs resolves
5
5
  // here.
6
6
  #[allow(dead_code)]
7
- #[path = "../log.rs"]
8
- mod log;
7
+ #[path = "../expr_json.rs"]
8
+ mod expr_json;
9
+ #[allow(dead_code)]
10
+ #[path = "../../../codegen/src/hecks_naming.rs"]
11
+ mod hecks_naming;
9
12
  #[allow(dead_code)]
10
13
  #[path = "../journal.rs"]
11
14
  mod journal;
12
15
  #[allow(dead_code)]
13
- #[path = "../storage_shape.rs"]
14
- mod storage_shape;
16
+ #[path = "../log.rs"]
17
+ mod log;
18
+ #[allow(dead_code)]
19
+ #[path = "../mint.rs"]
20
+ mod mint;
15
21
  #[allow(dead_code)]
16
22
  #[path = "../reference_transform.rs"]
17
23
  mod reference_transform;
18
24
  #[allow(dead_code)]
19
- #[path = "../expr_json.rs"]
20
- mod expr_json;
21
- #[allow(dead_code)]
22
25
  #[path = "../reference_validate.rs"]
23
26
  mod reference_validate;
24
27
  #[allow(dead_code)]
25
- #[path = "../approval.rs"]
26
- mod approval;
27
- #[allow(dead_code)]
28
- #[path = "../mint.rs"]
29
- mod mint;
28
+ #[path = "../storage_shape.rs"]
29
+ mod storage_shape;
30
30
 
31
31
  // The shared modules' Postgres tests connect through `crate::test_pg`, so the harness's own test
32
32
  // build carries the same connection-string helpers.
@@ -48,8 +48,10 @@ async fn main() -> anyhow::Result<()> {
48
48
  anyhow::bail!("usage: mint_harness <db_name> <owner_role> <domain> <ir_json_path>");
49
49
  };
50
50
 
51
- let ir_text = std::fs::read_to_string(ir_path).map_err(|e| anyhow::anyhow!("reading {ir_path}: {e}"))?;
52
- let ir: Value = serde_json::from_str(&ir_text).map_err(|e| anyhow::anyhow!("parsing {ir_path}: {e}"))?;
51
+ let ir_text =
52
+ std::fs::read_to_string(ir_path).map_err(|e| anyhow::anyhow!("reading {ir_path}: {e}"))?;
53
+ let ir: Value =
54
+ serde_json::from_str(&ir_text).map_err(|e| anyhow::anyhow!("parsing {ir_path}: {e}"))?;
53
55
 
54
56
  // A server that wants a password over TCP gets it from PGPASSWORD, as libpq would read it.
55
57
  // Built field by field, not spliced into a connection string, so a password with a space,
@@ -81,7 +83,11 @@ async fn main() -> anyhow::Result<()> {
81
83
  .unwrap_or_default()
82
84
  .iter()
83
85
  .map(|agg| {
84
- let name = agg.get("name").and_then(Value::as_str).unwrap_or("").to_string();
86
+ let name = agg
87
+ .get("name")
88
+ .and_then(Value::as_str)
89
+ .unwrap_or("")
90
+ .to_string();
85
91
  let storage_name = journal::snake(&name);
86
92
  mint::Aggregate { name, storage_name }
87
93
  })
@@ -92,40 +98,67 @@ async fn main() -> anyhow::Result<()> {
92
98
  let era = match mint::decide_boot_action(&held, &my_label) {
93
99
  mint::BootDecision::UseExisting { ordinal } => ordinal,
94
100
  mint::BootDecision::HoldFirst => {
95
- let source_text = ir.get("source_text").and_then(Value::as_str).unwrap_or("mint_harness fixture source");
101
+ let source_text = ir
102
+ .get("source_text")
103
+ .and_then(Value::as_str)
104
+ .unwrap_or("mint_harness fixture source");
96
105
  mint::hold_first(&client, domain, source_text, &ir, &aggregates, None).await?;
97
106
  1
98
107
  }
99
108
  mint::BootDecision::LatestUnnamed { ordinal } => {
100
109
  anyhow::bail!("latest held era {ordinal} has no label -- mint_harness has no bluebook parser to name it with");
101
110
  }
102
- mint::BootDecision::Mint { ordinal, from_ordinal, from_label } => {
103
- let mut labels: Vec<String> = held.iter().map(|h| h.label.clone().unwrap_or_default()).collect();
111
+ mint::BootDecision::Mint {
112
+ ordinal,
113
+ from_ordinal,
114
+ from_label,
115
+ } => {
116
+ let mut labels: Vec<String> = held
117
+ .iter()
118
+ .map(|h| h.label.clone().unwrap_or_default())
119
+ .collect();
104
120
  labels.push(my_label.clone());
105
121
  let edges = mint::parse_edges(&ir, domain);
106
122
  let chain = mint::edge_chain(&edges, &labels)
107
123
  .map_err(|e| anyhow::anyhow!("drifted from era {from_ordinal} ({from_label}) to {my_label} with no covering edge -- {e}"))?;
108
124
 
109
- // The same gate the host runs: a compute/rekey edge mints only on an approval, from the
110
- // journal or committed in ir.json's `approvals`.
111
- let raw_edges = ir.get("translations").and_then(Value::as_array).cloned().unwrap_or_default();
112
- let committed_approvals = approval::committed(&ir);
113
- for edge in &chain {
114
- // An edge with no raw entry fails closed, as the host does, and never skips the gate.
115
- let Some(raw_edge) = raw_edges.iter().find(|candidate| {
116
- candidate.get("domain").and_then(Value::as_str) == Some(domain.as_str())
117
- && candidate.get("from").and_then(Value::as_str) == Some(edge.from.as_str())
118
- && candidate.get("to").and_then(Value::as_str) == Some(edge.to.as_str())
119
- }) else {
120
- anyhow::bail!("cannot boot: {domain}'s edge {} -> {} vanished between parsing and approval-checking it", edge.from, edge.to);
121
- };
122
- approval::check(&client, domain, raw_edge, ordinal, &committed_approvals).await?;
123
- }
124
- let watermarks: HashMap<i32, Option<i64>> = held.iter().map(|h| (h.ordinal, h.watermark)).collect();
125
- mint::audit_before_mint(&client, domain, &ir, &aggregates, ordinal, &chain, &raw_edges, &watermarks).await?;
125
+ // The raw ir.json edges, matched to the chain by from/to pair for the audit.
126
+ let raw_edges = ir
127
+ .get("translations")
128
+ .and_then(Value::as_array)
129
+ .cloned()
130
+ .unwrap_or_default();
131
+ let watermarks: HashMap<i32, Option<i64>> =
132
+ held.iter().map(|h| (h.ordinal, h.watermark)).collect();
133
+ mint::audit_before_mint(
134
+ &client,
135
+ domain,
136
+ &ir,
137
+ &aggregates,
138
+ ordinal,
139
+ &chain,
140
+ &raw_edges,
141
+ &watermarks,
142
+ )
143
+ .await?;
126
144
 
127
- let held_text = ir.get("source_text").and_then(Value::as_str).unwrap_or("mint_harness fixture source");
128
- mint::mint_era(&client, domain, ordinal, &my_hash, &my_label, held_text, &aggregates, &chain, None, &mint::lifecycle_defaults(&ir)).await?;
145
+ let held_text = ir
146
+ .get("source_text")
147
+ .and_then(Value::as_str)
148
+ .unwrap_or("mint_harness fixture source");
149
+ mint::mint_era(
150
+ &client,
151
+ domain,
152
+ ordinal,
153
+ &my_hash,
154
+ &my_label,
155
+ held_text,
156
+ &aggregates,
157
+ &chain,
158
+ None,
159
+ &mint::lifecycle_defaults(&ir),
160
+ )
161
+ .await?;
129
162
  ordinal
130
163
  }
131
164
  };
@@ -19,8 +19,13 @@ fn main() -> anyhow::Result<()> {
19
19
  let mut input = String::new();
20
20
  std::io::stdin().read_to_string(&mut input)?;
21
21
  let request: Value = serde_json::from_str(&input)?;
22
- let ir = request.get("ir").ok_or_else(|| anyhow::anyhow!("no \"ir\" on stdin"))?;
23
- let cases = request.get("cases").and_then(Value::as_array).ok_or_else(|| anyhow::anyhow!("no \"cases\" array on stdin"))?;
22
+ let ir = request
23
+ .get("ir")
24
+ .ok_or_else(|| anyhow::anyhow!("no \"ir\" on stdin"))?;
25
+ let cases = request
26
+ .get("cases")
27
+ .and_then(Value::as_array)
28
+ .ok_or_else(|| anyhow::anyhow!("no \"cases\" array on stdin"))?;
24
29
 
25
30
  let results: Vec<Value> = cases.iter().map(|case| answer(ir, case)).collect();
26
31
  println!("{}", json!({ "results": results }));
@@ -32,12 +37,15 @@ fn answer(ir: &Value, case: &Value) -> Value {
32
37
  let aggregate = ir
33
38
  .get("aggregates")
34
39
  .and_then(Value::as_array)
35
- .and_then(|list| list.iter().find(|a| a.get("name").and_then(Value::as_str) == Some(name)));
36
- match aggregate {
37
- None => json!({ "error": format!("no aggregate {name:?} in the IR") }),
38
- Some(aggregate) => {
40
+ .and_then(|list| {
41
+ list.iter()
42
+ .find(|a| a.get("name").and_then(Value::as_str) == Some(name))
43
+ });
44
+ aggregate.map_or_else(
45
+ || json!({ "error": format!("no aggregate {name:?} in the IR") }),
46
+ |aggregate| {
39
47
  let id = case.get("id").and_then(Value::as_str).unwrap_or("");
40
48
  json!({ "violations": reference_validate::validate(ir, aggregate, id, &case["state"]) })
41
- }
42
- }
49
+ },
50
+ )
43
51
  }