hecks 3.9.1 → 3.11.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 (504) 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 +155 -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 +69 -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/ruby/aggregate_module.rb +171 -0
  40. data/lib/hecks/adapters/driving/ruby/chapter.rb +91 -0
  41. data/lib/hecks/adapters/driving/ruby.rb +83 -0
  42. data/lib/hecks/adapters/driving/usage_cache.rb +144 -0
  43. data/lib/hecks/{doors.rb → adapters/driving.rb} +10 -6
  44. data/lib/hecks/behaviors/expectations/boot.rb +1 -1
  45. data/lib/hecks/bench/ruby_runner.rb +1 -1
  46. data/lib/hecks/bluebook/ask_resolution.rb +130 -0
  47. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +8 -2
  48. data/lib/hecks/bluebook/assembly/contracts/rules.rb +4 -2
  49. data/lib/hecks/bluebook/assembly/contracts/structure.rb +3 -1
  50. data/lib/hecks/bluebook/assembly/marks.rb +1 -0
  51. data/lib/hecks/bluebook/attribute.rb +1 -1
  52. data/lib/hecks/bluebook/behaviour/command.rb +13 -8
  53. data/lib/hecks/bluebook/behaviour/policy.rb +30 -0
  54. data/lib/hecks/bluebook/capabilities/attribute_values.rb +72 -0
  55. data/lib/hecks/bluebook/capabilities.rb +91 -9
  56. data/lib/hecks/bluebook/domain_port.rb +16 -4
  57. data/lib/hecks/bluebook/dsl/adapter_builder.rb +18 -6
  58. data/lib/hecks/bluebook/dsl/binding_proxy.rb +13 -0
  59. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/computed_sources.rb +98 -0
  60. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/fan_out_rows.rb +42 -0
  61. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/projected_fields.rb +14 -2
  62. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/provisions.rb +69 -3
  63. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/with_projections.rb +17 -10
  64. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +5 -0
  65. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -0
  66. data/lib/hecks/bluebook/dsl/command_builder/mutations.rb +8 -1
  67. data/lib/hecks/bluebook/dsl/command_builder/operands.rb +121 -0
  68. data/lib/hecks/bluebook/dsl/command_builder.rb +2 -0
  69. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +10 -1
  70. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +45 -2
  71. data/lib/hecks/bluebook/dsl/policy_builder.rb +47 -10
  72. data/lib/hecks/bluebook/dsl/rule_reference.rb +7 -4
  73. data/lib/hecks/bluebook/dsl/world_builder.rb +1 -1
  74. data/lib/hecks/bluebook/expression/ast_json/emitters.rb +6 -0
  75. data/lib/hecks/bluebook/expression/ast_json.rb +9 -6
  76. data/lib/hecks/bluebook/expression/ast_reader.rb +14 -9
  77. data/lib/hecks/bluebook/expression/projection.json +36 -0
  78. data/lib/hecks/bluebook/expression/resolver/operations.rb +31 -0
  79. data/lib/hecks/bluebook/expression/resolver/parsing.rb +38 -5
  80. data/lib/hecks/bluebook/expression/resolver/scanning.rb +22 -5
  81. data/lib/hecks/bluebook/expression/resolver/values.rb +10 -0
  82. data/lib/hecks/bluebook/expression/resolver.rb +20 -1
  83. data/lib/hecks/bluebook/hecksagon.rb +23 -3
  84. data/lib/hecks/bluebook/lifecycle.rb +22 -3
  85. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +13 -1
  86. data/lib/hecks/bluebook/meta_validator/modes.rb +4 -1
  87. data/lib/hecks/bluebook/meta_validator/readings.rb +18 -1
  88. data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +2 -1
  89. data/lib/hecks/bluebook/meta_validator/shapes.rb +5 -0
  90. data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +1 -1
  91. data/lib/hecks/bluebook/meta_validator.rb +12 -12
  92. data/lib/hecks/bluebook/model_check/ask_checks.rb +71 -0
  93. data/lib/hecks/bluebook/model_check/policy_checks.rb +2 -1
  94. data/lib/hecks/bluebook/model_check/reference_checks.rb +70 -0
  95. data/lib/hecks/bluebook/model_check.rb +8 -2
  96. data/lib/hecks/bluebook/policy.rb +4 -2
  97. data/lib/hecks/bluebook/smoke_test.rb +1 -1
  98. data/lib/hecks/bluebook/synthesizer.rb +2 -0
  99. data/lib/hecks/bluebook.rb +1 -0
  100. data/lib/hecks/cli/command_table.rb +1 -1
  101. data/lib/hecks/cli/console.rb +2 -1
  102. data/lib/hecks/cli/document.rb +1 -1
  103. data/lib/hecks/cli/launcher_words.rb +4 -4
  104. data/lib/hecks/cli/mcp.rb +4 -4
  105. data/lib/hecks/cli/project_cli/launcher_source.rb +2 -2
  106. data/lib/hecks/cli/project_cli/templates.rb +5 -5
  107. data/lib/hecks/cli/project_cli.rb +9 -6
  108. data/lib/hecks/cli/run.rb +2 -2
  109. data/lib/hecks/cli/smoke_http/checks.rb +4 -1
  110. data/lib/hecks/cli/smoke_http/transport.rb +3 -3
  111. data/lib/hecks/cli/smoke_http.rb +3 -0
  112. data/lib/hecks/codemod.rb +5 -2
  113. data/lib/hecks/corpus/routes.rb +7 -0
  114. data/lib/hecks/corpus/rust.rb +3 -2
  115. data/lib/hecks/deploy/bluebook/deploy.bluebook +124 -2
  116. data/lib/hecks/deploy/bluebook/deploy.hecksagon +8 -0
  117. data/lib/hecks/deploy/oidc.json +16 -3
  118. data/lib/hecks/doc/reference/rendering.rb +6 -3
  119. data/lib/hecks/forms/app/commands.rb +8 -7
  120. data/lib/hecks/forms/app/queries.rb +2 -1
  121. data/lib/hecks/forms/app.rb +1 -1
  122. data/lib/hecks/forms/record_renderer.rb +1 -1
  123. data/lib/hecks/framework/bluebook/privacy.bluebook +11 -0
  124. data/lib/hecks/fuzzing/concurrent_dispatch.rb +4 -1
  125. data/lib/hecks/fuzzing/failure_triage.rb +2 -1
  126. data/lib/hecks/fuzzing/mutation/run.rb +11 -4
  127. data/lib/hecks/fuzzing/properties/catalog.rb +6 -4
  128. data/lib/hecks/fuzzing/properties/guaranteed_by_construction.rb +18 -11
  129. data/lib/hecks/fuzzing/properties/guards.rb +1 -1
  130. data/lib/hecks/fuzzing/self_consistency/saga_redelivery.rb +1 -1
  131. data/lib/hecks/fuzzing/self_consistency.rb +6 -2
  132. data/lib/hecks/fuzzing/shrinker.rb +3 -1
  133. data/lib/hecks/fuzzing/value_generator.rb +19 -5
  134. data/lib/hecks/gate/stages.yml +4 -10
  135. data/lib/hecks/grammar/evolve.rb +1 -1
  136. data/lib/hecks/grammar/expression_operators.json +372 -0
  137. data/lib/hecks/grammar/operators.rb +3 -1
  138. data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +10 -10
  139. data/lib/hecks/hecks/adapters/codebase/inspection/rubycritic.rb +35 -0
  140. data/lib/hecks/hecks/adapters/codebase/inspection.rb +104 -0
  141. data/lib/hecks/hecks/adapters/codebase/publishing.rb +2 -1
  142. data/lib/hecks/hecks/adapters/codebase/release_facts.rb +12 -2
  143. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +2 -1
  144. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +1 -1
  145. data/lib/hecks/hecks/adapters/cost_explorer.rb +8 -5
  146. data/lib/hecks/hecks/adapters/deploy_toolchain/clearing.rb +51 -0
  147. data/lib/hecks/hecks/adapters/deploy_toolchain/statuses.rb +2 -1
  148. data/lib/hecks/hecks/adapters/deploy_toolchain.rb +2 -0
  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 +129 -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/site_toolchain/role_prober.rb +78 -0
  173. data/lib/hecks/hecks/adapters/site_toolchain.rb +29 -4
  174. data/lib/hecks/hecks/adapters/terminal.rb +13 -11
  175. data/lib/hecks/hecks/adapters/world_clearing.rb +65 -0
  176. data/lib/hecks/hecks/codebase.behaviors +13 -1
  177. data/lib/hecks/hecks/codebase.bluebook +239 -5
  178. data/lib/hecks/hecks/custodian.behaviors +24 -6
  179. data/lib/hecks/hecks/custodian.bluebook +6 -1227
  180. data/lib/hecks/hecks/deploy.behaviors +1 -1
  181. data/lib/hecks/hecks/deploy.world +1 -3
  182. data/lib/hecks/hecks/hecks.behaviors +1 -1
  183. data/lib/hecks/hecks/hecks.hecksagon +61 -18
  184. data/lib/hecks/hecks/hecks.world +11 -10
  185. data/lib/hecks/hecks/rehearsal.bluebook +477 -0
  186. data/lib/hecks/hecks/site.behaviors +1 -1
  187. data/lib/hecks/hecks/site.world +0 -1
  188. data/lib/hecks/hecks/tooling.bluebook +1238 -0
  189. data/lib/hecks/indifferent_key.rb +20 -0
  190. data/lib/hecks/language/adapter.bluebook +13 -3
  191. data/lib/hecks/language/bluebook/aggregate.bluebook +23 -0
  192. data/lib/hecks/language/bluebook/bluebook.bluebook +15 -0
  193. data/lib/hecks/language/bluebook/entity.bluebook +18 -0
  194. data/lib/hecks/language/bluebook/policy.bluebook +9 -1
  195. data/lib/hecks/language/bluebook/query.bluebook +1 -1
  196. data/lib/hecks/language/bluebook/vocabulary.bluebook +11 -4
  197. data/lib/hecks/language/hecksagon/domain_port.bluebook +1 -1
  198. data/lib/hecks/language/hecksagon/hecksagon.bluebook +22 -0
  199. data/lib/hecks/language/oidc.json +10 -0
  200. data/lib/hecks/language/port.bluebook +4 -4
  201. data/lib/hecks/literal.rb +12 -3
  202. data/lib/hecks/ports/key_vault.rb +7 -2
  203. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +21 -10
  204. data/lib/hecks/ports/persistence/plugins/era/postgres_era/boot.rb +4 -2
  205. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +2 -1
  206. data/lib/hecks/ports/persistence/repository_factory.rb +6 -3
  207. data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +29 -0
  208. data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +1 -1
  209. data/lib/hecks/projections/deploy/fargate/settings/tuning.rb +15 -0
  210. data/lib/hecks/projections/deploy/fargate/settings.rb +3 -1
  211. data/lib/hecks/projections/deploy/fargate/stack/readers.rb +1 -0
  212. data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
  213. data/lib/hecks/projections/deploy/shared.rb +5 -2
  214. data/lib/hecks/projections/deploy/templates/fargate/Makefile.tmpl +7 -4
  215. data/lib/hecks/projections/model/deviations.rb +2 -2
  216. data/lib/hecks/projections/model.rb +2 -2
  217. data/lib/hecks/projections/oidc.rb +13 -1
  218. data/lib/hecks/projections/shape.rb +5 -2
  219. data/lib/hecks/projections/site/cms_editor/attributes.rb +95 -0
  220. data/lib/hecks/projections/site/cms_editor/blocks.rb +157 -0
  221. data/lib/hecks/projections/site/cms_editor/checks.rb +77 -0
  222. data/lib/hecks/projections/site/cms_editor/clearing.rb +70 -0
  223. data/lib/hecks/projections/site/cms_editor/color.rb +124 -0
  224. data/lib/hecks/projections/site/cms_editor/composition.rb +42 -0
  225. data/lib/hecks/projections/site/cms_editor/destructive.rb +61 -0
  226. data/lib/hecks/projections/site/cms_editor/drafts.rb +102 -0
  227. data/lib/hecks/projections/site/cms_editor/hints.rb +74 -0
  228. data/lib/hecks/projections/site/cms_editor/icons.rb +86 -0
  229. data/lib/hecks/projections/site/cms_editor/key_kinds.rb +31 -0
  230. data/lib/hecks/projections/site/cms_editor/limits.rb +72 -0
  231. data/lib/hecks/projections/site/cms_editor/media.rb +85 -0
  232. data/lib/hecks/projections/site/cms_editor/moment.rb +34 -0
  233. data/lib/hecks/projections/site/cms_editor/palette.rb +115 -0
  234. data/lib/hecks/projections/site/cms_editor/pickers.rb +85 -0
  235. data/lib/hecks/projections/site/cms_editor/pretty.rb +40 -0
  236. data/lib/hecks/projections/site/cms_editor/preview.rb +91 -0
  237. data/lib/hecks/projections/site/cms_editor/relations.rb +92 -0
  238. data/lib/hecks/projections/site/cms_editor/scale_checks.rb +66 -0
  239. data/lib/hecks/projections/site/cms_editor/scheduling.rb +150 -0
  240. data/lib/hecks/projections/site/cms_editor/schema.rb +161 -0
  241. data/lib/hecks/projections/site/cms_editor/setting.rb +130 -0
  242. data/lib/hecks/projections/site/cms_editor/targets.rb +86 -0
  243. data/lib/hecks/projections/site/cms_editor/templates/package.json.tmpl +36 -0
  244. data/lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl +370 -0
  245. data/lib/hecks/projections/site/cms_editor/templates/src/assets.ts.tmpl +98 -0
  246. data/lib/hecks/projections/site/cms_editor/templates/src/auth/membership.ts.tmpl +87 -0
  247. data/lib/hecks/projections/site/cms_editor/templates/src/auth/session.ts.tmpl +36 -0
  248. data/lib/hecks/projections/site/cms_editor/templates/src/auth/sso.ts.tmpl +20 -0
  249. data/lib/hecks/projections/site/cms_editor/templates/src/browser/app.css.tmpl +412 -0
  250. data/lib/hecks/projections/site/cms_editor/templates/src/browser/autosave.js.tmpl +144 -0
  251. data/lib/hecks/projections/site/cms_editor/templates/src/browser/blocks.js.tmpl +500 -0
  252. data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_doc.js.tmpl +175 -0
  253. data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_editor.js.tmpl +418 -0
  254. data/lib/hecks/projections/site/cms_editor/templates/src/browser/epoch.js.tmpl +61 -0
  255. data/lib/hecks/projections/site/cms_editor/templates/src/browser/forms.js.tmpl +210 -0
  256. data/lib/hecks/projections/site/cms_editor/templates/src/browser/lists.js.tmpl +40 -0
  257. data/lib/hecks/projections/site/cms_editor/templates/src/browser/main.js.tmpl +26 -0
  258. data/lib/hecks/projections/site/cms_editor/templates/src/browser/media_picker.js.tmpl +232 -0
  259. data/lib/hecks/projections/site/cms_editor/templates/src/browser/moments.js.tmpl +73 -0
  260. data/lib/hecks/projections/site/cms_editor/templates/src/browser/pickers.js.tmpl +152 -0
  261. data/lib/hecks/projections/site/cms_editor/templates/src/browser/preview.js.tmpl +98 -0
  262. data/lib/hecks/projections/site/cms_editor/templates/src/browser/shell.js.tmpl +140 -0
  263. data/lib/hecks/projections/site/cms_editor/templates/src/browser/toast.js.tmpl +66 -0
  264. data/lib/hecks/projections/site/cms_editor/templates/src/choices.ts.tmpl +99 -0
  265. data/lib/hecks/projections/site/cms_editor/templates/src/commands.ts.tmpl +133 -0
  266. data/lib/hecks/projections/site/cms_editor/templates/src/config.ts.tmpl +29 -0
  267. data/lib/hecks/projections/site/cms_editor/templates/src/flash.ts.tmpl +52 -0
  268. data/lib/hecks/projections/site/cms_editor/templates/src/host.ts.tmpl +43 -0
  269. data/lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl +177 -0
  270. data/lib/hecks/projections/site/cms_editor/templates/src/media/multipart.ts.tmpl +53 -0
  271. data/lib/hecks/projections/site/cms_editor/templates/src/media/sniff.ts.tmpl +94 -0
  272. data/lib/hecks/projections/site/cms_editor/templates/src/media/storage.ts.tmpl +50 -0
  273. data/lib/hecks/projections/site/cms_editor/templates/src/names.ts.tmpl +36 -0
  274. data/lib/hecks/projections/site/cms_editor/templates/src/schema.ts.tmpl +214 -0
  275. data/lib/hecks/projections/site/cms_editor/templates/src/server.ts.tmpl +65 -0
  276. data/lib/hecks/projections/site/cms_editor/templates/src/ui/availability.ts.tmpl +15 -0
  277. data/lib/hecks/projections/site/cms_editor/templates/src/ui/block_list.js.tmpl +213 -0
  278. data/lib/hecks/projections/site/cms_editor/templates/src/ui/blocks.ts.tmpl +275 -0
  279. data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_model.js.tmpl +123 -0
  280. data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_parse.js.tmpl +320 -0
  281. data/lib/hecks/projections/site/cms_editor/templates/src/ui/detail.ts.tmpl +88 -0
  282. data/lib/hecks/projections/site/cms_editor/templates/src/ui/dialogs.ts.tmpl +43 -0
  283. data/lib/hecks/projections/site/cms_editor/templates/src/ui/fields.ts.tmpl +275 -0
  284. data/lib/hecks/projections/site/cms_editor/templates/src/ui/html.ts.tmpl +61 -0
  285. data/lib/hecks/projections/site/cms_editor/templates/src/ui/icons.ts.tmpl +15 -0
  286. data/lib/hecks/projections/site/cms_editor/templates/src/ui/input.ts.tmpl +92 -0
  287. data/lib/hecks/projections/site/cms_editor/templates/src/ui/links.ts.tmpl +100 -0
  288. data/lib/hecks/projections/site/cms_editor/templates/src/ui/moments.ts.tmpl +44 -0
  289. data/lib/hecks/projections/site/cms_editor/templates/src/ui/outline.ts.tmpl +63 -0
  290. data/lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl +213 -0
  291. data/lib/hecks/projections/site/cms_editor/templates/src/ui/paging.ts.tmpl +82 -0
  292. data/lib/hecks/projections/site/cms_editor/templates/src/ui/pickers.ts.tmpl +110 -0
  293. data/lib/hecks/projections/site/cms_editor/templates/src/ui/preview.ts.tmpl +87 -0
  294. data/lib/hecks/projections/site/cms_editor/templates/src/ui/related.ts.tmpl +97 -0
  295. data/lib/hecks/projections/site/cms_editor/templates/src/ui/schedule.ts.tmpl +160 -0
  296. data/lib/hecks/projections/site/cms_editor/templates/src/ui/shell.ts.tmpl +211 -0
  297. data/lib/hecks/projections/site/cms_editor/templates/src/ui/table.ts.tmpl +151 -0
  298. data/lib/hecks/projections/site/cms_editor/templates/src/ui/theme.js.tmpl +16 -0
  299. data/lib/hecks/projections/site/cms_editor/templates/src/ui/values.ts.tmpl +69 -0
  300. data/lib/hecks/projections/site/cms_editor/templates/src/ui/words.ts.tmpl +97 -0
  301. data/lib/hecks/projections/site/cms_editor/templates/src/ui/world.ts.tmpl +35 -0
  302. data/lib/hecks/projections/site/cms_editor/templates/tsconfig.json.tmpl +17 -0
  303. data/lib/hecks/projections/site/cms_editor/theme.rb +29 -0
  304. data/lib/hecks/projections/site/cms_editor/theme_checks.rb +57 -0
  305. data/lib/hecks/projections/site/cms_editor.rb +133 -0
  306. data/lib/hecks/projections/site/role_probe.rb +74 -0
  307. data/lib/hecks/projector/cli_audience.rb +2 -1
  308. data/lib/hecks/projector/cli_projector/listing.rb +1 -1
  309. data/lib/hecks/projector/cli_projector/option_specs.rb +1 -1
  310. data/lib/hecks/projector/docs_projector/closing.rb +1 -1
  311. data/lib/hecks/projector/docs_projector.rb +1 -1
  312. data/lib/hecks/projector/exporter/bindings.rb +40 -10
  313. data/lib/hecks/projector/exporter/capability_values.rb +55 -0
  314. data/lib/hecks/projector/narrate_projector/reactions.rb +1 -1
  315. data/lib/hecks/projector/target.rb +11 -0
  316. data/lib/hecks/projector.rb +32 -5
  317. data/lib/hecks/quality_control/adapters/github_checks.rb +12 -8
  318. data/lib/hecks/quality_control/adapters/github_issues.rb +8 -4
  319. data/lib/hecks/quality_control/cli/qa_open_pr.rb +2 -2
  320. data/lib/hecks/quality_control/cli/qa_sweep/checks/shrinking.rb +1 -1
  321. data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +1 -1
  322. data/lib/hecks/quality_control/cli/qa_sweep.rb +1 -1
  323. data/lib/hecks/quality_control/quality_control.bluebook +6 -2
  324. data/lib/hecks/release/approval.rb +64 -0
  325. data/lib/hecks/router/{door.rb → aggregate_reader.rb} +5 -4
  326. data/lib/hecks/router/namespace_installer.rb +16 -16
  327. data/lib/hecks/router.rb +1 -1
  328. data/lib/hecks/runtime/best_effort.rb +22 -0
  329. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +12 -2
  330. data/lib/hecks/runtime/command_interpreter.rb +3 -2
  331. data/lib/hecks/runtime/command_rules/emission.rb +1 -1
  332. data/lib/hecks/runtime/dispatcher.rb +4 -4
  333. data/lib/hecks/runtime/entity_element/location.rb +1 -1
  334. data/lib/hecks/runtime/event.rb +5 -0
  335. data/lib/hecks/runtime/identity.rb +7 -6
  336. data/lib/hecks/runtime/interpreting.rb +2 -1
  337. data/lib/hecks/runtime/invocation_builder.rb +1 -1
  338. data/lib/hecks/runtime/loader/boot_steps.rb +8 -5
  339. data/lib/hecks/runtime/loader.rb +10 -10
  340. data/lib/hecks/runtime/policy_interpreter/arguments.rb +7 -4
  341. data/lib/hecks/runtime/policy_interpreter/fan_out.rb +3 -3
  342. data/lib/hecks/runtime/policy_interpreter.rb +6 -6
  343. data/lib/hecks/runtime/port_operation_interpreter.rb +1 -1
  344. data/lib/hecks/runtime/reaction_invocation.rb +1 -1
  345. data/lib/hecks/runtime/rebuild_sweep.rb +11 -1
  346. data/lib/hecks/runtime/registry/ask_verification.rb +35 -0
  347. data/lib/hecks/runtime/registry/hecksagon_rules.rb +10 -0
  348. data/lib/hecks/runtime/registry/merging.rb +1 -1
  349. data/lib/hecks/runtime/registry/providers.rb +16 -0
  350. data/lib/hecks/runtime/registry/read_repository.rb +6 -4
  351. data/lib/hecks/runtime/registry/verification.rb +4 -1
  352. data/lib/hecks/runtime/registry/world_defaults.rb +29 -0
  353. data/lib/hecks/runtime/registry.rb +1 -1
  354. data/lib/hecks/runtime/saga_interpreter/compensation.rb +1 -1
  355. data/lib/hecks/runtime/saga_interpreter/delivery.rb +4 -4
  356. data/lib/hecks/runtime/saga_interpreter/transitions.rb +1 -1
  357. data/lib/hecks/runtime/saga_interpreter.rb +3 -3
  358. data/lib/hecks/runtime/tenant_check.rb +5 -4
  359. data/lib/hecks/runtime/value/coercion.rb +2 -2
  360. data/lib/hecks/runtime/value/validation.rb +16 -4
  361. data/lib/hecks/runtime.rb +9 -9
  362. data/lib/hecks/rust_build/project_rust/target_ir.rb +1 -1
  363. data/lib/hecks/rust_build/wasm.rb +1 -1
  364. data/lib/hecks/rust_build/wasm_browser.rb +1 -1
  365. data/lib/hecks/rust_build.rb +11 -0
  366. data/lib/hecks/served_options.rb +53 -0
  367. data/lib/hecks/site/bluebook/site.bluebook +29 -1
  368. data/lib/hecks/site/bluebook/site.ports.hecksagon +6 -0
  369. data/lib/hecks/storehouse/audit.rb +1 -1
  370. data/lib/hecks/storehouse/dispatching.rb +8 -6
  371. data/lib/hecks/storehouse/introspection.rb +2 -2
  372. data/lib/hecks/storehouse/querying.rb +6 -4
  373. data/lib/hecks/storehouse.rb +4 -4
  374. data/lib/hecks/tools/comment_style/source_file.rb +4 -1
  375. data/lib/hecks/tools/deploy_recipe_lint/fixtures.rb +4 -1
  376. data/lib/hecks/tools/lanes/rows.rb +6 -0
  377. data/lib/hecks/tools/oidc_manifests.rb +4 -5
  378. data/lib/hecks/tools/regeneration_run.rb +11 -4
  379. data/lib/hecks/tools/site_routes/cli.rb +1 -1
  380. data/lib/hecks/tools/site_routes/editor_files.rb +45 -0
  381. data/lib/hecks/tools/site_routes.rb +14 -7
  382. data/lib/hecks/tools/tenant_provisioning.rb +2 -2
  383. data/lib/hecks/tools/tools_doc.rb +4 -4
  384. data/lib/hecks/version.rb +1 -1
  385. data/lib/hecks/vocabulary.rb +4 -4
  386. data/lib/hecks.rb +15 -15
  387. data/lib/rubocop/cop/hecks/env_dump.rb +69 -0
  388. data/lib/rubocop/cop/hecks/monotonic_duration.rb +53 -0
  389. data/lib/rubocop/cop/hecks/no_wall_clock_in_runtime.rb +34 -0
  390. data/lib/rubocop/cop/hecks/raw_shell_interpolation.rb +79 -0
  391. data/lib/rubocop/cop/hecks/sleep_in_spec.rb +34 -0
  392. data/lib/rubocop/cop/hecks/swallowed_rescue.rb +37 -0
  393. data/lib/rubocop/cop/hecks/symbol_string_key_mix.rb +50 -0
  394. data/lib/rubocop/cop/hecks/untyped_raise.rb +37 -0
  395. data/prebuilt/05c358d38d661a3774f813d49c66f5b68939af94432d66257a56f49ee2598994.marshal +0 -0
  396. data/prebuilt/26c40c61f09b09b11651c64668eda3ceb180f83cf2a3802d3033d2fd99ac841b.marshal +0 -0
  397. data/prebuilt/verdicts-230ac18c25abfd3d92ede032bee2661a4c2cd2773ab0cf0e2ae52546ba2f7af9.json +1 -0
  398. data/rust/.gitignore +6 -0
  399. data/rust/Cargo.toml +9 -1
  400. data/rust/build/src/binding_pass.rs +103 -0
  401. data/rust/build/src/cargo_sync.rs +6 -0
  402. data/rust/build/src/lineage_pass.rs +3 -3
  403. data/rust/build/src/main.rs +17 -5
  404. data/rust/build/src/pipeline.rs +48 -5
  405. data/rust/build/src/seams_pass.rs +123 -0
  406. data/rust/build/src/translation_pass.rs +167 -0
  407. data/rust/codegen/src/asks.rs +103 -0
  408. data/rust/codegen/src/bridging.rs +1 -1
  409. data/rust/codegen/src/commands.rs +13 -8
  410. data/rust/codegen/src/constraints.rs +25 -0
  411. data/rust/codegen/src/domain_generator.rs +11 -9
  412. data/rust/codegen/src/expr_emitter.rs +13 -0
  413. data/rust/codegen/src/json_codec.rs +54 -15
  414. data/rust/codegen/src/main.rs +2 -1
  415. data/rust/codegen/src/mutations.rs +174 -4
  416. data/rust/codegen/src/naming.rs +30 -0
  417. data/rust/codegen/src/queries.rs +11 -2
  418. data/rust/codegen/src/reactions.rs +1 -1
  419. data/rust/codegen/src/types.rs +166 -8
  420. data/rust/host/HECKS_RELEASE +1 -1
  421. data/rust/host/src/api.rs +4 -4
  422. data/rust/host/src/bin/validate_harness.rs +43 -0
  423. data/rust/host/src/boundary_fuzz/expr_json.rs +2 -2
  424. data/rust/host/src/boundary_fuzz/ir.rs +1 -0
  425. data/rust/host/src/boundary_fuzz/server.rs +1 -1
  426. data/rust/host/src/checkout.rs +35 -19
  427. data/rust/host/src/commerce_ir.rs +408 -2
  428. data/rust/host/src/expr_json.rs +118 -0
  429. data/rust/host/src/mint.rs +1 -1
  430. data/rust/host/src/payments/tests.rs +27 -1
  431. data/rust/host/src/payments.rs +12 -4
  432. data/rust/host/src/query_step.rs +22 -4
  433. data/rust/host/src/reference_validate.rs +653 -108
  434. data/rust/host/src/resend.rs +2 -0
  435. data/rust/host/src/server.rs +19 -6
  436. data/rust/host/src/ui_schema.rs +132 -5
  437. data/rust/host/src/web/newsletter.rs +7 -8
  438. data/rust/host/src/web/newsletter_send.rs +38 -13
  439. data/rust/host/src/web/registrations.rs +229 -26
  440. data/rust/host/src/web.rs +3 -3
  441. data/rust/parser/src/emit.rs +38 -6
  442. data/rust/parser/src/expr/ast_json.rs +7 -1
  443. data/rust/parser/src/expr/resolver.rs +171 -6
  444. data/rust/parser/src/ir.rs +7 -0
  445. data/rust/parser/src/keywords.rs +24 -0
  446. data/rust/parser/src/main.rs +3 -0
  447. data/rust/parser/src/parse/aggregate.rs +2 -1
  448. data/rust/parser/src/parse/chapter.rs +2 -2
  449. data/rust/parser/src/parse/command.rs +2 -0
  450. data/rust/parser/src/parse/hecksagon.rs +5 -2
  451. data/rust/parser/src/parse/lifecycle.rs +81 -0
  452. data/rust/parser/src/parse/mod.rs +15 -1
  453. data/rust/parser/src/parse/policy.rs +13 -2
  454. data/rust/parser/src/parse/value_object.rs +13 -8
  455. data/rust/parser/src/ruby_value.rs +1 -1
  456. data/rust/src/exemplar/commands.rs +4 -4
  457. data/rust/src/exemplar/constraints.rs +1 -1
  458. data/rust/src/exemplar/json.rs +43 -1
  459. data/rust/src/kernel/cli.rs +7 -5
  460. data/rust/src/kernel/dispatch.rs +2 -2
  461. data/rust/src/kernel/dispatch_guard_tests.rs +1 -1
  462. data/rust/src/kernel/expr.rs +73 -4
  463. data/rust/src/kernel/expression_operators/arithmetic.rs +130 -5
  464. data/rust/src/kernel/expression_operators/presence.rs +41 -3
  465. data/rust/src/kernel/expression_operators/text.rs +26 -2
  466. data/rust/src/kernel/json.rs +15 -0
  467. data/rust/src/kernel/mod.rs +1 -1
  468. data/rust/src/kernel/orchestrate.rs +54 -5
  469. data/rust/src/kernel/orchestrate_guard_tests.rs +67 -0
  470. data/rust/src/kernel/pattern.rs +60 -0
  471. data/rust/src/kernel/reference_lookup.rs +90 -7
  472. metadata +174 -36
  473. data/lib/hecks/doors/cli_door/nesting.rb +0 -34
  474. data/lib/hecks/doors/cli_door/shorthand.rb +0 -85
  475. data/lib/hecks/doors/cli_door.rb +0 -124
  476. data/lib/hecks/doors/cli_runner/answers.rb +0 -138
  477. data/lib/hecks/doors/cli_runner/resolution.rb +0 -146
  478. data/lib/hecks/doors/cli_runner/settling.rb +0 -115
  479. data/lib/hecks/doors/cli_runner/streaming.rb +0 -90
  480. data/lib/hecks/doors/cli_runner/suggestions.rb +0 -43
  481. data/lib/hecks/doors/cli_runner.rb +0 -66
  482. data/lib/hecks/doors/command_request.rb +0 -119
  483. data/lib/hecks/doors/handle.rb +0 -208
  484. data/lib/hecks/doors/json_door.rb +0 -132
  485. data/lib/hecks/doors/launcher_options.rb +0 -247
  486. data/lib/hecks/doors/mcp_door/properties.rb +0 -47
  487. data/lib/hecks/doors/mcp_door/tool_calls.rb +0 -113
  488. data/lib/hecks/doors/mcp_door/tool_definitions/auditing.rb +0 -51
  489. data/lib/hecks/doors/mcp_door/tool_definitions/calling.rb +0 -69
  490. data/lib/hecks/doors/mcp_door/tool_definitions/reading.rb +0 -97
  491. data/lib/hecks/doors/mcp_door/tool_definitions.rb +0 -15
  492. data/lib/hecks/doors/mcp_door.rb +0 -156
  493. data/lib/hecks/doors/mcp_door_scope/argument_policy.rb +0 -92
  494. data/lib/hecks/doors/mcp_door_scope/env_problems.rb +0 -55
  495. data/lib/hecks/doors/mcp_door_scope/presenter.rb +0 -78
  496. data/lib/hecks/doors/mcp_door_scope.rb +0 -201
  497. data/lib/hecks/doors/mcp_guide_cache.rb +0 -75
  498. data/lib/hecks/doors/ruby_door/aggregate_door.rb +0 -162
  499. data/lib/hecks/doors/ruby_door/chapter.rb +0 -89
  500. data/lib/hecks/doors/ruby_door.rb +0 -80
  501. data/lib/hecks/doors/usage_cache.rb +0 -139
  502. data/prebuilt/0ee7f83cba59ce7d1c45c65ba166b071779f70143449f584f33ff7989f64eccb.marshal +0 -0
  503. data/prebuilt/6e4a6bcf0aa880e2e6b056e1846b70e5a768090b9dc998bbadeaf5d6bcfd3db8.marshal +0 -0
  504. data/prebuilt/verdicts-91aaf93ce8981bd9a754948f075d95650dc2ec6435015376f5c60992b36a24b1.json +0 -1
