hecks 3.10.0 → 3.12.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 (542) hide show
  1. checksums.yaml +4 -4
  2. data/examples/pizzas/bluebook/pizzas.bluebook +29 -0
  3. data/examples/pizzas/bluebook/pizzas.hecksagon +7 -0
  4. data/exe/hecks +4 -4
  5. data/lib/hecks/adapters/driven/d1.rb +2 -10
  6. data/lib/hecks/adapters/driven/heki.adapter +1 -1
  7. data/lib/hecks/adapters/driven/heki.rb +2 -12
  8. data/lib/hecks/adapters/driven/lambda.adapter +1 -1
  9. data/lib/hecks/adapters/driven/lambda.rb +3 -18
  10. data/lib/hecks/adapters/driven/postgres.rb +4 -11
  11. data/lib/hecks/adapters/driven/sqlite.adapter +1 -1
  12. data/lib/hecks/adapters/driven/sqlite.rb +2 -10
  13. data/lib/hecks/adapters/driving/admission.rb +46 -0
  14. data/lib/hecks/adapters/driving/cli/nesting.rb +36 -0
  15. data/lib/hecks/adapters/driving/cli/shorthand.rb +88 -0
  16. data/lib/hecks/adapters/driving/cli.rb +127 -0
  17. data/lib/hecks/adapters/driving/cli_runner/answers.rb +160 -0
  18. data/lib/hecks/adapters/driving/cli_runner/resolution.rb +158 -0
  19. data/lib/hecks/adapters/driving/cli_runner/settling.rb +120 -0
  20. data/lib/hecks/adapters/driving/cli_runner/streaming.rb +93 -0
  21. data/lib/hecks/adapters/driving/cli_runner/suggestions.rb +47 -0
  22. data/lib/hecks/adapters/driving/cli_runner.rb +70 -0
  23. data/lib/hecks/adapters/driving/command_request.rb +121 -0
  24. data/lib/hecks/adapters/driving/handle.rb +214 -0
  25. data/lib/hecks/adapters/driving/json.rb +136 -0
  26. data/lib/hecks/adapters/driving/launcher_options.rb +267 -0
  27. data/lib/hecks/adapters/driving/mcp/properties.rb +49 -0
  28. data/lib/hecks/adapters/driving/mcp/tool_calls.rb +116 -0
  29. data/lib/hecks/adapters/driving/mcp/tool_definitions/auditing.rb +53 -0
  30. data/lib/hecks/adapters/driving/mcp/tool_definitions/calling.rb +71 -0
  31. data/lib/hecks/adapters/driving/mcp/tool_definitions/reading.rb +99 -0
  32. data/lib/hecks/adapters/driving/mcp/tool_definitions.rb +18 -0
  33. data/lib/hecks/adapters/driving/mcp.rb +159 -0
  34. data/lib/hecks/adapters/driving/mcp_guide_cache.rb +78 -0
  35. data/lib/hecks/adapters/driving/mcp_scope/argument_policy.rb +97 -0
  36. data/lib/hecks/adapters/driving/mcp_scope/env_problems.rb +69 -0
  37. data/lib/hecks/adapters/driving/mcp_scope/presenter.rb +83 -0
  38. data/lib/hecks/adapters/driving/mcp_scope.rb +213 -0
  39. data/lib/hecks/adapters/driving/newcomer.rb +50 -0
  40. data/lib/hecks/adapters/driving/ruby/aggregate_module.rb +171 -0
  41. data/lib/hecks/adapters/driving/ruby/chapter.rb +91 -0
  42. data/lib/hecks/adapters/driving/ruby.rb +83 -0
  43. data/lib/hecks/adapters/driving/usage_cache.rb +144 -0
  44. data/lib/hecks/{doors.rb → adapters/driving.rb} +10 -6
  45. data/lib/hecks/behaviors/expectations/boot.rb +1 -1
  46. data/lib/hecks/bench/ruby_runner.rb +1 -1
  47. data/lib/hecks/bluebook/ask_resolution.rb +130 -0
  48. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +8 -2
  49. data/lib/hecks/bluebook/assembly/contracts/read_models.rb +1 -1
  50. data/lib/hecks/bluebook/assembly/contracts/rules.rb +4 -2
  51. data/lib/hecks/bluebook/assembly/contracts/structure.rb +3 -1
  52. data/lib/hecks/bluebook/assembly/marks.rb +4 -15
  53. data/lib/hecks/bluebook/assembly/scalars.rb +39 -0
  54. data/lib/hecks/bluebook/attribute.rb +1 -1
  55. data/lib/hecks/bluebook/behaviour/command.rb +13 -8
  56. data/lib/hecks/bluebook/behaviour/policy.rb +30 -0
  57. data/lib/hecks/bluebook/capabilities/attribute_values.rb +72 -0
  58. data/lib/hecks/bluebook/capabilities.rb +91 -9
  59. data/lib/hecks/bluebook/domain_port.rb +16 -4
  60. data/lib/hecks/bluebook/dsl/adapter_builder.rb +18 -6
  61. data/lib/hecks/bluebook/dsl/binding_proxy.rb +13 -0
  62. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/computed_sources.rb +98 -0
  63. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/fan_out_rows.rb +42 -0
  64. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/projected_fields.rb +14 -2
  65. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/provisions.rb +69 -3
  66. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/with_projections.rb +17 -10
  67. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +5 -0
  68. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -0
  69. data/lib/hecks/bluebook/dsl/command_builder/mutations.rb +8 -1
  70. data/lib/hecks/bluebook/dsl/command_builder/operands.rb +121 -0
  71. data/lib/hecks/bluebook/dsl/command_builder.rb +2 -0
  72. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +10 -1
  73. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +45 -2
  74. data/lib/hecks/bluebook/dsl/policy_builder.rb +47 -10
  75. data/lib/hecks/bluebook/dsl/rule_reference.rb +7 -4
  76. data/lib/hecks/bluebook/dsl/world_builder.rb +1 -1
  77. data/lib/hecks/bluebook/expression/ast_json/emitters.rb +6 -0
  78. data/lib/hecks/bluebook/expression/ast_json.rb +9 -6
  79. data/lib/hecks/bluebook/expression/ast_reader.rb +14 -9
  80. data/lib/hecks/bluebook/expression/projection.json +36 -0
  81. data/lib/hecks/bluebook/expression/resolver/operations.rb +31 -0
  82. data/lib/hecks/bluebook/expression/resolver/parsing.rb +38 -5
  83. data/lib/hecks/bluebook/expression/resolver/scanning.rb +22 -5
  84. data/lib/hecks/bluebook/expression/resolver/values.rb +10 -0
  85. data/lib/hecks/bluebook/expression/resolver.rb +20 -1
  86. data/lib/hecks/bluebook/hecksagon.rb +23 -3
  87. data/lib/hecks/bluebook/lifecycle.rb +22 -3
  88. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +13 -1
  89. data/lib/hecks/bluebook/meta_validator/modes.rb +4 -1
  90. data/lib/hecks/bluebook/meta_validator/readings.rb +24 -1
  91. data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +2 -1
  92. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +6 -3
  93. data/lib/hecks/bluebook/meta_validator/shapes.rb +5 -0
  94. data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +1 -1
  95. data/lib/hecks/bluebook/meta_validator.rb +12 -12
  96. data/lib/hecks/bluebook/model_check/ask_checks.rb +71 -0
  97. data/lib/hecks/bluebook/model_check/policy_checks.rb +2 -1
  98. data/lib/hecks/bluebook/model_check/reference_checks.rb +70 -0
  99. data/lib/hecks/bluebook/model_check.rb +8 -2
  100. data/lib/hecks/bluebook/policy.rb +4 -2
  101. data/lib/hecks/bluebook/smoke_test.rb +1 -1
  102. data/lib/hecks/bluebook/synthesizer.rb +2 -0
  103. data/lib/hecks/bluebook.rb +2 -0
  104. data/lib/hecks/cli/command_table.rb +1 -1
  105. data/lib/hecks/cli/console.rb +2 -1
  106. data/lib/hecks/cli/document.rb +1 -1
  107. data/lib/hecks/cli/launcher_words.rb +4 -4
  108. data/lib/hecks/cli/mcp.rb +4 -4
  109. data/lib/hecks/cli/project_cli/launcher_source.rb +2 -2
  110. data/lib/hecks/cli/project_cli/templates.rb +5 -5
  111. data/lib/hecks/cli/project_cli.rb +9 -6
  112. data/lib/hecks/cli/run.rb +2 -2
  113. data/lib/hecks/cli/smoke_http/checks.rb +4 -1
  114. data/lib/hecks/cli/smoke_http/transport.rb +3 -3
  115. data/lib/hecks/cli/smoke_http.rb +3 -0
  116. data/lib/hecks/codemod.rb +5 -2
  117. data/lib/hecks/corpus/routes.rb +7 -0
  118. data/lib/hecks/corpus/rust.rb +3 -2
  119. data/lib/hecks/deploy/bluebook/deploy.bluebook +34 -4
  120. data/lib/hecks/doc/reference/rendering.rb +6 -3
  121. data/lib/hecks/forms/app/commands.rb +8 -7
  122. data/lib/hecks/forms/app/queries.rb +2 -1
  123. data/lib/hecks/forms/app.rb +1 -1
  124. data/lib/hecks/forms/record_renderer.rb +1 -1
  125. data/lib/hecks/framework/bluebook/privacy.bluebook +11 -0
  126. data/lib/hecks/fuzzing/concurrent_dispatch.rb +4 -1
  127. data/lib/hecks/fuzzing/failure_triage.rb +2 -1
  128. data/lib/hecks/fuzzing/mutation/run.rb +11 -4
  129. data/lib/hecks/fuzzing/properties/catalog.rb +6 -4
  130. data/lib/hecks/fuzzing/properties/guaranteed_by_construction.rb +18 -11
  131. data/lib/hecks/fuzzing/properties/guards.rb +1 -1
  132. data/lib/hecks/fuzzing/self_consistency/saga_redelivery.rb +1 -1
  133. data/lib/hecks/fuzzing/self_consistency.rb +6 -2
  134. data/lib/hecks/fuzzing/shrinker.rb +3 -1
  135. data/lib/hecks/fuzzing/value_generator.rb +19 -5
  136. data/lib/hecks/gate/stages.yml +33 -7
  137. data/lib/hecks/grammar/evolve.rb +1 -1
  138. data/lib/hecks/grammar/expression_operators.json +372 -0
  139. data/lib/hecks/grammar/operators.rb +3 -1
  140. data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +10 -10
  141. data/lib/hecks/hecks/adapters/codebase/inspection/rubycritic.rb +35 -0
  142. data/lib/hecks/hecks/adapters/codebase/inspection.rb +104 -0
  143. data/lib/hecks/hecks/adapters/codebase/publishing.rb +2 -1
  144. data/lib/hecks/hecks/adapters/codebase/release_facts.rb +12 -2
  145. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +2 -1
  146. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +1 -1
  147. data/lib/hecks/hecks/adapters/cost_explorer.rb +8 -5
  148. data/lib/hecks/hecks/adapters/deploy_toolchain/statuses.rb +2 -1
  149. data/lib/hecks/hecks/adapters/finding_github.rb +13 -6
  150. data/lib/hecks/hecks/adapters/first_admin.rb +2 -2
  151. data/lib/hecks/hecks/adapters/github_rulesets.rb +6 -3
  152. data/lib/hecks/hecks/adapters/in_process_boot.rb +1 -1
  153. data/lib/hecks/hecks/adapters/journal_store/compaction.rb +1 -1
  154. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +10 -20
  155. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +28 -5
  156. data/lib/hecks/hecks/adapters/local_files.rb +2 -2
  157. data/lib/hecks/hecks/adapters/rehearsal/audit_report.rb +107 -0
  158. data/lib/hecks/hecks/adapters/rehearsal/census.rb +71 -0
  159. data/lib/hecks/hecks/adapters/rehearsal/declaration.rb +133 -0
  160. data/lib/hecks/hecks/adapters/rehearsal/environment.rb +83 -0
  161. data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +142 -0
  162. data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +96 -0
  163. data/lib/hecks/hecks/adapters/rehearsal/postgres_census.rb +100 -0
  164. data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +69 -0
  165. data/lib/hecks/hecks/adapters/rehearsal/postgres_store.rb +133 -0
  166. data/lib/hecks/hecks/adapters/rehearsal/rows.rb +41 -0
  167. data/lib/hecks/hecks/adapters/rehearsal/rust_audit.rb +83 -0
  168. data/lib/hecks/hecks/adapters/rehearsal/subject.rb +104 -0
  169. data/lib/hecks/hecks/adapters/rehearsal.rb +54 -0
  170. data/lib/hecks/hecks/adapters/rehearsal_store.adapter +7 -0
  171. data/lib/hecks/hecks/adapters/rehearsal_store.rb +81 -0
  172. data/lib/hecks/hecks/adapters/terminal.rb +13 -11
  173. data/lib/hecks/hecks/codebase.behaviors +13 -1
  174. data/lib/hecks/hecks/codebase.bluebook +239 -5
  175. data/lib/hecks/hecks/custodian.behaviors +24 -6
  176. data/lib/hecks/hecks/custodian.bluebook +6 -1227
  177. data/lib/hecks/hecks/deploy.behaviors +1 -1
  178. data/lib/hecks/hecks/deploy.world +1 -3
  179. data/lib/hecks/hecks/hecks.behaviors +1 -1
  180. data/lib/hecks/hecks/hecks.hecksagon +53 -18
  181. data/lib/hecks/hecks/hecks.world +13 -10
  182. data/lib/hecks/hecks/rehearsal.bluebook +477 -0
  183. data/lib/hecks/hecks/site.behaviors +1 -1
  184. data/lib/hecks/hecks/site.world +0 -1
  185. data/lib/hecks/hecks/tooling.bluebook +1238 -0
  186. data/lib/hecks/indifferent_key.rb +20 -0
  187. data/lib/hecks/language/adapter.bluebook +13 -3
  188. data/lib/hecks/language/bluebook/aggregate.bluebook +23 -0
  189. data/lib/hecks/language/bluebook/bluebook.behaviors +23 -0
  190. data/lib/hecks/language/bluebook/bluebook.bluebook +15 -0
  191. data/lib/hecks/language/bluebook/entity.bluebook +18 -0
  192. data/lib/hecks/language/bluebook/policy.behaviors +19 -0
  193. data/lib/hecks/language/bluebook/policy.bluebook +9 -1
  194. data/lib/hecks/language/bluebook/query.bluebook +1 -1
  195. data/lib/hecks/language/bluebook/vocabulary.bluebook +63 -4
  196. data/lib/hecks/language/hecksagon/domain_port.bluebook +1 -1
  197. data/lib/hecks/language/hecksagon/hecksagon.bluebook +22 -0
  198. data/lib/hecks/language/oidc.json +10 -0
  199. data/lib/hecks/language/port.bluebook +4 -4
  200. data/lib/hecks/literal.rb +12 -3
  201. data/lib/hecks/ports/key_vault.rb +7 -2
  202. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +21 -10
  203. data/lib/hecks/ports/persistence/plugins/era/postgres_era/boot.rb +4 -2
  204. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +2 -1
  205. data/lib/hecks/ports/persistence/repository_factory.rb +6 -3
  206. data/lib/hecks/projection_files/expression_tables.rb +7 -2
  207. data/lib/hecks/projections/deploy/box/compose.rb +6 -4
  208. data/lib/hecks/projections/deploy/box/edge.rb +62 -0
  209. data/lib/hecks/projections/deploy/box/logging.rb +99 -0
  210. data/lib/hecks/projections/deploy/box/roll_scripts.rb +16 -8
  211. data/lib/hecks/projections/deploy/box/settings/cdn.rb +40 -0
  212. data/lib/hecks/projections/deploy/box/settings/logs.rb +40 -0
  213. data/lib/hecks/projections/deploy/box/settings/patterns.rb +11 -0
  214. data/lib/hecks/projections/deploy/box/settings/types.rb +16 -1
  215. data/lib/hecks/projections/deploy/box/settings.rb +6 -2
  216. data/lib/hecks/projections/deploy/box/stack_yaml.rb +5 -2
  217. data/lib/hecks/projections/deploy/box/templates/Makefile.tmpl +16 -0
  218. data/lib/hecks/projections/deploy/box/templates/box.yaml.tmpl +8 -4
  219. data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +32 -0
  220. data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +1 -1
  221. data/lib/hecks/projections/deploy/box/templates/edge.mk.tmpl +17 -0
  222. data/lib/hecks/projections/deploy/box/templates/edge.yaml.tmpl +65 -0
  223. data/lib/hecks/projections/deploy/box/templates/log-group.yaml.tmpl +12 -0
  224. data/lib/hecks/projections/deploy/box/templates/log-policy.yaml.tmpl +7 -0
  225. data/lib/hecks/projections/deploy/box/templates/render-compose-taskdef.sh.tmpl +5 -4
  226. data/lib/hecks/projections/deploy/box/templates/render-compose.sh.tmpl +5 -4
  227. data/lib/hecks/projections/deploy/box.rb +15 -3
  228. data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
  229. data/lib/hecks/projections/deploy/shared.rb +5 -2
  230. data/lib/hecks/projections/model/deviations.rb +2 -2
  231. data/lib/hecks/projections/model.rb +2 -2
  232. data/lib/hecks/projections/oidc.rb +13 -1
  233. data/lib/hecks/projections/shape.rb +5 -2
  234. data/lib/hecks/projections/site/cms_editor/attributes.rb +26 -6
  235. data/lib/hecks/projections/site/cms_editor/blocks.rb +157 -0
  236. data/lib/hecks/projections/site/cms_editor/checks.rb +14 -1
  237. data/lib/hecks/projections/site/cms_editor/clearing.rb +70 -0
  238. data/lib/hecks/projections/site/cms_editor/color.rb +124 -0
  239. data/lib/hecks/projections/site/cms_editor/composition.rb +42 -0
  240. data/lib/hecks/projections/site/cms_editor/destructive.rb +61 -0
  241. data/lib/hecks/projections/site/cms_editor/drafts.rb +102 -0
  242. data/lib/hecks/projections/site/cms_editor/hints.rb +74 -0
  243. data/lib/hecks/projections/site/cms_editor/icons.rb +86 -0
  244. data/lib/hecks/projections/site/cms_editor/key_kinds.rb +31 -0
  245. data/lib/hecks/projections/site/cms_editor/limits.rb +72 -0
  246. data/lib/hecks/projections/site/cms_editor/media.rb +1 -1
  247. data/lib/hecks/projections/site/cms_editor/moment.rb +34 -0
  248. data/lib/hecks/projections/site/cms_editor/palette.rb +115 -0
  249. data/lib/hecks/projections/site/cms_editor/pickers.rb +85 -0
  250. data/lib/hecks/projections/site/cms_editor/preview.rb +91 -0
  251. data/lib/hecks/projections/site/cms_editor/relations.rb +92 -0
  252. data/lib/hecks/projections/site/cms_editor/scale_checks.rb +66 -0
  253. data/lib/hecks/projections/site/cms_editor/scheduling.rb +150 -0
  254. data/lib/hecks/projections/site/cms_editor/schema.rb +96 -19
  255. data/lib/hecks/projections/site/cms_editor/setting.rb +52 -9
  256. data/lib/hecks/projections/site/cms_editor/targets.rb +86 -0
  257. data/lib/hecks/projections/site/cms_editor/templates/package.json.tmpl +18 -1
  258. data/lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl +251 -57
  259. data/lib/hecks/projections/site/cms_editor/templates/src/assets.ts.tmpl +98 -0
  260. data/lib/hecks/projections/site/cms_editor/templates/src/auth/membership.ts.tmpl +32 -24
  261. data/lib/hecks/projections/site/cms_editor/templates/src/browser/app.css.tmpl +412 -0
  262. data/lib/hecks/projections/site/cms_editor/templates/src/browser/autosave.js.tmpl +144 -0
  263. data/lib/hecks/projections/site/cms_editor/templates/src/browser/blocks.js.tmpl +500 -0
  264. data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_doc.js.tmpl +175 -0
  265. data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_editor.js.tmpl +418 -0
  266. data/lib/hecks/projections/site/cms_editor/templates/src/browser/epoch.js.tmpl +61 -0
  267. data/lib/hecks/projections/site/cms_editor/templates/src/browser/forms.js.tmpl +210 -0
  268. data/lib/hecks/projections/site/cms_editor/templates/src/browser/lists.js.tmpl +40 -0
  269. data/lib/hecks/projections/site/cms_editor/templates/src/browser/main.js.tmpl +26 -0
  270. data/lib/hecks/projections/site/cms_editor/templates/src/browser/media_picker.js.tmpl +232 -0
  271. data/lib/hecks/projections/site/cms_editor/templates/src/browser/moments.js.tmpl +73 -0
  272. data/lib/hecks/projections/site/cms_editor/templates/src/browser/pickers.js.tmpl +152 -0
  273. data/lib/hecks/projections/site/cms_editor/templates/src/browser/preview.js.tmpl +98 -0
  274. data/lib/hecks/projections/site/cms_editor/templates/src/browser/shell.js.tmpl +140 -0
  275. data/lib/hecks/projections/site/cms_editor/templates/src/browser/toast.js.tmpl +66 -0
  276. data/lib/hecks/projections/site/cms_editor/templates/src/choices.ts.tmpl +99 -0
  277. data/lib/hecks/projections/site/cms_editor/templates/src/commands.ts.tmpl +78 -24
  278. data/lib/hecks/projections/site/cms_editor/templates/src/config.ts.tmpl +6 -0
  279. data/lib/hecks/projections/site/cms_editor/templates/src/flash.ts.tmpl +52 -0
  280. data/lib/hecks/projections/site/cms_editor/templates/src/host.ts.tmpl +19 -2
  281. data/lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl +31 -8
  282. data/lib/hecks/projections/site/cms_editor/templates/src/names.ts.tmpl +36 -0
  283. data/lib/hecks/projections/site/cms_editor/templates/src/schema.ts.tmpl +131 -2
  284. data/lib/hecks/projections/site/cms_editor/templates/src/ui/availability.ts.tmpl +15 -0
  285. data/lib/hecks/projections/site/cms_editor/templates/src/ui/block_list.js.tmpl +213 -0
  286. data/lib/hecks/projections/site/cms_editor/templates/src/ui/blocks.ts.tmpl +275 -0
  287. data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_model.js.tmpl +8 -5
  288. data/lib/hecks/projections/site/cms_editor/templates/src/ui/detail.ts.tmpl +88 -0
  289. data/lib/hecks/projections/site/cms_editor/templates/src/ui/dialogs.ts.tmpl +43 -0
  290. data/lib/hecks/projections/site/cms_editor/templates/src/ui/fields.ts.tmpl +229 -34
  291. data/lib/hecks/projections/site/cms_editor/templates/src/ui/html.ts.tmpl +40 -81
  292. data/lib/hecks/projections/site/cms_editor/templates/src/ui/icons.ts.tmpl +15 -0
  293. data/lib/hecks/projections/site/cms_editor/templates/src/ui/input.ts.tmpl +29 -12
  294. data/lib/hecks/projections/site/cms_editor/templates/src/ui/links.ts.tmpl +100 -0
  295. data/lib/hecks/projections/site/cms_editor/templates/src/ui/moments.ts.tmpl +44 -0
  296. data/lib/hecks/projections/site/cms_editor/templates/src/ui/outline.ts.tmpl +53 -17
  297. data/lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl +178 -88
  298. data/lib/hecks/projections/site/cms_editor/templates/src/ui/paging.ts.tmpl +82 -0
  299. data/lib/hecks/projections/site/cms_editor/templates/src/ui/pickers.ts.tmpl +110 -0
  300. data/lib/hecks/projections/site/cms_editor/templates/src/ui/preview.ts.tmpl +87 -0
  301. data/lib/hecks/projections/site/cms_editor/templates/src/ui/related.ts.tmpl +97 -0
  302. data/lib/hecks/projections/site/cms_editor/templates/src/ui/schedule.ts.tmpl +160 -0
  303. data/lib/hecks/projections/site/cms_editor/templates/src/ui/shell.ts.tmpl +211 -0
  304. data/lib/hecks/projections/site/cms_editor/templates/src/ui/table.ts.tmpl +151 -0
  305. data/lib/hecks/projections/site/cms_editor/templates/src/ui/theme.js.tmpl +16 -0
  306. data/lib/hecks/projections/site/cms_editor/templates/src/ui/values.ts.tmpl +69 -0
  307. data/lib/hecks/projections/site/cms_editor/templates/src/ui/words.ts.tmpl +97 -0
  308. data/lib/hecks/projections/site/cms_editor/templates/src/ui/world.ts.tmpl +35 -0
  309. data/lib/hecks/projections/site/cms_editor/templates/tsconfig.json.tmpl +2 -1
  310. data/lib/hecks/projections/site/cms_editor/theme.rb +29 -0
  311. data/lib/hecks/projections/site/cms_editor/theme_checks.rb +57 -0
  312. data/lib/hecks/projections/site/cms_editor.rb +49 -23
  313. data/lib/hecks/projections/site/role_probe.rb +2 -0
  314. data/lib/hecks/projections/site/site_root/workflow.rb +5 -0
  315. data/lib/hecks/projector/cli_audience.rb +22 -1
  316. data/lib/hecks/projector/cli_projector/listing.rb +1 -1
  317. data/lib/hecks/projector/cli_projector/option_specs.rb +1 -1
  318. data/lib/hecks/projector/cli_projector/usage.rb +15 -4
  319. data/lib/hecks/projector/docs_projector/closing.rb +1 -1
  320. data/lib/hecks/projector/docs_projector.rb +1 -1
  321. data/lib/hecks/projector/exporter/bindings.rb +40 -10
  322. data/lib/hecks/projector/exporter/capability_values.rb +55 -0
  323. data/lib/hecks/projector/narrate_projector/reactions.rb +1 -1
  324. data/lib/hecks/projector/target.rb +11 -0
  325. data/lib/hecks/projector.rb +32 -5
  326. data/lib/hecks/quality_control/adapters/github_checks.rb +12 -8
  327. data/lib/hecks/quality_control/adapters/github_issues.rb +8 -4
  328. data/lib/hecks/quality_control/cli/qa_open_pr.rb +2 -2
  329. data/lib/hecks/quality_control/cli/qa_sweep/checks/shrinking.rb +1 -1
  330. data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +1 -1
  331. data/lib/hecks/quality_control/cli/qa_sweep.rb +1 -1
  332. data/lib/hecks/quality_control/quality_control.bluebook +6 -2
  333. data/lib/hecks/release/approval.rb +64 -0
  334. data/lib/hecks/router/{door.rb → aggregate_reader.rb} +5 -4
  335. data/lib/hecks/router/namespace_installer.rb +16 -16
  336. data/lib/hecks/router.rb +1 -1
  337. data/lib/hecks/runtime/best_effort.rb +22 -0
  338. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +12 -2
  339. data/lib/hecks/runtime/command_interpreter.rb +3 -2
  340. data/lib/hecks/runtime/command_rules/emission.rb +1 -1
  341. data/lib/hecks/runtime/dispatcher.rb +4 -4
  342. data/lib/hecks/runtime/entity_element/location.rb +1 -1
  343. data/lib/hecks/runtime/event.rb +5 -0
  344. data/lib/hecks/runtime/identity.rb +7 -6
  345. data/lib/hecks/runtime/interpreting.rb +2 -1
  346. data/lib/hecks/runtime/invocation_builder.rb +1 -1
  347. data/lib/hecks/runtime/loader/boot_steps.rb +8 -5
  348. data/lib/hecks/runtime/loader.rb +10 -10
  349. data/lib/hecks/runtime/policy_interpreter/arguments.rb +7 -4
  350. data/lib/hecks/runtime/policy_interpreter/fan_out.rb +3 -3
  351. data/lib/hecks/runtime/policy_interpreter.rb +6 -6
  352. data/lib/hecks/runtime/port_operation_interpreter.rb +1 -1
  353. data/lib/hecks/runtime/reaction_invocation.rb +1 -1
  354. data/lib/hecks/runtime/rebuild_sweep.rb +11 -1
  355. data/lib/hecks/runtime/registry/ask_verification.rb +35 -0
  356. data/lib/hecks/runtime/registry/hecksagon_rules.rb +10 -0
  357. data/lib/hecks/runtime/registry/merging.rb +1 -1
  358. data/lib/hecks/runtime/registry/providers.rb +16 -0
  359. data/lib/hecks/runtime/registry/read_repository.rb +6 -4
  360. data/lib/hecks/runtime/registry/verification.rb +4 -1
  361. data/lib/hecks/runtime/registry/world_defaults.rb +29 -0
  362. data/lib/hecks/runtime/registry.rb +1 -1
  363. data/lib/hecks/runtime/saga_interpreter/compensation.rb +1 -1
  364. data/lib/hecks/runtime/saga_interpreter/delivery.rb +4 -4
  365. data/lib/hecks/runtime/saga_interpreter/transitions.rb +1 -1
  366. data/lib/hecks/runtime/saga_interpreter.rb +3 -3
  367. data/lib/hecks/runtime/tenant_check.rb +5 -4
  368. data/lib/hecks/runtime/value/coercion.rb +2 -2
  369. data/lib/hecks/runtime/value/validation.rb +16 -4
  370. data/lib/hecks/runtime.rb +9 -9
  371. data/lib/hecks/rust_build/host.rb +11 -4
  372. data/lib/hecks/rust_build/prebuilt_binary.rb +101 -0
  373. data/lib/hecks/rust_build/project_rust/target_ir.rb +1 -1
  374. data/lib/hecks/rust_build/wasm.rb +1 -1
  375. data/lib/hecks/rust_build/wasm_browser.rb +1 -1
  376. data/lib/hecks/rust_build.rb +11 -0
  377. data/lib/hecks/served_options.rb +53 -0
  378. data/lib/hecks/site/bluebook/site.bluebook +1 -0
  379. data/lib/hecks/storehouse/audit.rb +1 -1
  380. data/lib/hecks/storehouse/dispatching.rb +8 -6
  381. data/lib/hecks/storehouse/introspection.rb +2 -2
  382. data/lib/hecks/storehouse/querying.rb +6 -4
  383. data/lib/hecks/storehouse.rb +4 -4
  384. data/lib/hecks/tools/ci_gate_decision.rb +35 -0
  385. data/lib/hecks/tools/ci_gates.rb +20 -1
  386. data/lib/hecks/tools/comment_style/source_file.rb +4 -1
  387. data/lib/hecks/tools/deploy_recipe_lint/fixtures.rb +4 -1
  388. data/lib/hecks/tools/lanes/files.rb +8 -0
  389. data/lib/hecks/tools/lanes/prebuilt_workflow.rb +81 -0
  390. data/lib/hecks/tools/lanes/rows.rb +6 -0
  391. data/lib/hecks/tools/lanes.rb +1 -0
  392. data/lib/hecks/tools/oidc_manifests.rb +4 -5
  393. data/lib/hecks/tools/regeneration_run.rb +11 -4
  394. data/lib/hecks/tools/release_only.rb +111 -0
  395. data/lib/hecks/tools/site_routes/editor_files.rb +12 -5
  396. data/lib/hecks/tools/tenant_provisioning.rb +2 -2
  397. data/lib/hecks/tools/tools_doc.rb +4 -4
  398. data/lib/hecks/version.rb +1 -1
  399. data/lib/hecks/vocabulary.rb +19 -5
  400. data/lib/hecks.rb +15 -15
  401. data/lib/rubocop/cop/hecks/env_dump.rb +69 -0
  402. data/lib/rubocop/cop/hecks/monotonic_duration.rb +53 -0
  403. data/lib/rubocop/cop/hecks/no_wall_clock_in_runtime.rb +34 -0
  404. data/lib/rubocop/cop/hecks/raw_shell_interpolation.rb +79 -0
  405. data/lib/rubocop/cop/hecks/sleep_in_spec.rb +34 -0
  406. data/lib/rubocop/cop/hecks/swallowed_rescue.rb +37 -0
  407. data/lib/rubocop/cop/hecks/symbol_string_key_mix.rb +50 -0
  408. data/lib/rubocop/cop/hecks/untyped_raise.rb +37 -0
  409. data/prebuilt/9ee54e2f0d4d6d3fe046827779b221e02de665fba911a048ae5dd8b8fbfb7d90.marshal +0 -0
  410. data/prebuilt/d74a00e996222c1d8b676d5959092effc46b4dc59e0555f3bf9554ac58e3094a.marshal +0 -0
  411. data/prebuilt/verdicts-df19f35868d3284a70f55e42dcef87ef4e65e6a678e5135f72e1f6cff4c1357b.json +1 -0
  412. data/rust/.gitignore +6 -0
  413. data/rust/Cargo.toml +6 -0
  414. data/rust/build/src/binding_pass.rs +103 -0
  415. data/rust/build/src/cargo_sync.rs +6 -0
  416. data/rust/build/src/lineage_pass.rs +3 -3
  417. data/rust/build/src/main.rs +17 -5
  418. data/rust/build/src/pipeline.rs +48 -5
  419. data/rust/build/src/seams_pass.rs +123 -0
  420. data/rust/build/src/translation_pass.rs +167 -0
  421. data/rust/codegen/src/asks.rs +103 -0
  422. data/rust/codegen/src/commands.rs +13 -8
  423. data/rust/codegen/src/constraints.rs +25 -0
  424. data/rust/codegen/src/domain_generator.rs +2 -0
  425. data/rust/codegen/src/expr_emitter.rs +13 -0
  426. data/rust/codegen/src/json_codec.rs +54 -15
  427. data/rust/codegen/src/main.rs +1 -0
  428. data/rust/codegen/src/mutations.rs +128 -3
  429. data/rust/codegen/src/queries.rs +11 -2
  430. data/rust/codegen/src/reactions.rs +1 -1
  431. data/rust/codegen/src/types.rs +166 -8
  432. data/rust/host/HECKS_RELEASE +1 -1
  433. data/rust/host/src/api.rs +4 -4
  434. data/rust/host/src/bin/validate_harness.rs +43 -0
  435. data/rust/host/src/boundary_fuzz/expr_json.rs +2 -2
  436. data/rust/host/src/boundary_fuzz/ir.rs +1 -0
  437. data/rust/host/src/boundary_fuzz/server.rs +1 -1
  438. data/rust/host/src/checkout.rs +35 -19
  439. data/rust/host/src/commerce_ir.rs +408 -2
  440. data/rust/host/src/expr_json.rs +118 -0
  441. data/rust/host/src/extension.rs +13 -1
  442. data/rust/host/src/lib.rs +1 -0
  443. data/rust/host/src/mint.rs +1 -1
  444. data/rust/host/src/payments/tests.rs +27 -1
  445. data/rust/host/src/payments.rs +12 -4
  446. data/rust/host/src/platform_signin/attack_tests.rs +1100 -0
  447. data/rust/host/src/platform_signin/config.rs +512 -0
  448. data/rust/host/src/platform_signin/cookie.rs +237 -0
  449. data/rust/host/src/platform_signin/extension.rs +190 -0
  450. data/rust/host/src/platform_signin/fetcher.rs +322 -0
  451. data/rust/host/src/platform_signin/handler.rs +251 -0
  452. data/rust/host/src/platform_signin/handler_tests.rs +554 -0
  453. data/rust/host/src/platform_signin/jti.rs +196 -0
  454. data/rust/host/src/platform_signin/jwks.rs +542 -0
  455. data/rust/host/src/platform_signin/jws.rs +249 -0
  456. data/rust/host/src/platform_signin/known_answer_tests.rs +237 -0
  457. data/rust/host/src/platform_signin/mapping_tests.rs +254 -0
  458. data/rust/host/src/platform_signin/mod.rs +75 -0
  459. data/rust/host/src/platform_signin/mode_tests.rs +382 -0
  460. data/rust/host/src/platform_signin/pages.rs +204 -0
  461. data/rust/host/src/platform_signin/query.rs +233 -0
  462. data/rust/host/src/platform_signin/session.rs +151 -0
  463. data/rust/host/src/platform_signin/settings.rs +385 -0
  464. data/rust/host/src/platform_signin/strict_json.rs +351 -0
  465. data/rust/host/src/platform_signin/test_support.rs +235 -0
  466. data/rust/host/src/platform_signin/ttl_tests.rs +94 -0
  467. data/rust/host/src/platform_signin/verify.rs +604 -0
  468. data/rust/host/src/platform_signin/wiring_support.rs +319 -0
  469. data/rust/host/src/query_step.rs +22 -4
  470. data/rust/host/src/reference_validate.rs +653 -108
  471. data/rust/host/src/resend.rs +2 -0
  472. data/rust/host/src/server.rs +19 -6
  473. data/rust/host/src/ui_schema.rs +132 -5
  474. data/rust/host/src/web/newsletter.rs +7 -8
  475. data/rust/host/src/web/newsletter_send.rs +38 -13
  476. data/rust/host/src/web/registrations.rs +229 -26
  477. data/rust/host/src/web.rs +53 -9
  478. data/rust/parser/src/emit.rs +38 -6
  479. data/rust/parser/src/expr/ast_json.rs +7 -1
  480. data/rust/parser/src/expr/resolver.rs +171 -6
  481. data/rust/parser/src/ir.rs +7 -0
  482. data/rust/parser/src/keywords.rs +24 -0
  483. data/rust/parser/src/main.rs +3 -0
  484. data/rust/parser/src/parse/aggregate.rs +2 -1
  485. data/rust/parser/src/parse/chapter.rs +2 -2
  486. data/rust/parser/src/parse/command.rs +2 -0
  487. data/rust/parser/src/parse/hecksagon.rs +5 -2
  488. data/rust/parser/src/parse/lifecycle.rs +81 -0
  489. data/rust/parser/src/parse/mod.rs +15 -1
  490. data/rust/parser/src/parse/policy.rs +13 -2
  491. data/rust/parser/src/parse/value_object.rs +34 -17
  492. data/rust/parser/src/ruby_value.rs +1 -1
  493. data/rust/src/exemplar/commands.rs +4 -4
  494. data/rust/src/exemplar/constraints.rs +1 -1
  495. data/rust/src/exemplar/json.rs +43 -1
  496. data/rust/src/kernel/cli.rs +7 -5
  497. data/rust/src/kernel/dispatch.rs +2 -2
  498. data/rust/src/kernel/dispatch_guard_tests.rs +1 -1
  499. data/rust/src/kernel/expr.rs +66 -3
  500. data/rust/src/kernel/expression_operators/arithmetic.rs +130 -5
  501. data/rust/src/kernel/expression_operators/text.rs +26 -2
  502. data/rust/src/kernel/json.rs +15 -0
  503. data/rust/src/kernel/mod.rs +1 -1
  504. data/rust/src/kernel/orchestrate.rs +54 -5
  505. data/rust/src/kernel/orchestrate_guard_tests.rs +67 -0
  506. data/rust/src/kernel/pattern.rs +60 -0
  507. data/rust/src/kernel/reference_lookup.rs +90 -7
  508. metadata +178 -38
  509. data/lib/hecks/doors/cli_door/nesting.rb +0 -34
  510. data/lib/hecks/doors/cli_door/shorthand.rb +0 -85
  511. data/lib/hecks/doors/cli_door.rb +0 -124
  512. data/lib/hecks/doors/cli_runner/answers.rb +0 -138
  513. data/lib/hecks/doors/cli_runner/resolution.rb +0 -146
  514. data/lib/hecks/doors/cli_runner/settling.rb +0 -115
  515. data/lib/hecks/doors/cli_runner/streaming.rb +0 -90
  516. data/lib/hecks/doors/cli_runner/suggestions.rb +0 -43
  517. data/lib/hecks/doors/cli_runner.rb +0 -66
  518. data/lib/hecks/doors/command_request.rb +0 -119
  519. data/lib/hecks/doors/handle.rb +0 -208
  520. data/lib/hecks/doors/json_door.rb +0 -132
  521. data/lib/hecks/doors/launcher_options.rb +0 -247
  522. data/lib/hecks/doors/mcp_door/properties.rb +0 -47
  523. data/lib/hecks/doors/mcp_door/tool_calls.rb +0 -113
  524. data/lib/hecks/doors/mcp_door/tool_definitions/auditing.rb +0 -51
  525. data/lib/hecks/doors/mcp_door/tool_definitions/calling.rb +0 -69
  526. data/lib/hecks/doors/mcp_door/tool_definitions/reading.rb +0 -97
  527. data/lib/hecks/doors/mcp_door/tool_definitions.rb +0 -15
  528. data/lib/hecks/doors/mcp_door.rb +0 -156
  529. data/lib/hecks/doors/mcp_door_scope/argument_policy.rb +0 -92
  530. data/lib/hecks/doors/mcp_door_scope/env_problems.rb +0 -55
  531. data/lib/hecks/doors/mcp_door_scope/presenter.rb +0 -78
  532. data/lib/hecks/doors/mcp_door_scope.rb +0 -201
  533. data/lib/hecks/doors/mcp_guide_cache.rb +0 -75
  534. data/lib/hecks/doors/ruby_door/aggregate_door.rb +0 -162
  535. data/lib/hecks/doors/ruby_door/chapter.rb +0 -89
  536. data/lib/hecks/doors/ruby_door.rb +0 -80
  537. data/lib/hecks/doors/usage_cache.rb +0 -139
  538. data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_widget.js.tmpl +0 -282
  539. data/lib/hecks/projections/site/cms_editor/templates/src/ui/media_picker.js.tmpl +0 -109
  540. data/prebuilt/c28d6d9db14eea3e17161e9d9c262efee30b256cf97693a7cfd552bce24b2f7f.marshal +0 -0
  541. data/prebuilt/cb375cba61ca0dbe8ddb9739c306510fe05e5f4b7a9b6955caff8224c63ea0e0.marshal +0 -0
  542. data/prebuilt/verdicts-d6d584ad43b5f3cebf88aafbbdbf024c38574acf18e06adffbc555f7786b1c2f.json +0 -1
