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
@@ -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
@@ -167,6 +167,7 @@ Hecks.bluebook "Site" do
167
167
  end
168
168
 
169
169
  lifecycle :status, default: "requested" do
170
+ mark :failure, "faulted"
170
171
  transition "Complete" => "projected", from: "requested"
171
172
  transition "Fault" => "faulted", from: "requested"
172
173
  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] || {}
@@ -5,6 +5,7 @@ require "open3"
5
5
  require "hecks/vocabulary"
6
6
  require_relative "../tools"
7
7
  require_relative "ci_gates"
8
+ require_relative "release_only"
8
9
 
9
10
  module Hecks
10
11
  module Tools
@@ -43,6 +44,8 @@ module Hecks
43
44
  # @param env [Hash{String => String}] the runner's environment
44
45
  # @return [Boolean] whether the gated job should run
45
46
  def touched?(gate, root:, env:)
47
+ return !inherits?(gate, root: root, env: env) if gate.fetch("mode") == "release_only"
48
+
46
49
  changed, reason = change_set(gate, root: root, env: env)
47
50
  if reason
48
51
  explain(gate, reason)
@@ -54,6 +57,38 @@ module Hecks
54
57
  gate.fetch("mode") == "touches" ? matches.any? : matches.any?(false)
55
58
  end
56
59
 
60
+ # Whether the change is only a release bump on a base whose required checks all passed, so
61
+ # the run may inherit the base's certification (`ReleaseOnly`). Anything unconfirmed answers
62
+ # false and the suite runs.
63
+ #
64
+ # @param gate [Hash{String => String}] the `CiGate` row
65
+ # @return [Boolean]
66
+ def inherits?(gate, root:, env:)
67
+ base = base_of(gate, root: root, env: env)
68
+ reason = inheritance_refusal(base, root: root, env: env)
69
+ warn "decide_ci_gate: #{reason}: running the suite rather than inheriting certification" if reason
70
+ reason.nil?
71
+ end
72
+
73
+ # @return [String, nil] why the change cannot inherit, nil when it can
74
+ def inheritance_refusal(base, root:, env:)
75
+ return "no usable base to diff against" if base.nil? || base.empty? || base == NO_COMMIT
76
+
77
+ changes = ReleaseOnly.changes(base, env.fetch("GITHUB_SHA", "HEAD"), root: root)
78
+ return "git diff itself failed" if changes.nil?
79
+ return "the change is not only release files and lines" unless ReleaseOnly.release_only?(changes)
80
+
81
+ base_refusal(base, env)
82
+ end
83
+
84
+ # @return [String, nil] why the base is not certified, nil when it is
85
+ def base_refusal(base, env)
86
+ runs = ReleaseOnly.check_runs(env.fetch("GITHUB_REPOSITORY", ""), base, env: env)
87
+ return "the base's check runs could not be read" if runs.nil?
88
+
89
+ "the base is not fully certified" unless ReleaseOnly.certified?(runs)
90
+ end
91
+
57
92
  # @return [Array(Array<String>, nil), Array(nil, String)] the changed paths, or the reason the
58
93
  # change cannot be confirmed
59
94
  def change_set(gate, root:, env:)
@@ -46,7 +46,7 @@ module Hecks
46
46
 
47
47
  # The values a row's `mode` and `push` may take: the language holds one closed set to a value
48
48
  # object, so the rest are held here.
49
- MODES = %w[touches skips_unless].freeze
49
+ MODES = %w[touches skips_unless release_only].freeze
50
50
  PUSHES = %w[skip before_sha].freeze
51
51
 
52
52
  # @return [Array<Hash{String => String}>] the `CiGate` rows
@@ -111,16 +111,35 @@ module Hecks
111
111
  " #{name}:",
112
112
  " runs-on: ubuntu-latest",
113
113
  " timeout-minutes: 10",
114
+ *job_permissions(gate),
114
115
  *job_condition(gate)]
115
116
  end