@@ -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
@@ -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:
@@ -83,6 +83,17 @@ module Hecks
83
83
  raise Failure, "`#{command.join(" ")}` failed#{" in #{chdir}" if chdir}"
84
84
  end
85
85
 
86
+ # Asks rustup whether a compile target is installed for the active toolchain.
87
+ #
88
+ # @param target [String] the target triple, such as `wasm32-unknown-unknown`
89
+ # @return [Boolean] false when rustup is missing or does not list the target
90
+ def target_installed?(target)
91
+ listed = IO.popen(["rustup", "target", "list", "--installed", { err: File::NULL }], &:read)
92
+ listed.split("\n").include?(target)
93
+ rescue SystemCallError
94
+ false
95
+ end
96
+
86
97
  # Runs a tool and holds what it printed.
87
98
  #
88
99
  # @param tool [String] a key of `TOOLS`
@@ -0,0 +1,53 @@
1
+ require "rack"
2
+
3
+ module Hecks
4
+ # What a domain's world file says it is served by: each `served_by("Adapter") { ... }` line
5
+ # names an inbound adapter and the per-environment values it needs. The route is derived,
6
+ # never written: a driving adapter answers at `/webhooks/<adapter name, snake-cased>` unless
7
+ # its `path` says otherwise, so a world holds only what the domain cannot know (secret,
8
+ # path override) and the same domain can be served differently in each environment.
9
+ #
10
+ # A secret is named by the environment variable that holds it, never inline.
11
+ module ServedOptions
12
+ VERB = "served_by".freeze
13
+
14
+ module_function
15
+
16
+ # @param world [Bluebook::World, nil] a domain's judged world
17
+ # @return [Array<Hash>] one entry per `served_by` line: `adapter`, `path` and its settings
18
+ def entries(world)
19
+ return [] unless world
20
+
21
+ world.settings.filter_map do |key, values|
22
+ next unless key.to_s.start_with?("#{VERB}:")
23
+
24
+ adapter = values.fetch(:adapter)
25
+ values.merge(adapter: adapter, path: values.fetch(:path) { "/webhooks/#{snake(adapter)}" })
26
+ end
27
+ end
28
+
29
+ # A Rack app mounting every `served_by` adapter the world names at its derived path.
30
+ #
31
+ # @param world [Bluebook::World, nil]
32
+ # @param adapters [Hash{String => Class}] driving adapter classes by the name a world uses;
33
+ # each is built with `secret:` read from the environment variable the line names
34
+ # @param env [#fetch] where secrets are read from (`ENV` in production)
35
+ # @return [Rack::URLMap]
36
+ # @raise [KeyError] when a line names an adapter no class answers for
37
+ # @raise [ArgumentError] when a line names a secret variable the environment does not hold
38
+ def rack_app(world, adapters:, env: ENV)
39
+ routes = entries(world).to_h do |entry|
40
+ klass = adapters.fetch(entry[:adapter])
41
+ [entry[:path], klass.new(secret: secret_for(entry, env))]
42
+ end
43
+ Rack::URLMap.new(routes)
44
+ end
45
+
46
+ def secret_for(entry, env)
47
+ name = entry.fetch(:secret) { raise ArgumentError, "#{entry[:adapter]} names no secret" }
48
+ env.fetch(name) { raise ArgumentError, "#{entry[:adapter]}: environment variable #{name} is not set" }
49
+ end
50
+
51
+ def snake(name) = name.to_s.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
52
+ end
53
+ end
@@ -101,6 +101,7 @@ Hecks.bluebook "Site" do
101
101
  attribute :template, Location, optional: true