@@ -20,11 +20,11 @@ module Hecks
20
20
 
21
21
  # @param registry [Runtime::Registry] the booted registry whose loaded
22
22
  # bluebooks are scanned for candidate policies
23
- # @param door [Runtime::Dispatcher] the dispatcher reactions re-enter through,
23
+ # @param dispatcher [Runtime::Dispatcher] the dispatcher reactions re-enter through,
24
24
  # and whose reaction-depth guard is checked before each delivery
25
- def initialize(registry, door:)
25
+ def initialize(registry, dispatcher:)
26
26
  @registry = registry
27
- @door = door
27
+ @dispatcher = dispatcher
28
28
  end
29
29
 
30
30
  # Fires every declared policy `event` triggers, recording each outcome on
@@ -96,15 +96,15 @@ module Hecks
96
96
  # may go.
97
97
  def fire(policy, event, target, record)
98
98
  return nil unless where_holds?(policy, event)
99
- return depth_refusal(record) if @door.reaction_depth_reached?
99
+ return depth_refusal(record) if @dispatcher.reaction_depth_reached?
100
100
 
101
101
  args = trigger_args(policy, event)
102
- @door.reenter(target, **reaction_invocation(target, args, policy, event))
102
+ @dispatcher.reenter(target, **reaction_invocation(target, args, policy, event))
103
103
  record.merge(delivered: true)