116
117
 
117
118
  # @return [Array<String>] the deciding step and the closing marker
118
119
  def job_footer(gate, name)
119
120
  [" name: #{quoted(gate.fetch("label"))}",
121
+ *job_env(gate),
120
122
  " run: bundle exec exe/hecks regeneration_run.decide_ci_gate gate=#{name} --wait",
121
123
  " # END GENERATED ci_gate #{name}"]
122
124
  end
123
125
 
126
+ # A `release_only` gate reads the base commit's check runs through the API, so its job may
127
+ # read checks and nothing more.
128
+ #
129
+ # @return [Array<String>] the job's `permissions:` lines, none for any other mode
130
+ def job_permissions(gate)
131
+ return [] unless gate.fetch("mode") == "release_only"
132
+
133
+ [" permissions:", " contents: read", " checks: read"]
134
+ end
135
+
136
+ # @return [Array<String>] the deciding step's `env:` lines, none unless the gate calls the API
137
+ def job_env(gate)
138
+ return [] unless gate.fetch("mode") == "release_only"
139
+
140
+ [" env:", " GH_TOKEN: ${{ github.token }}"]
141
+ end
142
+
124
143
  # @param gate [Hash{String => String}] a `CiGate` row
125
144
  # @return [Array<String>] the job-level `if:` lines for a gate that skips push runs
126
145
  def job_condition(gate)
@@ -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
@@ -18,6 +18,7 @@ module Hecks
18
18
  def projection
19
19
  rulesets.merge(workflow(Lanes::WORKFLOW, "follows") { |lanes| Lanes.workflow(lanes) })
20
20
  .merge(workflow(Lanes::WATCH_WORKFLOW, "alert_after") { |lanes| WatchWorkflow.text(lanes) })
21
+ .merge(prebuilt)
21
22
  end
22
23
 
23
24
  # @param files [Hash{String => String}] the projection
@@ -44,6 +45,13 @@ module Hecks
44
45
  Lanes.rulesets.to_h { |name, ruleset| [ruleset_path(name), "#{JSON.pretty_generate(ruleset)}\n"] }
45
46
  end
46
47
 
48
+ # The workflow that publishes each `PrebuiltBinary` row.
49
+ def prebuilt
50
+ Hecks::Vocabulary.rows("PrebuiltBinary").to_h do |row|
51
+ [File.join(@root, PrebuiltWorkflow.path(row)), PrebuiltWorkflow.text(row)]
52
+ end
53
+ end
54
+
47
55
  # The workflow at `path` for the lanes whose `column` is set, or no file if none is.
48
56
  def workflow(path, column)