102
102
  attribute :cms, Location, optional: true
103
103
  attribute :root, Location, optional: true
104
+ attribute :editor, Location, optional: true
104
105
  attribute :extension, Extension, optional: true
105
106
  attribute :check, Switch, optional: true
106
107
  attribute :live, Location, optional: true
@@ -166,11 +167,12 @@ Hecks.bluebook "Site" do
166
167
  end
167
168
 
168
169
  lifecycle :status, default: "requested" do
170
+ mark :failure, "faulted"
169
171
  transition "Complete" => "projected", from: "requested"
170
172
  transition "Fault" => "faulted", from: "requested"
171
173
  end
172
174
 
173
- # `hecks site site_projection.project_site <project> [out=<dir>] [template=<file>] [cms=<dir>] [root=<dir>] [extension=ts|mts] [--check]`.
175
+ # `hecks site site_projection.project_site <project> [out=<dir>] [template=<file>] [cms=<dir>] [root=<dir>] [editor=<dir>] [extension=ts|mts] [--check]`.
174
176
  # With `check` nothing is written: a routes.ts that differs from the table is faulted, naming the
175
177
  # file, so a CI job fails on drift.
176
178
  command "ProjectSite" do
@@ -182,6 +184,7 @@ Hecks.bluebook "Site" do
182
184
  attribute :template, Location, optional: true