104
104
  end
105
105
 
106
106
  def depth_refusal(record)
107
- record.merge(delivered: false, reason: "reaction depth #{@door.max_reaction_depth} reached")
107
+ record.merge(delivered: false, reason: "reaction depth #{@dispatcher.max_reaction_depth} reached")
108
108
  end
109
109
 
110
110
  # A defect, not a refusal: recorded with `defect: true` and warned, never
@@ -157,7 +157,7 @@ module Hecks
157
157
  aggregate: "#{ctx.domain}::#{ctx.aggregate.hecks_name}",
158
158
  id: ctx.route.aggregate,
159
159
  payload: payload,
160
- occurred_at: Time.now.utc.iso8601
160
+ occurred_at: Event.stamp
161
161
  )
162
162
  end
163
163
  end
@@ -90,7 +90,7 @@ module Hecks
90
90
  # @raise [Runtime::UnknownVerb] if `verb` does not resolve (only when `explicit`)
91
91
  # @raise [Runtime::TypeMismatch] if no receiver identity resolves for an explicit target
92
92
  # @raise [Runtime::UnknownArgument] if an explicit projection has an undeclared fact
93
- # rubocop:disable-next Metrics/ParameterLists -- the keyword door both interpreters call
93
+ # rubocop:disable-next Metrics/ParameterLists -- the keyword entry point both interpreters call
94
94
  def build(registry:, verb:, projected:, explicit:, passthrough: [], source_receiver: nil)
