hecks 3.10.0 → 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 (481) 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 +18 -2
  116. data/lib/hecks/doc/reference/rendering.rb +6 -3
  117. data/lib/hecks/forms/app/commands.rb +8 -7
  118. data/lib/hecks/forms/app/queries.rb +2 -1
  119. data/lib/hecks/forms/app.rb +1 -1
  120. data/lib/hecks/forms/record_renderer.rb +1 -1
  121. data/lib/hecks/framework/bluebook/privacy.bluebook +11 -0
  122. data/lib/hecks/fuzzing/concurrent_dispatch.rb +4 -1
  123. data/lib/hecks/fuzzing/failure_triage.rb +2 -1
  124. data/lib/hecks/fuzzing/mutation/run.rb +11 -4
  125. data/lib/hecks/fuzzing/properties/catalog.rb +6 -4
  126. data/lib/hecks/fuzzing/properties/guaranteed_by_construction.rb +18 -11
  127. data/lib/hecks/fuzzing/properties/guards.rb +1 -1
  128. data/lib/hecks/fuzzing/self_consistency/saga_redelivery.rb +1 -1
  129. data/lib/hecks/fuzzing/self_consistency.rb +6 -2
  130. data/lib/hecks/fuzzing/shrinker.rb +3 -1
  131. data/lib/hecks/fuzzing/value_generator.rb +19 -5
  132. data/lib/hecks/gate/stages.yml +4 -10
  133. data/lib/hecks/grammar/evolve.rb +1 -1
  134. data/lib/hecks/grammar/expression_operators.json +372 -0
  135. data/lib/hecks/grammar/operators.rb +3 -1
  136. data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +10 -10
  137. data/lib/hecks/hecks/adapters/codebase/inspection/rubycritic.rb +35 -0
  138. data/lib/hecks/hecks/adapters/codebase/inspection.rb +104 -0
  139. data/lib/hecks/hecks/adapters/codebase/publishing.rb +2 -1
  140. data/lib/hecks/hecks/adapters/codebase/release_facts.rb +12 -2
  141. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +2 -1
  142. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +1 -1
  143. data/lib/hecks/hecks/adapters/cost_explorer.rb +8 -5
  144. data/lib/hecks/hecks/adapters/deploy_toolchain/statuses.rb +2 -1
  145. data/lib/hecks/hecks/adapters/finding_github.rb +13 -6
  146. data/lib/hecks/hecks/adapters/first_admin.rb +2 -2
  147. data/lib/hecks/hecks/adapters/github_rulesets.rb +6 -3
  148. data/lib/hecks/hecks/adapters/in_process_boot.rb +1 -1
  149. data/lib/hecks/hecks/adapters/journal_store/compaction.rb +1 -1
  150. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +10 -20
  151. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +28 -5
  152. data/lib/hecks/hecks/adapters/local_files.rb +2 -2
  153. data/lib/hecks/hecks/adapters/rehearsal/audit_report.rb +107 -0
  154. data/lib/hecks/hecks/adapters/rehearsal/census.rb +71 -0
  155. data/lib/hecks/hecks/adapters/rehearsal/declaration.rb +133 -0
  156. data/lib/hecks/hecks/adapters/rehearsal/environment.rb +83 -0
  157. data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +142 -0
  158. data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +96 -0
  159. data/lib/hecks/hecks/adapters/rehearsal/postgres_census.rb +100 -0
  160. data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +69 -0
  161. data/lib/hecks/hecks/adapters/rehearsal/postgres_store.rb +129 -0
  162. data/lib/hecks/hecks/adapters/rehearsal/rows.rb +41 -0
  163. data/lib/hecks/hecks/adapters/rehearsal/rust_audit.rb +83 -0
  164. data/lib/hecks/hecks/adapters/rehearsal/subject.rb +104 -0
  165. data/lib/hecks/hecks/adapters/rehearsal.rb +54 -0
  166. data/lib/hecks/hecks/adapters/rehearsal_store.adapter +7 -0
  167. data/lib/hecks/hecks/adapters/rehearsal_store.rb +81 -0
  168. data/lib/hecks/hecks/adapters/terminal.rb +13 -11
  169. data/lib/hecks/hecks/codebase.behaviors +13 -1
  170. data/lib/hecks/hecks/codebase.bluebook +239 -5
  171. data/lib/hecks/hecks/custodian.behaviors +24 -6
  172. data/lib/hecks/hecks/custodian.bluebook +6 -1227
  173. data/lib/hecks/hecks/deploy.behaviors +1 -1
  174. data/lib/hecks/hecks/deploy.world +1 -3
  175. data/lib/hecks/hecks/hecks.behaviors +1 -1
  176. data/lib/hecks/hecks/hecks.hecksagon +53 -18
  177. data/lib/hecks/hecks/hecks.world +10 -10
  178. data/lib/hecks/hecks/rehearsal.bluebook +477 -0
  179. data/lib/hecks/hecks/site.behaviors +1 -1
  180. data/lib/hecks/hecks/site.world +0 -1
  181. data/lib/hecks/hecks/tooling.bluebook +1238 -0
  182. data/lib/hecks/indifferent_key.rb +20 -0
  183. data/lib/hecks/language/adapter.bluebook +13 -3
  184. data/lib/hecks/language/bluebook/aggregate.bluebook +23 -0
  185. data/lib/hecks/language/bluebook/bluebook.bluebook +15 -0
  186. data/lib/hecks/language/bluebook/entity.bluebook +18 -0
  187. data/lib/hecks/language/bluebook/policy.bluebook +9 -1
  188. data/lib/hecks/language/bluebook/query.bluebook +1 -1
  189. data/lib/hecks/language/bluebook/vocabulary.bluebook +11 -4
  190. data/lib/hecks/language/hecksagon/domain_port.bluebook +1 -1
  191. data/lib/hecks/language/hecksagon/hecksagon.bluebook +22 -0
  192. data/lib/hecks/language/oidc.json +10 -0
  193. data/lib/hecks/language/port.bluebook +4 -4
  194. data/lib/hecks/literal.rb +12 -3
  195. data/lib/hecks/ports/key_vault.rb +7 -2
  196. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +21 -10
  197. data/lib/hecks/ports/persistence/plugins/era/postgres_era/boot.rb +4 -2
  198. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +2 -1
  199. data/lib/hecks/ports/persistence/repository_factory.rb +6 -3
  200. data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +29 -0
  201. data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +1 -1
  202. data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
  203. data/lib/hecks/projections/deploy/shared.rb +5 -2
  204. data/lib/hecks/projections/model/deviations.rb +2 -2
  205. data/lib/hecks/projections/model.rb +2 -2
  206. data/lib/hecks/projections/oidc.rb +13 -1
  207. data/lib/hecks/projections/shape.rb +5 -2
  208. data/lib/hecks/projections/site/cms_editor/attributes.rb +26 -6
  209. data/lib/hecks/projections/site/cms_editor/blocks.rb +157 -0
  210. data/lib/hecks/projections/site/cms_editor/checks.rb +14 -1
  211. data/lib/hecks/projections/site/cms_editor/clearing.rb +70 -0
  212. data/lib/hecks/projections/site/cms_editor/color.rb +124 -0
  213. data/lib/hecks/projections/site/cms_editor/composition.rb +42 -0
  214. data/lib/hecks/projections/site/cms_editor/destructive.rb +61 -0
  215. data/lib/hecks/projections/site/cms_editor/drafts.rb +102 -0
  216. data/lib/hecks/projections/site/cms_editor/hints.rb +74 -0
  217. data/lib/hecks/projections/site/cms_editor/icons.rb +86 -0
  218. data/lib/hecks/projections/site/cms_editor/key_kinds.rb +31 -0
  219. data/lib/hecks/projections/site/cms_editor/limits.rb +72 -0
  220. data/lib/hecks/projections/site/cms_editor/media.rb +1 -1
  221. data/lib/hecks/projections/site/cms_editor/moment.rb +34 -0
  222. data/lib/hecks/projections/site/cms_editor/palette.rb +115 -0
  223. data/lib/hecks/projections/site/cms_editor/pickers.rb +85 -0
  224. data/lib/hecks/projections/site/cms_editor/preview.rb +91 -0
  225. data/lib/hecks/projections/site/cms_editor/relations.rb +92 -0
  226. data/lib/hecks/projections/site/cms_editor/scale_checks.rb +66 -0
  227. data/lib/hecks/projections/site/cms_editor/scheduling.rb +150 -0
  228. data/lib/hecks/projections/site/cms_editor/schema.rb +96 -19
  229. data/lib/hecks/projections/site/cms_editor/setting.rb +52 -9
  230. data/lib/hecks/projections/site/cms_editor/targets.rb +86 -0
  231. data/lib/hecks/projections/site/cms_editor/templates/package.json.tmpl +18 -1
  232. data/lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl +251 -57
  233. data/lib/hecks/projections/site/cms_editor/templates/src/assets.ts.tmpl +98 -0
  234. data/lib/hecks/projections/site/cms_editor/templates/src/auth/membership.ts.tmpl +32 -24
  235. data/lib/hecks/projections/site/cms_editor/templates/src/browser/app.css.tmpl +412 -0
  236. data/lib/hecks/projections/site/cms_editor/templates/src/browser/autosave.js.tmpl +144 -0
  237. data/lib/hecks/projections/site/cms_editor/templates/src/browser/blocks.js.tmpl +500 -0
  238. data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_doc.js.tmpl +175 -0
  239. data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_editor.js.tmpl +418 -0
  240. data/lib/hecks/projections/site/cms_editor/templates/src/browser/epoch.js.tmpl +61 -0
  241. data/lib/hecks/projections/site/cms_editor/templates/src/browser/forms.js.tmpl +210 -0
  242. data/lib/hecks/projections/site/cms_editor/templates/src/browser/lists.js.tmpl +40 -0
  243. data/lib/hecks/projections/site/cms_editor/templates/src/browser/main.js.tmpl +26 -0
  244. data/lib/hecks/projections/site/cms_editor/templates/src/browser/media_picker.js.tmpl +232 -0
  245. data/lib/hecks/projections/site/cms_editor/templates/src/browser/moments.js.tmpl +73 -0
  246. data/lib/hecks/projections/site/cms_editor/templates/src/browser/pickers.js.tmpl +152 -0
  247. data/lib/hecks/projections/site/cms_editor/templates/src/browser/preview.js.tmpl +98 -0
  248. data/lib/hecks/projections/site/cms_editor/templates/src/browser/shell.js.tmpl +140 -0
  249. data/lib/hecks/projections/site/cms_editor/templates/src/browser/toast.js.tmpl +66 -0
  250. data/lib/hecks/projections/site/cms_editor/templates/src/choices.ts.tmpl +99 -0
  251. data/lib/hecks/projections/site/cms_editor/templates/src/commands.ts.tmpl +78 -24
  252. data/lib/hecks/projections/site/cms_editor/templates/src/config.ts.tmpl +6 -0
  253. data/lib/hecks/projections/site/cms_editor/templates/src/flash.ts.tmpl +52 -0
  254. data/lib/hecks/projections/site/cms_editor/templates/src/host.ts.tmpl +19 -2
  255. data/lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl +31 -8
  256. data/lib/hecks/projections/site/cms_editor/templates/src/names.ts.tmpl +36 -0
  257. data/lib/hecks/projections/site/cms_editor/templates/src/schema.ts.tmpl +131 -2
  258. data/lib/hecks/projections/site/cms_editor/templates/src/ui/availability.ts.tmpl +15 -0
  259. data/lib/hecks/projections/site/cms_editor/templates/src/ui/block_list.js.tmpl +213 -0
  260. data/lib/hecks/projections/site/cms_editor/templates/src/ui/blocks.ts.tmpl +275 -0
  261. data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_model.js.tmpl +8 -5
  262. data/lib/hecks/projections/site/cms_editor/templates/src/ui/detail.ts.tmpl +88 -0
  263. data/lib/hecks/projections/site/cms_editor/templates/src/ui/dialogs.ts.tmpl +43 -0
  264. data/lib/hecks/projections/site/cms_editor/templates/src/ui/fields.ts.tmpl +229 -34
  265. data/lib/hecks/projections/site/cms_editor/templates/src/ui/html.ts.tmpl +40 -81
  266. data/lib/hecks/projections/site/cms_editor/templates/src/ui/icons.ts.tmpl +15 -0
  267. data/lib/hecks/projections/site/cms_editor/templates/src/ui/input.ts.tmpl +29 -12
  268. data/lib/hecks/projections/site/cms_editor/templates/src/ui/links.ts.tmpl +100 -0
  269. data/lib/hecks/projections/site/cms_editor/templates/src/ui/moments.ts.tmpl +44 -0
  270. data/lib/hecks/projections/site/cms_editor/templates/src/ui/outline.ts.tmpl +53 -17
  271. data/lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl +178 -88
  272. data/lib/hecks/projections/site/cms_editor/templates/src/ui/paging.ts.tmpl +82 -0
  273. data/lib/hecks/projections/site/cms_editor/templates/src/ui/pickers.ts.tmpl +110 -0
  274. data/lib/hecks/projections/site/cms_editor/templates/src/ui/preview.ts.tmpl +87 -0
  275. data/lib/hecks/projections/site/cms_editor/templates/src/ui/related.ts.tmpl +97 -0
  276. data/lib/hecks/projections/site/cms_editor/templates/src/ui/schedule.ts.tmpl +160 -0
  277. data/lib/hecks/projections/site/cms_editor/templates/src/ui/shell.ts.tmpl +211 -0
  278. data/lib/hecks/projections/site/cms_editor/templates/src/ui/table.ts.tmpl +151 -0
  279. data/lib/hecks/projections/site/cms_editor/templates/src/ui/theme.js.tmpl +16 -0
  280. data/lib/hecks/projections/site/cms_editor/templates/src/ui/values.ts.tmpl +69 -0
  281. data/lib/hecks/projections/site/cms_editor/templates/src/ui/words.ts.tmpl +97 -0
  282. data/lib/hecks/projections/site/cms_editor/templates/src/ui/world.ts.tmpl +35 -0
  283. data/lib/hecks/projections/site/cms_editor/templates/tsconfig.json.tmpl +2 -1
  284. data/lib/hecks/projections/site/cms_editor/theme.rb +29 -0
  285. data/lib/hecks/projections/site/cms_editor/theme_checks.rb +57 -0
  286. data/lib/hecks/projections/site/cms_editor.rb +49 -23
  287. data/lib/hecks/projections/site/role_probe.rb +2 -0
  288. data/lib/hecks/projector/cli_audience.rb +2 -1
  289. data/lib/hecks/projector/cli_projector/listing.rb +1 -1
  290. data/lib/hecks/projector/cli_projector/option_specs.rb +1 -1
  291. data/lib/hecks/projector/docs_projector/closing.rb +1 -1
  292. data/lib/hecks/projector/docs_projector.rb +1 -1
  293. data/lib/hecks/projector/exporter/bindings.rb +40 -10
  294. data/lib/hecks/projector/exporter/capability_values.rb +55 -0
  295. data/lib/hecks/projector/narrate_projector/reactions.rb +1 -1
  296. data/lib/hecks/projector/target.rb +11 -0
  297. data/lib/hecks/projector.rb +32 -5
  298. data/lib/hecks/quality_control/adapters/github_checks.rb +12 -8
  299. data/lib/hecks/quality_control/adapters/github_issues.rb +8 -4
  300. data/lib/hecks/quality_control/cli/qa_open_pr.rb +2 -2
  301. data/lib/hecks/quality_control/cli/qa_sweep/checks/shrinking.rb +1 -1
  302. data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +1 -1
  303. data/lib/hecks/quality_control/cli/qa_sweep.rb +1 -1
  304. data/lib/hecks/quality_control/quality_control.bluebook +6 -2
  305. data/lib/hecks/release/approval.rb +64 -0
  306. data/lib/hecks/router/{door.rb → aggregate_reader.rb} +5 -4
  307. data/lib/hecks/router/namespace_installer.rb +16 -16
  308. data/lib/hecks/router.rb +1 -1
  309. data/lib/hecks/runtime/best_effort.rb +22 -0
  310. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +12 -2
  311. data/lib/hecks/runtime/command_interpreter.rb +3 -2
  312. data/lib/hecks/runtime/command_rules/emission.rb +1 -1
  313. data/lib/hecks/runtime/dispatcher.rb +4 -4
  314. data/lib/hecks/runtime/entity_element/location.rb +1 -1
  315. data/lib/hecks/runtime/event.rb +5 -0
  316. data/lib/hecks/runtime/identity.rb +7 -6
  317. data/lib/hecks/runtime/interpreting.rb +2 -1
  318. data/lib/hecks/runtime/invocation_builder.rb +1 -1
  319. data/lib/hecks/runtime/loader/boot_steps.rb +8 -5
  320. data/lib/hecks/runtime/loader.rb +10 -10
  321. data/lib/hecks/runtime/policy_interpreter/arguments.rb +7 -4
  322. data/lib/hecks/runtime/policy_interpreter/fan_out.rb +3 -3
  323. data/lib/hecks/runtime/policy_interpreter.rb +6 -6
  324. data/lib/hecks/runtime/port_operation_interpreter.rb +1 -1
  325. data/lib/hecks/runtime/reaction_invocation.rb +1 -1
  326. data/lib/hecks/runtime/rebuild_sweep.rb +11 -1
  327. data/lib/hecks/runtime/registry/ask_verification.rb +35 -0
  328. data/lib/hecks/runtime/registry/hecksagon_rules.rb +10 -0
  329. data/lib/hecks/runtime/registry/merging.rb +1 -1
  330. data/lib/hecks/runtime/registry/providers.rb +16 -0
  331. data/lib/hecks/runtime/registry/read_repository.rb +6 -4
  332. data/lib/hecks/runtime/registry/verification.rb +4 -1
  333. data/lib/hecks/runtime/registry/world_defaults.rb +29 -0
  334. data/lib/hecks/runtime/registry.rb +1 -1
  335. data/lib/hecks/runtime/saga_interpreter/compensation.rb +1 -1
  336. data/lib/hecks/runtime/saga_interpreter/delivery.rb +4 -4
  337. data/lib/hecks/runtime/saga_interpreter/transitions.rb +1 -1
  338. data/lib/hecks/runtime/saga_interpreter.rb +3 -3
  339. data/lib/hecks/runtime/tenant_check.rb +5 -4
  340. data/lib/hecks/runtime/value/coercion.rb +2 -2
  341. data/lib/hecks/runtime/value/validation.rb +16 -4
  342. data/lib/hecks/runtime.rb +9 -9
  343. data/lib/hecks/rust_build/project_rust/target_ir.rb +1 -1
  344. data/lib/hecks/rust_build/wasm.rb +1 -1
  345. data/lib/hecks/rust_build/wasm_browser.rb +1 -1
  346. data/lib/hecks/rust_build.rb +11 -0
  347. data/lib/hecks/served_options.rb +53 -0
  348. data/lib/hecks/site/bluebook/site.bluebook +1 -0
  349. data/lib/hecks/storehouse/audit.rb +1 -1
  350. data/lib/hecks/storehouse/dispatching.rb +8 -6
  351. data/lib/hecks/storehouse/introspection.rb +2 -2
  352. data/lib/hecks/storehouse/querying.rb +6 -4
  353. data/lib/hecks/storehouse.rb +4 -4
  354. data/lib/hecks/tools/comment_style/source_file.rb +4 -1
  355. data/lib/hecks/tools/deploy_recipe_lint/fixtures.rb +4 -1
  356. data/lib/hecks/tools/lanes/rows.rb +6 -0
  357. data/lib/hecks/tools/oidc_manifests.rb +4 -5
  358. data/lib/hecks/tools/regeneration_run.rb +11 -4
  359. data/lib/hecks/tools/site_routes/editor_files.rb +12 -5
  360. data/lib/hecks/tools/tenant_provisioning.rb +2 -2
  361. data/lib/hecks/tools/tools_doc.rb +4 -4
  362. data/lib/hecks/version.rb +1 -1
  363. data/lib/hecks/vocabulary.rb +4 -4
  364. data/lib/hecks.rb +15 -15
  365. data/lib/rubocop/cop/hecks/env_dump.rb +69 -0
  366. data/lib/rubocop/cop/hecks/monotonic_duration.rb +53 -0
  367. data/lib/rubocop/cop/hecks/no_wall_clock_in_runtime.rb +34 -0
  368. data/lib/rubocop/cop/hecks/raw_shell_interpolation.rb +79 -0
  369. data/lib/rubocop/cop/hecks/sleep_in_spec.rb +34 -0
  370. data/lib/rubocop/cop/hecks/swallowed_rescue.rb +37 -0
  371. data/lib/rubocop/cop/hecks/symbol_string_key_mix.rb +50 -0
  372. data/lib/rubocop/cop/hecks/untyped_raise.rb +37 -0
  373. data/prebuilt/05c358d38d661a3774f813d49c66f5b68939af94432d66257a56f49ee2598994.marshal +0 -0
  374. data/prebuilt/26c40c61f09b09b11651c64668eda3ceb180f83cf2a3802d3033d2fd99ac841b.marshal +0 -0
  375. data/prebuilt/verdicts-230ac18c25abfd3d92ede032bee2661a4c2cd2773ab0cf0e2ae52546ba2f7af9.json +1 -0
  376. data/rust/.gitignore +6 -0
  377. data/rust/Cargo.toml +6 -0
  378. data/rust/build/src/binding_pass.rs +103 -0
  379. data/rust/build/src/cargo_sync.rs +6 -0
  380. data/rust/build/src/lineage_pass.rs +3 -3
  381. data/rust/build/src/main.rs +17 -5
  382. data/rust/build/src/pipeline.rs +48 -5
  383. data/rust/build/src/seams_pass.rs +123 -0
  384. data/rust/build/src/translation_pass.rs +167 -0
  385. data/rust/codegen/src/asks.rs +103 -0
  386. data/rust/codegen/src/commands.rs +13 -8
  387. data/rust/codegen/src/constraints.rs +25 -0
  388. data/rust/codegen/src/domain_generator.rs +2 -0
  389. data/rust/codegen/src/expr_emitter.rs +13 -0
  390. data/rust/codegen/src/json_codec.rs +54 -15
  391. data/rust/codegen/src/main.rs +1 -0
  392. data/rust/codegen/src/mutations.rs +128 -3
  393. data/rust/codegen/src/queries.rs +11 -2
  394. data/rust/codegen/src/reactions.rs +1 -1
  395. data/rust/codegen/src/types.rs +166 -8
  396. data/rust/host/HECKS_RELEASE +1 -1
  397. data/rust/host/src/api.rs +4 -4
  398. data/rust/host/src/bin/validate_harness.rs +43 -0
  399. data/rust/host/src/boundary_fuzz/expr_json.rs +2 -2
  400. data/rust/host/src/boundary_fuzz/ir.rs +1 -0
  401. data/rust/host/src/boundary_fuzz/server.rs +1 -1
  402. data/rust/host/src/checkout.rs +35 -19
  403. data/rust/host/src/commerce_ir.rs +408 -2
  404. data/rust/host/src/expr_json.rs +118 -0
  405. data/rust/host/src/mint.rs +1 -1
  406. data/rust/host/src/payments/tests.rs +27 -1
  407. data/rust/host/src/payments.rs +12 -4
  408. data/rust/host/src/query_step.rs +22 -4
  409. data/rust/host/src/reference_validate.rs +653 -108
  410. data/rust/host/src/resend.rs +2 -0
  411. data/rust/host/src/server.rs +19 -6
  412. data/rust/host/src/ui_schema.rs +132 -5
  413. data/rust/host/src/web/newsletter.rs +7 -8
  414. data/rust/host/src/web/newsletter_send.rs +38 -13
  415. data/rust/host/src/web/registrations.rs +229 -26
  416. data/rust/host/src/web.rs +3 -3
  417. data/rust/parser/src/emit.rs +38 -6
  418. data/rust/parser/src/expr/ast_json.rs +7 -1
  419. data/rust/parser/src/expr/resolver.rs +171 -6
  420. data/rust/parser/src/ir.rs +7 -0
  421. data/rust/parser/src/keywords.rs +24 -0
  422. data/rust/parser/src/main.rs +3 -0
  423. data/rust/parser/src/parse/aggregate.rs +2 -1
  424. data/rust/parser/src/parse/chapter.rs +2 -2
  425. data/rust/parser/src/parse/command.rs +2 -0
  426. data/rust/parser/src/parse/hecksagon.rs +5 -2
  427. data/rust/parser/src/parse/lifecycle.rs +81 -0
  428. data/rust/parser/src/parse/mod.rs +15 -1
  429. data/rust/parser/src/parse/policy.rs +13 -2
  430. data/rust/parser/src/parse/value_object.rs +13 -8
  431. data/rust/parser/src/ruby_value.rs +1 -1
  432. data/rust/src/exemplar/commands.rs +4 -4
  433. data/rust/src/exemplar/constraints.rs +1 -1
  434. data/rust/src/exemplar/json.rs +43 -1
  435. data/rust/src/kernel/cli.rs +7 -5
  436. data/rust/src/kernel/dispatch.rs +2 -2
  437. data/rust/src/kernel/dispatch_guard_tests.rs +1 -1
  438. data/rust/src/kernel/expr.rs +66 -3
  439. data/rust/src/kernel/expression_operators/arithmetic.rs +130 -5
  440. data/rust/src/kernel/expression_operators/text.rs +26 -2
  441. data/rust/src/kernel/json.rs +15 -0
  442. data/rust/src/kernel/mod.rs +1 -1
  443. data/rust/src/kernel/orchestrate.rs +54 -5
  444. data/rust/src/kernel/orchestrate_guard_tests.rs +67 -0
  445. data/rust/src/kernel/pattern.rs +60 -0
  446. data/rust/src/kernel/reference_lookup.rs +90 -7
  447. metadata +140 -38
  448. data/lib/hecks/doors/cli_door/nesting.rb +0 -34
  449. data/lib/hecks/doors/cli_door/shorthand.rb +0 -85
  450. data/lib/hecks/doors/cli_door.rb +0 -124
  451. data/lib/hecks/doors/cli_runner/answers.rb +0 -138
  452. data/lib/hecks/doors/cli_runner/resolution.rb +0 -146
  453. data/lib/hecks/doors/cli_runner/settling.rb +0 -115
  454. data/lib/hecks/doors/cli_runner/streaming.rb +0 -90
  455. data/lib/hecks/doors/cli_runner/suggestions.rb +0 -43
  456. data/lib/hecks/doors/cli_runner.rb +0 -66
  457. data/lib/hecks/doors/command_request.rb +0 -119
  458. data/lib/hecks/doors/handle.rb +0 -208
  459. data/lib/hecks/doors/json_door.rb +0 -132
  460. data/lib/hecks/doors/launcher_options.rb +0 -247
  461. data/lib/hecks/doors/mcp_door/properties.rb +0 -47
  462. data/lib/hecks/doors/mcp_door/tool_calls.rb +0 -113
  463. data/lib/hecks/doors/mcp_door/tool_definitions/auditing.rb +0 -51
  464. data/lib/hecks/doors/mcp_door/tool_definitions/calling.rb +0 -69
  465. data/lib/hecks/doors/mcp_door/tool_definitions/reading.rb +0 -97
  466. data/lib/hecks/doors/mcp_door/tool_definitions.rb +0 -15
  467. data/lib/hecks/doors/mcp_door.rb +0 -156
  468. data/lib/hecks/doors/mcp_door_scope/argument_policy.rb +0 -92
  469. data/lib/hecks/doors/mcp_door_scope/env_problems.rb +0 -55
  470. data/lib/hecks/doors/mcp_door_scope/presenter.rb +0 -78
  471. data/lib/hecks/doors/mcp_door_scope.rb +0 -201
  472. data/lib/hecks/doors/mcp_guide_cache.rb +0 -75
  473. data/lib/hecks/doors/ruby_door/aggregate_door.rb +0 -162
  474. data/lib/hecks/doors/ruby_door/chapter.rb +0 -89
  475. data/lib/hecks/doors/ruby_door.rb +0 -80
  476. data/lib/hecks/doors/usage_cache.rb +0 -139
  477. data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_widget.js.tmpl +0 -282
  478. data/lib/hecks/projections/site/cms_editor/templates/src/ui/media_picker.js.tmpl +0 -109
  479. data/prebuilt/c28d6d9db14eea3e17161e9d9c262efee30b256cf97693a7cfd552bce24b2f7f.marshal +0 -0
  480. data/prebuilt/cb375cba61ca0dbe8ddb9739c306510fe05e5f4b7a9b6955caff8224c63ea0e0.marshal +0 -0
  481. data/prebuilt/verdicts-d6d584ad43b5f3cebf88aafbbdbf024c38574acf18e06adffbc555f7786b1c2f.json +0 -1
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "color"
4
+
5
+ module Hecks
6
+ module Projections
7
+ module Site
8
+ module CmsEditor
9
+ # What the `Editor` row's look settings must satisfy: an accent that is a six-digit hex
10
+ # colour, a logo that is a relative path to a picture file the server can read from its
11
+ # own directory, and a brand that is one line of text.
12
+ module ThemeChecks
13
+ # The file types a logo may be.
14
+ LOGO_TYPES = %w[png jpg jpeg webp gif avif svg].freeze
15
+
16
+ # The longest brand the header has room for.
17
+ BRAND_LENGTH = 60
18
+
19
+ module_function
20
+
21
+ # @param row [Hash{Symbol => String}] the row, defaults filled
22
+ # @return [Array<String>] every problem with `brand`, `accent` and `logo`
23
+ def problems(row)
24
+ [*accent_problems(row[:accent].strip), *logo_problems(row[:logo].strip), *brand_problems(row[:brand].strip)]
25
+ end
26
+
27
+ # @return [Array<String>] the problem with an accent that is not blank or six hex digits
28
+ def accent_problems(accent)
29
+ return [] if accent.empty? || Color::HEX.match?(accent)
30
+
31
+ ["accent #{accent.inspect} must be a six-digit hex colour such as #1f7a6d"]
32
+ end
33
+
34
+ # @return [Array<String>] the problem with a logo that is not a safe relative picture path
35
+ def logo_problems(logo)
36
+ return [] if logo.empty? || safe_path?(logo)
37
+
38
+ ["logo #{logo.inspect} must be a relative path to a #{LOGO_TYPES.join(", ")} file, with no .. or hidden part"]
39
+ end
40
+
41
+ # @return [Array<String>] the problem with a brand that is long or has more than one line
42
+ def brand_problems(brand)
43
+ return [] if brand.length <= BRAND_LENGTH && !brand.match?(/[[:cntrl:]]/)
44
+
45
+ ["brand must be one line of at most #{BRAND_LENGTH} characters"]
46
+ end
47
+
48
+ # @return [Boolean] whether `path` is relative, has no hidden part, and is a picture
49
+ def safe_path?(path)
50
+ LOGO_TYPES.include?(File.extname(path).delete_prefix(".").downcase) && !path.start_with?("/") &&
51
+ path.split("/", -1).none? { |part| part.empty? || part.start_with?(".") } && !path.match?(/[\\[:cntrl:]]/)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -5,6 +5,8 @@ require_relative "../../projector"
5
5
  require_relative "cms_editor/setting"