49
57
  lanes = Lanes.lanes.reject { |lane| lane[column].to_s.empty? }
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hecks
4
+ module Tools
5
+ module Lanes
6
+ # The workflow that builds and publishes one `PrebuiltBinary` row (ADR 0110): after a push to
7
+ # `main` that touches the row's crate, it builds the binary on the row's runner and, unless
8
+ # a release for that key already exists, publishes it with its sha256. What the key is and
9
+ # where a client looks is `Hecks::RustBuild::PrebuiltBinary`, not anything written here.
10
+ module PrebuiltWorkflow
11
+ module_function
12
+
13
+ # @param row [Hash{String => String}] a `PrebuiltBinary` row
14
+ # @return [String] the path of the workflow, relative to the checkout
15
+ def path(row) = ".github/workflows/publish-#{row["name"]}.yml"
16
+
17
+ # @param row [Hash{String => String}] a `PrebuiltBinary` row
18
+ # @return [String] the workflow
19
+ def text(row)
20
+ [*header(row), *trigger(row), *job(row)].join("\n") << "\n"
21
+ end
22
+
23
+ def header(row)
24
+ name = row["name"]
25
+ ["name: Publish #{name}", "",
26
+ "# Generated by hecks project_lanes from the PrebuiltBinary rows of the Vocabulary chapter. Do not hand-edit.",
27
+ "#",
28
+ "# Builds #{row["executable"]} from #{row["crate"]} for #{row["target"]} and publishes it as the release",
29
+ "# #{name}-<key>, where the key is a hash of the crate's build inputs. A client that needs the same",
30
+ "# bytes downloads it instead of compiling (Hecks::RustBuild::PrebuiltBinary); a key that already has a",
31
+ "# release is left alone, so a push that changed nothing the build reads publishes nothing."]
32
+ end
33
+
34
+ def trigger(row)
35
+ ["on:", " push:", " branches: [main]", " paths:", " - \"#{row["crate"]}/**\"",
36
+ " - \".github/workflows/publish-#{row["name"]}.yml\"",
37
+ " - \"lib/hecks/rust_build/prebuilt_binary.rb\"",
38
+ " workflow_dispatch: {}", "",
39
+ "concurrency:", " group: publish-#{row["name"]}", " cancel-in-progress: false", "",
40
+ "permissions:", " contents: write", ""]
41
+ end
42
+
43
+ def job(row)
44
+ ["jobs:", " publish:", " runs-on: #{row["runner"]}", " timeout-minutes: 40", " steps:",
45
+ " - uses: actions/checkout@v4", " - uses: ./.github/actions/setup-ruby", *key_step(row),
46
+ *build_steps(row), *release_step(row)]
47
+ end
48
+
49
+ def key_step(row)
50
+ [" - name: Name the release", " id: key", " run: |",
51
+ " key=$(bundle exec ruby -Ilib -rhecks/rust_build/prebuilt_binary -e \\",
52
+ " 'puts Hecks::RustBuild::PrebuiltBinary.key(ARGV.fetch(0))' #{row["crate"]})",
53
+ " tag=#{row["name"]}-$key",
54
+ " echo \"tag=$tag\" >> \"$GITHUB_OUTPUT\"",
55
+ " if gh release view \"$tag\" > /dev/null 2>&1; then echo \"exists=true\" >> \"$GITHUB_OUTPUT\"; fi",
56
+ " env:", " GH_TOKEN: ${{ github.token }}"]
57
+ end
58
+
59
+ def build_steps(row)
60
+ [" - name: Build #{row["executable"]}", " if: steps.key.outputs.exists != 'true'",
61
+ " working-directory: #{row["crate"]}", " run: |",
62
+ " rustup toolchain install stable --profile minimal",
63
+ " rustup run stable cargo build --release --target #{row["target"]} --bin #{row["executable"]}"]
64
+ end
65
+
66
+ def release_step(row)
67
+ asset = "#{row["executable"]}-#{row["target"]}"
68
+ [" - name: Publish the release", " if: steps.key.outputs.exists != 'true'",
69
+ " env:", " GH_TOKEN: ${{ github.token }}", " TAG: ${{ steps.key.outputs.tag }}",
70
+ " run: |",
71
+ " mkdir out",
72
+ " cp #{row["crate"]}/target/#{row["target"]}/release/#{row["executable"]} out/#{asset}",
73
+ " (cd out && sha256sum #{asset} > #{asset}.sha256)",
74
+ " gh release create \"$TAG\" out/#{asset} out/#{asset}.sha256 --prerelease --target \"$GITHUB_SHA\" \\",
75
+ " --title \"$TAG\" \\",
76
+ " --notes \"#{row["executable"]} for #{row["target"]}, built from #{row["crate"]} at $GITHUB_SHA.\""]
77
+ end
78
+ end
79
+ end
80
+ end
81
+ 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
 
@@ -78,5 +78,6 @@ require_relative "lanes/rows"
78
78
  require_relative "lanes/ruleset"
79
79
  require_relative "lanes/workflow"
80
80
  require_relative "lanes/watch_workflow"
81
+ require_relative "lanes/prebuilt_workflow"
81
82
  require_relative "lanes/files"
82
83
  require_relative "lanes/live"
@@ -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"))