95
95
  args = projected.transform_keys(&:to_sym)
96
96
  return forwarded(registry, verb, args, source_receiver) unless explicit
@@ -49,7 +49,17 @@ module Hecks
49
49
  return nil if id.nil?
50
50
 
51
51
  remote = registry.repository(domain, target).find(id.to_s)
52
- remote&.[](field.remote_field)
52
+ unwrap_single_field(target, field, remote&.[](field.remote_field))
53
+ end
54
+
55
+ # A remote field typed by a single-field value object is copied as its one scalar, so the
56
+ # projecting aggregate holds `123`, never `{ value: 123 }`. Any other value is copied as is.
57
+ def unwrap_single_field(target, field, value)
58
+ attribute = target.attribute(field.remote_field)
59
+ sole = attribute && target.value_object(attribute.type)&.sole_attribute
60
+ return value unless sole && !value.nil?
61
+
62
+ value.is_a?(Hash) ? value.fetch(sole.name) { value[sole.name.to_s] } : value[sole.name]
53
63
  end
54
64
  end
55
65
  end
@@ -0,0 +1,35 @@
1
+ require_relative "../../bluebook/ask_resolution"
2
+
3
+ module Hecks
4
+ module Runtime
5
+ class Registry
6
+ # The boot gate for `ask`: every policy's ask must resolve to one declared port operation,
7
+ # so a name the hecksagon never declared stops the boot instead of firing at nothing.
8
+ # Mixed into {Verification}.
9
+ module AskVerification
10
+ private
11
+
12
+ # A port operation a chapter provides, and an ask a policy makes, each name a port
13
+ # operation the hecksagon declared.
14
+ def refuse_unresolved_ports!
15
+ refuse_unresolved_port_operations!
16
+ refuse_unresolved_asks!
17
+ end
18
+
19
+ # Binds each ask to the operation it resolves to, refusing the first that resolves to none.
20
+ #
21
+ # @raise [WiringError] naming the policy, the ask and what the hecksagon would need
22
+ def refuse_unresolved_asks!
23
+ @declared.bluebooks.each_value do |chapter|
24
+ chapter.policies.select(&:asks?).each do |policy|
25
+ outcome = Bluebook::AskResolution.call(chapter, policy)
26
+ raise WiringError, outcome.detail unless outcome.resolved?
27
+
28
+ policy.resolve_ask!(outcome.verb)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -27,6 +27,16 @@ module Hecks
27
27
  "without that it is silent decoration, the exact defect this refusal exists to catch"