6
6
  require_relative "cms_editor/schema"
7
7
  require_relative "cms_editor/pretty"
8
+ require_relative "cms_editor/icons"
9
+ require_relative "cms_editor/theme"
8
10
 
9
11
  module Hecks
10
12
  module Projections
@@ -28,29 +30,36 @@ module Hecks
28
30
 
29
31
  # The files, by path relative to the directory they are written to.
30
32
  FILES = %w[
31
- package.json tsconfig.json src/config.ts src/schema.ts src/host.ts src/commands.ts src/app.ts src/server.ts
32
- src/auth/membership.ts src/auth/session.ts src/auth/sso.ts
33
- src/ui/html.ts src/ui/outline.ts src/ui/fields.ts src/ui/input.ts src/ui/pages.ts
34
- src/ui/body_model.js src/ui/body_parse.js src/ui/body_widget.js
33
+ package.json tsconfig.json src/config.ts src/schema.ts src/names.ts src/host.ts src/commands.ts src/choices.ts
34
+ src/app.ts src/server.ts src/assets.ts src/flash.ts src/auth/membership.ts src/auth/session.ts src/auth/sso.ts
35
+ src/ui/html.ts src/ui/words.ts src/ui/icons.ts src/ui/shell.ts src/ui/outline.ts src/ui/fields.ts
36
+ src/ui/input.ts src/ui/table.ts src/ui/paging.ts src/ui/pickers.ts src/ui/moments.ts src/ui/detail.ts
37
+ src/ui/pages.ts src/ui/theme.js src/ui/body_model.js src/ui/body_parse.js src/ui/availability.ts src/ui/dialogs.ts
38
+ src/ui/links.ts src/ui/preview.ts src/ui/related.ts src/ui/schedule.ts src/ui/values.ts src/ui/world.ts
39
+ src/browser/app.css src/browser/main.js src/browser/shell.js src/browser/forms.js src/browser/toast.js
40
+ src/browser/lists.js src/browser/pickers.js src/browser/epoch.js src/browser/moments.js
41
+ src/browser/body_doc.js src/browser/body_editor.js src/browser/autosave.js src/browser/preview.js
42
+ src/ui/blocks.ts src/ui/block_list.js src/browser/blocks.js
35
43
  ].freeze