183
185
  attribute :cms, Location, optional: true
184
186
  attribute :root, Location, optional: true
187
+ attribute :editor, Location, optional: true
185
188
  attribute :extension, Extension, optional: true
186
189
  attribute :check, Switch, optional: true
187
190
 
@@ -191,6 +194,7 @@ Hecks.bluebook "Site" do
191
194
  sets :template
192
195
  sets :cms
193
196
  sets :root
197
+ sets :editor
194
198
  sets :extension
195
199
  sets :check
196
200
 
@@ -250,6 +254,25 @@ Hecks.bluebook "Site" do
250
254
  emits "SiteProbeRequested"
251
255
  end
252
256
 
257
+ # `hecks site site_projection.check_roles <project> url=<http://127.0.0.1:port>`. Dispatches every
258
+ # command the project declares a `role` for to a running host with no role and no actor, and
259
+ # checks the host refuses each as `Unauthorized`. Only a host on this machine is asked, and it
260
+ # must be running with `HECKS_ROLE_ENFORCEMENT=enforce`: a host that is not would run the
261
+ # commands. It prints a line per command and exits 1 when any is not refused for its role.
262
+ command "CheckRoles" do
263
+ goal "Check a host on this machine refuses every role-declaring command from a caller with no role"
264
+
265
+ attribute :domain, DomainPath
266
+ attribute :run, RunKey
267
+ attribute :url, SiteUrl
268
+
269
+ sets :domain
270
+ sets :run
271
+ sets :url
272
+
273
+ emits "RolesCheckRequested"
274
+ end
275
+
253
276
  command "Complete" do