28
28
  end
29
29
 
30
+ # `driven_by` names a driving adapter; a name none answers to would silently admit nothing.
31
+ def refuse_unknown_driving!(hecksagon)
32
+ unknown = hecksagon.driving - Bluebook::Hecksagon::DRIVING_ADAPTERS
33
+ return if unknown.empty?
34
+
35
+ raise WiringError,
36
+ "#{hecksagon.domain} is driven_by #{unknown.map(&:inspect).join(", ")}, which no driving " \
37
+ "adapter answers to — the adapters are #{Bluebook::Hecksagon::DRIVING_ADAPTERS.join(", ")}"
38
+ end
39
+
30
40
  # `attaches` loads a bounded context; the consumer must declare the sibling hecksagon
31
41
  # that is its ACL (Governance/Identity/Privacy already do). A vendored package only
32
42
  # loads its `.bluebook` files, so persistence, Governance and the `translates` ACL live
@@ -17,7 +17,7 @@ module Hecks
17
17
  def merge_hecksagons(base, overlay)
18
18
  # Order-independent: list facts uniq, so loading context_map before or after the
19
19
  # domain file yields the same merged hecksagon.
20
- lists = %i[subscriptions attachments translates].to_h do |facet|
20
+ lists = %i[subscriptions attachments translates driving].to_h do |facet|
21
21
  [facet, (base.public_send(facet) + overlay.public_send(facet)).uniq]