36
44
 
37
45
  # The files only an editor of a chapter with a picture aggregate has: the upload, the
38
- # storage port with its local-disk adapter, and the picker the rich-text widget opens.
46
+ # storage port with its local-disk adapter, and the picker the rich-text editor opens.
39
47
  MEDIA_FILES = %w[
40
- src/media/sniff.ts src/media/multipart.ts src/media/storage.ts src/media/handler.ts src/ui/media_picker.js
48
+ src/media/sniff.ts src/media/multipart.ts src/media/storage.ts src/media/handler.ts src/browser/media_picker.js
41
49
  ].freeze
42
50
 
43
- # The browser modules the rich-text widget loads, served to a signed-in editor.
44
- ASSETS = %w[body_widget.js body_model.js body_parse.js].freeze
45
-
46
- # What `app.ts` holds for a picture upload; each is left out when the chapter has none.
51
+ # What `app.ts` and the body editor hold for a picture upload; each is left out when the
52
+ # chapter has none.
47
53
  MEDIA_LINES = {
48
- "__MEDIA_IMPORT__" => ["import { mediaHandler } from \"./media/handler.ts\";",
49
- "import type { MediaStorage } from \"./media/storage.ts\";"].join("\n"),
50
- "__MEDIA_OPTION__" => [" /** Where picture bytes are kept: the local disk unless given (see media/storage.ts). */",
51
- " storage?: MediaStorage;"].join("\n"),
52
- "__MEDIA_SETUP__" => " const media = mediaHandler(options.storage);",
53
- "__MEDIA_ROUTE__" => " if (segments[0] === \"media\") return media(client, request, segments.slice(1));"
54
+ "__MEDIA_IMPORT__" => ["import { mediaHandler, mediaOpen } from \"./media/handler.ts\";",
55
+ "import type { MediaStorage } from \"./media/storage.ts\";"].join("\n"),
56
+ "__MEDIA_OPTION__" => [" /** Where picture bytes are kept: the local disk unless given (see media/storage.ts). */",
57
+ " storage?: MediaStorage;"].join("\n"),
58
+ "__MEDIA_SETUP__" => " const media = mediaHandler(options.storage, { url: options.url, fetch: options.fetch });",
59
+ "__MEDIA_ROUTE__" => [" if (segments[0] === \"media\") {",
60
+ " if (!mediaOpen(role)) return plain(\"Pictures are not open to your role.\", 403);",
61
+ " return media(client, request, segments.slice(1));", " }"].join("\n"),
62
+ "__PICKER_LOADER__" => "() => import(\"./media_picker.js\")"
54
63
  }.freeze