254
277
  goal "Record that routes.ts was written, or found current, or the live edge matched, and what it said"
255
278
 
@@ -301,6 +324,11 @@ Hecks.bluebook "Site" do
301
324
  trigger SiteProjection::SiteToolchain::Probe, with: { run: :run }
302
325
  end
303
326
 
327
+ policy "RolesWhenRequested" do
328
+ on "SiteProjection.RolesCheckRequested"
329
+ trigger SiteProjection::SiteToolchain::Roles, with: { run: :run }
330
+ end
331
+
304
332
  policy "RecordTheProjection" do
305
333
  on "SiteProjection.SiteAnswered"
306
334
  trigger SiteProjection::Complete, with: { output: :output }
@@ -23,5 +23,11 @@ Hecks.hecksagon "Site" do
23
23
  answers "SiteAnswered"
24
24
  refuses "SiteRefused"
25
25
  end
26
+
27
+ asks "Roles", to: SiteProjection do
28
+ attribute :run, RunKey
29
+ answers "SiteAnswered"
30
+ refuses "SiteRefused"
31
+ end
26
32
  end
27
33
  end
@@ -33,7 +33,7 @@ module Hecks
33
33
  end
34
34
 
35
35
  # Tails this bus's own dispatch/query/state audit log — a pull-based