22
22
  end
23
23
  Bluebook::Hecksagon.new(domain: base.domain, binds: base.binds + overlay.binds,
@@ -101,6 +101,16 @@ module Hecks
101
101
  vendored_provider_for(domain, Bluebook::Capabilities::PAYMENT_CONNECTION)
102
102
  end
103
103
 
104
+ # The chapter that owns the checkout boundary for `domain` — resolved by what it
105
+ # declares (`provides "checkout"`). Nil when none does.
106
+ #
107
+ # @param domain [String, Symbol] the domain whose checkout chapter is being resolved
108
+ # @return [Bluebook::Chapter, nil] the chapter that owns `domain`'s checkout windows,
109
+ # or nil if none does
110
+ def checkout_provider_for(domain)
111
+ vendored_provider_for(domain, Bluebook::Capabilities::CHECKOUT)
112
+ end
113
+
104
114
  # The chapter that takes payments for `domain`: the domain's own chapter, a
105
115
  # framework member, or a vendored embryonaut bluebook it attaches, that
106
116
  # declares `provides "payments"`.
@@ -112,6 +122,12 @@ module Hecks
112
122
  vendored_provider_for(domain, Bluebook::Capabilities::PAYMENTS)
113
123
  end
114
124
 
125
+ # The first loaded chapter that declares `capability`, whichever domain asks.
126
+ #
127
+ # @param capability [String] a `Bluebook::Capabilities` name
128
+ # @return [Bluebook::Chapter, nil] the providing chapter, or nil if none loaded does
129
+ def provider_of(capability) = bluebooks.values.find { |chapter| chapter.provides?(capability) }
130
+
115
131
  # The chapter that provides `capability` for `domain`: the domain's own chapter,
116
132
  # a framework member its hecksagon attaches, or a vendored embryonaut bluebook
117
133
  # it attaches, that declares it.
@@ -1,3 +1,5 @@
1
+ require_relative "../best_effort"
2
+
1
3
  module Hecks
2
4
  module Runtime
3
5
  class Registry
@@ -37,10 +39,10 @@ module Hecks
37
39
  # `authoritative`, in the same order; false on any mismatch, or if comparing
38
40
  # them raises
39
41
  def projection_current?(projection, authoritative)
40
- entries_match?(projection.entries, authoritative.entries) &&
41
- sorted_rows(projection) == sorted_rows(authoritative)
42
- rescue StandardError
43
- false
42
+ BestEffort.call(false) do
43
+ entries_match?(projection.entries, authoritative.entries) &&
44
+ sorted_rows(projection) == sorted_rows(authoritative)
45
+ end
44
46
  end
45
47
 
46
48
  private
@@ -1,5 +1,6 @@
1
1
  require_relative "../../bluebook/hecksagon"
2
2
  require_relative "hecksagon_rules"
3
+ require_relative "ask_verification"
3
4
  require_relative "query_verification"
4
5
  require_relative "chapter_verification"
5
6
  require_relative "durability_warnings"
@@ -11,6 +12,7 @@ module Hecks
11
12
  # port's verb, and every world default is usable. `verify!` runs it all at boot.
12
13
  module Verification
13
14
  include HecksagonRules
15
+ include AskVerification
14
16
  include QueryVerification
15
17
  include ChapterVerification
16
18
  include DurabilityWarnings
@@ -24,7 +26,7 @@ module Hecks
24
26
  refuse_cross_package_bluebook_merge!
25
27
  refuse_reserved_chapter_names!
26
28
  refuse_membership_without_identity!
27
- refuse_unresolved_port_operations!
29
+ refuse_unresolved_ports!
28
30
  refuse_unanswerable_queries!
29
31
 
30
32
  @declared.hecksagons.each_value { |hecksagon| verify_hecksagon!(hecksagon) }
@@ -126,6 +128,7 @@ module Hecks
126
128
  # warnings for its chapter.
127
129
  def verify_hecksagon!(hecksagon)
128
130
  refuse_ungoverned_roles!(hecksagon)
131
+ refuse_unknown_driving!(hecksagon)
129
132
  refuse_unwired_attachments!(hecksagon)
130
133
  refuse_bounded_without_acl!(hecksagon)
131
134
  hecksagon.binds.each { |bind| verify_bind!(hecksagon, bind) }
@@ -28,8 +28,37 @@ module Hecks
28
28
  self
29
29
  end
30
30
 
31
+ # The defaults an adapter's `.adapter` declares for its fields, with each `{name}` or
32
+ # `{storage_name}` in a string filled from `aggregate`. A world's own setting always wins.
33
+ #
34
+ # @param adapter [String, Symbol] the adapter's name
35
+ # @param aggregate [Bluebook::Aggregate] the aggregate the adapter is built for
36
+ # @return [Hash{Symbol => Object}] the defaults, empty when the adapter declares none
37
+ def adapter_defaults(adapter, aggregate)
38
+ declared = @declared.adapters[adapter.to_s]&.declared_defaults || {}
39
+ declared.transform_values { |value| fill_placeholders(value, aggregate) }
40
+ end
41
+
42
+ # `settings` laid over the adapter's declared defaults. A field a world gives as `:default`
43
+ # asks for the declared default, so it is left out and the default shows through.
44
+ #
45
+ # @param adapter [String, Symbol] the adapter's name
46
+ # @param aggregate [Bluebook::Aggregate] the aggregate the adapter is built for
47
+ # @param settings [Hash{Symbol => Object}] the settings the world gave
48
+ # @return [Hash{Symbol => Object}] the defaults, overridden by the settings given
49
+ def with_adapter_defaults(adapter, aggregate, settings)
50
+ adapter_defaults(adapter, aggregate).merge(settings.reject { |_, value| value == :default })
51
+ end
52
+
31
53
  private
32
54
 
55
+ # A string default with its placeholders filled from the aggregate; any other value as is.
56
+ def fill_placeholders(value, aggregate)
57
+ return value unless value.is_a?(String)
58
+
59
+ value.gsub(/\{(name|storage_name)\}/) { aggregate.public_send(Regexp.last_match(1)) }
60
+ end
61
+
33
62
  # The chapter's own world answers first; the project's world fills the gap.
34
63
  def world_default(domain, field)
35
64
  world(domain)&.public_send(field) || project_world&.public_send(field)
@@ -45,7 +45,7 @@ module Hecks
45
45
  # against; nil for a registry with no such root
46
46
  def initialize(root: nil)
47
47
  @root = root
48
- # Recorded at hecksagon-build time (AggregateDoor#mark_sensitive), Loader.boot's
48
+ # Recorded at hecksagon-build time (AggregateModule#mark_sensitive), Loader.boot's
49
49
  # post-dispatch step turns each pending privacy marking into a real Privacy::Marking.Mark,
50
50
  # idempotently. `resolved_eras` and `superseded_eras` are eager, not lazy, so no two
51
51
  # dispatching threads race to create them; all writes still happen at boot,
@@ -7,7 +7,7 @@ module Hecks
7
7
  module Compensation
8
8
  private
9
9
 
10
- # Recorded before dispatching, not after `@door.reenter` returns —
10
+ # Recorded before dispatching, not after `@dispatcher.reenter` returns —
11
11
  # reenter can recursively re-enter this interpreter and refuse
12
12
  # before ever returning here, and recording only on success would
13
13
  # be too late for that nested refusal to see this leg's own
@@ -24,7 +24,7 @@ module Hecks
24
24
  record = { process_manager: process_manager.name, instance: correlation, dispatch: spec.command_name }
25
25
 
26
26
  log_dispatch_inputs(leg, spec, args) unless spec.with_spec.to_a.empty?
27
- return refuse_at_depth_ceiling(leg, record) if @door.reaction_depth_reached?
27
+ return refuse_at_depth_ceiling(leg, record) if @dispatcher.reaction_depth_reached?
28
28
 
29
29
  attempt_dispatch(leg, spec, args, record)
30
30
  end
@@ -46,7 +46,7 @@ module Hecks
46
46
  # it unwinds like a refusal rather than stranding the instance.
47
47
  def refuse_at_depth_ceiling(leg, record)
48
48
  @registry.saga_log << record.merge(delivered: false,
49
- reason: "reaction depth #{@door.max_reaction_depth} reached")
49
+ reason: "reaction depth #{@dispatcher.max_reaction_depth} reached")
50
50
  unwind(leg)