55
64
 
56
65
  module_function
@@ -58,8 +67,11 @@ module Hecks
58
67
  # Renders the editor's files for a project that declares an `Editor` row.
59
68
  #
60
69
  # @param bluebook [Bluebook::Chapter] the chapter that declares the route table and the row
61
- # @param options [Hash{Symbol => Object}] `:domain_chapter` the chapter to edit; `:table`
62
- # the checked route table, when the login page is to be checked against it
70
+ # @param options [Hash{Symbol => Object}] `:domain_chapters` the chapters to edit, in the
71
+ # order the row names them (`:domain_chapter` for one);
72
+ # `:media_chapter` the chapter the row's `media` names, whose picture aggregate the
73
+ # pictures use; `:table` the checked route table, when the login page is to be checked
74
+ # against it
63
75
  # @return [Hash{String => String}] each file's path relative to the editor's directory to
64
76
  # its text; empty when the project declares no `Editor` row
65
77
  # @raise [Table::Invalid] when the row is refused
@@ -68,18 +80,32 @@ module Hecks
68
80
  setting = Setting.read(bluebook, table: options[:table])
69
81
  return {} unless setting
70
82
 
71
- schema = Schema.read(options.fetch(:domain_chapter), skip: setting.skip)
83
+ chapters = options[:domain_chapters] || options.fetch(:domain_chapter)
84
+ schema = Schema.read(chapters, skip: setting.skip, pictures: options[:media_chapter], roles: setting.chapter_roles)
72
85
  media = schema.key?("media")