36
- # substitute for a push subscription, since a stdio door answers one
36
+ # substitute for a push subscription, since a stdio server answers one
37
37
  # request at a time with no channel to push through.
38
38
  #
39
39
  # @param runtime [Runtime::Registry] the booted domain to tail
@@ -34,9 +34,9 @@ module Hecks
34
34
 
35
35
  # :nodoc:
36
36
  def command_envelope(args, spec)
37
- Doors::CommandRequest.normalize(Doors::JsonDoor.deep_symbolize(args),
38
- receiver: spec[:receiver],
39
- legacy_receiver: spec[:legacy_receiver])
37
+ Adapters::Driving::CommandRequest.normalize(Adapters::Driving::Json.deep_symbolize(args),
38
+ receiver: spec[:receiver],
39
+ legacy_receiver: spec[:legacy_receiver])
40
40
  end
41
41
 
42
42
  # :nodoc:
@@ -52,7 +52,9 @@ module Hecks
52
52
  ok(summary: summary,
53
53
  id: result.id,
54
54
  state: settled_state(runtime, spec, result),
55
- events: result.events.map { |event| { name: event.name, payload: Doors::JsonDoor.materialize(event.payload) } })
55
+ events: result.events.map do |event|
56
+ { name: event.name, payload: Adapters::Driving::Json.materialize(event.payload) }
57
+ end)
56
58
  end