51
51
  end
52
52
 
@@ -95,14 +95,14 @@ module Hecks
95
95
  nil
96
96
  end
97
97
 
98
- # Dispatches `command_name` through the door, stamped with this saga's correlation.
98
+ # Dispatches `command_name` through the dispatcher, stamped with this saga's correlation.
99
99
  def reenter_command(leg, command_name, projected, explicit:, source_receiver:)
100
100
  head = leg.process_manager.correlation_head
101
101
  verb = qualified(command_name, leg.domain)
102
102
  invocation = ReactionInvocation.build(registry: @registry, verb: verb, projected: projected,
103
103
  explicit: explicit, passthrough: [head],
104
104
  source_receiver: source_receiver)
105
- @door.reenter(verb, saga_correlation: { head.to_s => leg.correlation }, **invocation)
105
+ @dispatcher.reenter(verb, saga_correlation: { head.to_s => leg.correlation }, **invocation)
106
106
  end
107
107
 
108
108
  # Unlike a refusal, a crash isn't a domain decision, so it
@@ -21,7 +21,7 @@ module Hecks
21
21
 
22
22
  # The mutex covers only the check-mutate-checkpoint step, never the
23
23
  # dispatch cascade that follows — `deliver_saga_dispatch`'s
24
- # `@door.reenter` can recursively re-enter this interpreter on the
24
+ # `@dispatcher.reenter` can recursively re-enter this interpreter on the
25
25
  # same thread, and `Mutex` is not reentrant.
26
26
  def remembered_leg_taken?(leg)
27
27
  leg.instance = @registry.saga_instances[leg.process_manager.name][leg.correlation]
@@ -55,11 +55,11 @@ module Hecks
55
55
 
56
56
  # @param registry [Runtime::Registry] the booted registry whose declared
57
57
  # process managers and saga persistence this interpreter runs against
58
- # @param door [Runtime::Dispatcher] the dispatcher a saga leg's own dispatch
58
+ # @param dispatcher [Runtime::Dispatcher] the dispatcher a saga leg's own dispatch
59
59
  # re-enters through
60
- def initialize(registry, door:)
60
+ def initialize(registry, dispatcher:)
61
61
  @registry = registry
62
- @door = door
62
+ @dispatcher = dispatcher
63
63
  end
64
64
 
65
65
  # Runs `domain`'s declared process managers against `event`: begins,
@@ -1,4 +1,5 @@
1
1
  require_relative "../ports/persistence/binding_policy"
2
+ require_relative "best_effort"
2
3
 
3
4
  module Hecks
4
5
  module Runtime
@@ -37,10 +38,10 @@ module Hecks
37
38
  # Same defensive shape as EraCheck#lineage_capable? — a class that
38
39
  # doesn't respond at all, or whose lookup raises, is false, not an error.
39
40
  def tenant_capable?(registry, adapter_name)
40
- adapter_class = registry.adapters[adapter_name] && registry.adapter_class(adapter_name)
41
- adapter_class.respond_to?(:tenant_capable?) && adapter_class.tenant_capable?
42
- rescue StandardError
43
- false
41
+ BestEffort.call(false) do
42
+ adapter_class = registry.adapters[adapter_name] && registry.adapter_class(adapter_name)
43
+ adapter_class.respond_to?(:tenant_capable?) && adapter_class.tenant_capable?
44
+ end
44
45
  end
45
46
  end
46
47
  end
@@ -37,9 +37,9 @@ module Hecks
37
37
  # Coerces `value` for a single, already-resolved `attribute`, branching on
38
38
  # its declared shape (list, reference, composite, or bare scalar).
39
39
  #
40
- # `boundary: false` is the query door, where a declared type documents the
40
+ # `boundary: false` is the query entry point, where a declared type documents the
41
41
  # argument for callers/generators rather than naming a shape to enforce.
42
- # `argument: true` is the command/entity/port dispatch door, where a nil for
42
+ # `argument: true` is the command/entity/port dispatch entry point, where a nil for
43
43
  # a required attribute is a left-empty argument (C3.7), not ordinary state nil.
44
44
  #
45
45
  # @raise [Runtime::TypeMismatch] if `value` cannot be coerced, or a required
@@ -34,7 +34,11 @@ module Hecks
34
34
  fields
35
35
  end
36
36
 
37
- # Fills every declared attribute `fields` lacks with its own `default:`.
37
+ # Fills every declared attribute `fields` lacks with its own `default:`, and every required
38
+ # list it lacks with an empty one: a list left out reads as no members, the one shape the
39
+ # Rust runtime (a `Vec`) can hold, so a value object built from nothing (a required
40
+ # argument left empty, C3.7) is `{blocks: []}` on both sides rather than `{}` here.
41
+ # An optional list stays absent, and an offered list, empty or not, is kept as offered.
38
42
  #
39
43
  # @param value_object [Class] the `Bluebook::ValueObject` subclass whose
40
44
  # declared defaults are read
@@ -42,11 +46,11 @@ module Hecks
42
46
  # @return [Hash{Symbol => Object}] `fields`, with defaults filled in
43
47
  def apply_defaults(value_object, fields)
44
48
  value_object.attributes.each_with_object(fields) do |attribute, completed|
45
- completed[attribute.name] = attribute.default unless completed.key?(attribute.name) || attribute.default.nil?
49
+ fill_absent(completed, attribute) unless completed.key?(attribute.name)
46
50
  end
47
51
  end
48
52
 
49
- # The full door a value object's own fields pass through — shared by
53
+ # The full entry point a value object's own fields pass through — shared by
50
54
  # `build` and `normalize_composite_fields`, so a nested field refuses
51
55
  # exactly like the same type declared directly on a command.
52
56
  #
@@ -85,6 +89,13 @@ module Hecks
85
89
 
86
90
  private
87
91
 
92
+ # The default an absent attribute declares, else an empty list for a required list.
93
+ def fill_absent(fields, attribute)
94
+ return fields[attribute.name] = attribute.default unless attribute.default.nil?
95
+
96
+ fields[attribute.name] = [] if attribute.list? && !attribute.optional?
97
+ end
98
+
88
99
  def normalize_composite_field(aggregate, attribute, fields)
89
100
  # A list member hydrates the same as a top-level list, so a value
90
101
  # read back from the store matches the shape a live dispatch wrote.
@@ -109,7 +120,8 @@ module Hecks
109
120
  validate_input_list(aggregate, attribute, fields)
110
121
  end
111
122
 
112
- # Runs each value-object member of an input list through the same door a nested single
123
+ # Runs each value-object member of an input list through the same entry point a nested
124
+ # single
113
125
  # value goes through, so a member's own invariants and nested lists refuse on dispatch
114
126
  # exactly as they do when the list sits directly on a command. The members stay as offered.
115
127
  def validate_input_list(aggregate, attribute, fields)
data/lib/hecks/runtime.rb CHANGED
@@ -42,12 +42,12 @@ module Hecks
42
42
  #
43
43
  # @param path [String] path to a domain directory, or a file inside one
44
44
  # @param shared [String, nil] a shared-root override
45
- # @param install_doors [Boolean] whether to install the Ruby facade constants
45
+ # @param install_driving [Boolean] whether to install the Ruby facade constants
46
46
  # @param environment [String, nil] the environment name for `Adapters::Folder#load_domain`
47
47
  # @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the dispatcher bound
48
48
  # to the booted domain
49
- def boot(path, shared: nil, install_doors: true, environment: Runtime::Loader::FROM_ENV)
50
- Loader.boot(path, shared: shared, install_doors: install_doors, environment: environment)
49
+ def boot(path, shared: nil, install_driving: true, environment: Runtime::Loader::FROM_ENV)
50
+ Loader.boot(path, shared: shared, install_driving: install_driving, environment: environment)
51
51
  end
52
52
 
53
53
  # Loads a domain's declarations without binding any adapter. See Loader.describe.
@@ -63,23 +63,23 @@ module Hecks
63
63
  # Finishes a boot from declarations `describe` already loaded. See Loader.boot_described.
64
64
  #
65
65
  # @param described [Runtime::Loader::Described] what `describe` answered