73
- tokens = setting.tokens.merge("__SCHEMA__" => Pretty.generate(schema), **media_tokens(media))
86
+ tokens = tokens(setting, schema, media)
74
87
  [*FILES, *(MEDIA_FILES if media)].to_h { |path| [path, fill(File.read(File.join(TEMPLATES, "#{path}.tmpl")), tokens)] }
75
88
  end
76
89
 
90
+ # @return [Hash{String => String}] each placeholder of the templates and its text
91
+ def tokens(setting, schema, media)
92
+ setting.tokens.merge(look_tokens(setting, schema), "__SCHEMA__" => Pretty.generate(schema), **media_tokens(media))
93
+ end
94
+
77
95
  # @param media [Boolean] whether the chapter has a picture aggregate
78
96
  # @return [Hash{String => String}] each media placeholder to its text, empty when none
79
97
  def media_tokens(media)
80
- assets = RoutesTs.literal(media ? [*ASSETS, "media_picker.js"] : ASSETS)
81
- lines = media ? MEDIA_LINES : MEDIA_LINES.transform_values { "" }
82
- { "__ASSETS__" => assets, **lines }
98
+ return MEDIA_LINES if media
99
+
100
+ MEDIA_LINES.transform_values { "" }.merge("__PICKER_LOADER__" => "null")
101
+ end
102
+
103
+ # @param setting [Setting] the checked row
104
+ # @param schema [Hash{String => Object}] the chapter as the editor reads it
105
+ # @return [Hash{String => String}] the brand, the icon sprite and the theme's colours
106
+ def look_tokens(setting, schema)
107
+ { "__BRAND__" => JSON.generate(setting.brand || schema["domain"]), "__ICONS__" => Icons.sprite,
108
+ "__CSS_BANNER__" => "/* #{RoutesTs::BANNER.delete_prefix("// ")} */", **Theme.tokens(setting.accent) }
83
109
  end
84
110
 
85
111
  # @param text [String] a template with `__NAME__` placeholders
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../../bluebook/synthesizer"
4
+
3
5
  module Hecks
4
6
  module Projections
5
7
  module Site
@@ -2,7 +2,8 @@ module Hecks
2
2
  module Projector
3
3
  # What a launcher's help leaves out and points at for whoever typed the line: the aggregates
4
4
  # only a maintainer of a hecks checkout runs, and the attached chapters worth a line each.
5
- # `CliProjector` renders the help; the runner decides the audience (`Doors::LauncherOptions`).
5
+ # `CliProjector` renders the help; the runner decides the audience
6
+ # (`Adapters::Driving::LauncherOptions`).
6
7
  module CliAudience
7
8
  module_function
8
9
 
@@ -67,7 +67,7 @@ module Hecks
67
67
  end
68
68
 
69
69
  # " (also: mcp!)" for a spec the chapter gave a short name, else nothing. A short name that
70
- # is only the command's own name (`init` for `door.init`) is already in the line.
70
+ # is only the command's own name (`init` for `launch.init`) is already in the line.
71
71
  def alias_note(spec)
72
72
  return "" if spec[:short_was].nil? || spec[:short_was].split(".").last == spec[:short]
73
73
 
@@ -29,7 +29,7 @@ module Hecks
29
29
  # One option per field of a value object, recursing into a field that is itself one.
30
30
  #
31
31
  # The list flag rides on each leaf: without it a repeated flag overwrote the
32
- # leaf silently, and CliDoor only ever sees a path and a spec.
32
+ # leaf silently, and Cli only ever sees a path and a spec.
33
33
  def leaf_options(value_object, aggregate, path, optional)
34
34
  value_object.attributes.flat_map do |field|
35
35
  nested = value_object_for(field, value_object, aggregate)
@@ -18,7 +18,7 @@ module Hecks
18
18
  return [] if bluebook.policies.empty?
19
19
 
20
20
  rows = bluebook.policies.map do |policy|
21
- ["`#{policy.on_event}`", "`#{policy.trigger_command}`", policy.target_domain || bluebook.name]
21
+ ["`#{policy.on_event}`", "`#{policy.reaches}`", policy.target_domain || bluebook.name]
22
22
  end
23
23
  [DocsProjector.h(depth, "Reactions"), "",
24
24
  "These fire on their own. Issuing the verb on the left also causes the one on the right.", "",
@@ -110,7 +110,7 @@ module Hecks
110
110
  out.compact.join("\n")
111
111
  end
112
112
 
113
- # An entity has no door of its own; its verbs go through the holding aggregate.
113
+ # An entity has no entry point of its own; its verbs go through the holding aggregate.
114
114
  def entity_addressing(aggregate, entity)
115
115
  "Addressed through its holder — `#{aggregate.hecks_name}.#{entity.hecks_name}.<Verb>`, " \
116
116
  "passing the #{aggregate.hecks_name}'s `id` and this element's " \
@@ -1,3 +1,5 @@
1
+ require_relative "capability_values"
2
+
1
3
  module Hecks
2
4
  module Projector
3
5
  module Exporter
@@ -5,6 +7,8 @@ module Hecks
5
7
  # membership, identity, newsletter, registrations, payments): a per-deployment binding fact,
6
8
  # not part of the declared IR. Each answers `{}` when nothing the domain attaches provides it.
7
9
  module Bindings
10
+ include CapabilityValues
11
+
8
12
  # Which chapter this domain's role checks resolve against
9
13
  # (`Registry#authorization_provider_for`); `{}` if none does.
10
14
  #
@@ -70,16 +74,20 @@ module Hecks
70
74
  # @param registry [Runtime::Registry] the booted registry `domain_name` is loaded in
71
75
  # @param domain_name [String] the domain to export the newsletter binding for
72
76
  # @return [Hash{Symbol => String, nil}] `:provider` (name), `:subscribe`, `:add_name`,
73
- # `:confirm`, `:unsubscribe` (qualified verbs), and `:aggregate` (`:subscribe`'s own
74
- # leading qualified aggregate name); `{}` if nothing this domain attaches provides
75
- # newsletter
77
+ # `:confirm`, `:unsubscribe` (qualified verbs), `:aggregate` (`:subscribe`'s own
78
+ # leading qualified aggregate name) and, when declared, `:awaiting_confirmation`,
79
+ # `:receives_issues` and `:left` (the states of the lifecycle marks they name) and
80
+ # `:confirm_window` and `:unsubscribe_window` (seconds); `{}` if nothing this domain
81
+ # attaches provides newsletter
76
82
  def newsletter(registry, domain_name)
77
83
  provider = registry.newsletter_provider_for(domain_name)
78
84
  return {} unless provider
79
85
 
80
86
  verbs = verbs_of(provider, Bluebook::Capabilities::NEWSLETTER,
81
87
  :subscribe, :add_name, :confirm, :unsubscribe)
82
- { provider: provider.name, **verbs, aggregate: aggregate_of(verbs[:subscribe]) }
88
+ { provider: provider.name, **verbs, aggregate: aggregate_of(verbs[:subscribe]),
89
+ **all_marked_states(provider, Bluebook::Capabilities::NEWSLETTER),
90
+ **all_durations(provider, Bluebook::Capabilities::NEWSLETTER) }
83
91
  end
84
92
 
85
93
  # Which chapter answers sending a newsletter issue
@@ -107,15 +115,18 @@ module Hecks
107
115
  # @param domain_name [String] the domain to export the registrations binding for
108
116
  # @return [Hash{Symbol => String, nil}] `:provider` (name), `:schedule`, `:request`
109
117
  # (qualified verbs), `:event_aggregate` and `:registration_aggregate` (each verb's own
110
- # leading qualified aggregate name); `{}` if nothing this domain attaches provides
111
- # registrations
118
+ # leading qualified aggregate name) and, when declared, `:frees_seat` (the states of the
119
+ # lifecycle mark it names) and `:registered_at` (the attribute that stamps a request);
120
+ # `{}` if nothing this domain attaches provides registrations
112
121
  def registrations(registry, domain_name)
113
122
  provider = registry.registrations_provider_for(domain_name)
114
123
  return {} unless provider
115
124
 
116
125
  verbs = verbs_of(provider, Bluebook::Capabilities::REGISTRATIONS, :schedule, :request)
117
126
  { provider: provider.name, **verbs,
118
- **aggregates_of(verbs, event_aggregate: :schedule, registration_aggregate: :request) }
127
+ **aggregates_of(verbs, event_aggregate: :schedule, registration_aggregate: :request),
128
+ **all_marked_states(provider, Bluebook::Capabilities::REGISTRATIONS),
129
+ **all_words(provider, Bluebook::Capabilities::REGISTRATIONS) }
119
130
  end
120
131
 
121
132
  # Which chapter owns the payment-processor connection
@@ -142,14 +153,33 @@ module Hecks
142
153
  # @param registry [Runtime::Registry] the booted registry `domain_name` is loaded in
143
154
  # @param domain_name [String] the domain to export the payments binding for
144
155
  # @return [Hash{Symbol => String, nil}] `:provider` (name), `:initiate`, `:succeeded`,
145
- # `:failed` (qualified verbs), and `:aggregate` (`:initiate`'s own leading qualified
146
- # aggregate name); `{}` if nothing this domain attaches provides payments
156
+ # `:failed` (qualified verbs), `:aggregate` (`:initiate`'s own leading qualified
157
+ # aggregate name) and, when declared, `:holds_seat` (the states of the lifecycle mark
158
+ # it names) and `:lapse_reason` (the word a lapsed hold
159
+ # records); `{}` if nothing this domain attaches provides payments
147
160
  def payments(registry, domain_name)
148
161
  provider = registry.payments_provider_for(domain_name)
149
162
  return {} unless provider
150
163
 
151
164
  verbs = verbs_of(provider, Bluebook::Capabilities::PAYMENTS, :initiate, :succeeded, :failed)
152
- { provider: provider.name, **verbs, aggregate: aggregate_of(verbs[:initiate]) }
165
+ { provider: provider.name, **verbs, aggregate: aggregate_of(verbs[:initiate]),
166
+ **marked_states(provider, Bluebook::Capabilities::PAYMENTS, :holds_seat),
167
+ **all_words(provider, Bluebook::Capabilities::PAYMENTS) }
168
+ end
169
+
170
+ # Which chapter owns the checkout boundary (`Registry#checkout_provider_for`); `{}` if
171
+ # none does.
172
+ #
173
+ # @param registry [Runtime::Registry] the booted registry `domain_name` is loaded in
174
+ # @param domain_name [String] the domain to export the checkout binding for
175
+ # @return [Hash{Symbol => Object}] `:provider` (name) and, when declared,
176
+ # `:webhook_tolerance` and `:session_hold` (whole seconds); `{}` if nothing this
177
+ # domain attaches provides checkout
178
+ def checkout(registry, domain_name)
179
+ provider = registry.checkout_provider_for(domain_name)
180
+ return {} unless provider
181
+
182
+ { provider: provider.name, **all_durations(provider, Bluebook::Capabilities::CHECKOUT) }
153
183
  end
154
184
 
155
185
  private
@@ -0,0 +1,55 @@
1
+ module Hecks
2
+ module Projector
3
+ module Exporter
4
+ # The values a capability's optional contract entries resolve to in the exported fact: the
5
+ # states of a lifecycle `:mark` (ADR 0097), the whole seconds of a `:duration` (ADR 0098), and
6
+ # the word of a `:text` or `:attribute` entry (ADR 0099).
7
+ module CapabilityValues
8
+ private
9
+
10
+ # `{ key => states }` for each optional `:mark` entry `provider` declares under
11
+ # `capability`.
12
+ def all_marked_states(provider, capability)
13
+ mark_keys = declared_keys(capability, :mark)
14
+ mark_keys.reduce({}) { |marks, key| marks.merge(marked_states(provider, capability, key)) }
15
+ end
16
+
17
+ # `{ key => seconds }` for each optional `:duration` entry `provider` declares under
18
+ # `capability`: the whole-seconds default of the attribute it names.
19
+ def all_durations(provider, capability)
20
+ declared_keys(capability, :duration).each_with_object({}) do |key, durations|
21
+ verb = provider.provision(capability)&.fetch(key, nil)
22
+ durations[key] = Bluebook::Capabilities.duration_of(provider, verb) if verb
23
+ end
24
+ end
25
+
26
+ # `{ key => word }` for each optional `:text` entry and `{ key => attribute_name }` for each
27
+ # optional `:attribute` entry `provider` declares under `capability` (ADR 0099).
28
+ def all_words(provider, capability)
29
+ words = { text: :text_of, attribute: :attribute_of }.flat_map do |kind, resolver|
30
+ declared_keys(capability, kind).filter_map do |key|
31
+ verb = provider.provision(capability)&.fetch(key, nil)
32
+ [key, Bluebook::Capabilities.public_send(resolver, provider, verb)] if verb
33
+ end
34
+ end
35
+ words.to_h
36
+ end
37
+
38
+ # `{ key => states }` for an optional `:mark` entry `provider` declares under `capability`:
39
+ # the states of the named aggregate's lifecycle mark. `{}` when the entry is not declared.
40
+ def marked_states(provider, capability, key)
41
+ verb = provider.provision(capability)&.fetch(key, nil)
42
+ return {} unless verb
43
+
44
+ aggregate_name, mark = verb.split(".", 2)
45
+ { key => provider.aggregate(aggregate_name).lifecycle.marked(mark) }
46
+ end
47
+
48
+ # The contract keys of `capability` whose kind is `kind`.
49
+ def declared_keys(capability, kind)
50
+ Bluebook::Capabilities::CONTRACTS.fetch(capability).select { |_, entry| entry == kind }.keys
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -16,7 +16,7 @@ module Hecks
16
16
  # A policy as the sentence saying it fires on its own.
17
17
  def policy_sentence(policy)
18
18
  elsewhere = policy.target_domain ? " in #{policy.target_domain}" : ""
19
- "Whenever `#{policy.on_event}` happens, `#{policy.trigger_command}` fires on its own#{elsewhere} — " \
19
+ "Whenever `#{policy.on_event}` happens, `#{policy.reaches}` fires on its own#{elsewhere} — " \
20
20
  "nobody has to ask for it."
21
21
  end
22
22
 
@@ -58,6 +58,17 @@ module Hecks
58
58
  # before `projects_as` is called
59
59
  def projection_needs_world? = @projection_needs_world || false
60
60
 
61
+ # Derives what kind of target this is from flags it already declares,
62
+ # so there is no second spelling to drift.
63
+ #
64
+ # @return [Symbol] `:export` if it needs a world, `:meta` if it needs a
65
+ # chapter declaring particular aggregates, otherwise `:projection`
66
+ def projection_category
67
+ return :export if projection_needs_world?
68
+
69
+ projection_declares.empty? ? :projection : :meta
70
+ end
71
+
61
72
  # Names the capability module(s) a construct must satisfy, defaulting
62
73
  # to plain chapter-hood when `projects_as` named none.
63
74
  #
@@ -4,10 +4,13 @@ module Hecks
4
4
  #
5
5
  # Projector.call(:ir, bluebook: chapter)
6
6
  #
7
- # A projection is inert and derived from a chapter's declaration. An export
8
- # (rust crate, WASM, CloudFormation) also needs `.world` bindings and declares
9
- # `needs_world: true`. State projections (`hecks project_expression_tables`) and
10
- # `Ports::Projection` read-model catch-up are different things and not registered.
7
+ # A target's category is derived from the flags it declares (`category`):
8
+ #
9
+ # - `:projection` is inert and derived from any chapter's declaration.
10
+ # - `:meta` also needs a chapter declaring particular aggregates (`declares:`),
11
+ # so it only fits hecks's own grammar chapters.
12
+ # - `:export` (CloudFormation, ...) also needs `.world` bindings and declares
13
+ # `needs_world: true`; that is adapter wiring, not a projection of the domain.
11
14
  module Projector
12
15
  class UnknownProjector < StandardError; end
13
16
  # A chapter-scoped projector was handed something that is not a chapter.
@@ -38,7 +41,9 @@ module Hecks
38
41
  # @raise [WrongConstruct] if `bluebook` lacks what the projector requires
39
42
  def call(name, bluebook:, options: {}, world: nil)
40
43
  projector = registry.fetch(name.to_sym) do
41
- raise UnknownProjector, "no projector registered for #{name.inspect} — registered: #{registered.sort.inspect}"
44
+ raise UnknownProjector,
45
+ "no projector registered for #{name.inspect} — registered: " \
46
+ "#{registered_by_category.map { |kind, keys| "#{kind} #{keys.inspect}" }.join(", ")}"
42
47
  end
43
48
  admits!(name, projector, bluebook, world)
44
49
  projector.call(bluebook: bluebook, options: world ? options.merge(world: world) : options)
@@ -114,6 +119,28 @@ module Hecks
114
119
  # @return [Array<Symbol>] every key currently registered
115
120
  def registered = registry.keys
116
121
 
122
+ # Gives the category of a registered target, derived from its flags.
123
+ # A target that answers no `projection_category` (the built-ins, which do
124
+ # not extend `Target`) is a plain projection.
125
+ #
126
+ # @param name [String, Symbol] the registered projector's key
127
+ # @return [Symbol] `:projection`, `:meta` or `:export` (`:projection` for an
128
+ # unregistered `name`)
129
+ def category(name)
130
+ projector = registry.fetch(name.to_sym) { return :projection }
131
+ projector.respond_to?(:projection_category) ? projector.projection_category : :projection
132
+ end
133
+
134
+ # Lists every registered key under its category.
135
+ #
136
+ # @return [Hash{Symbol => Array<Symbol>}] `:projection`, `:meta` and `:export`
137
+ # (always all three), each with its sorted keys
138
+ def registered_by_category
139
+ grouped = { projection: [], meta: [], export: [] }
140
+ registered.sort.each { |key| grouped[category(key)] << key }
141
+ grouped
142
+ end
143
+
117
144
  # Gives the live registry, initializing it on first use.
118
145
  #
119
146
  # @return [Hash{Symbol => Module, Class, #call}] the live key => projector registry
@@ -2,12 +2,16 @@
2
2
 
3
3
  require "open3"
4
4
  require "json"
5
+ require_relative "../../indifferent_key"
5
6
 
6
7
  module Hecks
7
8
  module Adapters
8
9
  # The `CI` port adapter: answers `Clearance.CI.Run` from GitHub's check runs for a commit.
9
10
  # Raises when no checks exist, any are still running, or any failed.
10
11
  class GithubChecks
12
+ # Raised when check runs cannot be read or have not settled.
13
+ class Error < RuntimeError; end
14
+
11
15
  # All keywords are unused; the adapter takes no per-boot configuration.
12
16
  def initialize(aggregate: nil, settings: {}, root: nil); end
13
17
 
@@ -29,7 +33,7 @@ module Hecks
29
33
  #
30
34
  # @param commit [Hash, String] a materialized value object (`{value: sha}`) or a bare sha
31
35
  # @return [Hash] `{ summary: { value: ... } }` when every check is green
32
- # @raise [RuntimeError] when the sha is malformed, `gh` is missing or fails, no checks
36
+ # @raise [Error] when the sha is malformed, `gh` is missing or fails, no checks
33
37
  # exist, any are incomplete, or any failed
34
38
  def run(commit:, **)
35
39
  sha = valid_sha(commit)
@@ -49,7 +53,7 @@ module Hecks
49
53
  # @param names [Array<String>] the checks to look up
50
54
  # @return [Hash{String => Symbol}] each name to `:passed`, `:failed`, `:pending` (reported but
51
55
  # not completed) or `:missing` (not reported at all)
52
- # @raise [RuntimeError] when the sha is malformed or `gh` is missing or fails
56
+ # @raise [Error] when the sha is malformed or `gh` is missing or fails
53
57
  def states(commit:, names:)
54
58
  reported = check_runs(valid_sha(commit)).select { |run| actions?(run) }.group_by { |run| run["name"] }
55
59
  latest = reported.transform_values { |runs| runs.max_by { |run| run["id"].to_i } }
@@ -62,7 +66,7 @@ module Hecks
62
66
 
63
67
  def valid_sha(commit)
64
68
  sha = sha_of(commit)
65
- raise "not a commit sha: #{sha.inspect}" unless sha.match?(SHA_PATTERN)
69
+ raise Error, "not a commit sha: #{sha.inspect}" unless sha.match?(SHA_PATTERN)
66
70
 
67
71
  sha
68
72
  end
@@ -70,11 +74,11 @@ module Hecks
70
74
  # The check runs against `sha`, once none is still running.
71
75
  def settled_runs(sha)
72
76
  runs = check_runs(sha)
73
- raise "gh reports no checks at all against #{sha}" if runs.empty?
77
+ raise Error, "gh reports no checks at all against #{sha}" if runs.empty?
74
78
 
75
79
  # Refuse rather than answer on an incomplete run; asking again once it settles is safe.
76
80
  incomplete = runs.reject { |run| run["status"] == "completed" }
77
- raise "checks against #{sha} are still running — asked before they settled" if incomplete.any?
81
+ raise Error, "checks against #{sha} are still running — asked before they settled" if incomplete.any?
78
82
 
79
83
  runs
80
84
  end
@@ -95,7 +99,7 @@ module Hecks
95
99
  def sha_of(commit)
96
100
  return commit if commit.is_a?(String)
97
101
 
98
- (commit.key?(:value) ? commit[:value] : commit["value"]).to_s
102
+ IndifferentKey.read(commit, :value).to_s
99
103
  end
100
104
 
101
105
  # Every page of check runs: a red run past the first page must still be seen.
@@ -115,11 +119,11 @@ module Hecks
115
119
  def check_run_page(sha, page)
116
120
  path = "repos/{owner}/{repo}/commits/#{sha}/check-runs?per_page=#{PER_PAGE}&page=#{page}"
117
121
  out, err, status = Open3.capture3("gh", "api", path)
118
- raise "gh api check-runs failed for #{sha}: #{err.strip.empty? ? out.strip : err.strip}" unless status.success?
122
+ raise Error, "gh api check-runs failed for #{sha}: #{err.strip.empty? ? out.strip : err.strip}" unless status.success?
119
123
 
120
124
  JSON.parse(out)
121
125
  rescue Errno::ENOENT
122
- raise "gh is not installed or not on PATH — cannot read check runs for #{sha}"
126
+ raise Error, "gh is not installed or not on PATH — cannot read check runs for #{sha}"
123
127
  end
124
128
  end
125
129
  end
@@ -1,12 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "open3"
4
+ require_relative "../../indifferent_key"
4
5
 
5
6
  module Hecks
6
7
  module Adapters
7
8
  # The `IssueTracker` port's adapter: files a `QualityControl::Ticket` as a GitHub issue.
8
9
  # Raises when `gh` refuses, which the runtime records as the ticket's refusal.
9
10
  class GithubIssues
11
+ # Raised when `gh` cannot file the issue.
12
+ class Error < RuntimeError; end
13
+
10
14
  # @param aggregate [Object, nil] unused
11
15
  # @param settings [Hash] unused
12
16
  # @param root [String, nil] unused
@@ -18,7 +22,7 @@ module Hecks
18
22
  # value objects (`{value: ...}`) or bare strings, and `pull_request` names a proposed fix
19
23
  # @return [Hash{Symbol => Hash}] `number:` and `url:` of the issue, in the shape the
20
24
  # ticket's `Filed` command takes
21
- # @raise [RuntimeError] when `gh` exits non-zero or prints no issue URL
25
+ # @raise [Error] when `gh` exits non-zero or prints no issue URL
22
26
  def file(**held)
23
27
  out = create_issue(plain(held[:repository]), plain(held[:title]).to_s, issue_body(held))
24
28
  url, number = issue_url_and_number(out)
@@ -37,7 +41,7 @@ module Hecks
37
41
  def issue_url_and_number(out)
38
42
  url = out.strip.lines.last.to_s.strip
39
43
  number = url[%r{/issues/(\d+)\z}, 1]
40
- raise "gh issue create printed no issue URL: #{out.strip.inspect}" unless number
44
+ raise Error, "gh issue create printed no issue URL: #{out.strip.inspect}" unless number
41
45
 
42
46
  [url, number]
43
47
  end
@@ -45,7 +49,7 @@ module Hecks
45
49
  def create_issue(repository, title, body)
46
50
  out, err, status = Open3.capture3("gh", "issue", "create", "--repo", repository,
47
51
  "--title", title, "--body", body)
48
- raise "gh issue create failed — #{err.strip.empty? ? out.strip : err.strip}" unless status.success?
52
+ raise Error, "gh issue create failed — #{err.strip.empty? ? out.strip : err.strip}" unless status.success?
49
53
 
50
54
  out
51
55
  end
@@ -54,7 +58,7 @@ module Hecks
54
58
  def plain(field)
55
59
  return field unless field.is_a?(Hash)
56
60
 
57
- field.key?(:value) ? field[:value] : field["value"]
61
+ IndifferentKey.read(field, :value)
58
62
  end
59
63
  end
60
64
  end
@@ -11,8 +11,8 @@ require_relative "qa_open_pr/recording"
11
11
  module Hecks
12
12
  module QualityControlCli
13
13
  # The command behind `hecks quality_control patch.open`: opens a PR and records it in the
14
- # QualityControl ledger in one step. It is the only door into `QualityControl::Patch.Open` and
15
- # `QualityControl::Improvement.Open`.
14
+ # QualityControl ledger in one step. It is the only entry point into
15
+ # `QualityControl::Patch.Open` and `QualityControl::Improvement.Open`.
16
16
  #
17
17
  # It refuses (exit 1, nothing opened or recorded) unless the ledger's own `Open` command would
18
18
  # take the record and the `GitPr` adapter agrees. The command's `given`s are the rules, asked
@@ -10,7 +10,7 @@ module Hecks
10
10
  private
11
11
 
12
12
  # Re-runs only the comparison that surprised; `seat` matters only for `self_consistency`,
13
- # which reads the Rust binary's rehydration door under a differential seat.
13
+ # which reads the Rust binary's rehydration entry point under a differential seat.
14
14
  def candidate_divergences(check_mode, seat, steps)
15
15
  case check_mode
16
16
  when :differential
@@ -37,7 +37,7 @@ module Hecks
37
37
 
38
38
  def print_finding_instructions
39
39
  puts "No Bug was logged (that needs a real failing-test demonstration, which"
40
- puts "needs judgment this script does not have — hecks quality_control log is the door)"
40
+ puts "needs judgment this script does not have — hecks quality_control log is the entry point)"
41
41
  puts "and the sweep was not concluded. The ledger's own SuspendOnSurprise"
42
42
  puts "policy took the target out of the rotation; it stays out until a PERSON"
43
43
  puts "runs: hecks quality_control ask run target=#{@target_reference} " \