57
59
 
58
60
  # The record as its repository holds it once every reaction has run, which is the state the
@@ -65,7 +67,7 @@ module Hecks
65
67
  def settled_state(runtime, spec, result)
66
68
  return if result.state.nil?
67
69
 
68
- Doors::JsonDoor.materialize(settled_record(runtime, spec, result) || result.state)
70
+ Adapters::Driving::Json.materialize(settled_record(runtime, spec, result) || result.state)
69
71
  end
70
72
 
71
73
  # :nodoc:
@@ -141,7 +143,7 @@ module Hecks
141
143
 
142
144
  # :nodoc:
143
145
  def batch_step(runtime, raw, summary, options)
144
- step = Doors::JsonDoor.deep_symbolize(raw)
146
+ step = Adapters::Driving::Json.deep_symbolize(raw)
145
147
  dispatch(runtime: runtime, command: step[:command], args: step[:args] || {}, summary: summary, **options)
146
148
  end
147
149
  end
@@ -68,7 +68,7 @@ module Hecks
68
68
  # @return [Hash] {ok: true, domain:, valid: true} plus :findings when deep;
69
69
  # {ok: false, domain:, valid: false, error:} if the boot itself failed
70
70
  def validate(domain:, deep: false)
71
- runtime = Hecks.boot(confine!(domain, "domain"), install_doors: false)
71
+ runtime = Hecks.boot(confine!(domain, "domain"), install_driving: false)
72
72
  result = { ok: true, domain: domain, valid: true }
73
73
  result[:findings] = model_findings(runtime) if deep
74
74
  result
@@ -103,7 +103,7 @@ module Hecks
103
103
 
104
104
  # :nodoc:
105
105
  def journal_entries(repository)
106
- repository.entries.map { |entry| { operation: entry.operation, id: entry.id, state: Doors::JsonDoor.materialize(entry.state) } }
106
+ repository.entries.map { |entry| { operation: entry.operation, id: entry.id, state: Adapters::Driving::Json.materialize(entry.state) } }
107
107
  end
108
108
 
109
109
  # Runs a domain's hand-curated .behaviors examples and reports the results.
@@ -27,12 +27,14 @@ module Hecks
27
27
  spec = resolve!(cli_for(request.bluebook), request.name, asking: true)
28
28
  rows = with_caller(request.role, request.actor_id) { answer(request, spec) }
29
29
 
30
- ok(summary: request.summary, rows: rows.map { |row| Doors::JsonDoor.materialize(row) }).merge(verb: spec[:command])
30
+ ok(summary: request.summary, rows: rows.map do |row|
31
+ Adapters::Driving::Json.materialize(row)
32
+ end).merge(verb: spec[:command])
31
33
  end
32
34
 
33
35
  # :nodoc:
34
36
  def answer(request, spec)
35
- request.runtime.query(spec[:command], **Doors::JsonDoor.deep_symbolize(request.args))
37
+ request.runtime.query(spec[:command], **Adapters::Driving::Json.deep_symbolize(request.args))
36
38
  end
37
39
 
38
40
  # Reads one aggregate's stored records directly, bypassing any declared
@@ -63,7 +65,7 @@ module Hecks
63
65
  repository = runtime.registry.repository(bluebook.name, ir)
64
66
  return ok(summary: summary, record: single_record(repository, ir, id)) if id
65
67
 
66
- records = repository.all.map { |instance| Doors::JsonDoor.materialize(instance.to_h) }
68
+ records = repository.all.map { |instance| Adapters::Driving::Json.materialize(instance.to_h) }
67
69
  ok(summary: summary, count: records.length, records: records)
68
70
  end
69
71
 
@@ -71,7 +73,7 @@ module Hecks
71
73
  def single_record(repository, aggregate_ir, identity)
72
74
  instance = repository.find(identity) or
73
75
  raise Runtime::NotFound, "no #{aggregate_ir.hecks_name} found for id #{identity.inspect}"
74
- Doors::JsonDoor.materialize(instance.to_h)
76
+ Adapters::Driving::Json.materialize(instance.to_h)
75
77
  end
76
78
  end
77
79
  end
@@ -3,8 +3,8 @@ require "json"
3
3
  require "fileutils"
4
4
  require "time"
5
5
  require_relative "cache_dir"
6
- require_relative "doors/command_request"
7
- require_relative "doors/json_door"
6
+ require_relative "adapters/driving/command_request"
7
+ require_relative "adapters/driving/json"
8
8
  require_relative "naming"
9
9
  require_relative "projector"
10
10
  require_relative "runtime/errors"
@@ -55,7 +55,7 @@ module Hecks
55
55
  "own root (HECKS_STOREHOUSE_ROOT to widen it)"
56
56
  end
57
57
 
58
- # The one bluebook this runtime booted; every whole-domain door assumes
58
+ # The one bluebook this runtime booted; every whole-domain entry point assumes
59
59
  # the same one-bluebook-per-boot shape.
60
60
  # :nodoc:
61
61
  def bluebook_for(runtime)
@@ -137,7 +137,7 @@ module Hecks
137
137
  def audit_fields(request) = request.to_h.slice(:summary, :source, :role, :actor_id)
138
138
 
139
139
  # dry_run? (Runtime::Dispatcher) only understands the pre-envelope flat
140
- # args shape; this is the one door back into it from dispatch's own envelope.
140
+ # args shape; this is the one entry point back into it from dispatch's own envelope.
141
141
  # :nodoc:
142
142
  def flatten_legacy(envelope, receiver, legacy_receiver)
143
143
  facts = envelope[:with] || {}
@@ -14,6 +14,9 @@ module Hecks
14
14
  module CommentStyle
15
15
  # One parsed source file and the violations found in it.
16
16
  class SourceFile
17
+ # Raised when an automatic fix would change code rather than comments.
18
+ class Error < RuntimeError; end
19
+
17
20
  include LongBlocks
18
21
  include Masking
19
22
  include CapsWords
@@ -51,7 +54,7 @@ module Hecks
51
54
  return @source if output == @source
52
55
 
53
56
  unchanged = CommentStyle.code_tokens(@source) == CommentStyle.code_tokens(output)
54
- raise "#{path}: fix would change code, refusing" unless unchanged
57
+ raise Error, "#{path}: fix would change code, refusing" unless unchanged
55
58
 
56
59
  output
57
60
  end
@@ -9,6 +9,9 @@ module Hecks
9
9
  module DeployRecipeLint
10
10
  # Generated fixture domains for the deploy generator, so the lint has real Makefiles to read.
11
11
  module Fixtures
12
+ # Raised when a deploy fixture cannot be generated.
13
+ class Error < RuntimeError; end
14
+
12
15
  # The fixture's bluebook, where `__NAME__` stands for the domain's name.
13
16
  FIXTURE_BLUEBOOK = <<~BLUEBOOK
14
17
  Hecks.bluebook "__NAME__" do
@@ -59,7 +62,7 @@ module Hecks
59
62
  Dir.mktmpdir do |dir|
60
63
  domain_dir = write_fixture(dir, basename, world_body, env_local: env_local)
61
64
  outcome = Hecks::Adapters::ConsoleCapture.capture { DeployRecipe.main([domain_dir], root: root) }
62
- outcome.ok? or raise "hecks deploy project failed generating the #{basename} fixture: #{outcome.output}"
65
+ outcome.ok? or raise Error, "hecks deploy project failed generating the #{basename} fixture: #{outcome.output}"
63
66
  end
64
67
  File.join(root, "deploy", basename)
65
68
  end
@@ -29,9 +29,15 @@ module Hecks
29
29
  return "#{name} has guarded #{lane["guarded"].inspect}" unless %w[yes no].include?(lane["guarded"])
30
30
  return "#{name} has alert_after #{lane["alert_after"].inspect}, not whole hours" unless hours?(lane)
31
31
 
32
+ return "#{name} has release_trailer #{lane["release_trailer"].inspect}, not a trailer word" unless trailer?(lane)
33
+
32
34
  follows_problem(lane, names)
33
35
  end
34
36
 
37
+ # @return [Boolean] whether `release_trailer` is empty (nothing is released from the lane)
38
+ # or a git trailer key such as `Release-Approved-By`
39
+ def trailer?(lane) = lane["release_trailer"].to_s.match?(/\A([A-Za-z][A-Za-z0-9]*(-[A-Za-z0-9]+)*)?\z/)
40
+
35
41
  # @return [Boolean] whether `alert_after` is empty (never late) or whole hours
36
42
  def hours?(lane) = lane["alert_after"].to_s.match?(/\A\d*\z/)
37
43
 
@@ -10,9 +10,8 @@ module Hecks
10
10
  #
11
11
  # A domain that has no bluebook is skipped and one that cannot be projected is reported, so a
12
12
  # sweep over the whole checkout carries on past either. `hecks deploy
13
- # oidc_manifest.project_oidc` loads
14
- # `bundler/setup` first, which pins the `json` gem: newer releases pretty-print an empty array
15
- # as `[\n\n]`, a diff spec/oidc_manifest_spec.rb would report as drift.
13
+ # oidc_manifest.project_oidc` writes through `Hecks::Projections::OIDC.render`, which spells an
14
+ # empty list `[]` whichever json release is loaded, so the text does not depend on the machine.
16
15
  module OidcManifests
17
16
  # Directories that hold a `.hecksagon` but are never domains.
18
17
  NOT_DOMAINS = %r{\A(rust|deploy|tmp|coverage)/}
@@ -50,7 +49,7 @@ module Hecks
50
49
  # @param path [String] a domain directory, relative to `root`
51
50
  # @return [void]
52
51
  def project(root, path)
53
- runtime = Hecks.boot(File.join(root, path), install_doors: false)
52
+ runtime = Hecks.boot(File.join(root, path), install_driving: false)
54
53
  name = runtime.registry.bluebooks.keys.first
55
54
  return warn(" #{path}: no bluebook found — skipped") unless name
56
55
 
@@ -65,7 +64,7 @@ module Hecks
65
64
  # @param out [String] where the manifest goes
66
65
  # @return [void]
67
66
  def write_manifest(registry, name, out)
68
- Hecks::Projector.write(Hecks::Projector.call(:oidc, bluebook: registry.bluebook(name)), out)
67
+ File.write(out, Hecks::Projections::OIDC.render(Hecks::Projector.call(:oidc, bluebook: registry.bluebook(name))))
69
68
  end
70
69
  end
71
70
  end
@@ -8,13 +8,13 @@ require_relative "../corpus"
8
8
 
9
9
  module Hecks
10
10
  module Tools
11
- # Regenerates every corpus domain's committed Rust output with `hecks project_rust`, or checks
12
- # that the committed output is what a regeneration would write.
11
+ # Regenerates every corpus domain's Rust output with `hecks project_rust`, or checks that the
12
+ # output on disk is what that would write. Only pizzas, `mod.rs` and `Cargo.toml` are committed.
13
13
  #
14
14
  # The domain list comes from `Hecks::Corpus.rust_regen_order`, never a hand-kept list. The
15
15
  # order is fixed (sorted by relative path): domains that share governance/, identity/,
16
- # Cargo.toml and generated/mod.rs stamp them with whichever ran last, so it must not flap. If
17
- # the domain set or the sort rule changes, re-run and commit the output; never hand-edit stamps.
16
+ # Cargo.toml and generated/mod.rs stamp them with whichever ran last, so it must not flap.
17
+ # If the domain set or the sort rule changes, re-run and commit what changed.
18
18
  #
19
19
  # hecks regenerate_corpus # discover, regenerate, print the plan
20
20
  # hecks regenerate_corpus --check # regenerate into a scratch crate; fail on any difference
@@ -27,6 +27,11 @@ module Hecks
27
27
  "wrong directory, or something upstream deleted rust/src/generated/ entirely. Refusing " \
28
28
  "to silently treat that as \"nothing to regenerate.\""
29
29
 
30
+ # The refusal when a check finds nothing generated to compare.
31
+ NOT_MATERIALIZED = "hecks regenerate_corpus --check: rust/src/generated has no generated output to compare. " \
32
+ "Only pizzas, mod.rs and Cargo.toml are committed; run " \
33
+ "`hecks regenerate_corpus --confirm` first, then the check."
34
+
30
35
  module_function
31
36
 
32
37
  # Regenerates the corpus, or checks it.
@@ -147,6 +152,8 @@ module Hecks
147
152
  # @param root [String] the checkout
148
153
  # @return [String] the scratch directory
149
154
  def scratch_crate(root)
155
+ abort NOT_MATERIALIZED unless File.directory?(File.join(root, "rust/src/generated/meta"))
156
+
150
157
  scratch = Dir.mktmpdir("regen-codegen-check")
151
158
  FileUtils.mkdir_p(File.join(scratch, "src"))
152
159
  FileUtils.cp_r(File.join(root, "rust/src/generated"), File.join(scratch, "src/generated"))
@@ -13,7 +13,7 @@ module Hecks
13
13
  # The flags that take a value, by the keyword of `projection` each one sets.
14
14
  VALUE_FLAGS = {
15
15
  out: "--out=DIR", template: "--template=FILE", cms: "--cms=DIR", root_dir: "--root=DIR",
16
- extension: "--extension=EXT"
16
+ editor: "--editor=DIR", extension: "--extension=EXT"
17
17
  }.freeze
18
18
 
19
19
  # @param argv [Array<String>] the command line, consumed down to the project directory