66
- # @param install_doors [Boolean] whether to install the Ruby facade constants
66
+ # @param install_driving [Boolean] whether to install the Ruby facade constants
67
67
  # @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the dispatcher bound
68
68
  # to the booted domain
69
- def boot_described(described, install_doors: true)
70
- Loader.boot_described(described, install_doors: install_doors)
69
+ def boot_described(described, install_driving: true)
70
+ Loader.boot_described(described, install_driving: install_driving)
71
71
  end
72
72
 
73
73
  # Loads only the given files of a domain; otherwise like `boot`. See Loader.boot_files.
74
74
  #
75
75
  # @param paths [String, Array<String>] one or more file paths within the domain
76
76
  # @param shared [String, nil] a shared-root override
77
- # @param install_doors [Boolean] whether to install the Ruby facade constants
77
+ # @param install_driving [Boolean] whether to install the Ruby facade constants
78
78
  # @param environment [String, nil] the environment name for the selected-file loader
79
79
  # @return [Runtime::Dispatcher, Runtime::RemoteDispatcher] the dispatcher bound
80
80
  # to the booted domain
81
- def boot_files(paths, shared: nil, install_doors: true, environment: Runtime::Loader::FROM_ENV)
82
- Loader.boot_files(paths, shared: shared, install_doors: install_doors, environment: environment)
81
+ def boot_files(paths, shared: nil, install_driving: true, environment: Runtime::Loader::FROM_ENV)
82
+ Loader.boot_files(paths, shared: shared, install_driving: install_driving, environment: environment)
83
83
  end
84
84
 
85
85
  # Bind the ambient registry for the duration of the block, restoring
@@ -4,6 +4,7 @@ require "fileutils"
4
4
  require "open3"
5
5
  require_relative "../rust_build"
6
6
  require_relative "wasm"
7
+ require_relative "prebuilt_binary"
7
8
 
8
9
  module Hecks
9
10
  module RustBuild
@@ -102,13 +103,19 @@ module Hecks
102
103
  def compile(target)
103
104
  host_dir = File.join(RustBuild.rust_dir, "host")
104
105
  target_dir = ENV.fetch("CARGO_TARGET_DIR", File.join(host_dir, "target"))
106
+ binary = File.join(target_dir, target, "release", BINARY)
107
+ return binary if PrebuiltBinary.fetch("host", host_dir, target: target, into: binary)
108
+
109
+ cargo_build(target, host_dir, { "CARGO_TARGET_DIR" => target_dir }.merge(linker_for(target)))
110
+ binary
111
+ rescue Failure => e
112
+ raise Failure, "#{e.message}#{cross_hint(target)}"
113
+ end
114
+
115
+ def cargo_build(target, host_dir, env)
105
116
  puts "== cargo build --release --target #{target} --bin #{BINARY} (rust/host) =="
106
- env = { "CARGO_TARGET_DIR" => target_dir }.merge(linker_for(target))
107
117
  RustBuild.command!("rustup", "run", TOOLCHAIN, "cargo", "build", "--release", "--target", target,
108
118
  "--bin", BINARY, chdir: host_dir, env: env)
109
- File.join(target_dir, target, "release", BINARY)
110
- rescue Failure => e
111
- raise Failure, "#{e.message}#{cross_hint(target)}"
112
119
  end
113
120
 
114
121
  def linker_for(target)
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest"
4
+ require "fileutils"
5
+ require "net/http"
6
+ require "uri"
7
+ require "hecks/vocabulary"
8
+
9
+ module Hecks
10
+ module RustBuild
11
+ # A binary hecks has already compiled and published, named by what went into it (ADR 0110).
12
+ #
13
+ # The `PrebuiltBinary` rows of the Vocabulary chapter say which binaries are published: the
14
+ # crate to key, the Cargo binary, the target it is built for. A release tagged `<name>-<key>`
15
+ # holds the binary and its `.sha256`; the key is a hash of the crate's build inputs, so the
16
+ # same bytes are the same release, whichever commit they come from. `fetch` downloads it and
17
+ # checks its hash, and answers nil on any miss (not published yet, no network, a hash that
18
+ # does not match) so a caller compiles as it always did. `HECKS_PREBUILT=off` turns the
19
+ # download off.
20
+ module PrebuiltBinary
21
+ # Where releases are published.
22
+ REPOSITORY = "heckslabs/hecks"
23
+
24
+ # Left out of the key: Cargo's own output, and files that are never part of the binary.
25
+ EXCLUDED = %w[target tests .gitignore].freeze
26
+
27
+ MAX_REDIRECTS = 5
28
+
29
+ module_function
30
+
31
+ # @param name [String] a `PrebuiltBinary` row's name
32
+ # @return [Hash{String => String}] the row
33
+ # @raise [KeyError] when no row has the name
34
+ def row(name)
35
+ Hecks::Vocabulary.rows("PrebuiltBinary").find { |found| found["name"] == name } or
36
+ raise KeyError, "no PrebuiltBinary row named #{name.inspect}"
37
+ end
38
+
39
+ # @param crate_dir [String] the crate's directory
40
+ # @return [String] a hash of every file that goes into the build: each path and its bytes, in
41
+ # path order, so it does not depend on the checkout it is read from
42
+ def key(crate_dir)
43
+ files = Dir.glob("**/*", File::FNM_DOTMATCH, base: crate_dir).sort.select do |path|
44
+ File.file?(File.join(crate_dir, path)) && !EXCLUDED.include?(path.split("/").first)
45
+ end
46
+ digest = Digest::SHA256.new
47
+ files.each { |path| digest << "#{path}\0#{File.binread(File.join(crate_dir, path))}\0" }
48
+ digest.hexdigest[0, 24]
49
+ end
50
+
51
+ # @param name [String] a row's name
52
+ # @param key [String] the crate's key
53
+ # @return [String] the release tag
54
+ def tag(name, key) = "#{name}-#{key}"
55
+
56
+ # @param name [String] a row's name
57
+ # @return [String] the file the release holds the binary as
58
+ def asset(name)
59
+ found = row(name)
60
+ "#{found["executable"]}-#{found["target"]}"
61
+ end
62
+
63
+ # @param name [String] a row's name
64
+ # @param crate_dir [String] the crate's directory
65
+ # @param target [String] the triple the caller builds for
66
+ # @param into [String] the file to write the binary to
67
+ # @return [String, nil] `into`, or nil when the binary is not published for this target or
68
+ # could not be fetched and verified
69
+ def fetch(name, crate_dir, target:, into:)
70
+ return if ENV["HECKS_PREBUILT"] == "off" || row(name)["target"] != target
71
+
72
+ body = verified(name, crate_dir) or return
73
+ FileUtils.mkdir_p(File.dirname(into))
74
+ File.binwrite(into, body)
75
+ File.chmod(0o755, into)
76
+ puts "== downloaded the prebuilt #{asset(name)} (#{tag(name, key(crate_dir))}); nothing compiled =="
77
+ into
78
+ rescue SystemCallError, SocketError, Timeout::Error, OpenSSL::SSL::SSLError
79
+ nil
80
+ end
81
+
82
+ # @return [String, nil] the published binary, nil unless its bytes hash to the published
83
+ # sha256
84
+ def verified(name, crate_dir)
85
+ base = "https://github.com/#{REPOSITORY}/releases/download/#{tag(name, key(crate_dir))}/#{asset(name)}"
86
+ expected = get("#{base}.sha256")&.split&.first
87
+ body = expected && get(base)
88
+ body if body && Digest::SHA256.hexdigest(body) == expected
89
+ end
90
+
91
+ # @return [String, nil] the body at the URL, following redirects, nil unless it answers 200
92
+ def get(url, redirects = MAX_REDIRECTS)
93
+ response = Net::HTTP.get_response(URI(url))
94
+ return response.body if response.is_a?(Net::HTTPSuccess)
95
+ return get(response["location"], redirects - 1) if response.is_a?(Net::HTTPRedirection) && redirects.positive?
96
+
97
+ nil
98
+ end
99
+ end
100
+ end
101
+ end
@@ -11,7 +11,7 @@ module Hecks
11
11
  # The optional attachments `rust/host` reads from `ir.json`, each omitted when nothing
12
12
  # attached provides it: exporter method, then the key it is written under.
13
13
  SEAMS = %i[authorization membership identity newsletter newsletter_issues payments
14
- registrations payment_connection].freeze
14
+ registrations payment_connection checkout].freeze
15
15
 
16
16
  # Round-trips a value through JSON so generators see the string-keyed shape a real
17
17
  # `ir.json` carries, never live Ruby symbols.
@@ -60,7 +60,7 @@ module Hecks
60
60
  end
61
61
 
62
62
  def require_target!
63
- return if system("rustup target list --installed 2>/dev/null | grep -qx #{TARGET}")
63
+ return if RustBuild.target_installed?(TARGET)
64
64
 
65
65
  raise Failure, <<~MSG
66
66
  #{TARGET} isn't installed for this toolchain. Install it once with:
@@ -52,7 +52,7 @@ module Hecks
52
52
  end
53
53
 
54
54
  def require_target!
55
- return if system("rustup target list --installed 2>/dev/null | grep -qx #{TARGET}")
55
+ return if RustBuild.target_installed?(TARGET)
56
56
 
57
57
  raise Failure, <<~MSG
58
58
  #{TARGET} isn't installed for this toolchain. Install it once with: