hecks 3.9.1 → 3.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (504) hide show
  1. checksums.yaml +4 -4
  2. data/examples/pizzas/bluebook/pizzas.bluebook +29 -0
  3. data/examples/pizzas/bluebook/pizzas.hecksagon +7 -0
  4. data/exe/hecks +4 -4
  5. data/lib/hecks/adapters/driven/d1.rb +2 -10
  6. data/lib/hecks/adapters/driven/heki.adapter +1 -1
  7. data/lib/hecks/adapters/driven/heki.rb +2 -12
  8. data/lib/hecks/adapters/driven/lambda.adapter +1 -1
  9. data/lib/hecks/adapters/driven/lambda.rb +3 -18
  10. data/lib/hecks/adapters/driven/postgres.rb +4 -11
  11. data/lib/hecks/adapters/driven/sqlite.adapter +1 -1
  12. data/lib/hecks/adapters/driven/sqlite.rb +2 -10
  13. data/lib/hecks/adapters/driving/admission.rb +46 -0
  14. data/lib/hecks/adapters/driving/cli/nesting.rb +36 -0
  15. data/lib/hecks/adapters/driving/cli/shorthand.rb +88 -0
  16. data/lib/hecks/adapters/driving/cli.rb +127 -0
  17. data/lib/hecks/adapters/driving/cli_runner/answers.rb +160 -0
  18. data/lib/hecks/adapters/driving/cli_runner/resolution.rb +155 -0
  19. data/lib/hecks/adapters/driving/cli_runner/settling.rb +120 -0
  20. data/lib/hecks/adapters/driving/cli_runner/streaming.rb +93 -0
  21. data/lib/hecks/adapters/driving/cli_runner/suggestions.rb +47 -0
  22. data/lib/hecks/adapters/driving/cli_runner.rb +69 -0
  23. data/lib/hecks/adapters/driving/command_request.rb +121 -0
  24. data/lib/hecks/adapters/driving/handle.rb +214 -0
  25. data/lib/hecks/adapters/driving/json.rb +136 -0
  26. data/lib/hecks/adapters/driving/launcher_options.rb +267 -0
  27. data/lib/hecks/adapters/driving/mcp/properties.rb +49 -0
  28. data/lib/hecks/adapters/driving/mcp/tool_calls.rb +116 -0
  29. data/lib/hecks/adapters/driving/mcp/tool_definitions/auditing.rb +53 -0
  30. data/lib/hecks/adapters/driving/mcp/tool_definitions/calling.rb +71 -0
  31. data/lib/hecks/adapters/driving/mcp/tool_definitions/reading.rb +99 -0
  32. data/lib/hecks/adapters/driving/mcp/tool_definitions.rb +18 -0
  33. data/lib/hecks/adapters/driving/mcp.rb +159 -0
  34. data/lib/hecks/adapters/driving/mcp_guide_cache.rb +78 -0
  35. data/lib/hecks/adapters/driving/mcp_scope/argument_policy.rb +97 -0
  36. data/lib/hecks/adapters/driving/mcp_scope/env_problems.rb +69 -0
  37. data/lib/hecks/adapters/driving/mcp_scope/presenter.rb +83 -0
  38. data/lib/hecks/adapters/driving/mcp_scope.rb +213 -0
  39. data/lib/hecks/adapters/driving/ruby/aggregate_module.rb +171 -0
  40. data/lib/hecks/adapters/driving/ruby/chapter.rb +91 -0
  41. data/lib/hecks/adapters/driving/ruby.rb +83 -0
  42. data/lib/hecks/adapters/driving/usage_cache.rb +144 -0
  43. data/lib/hecks/{doors.rb → adapters/driving.rb} +10 -6
  44. data/lib/hecks/behaviors/expectations/boot.rb +1 -1
  45. data/lib/hecks/bench/ruby_runner.rb +1 -1
  46. data/lib/hecks/bluebook/ask_resolution.rb +130 -0
  47. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +8 -2
  48. data/lib/hecks/bluebook/assembly/contracts/rules.rb +4 -2
  49. data/lib/hecks/bluebook/assembly/contracts/structure.rb +3 -1
  50. data/lib/hecks/bluebook/assembly/marks.rb +1 -0
  51. data/lib/hecks/bluebook/attribute.rb +1 -1
  52. data/lib/hecks/bluebook/behaviour/command.rb +13 -8
  53. data/lib/hecks/bluebook/behaviour/policy.rb +30 -0
  54. data/lib/hecks/bluebook/capabilities/attribute_values.rb +72 -0
  55. data/lib/hecks/bluebook/capabilities.rb +91 -9
  56. data/lib/hecks/bluebook/domain_port.rb +16 -4
  57. data/lib/hecks/bluebook/dsl/adapter_builder.rb +18 -6
  58. data/lib/hecks/bluebook/dsl/binding_proxy.rb +13 -0
  59. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/computed_sources.rb +98 -0
  60. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/fan_out_rows.rb +42 -0
  61. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/projected_fields.rb +14 -2
  62. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/provisions.rb +69 -3
  63. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/with_projections.rb +17 -10
  64. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +5 -0
  65. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -0
  66. data/lib/hecks/bluebook/dsl/command_builder/mutations.rb +8 -1
  67. data/lib/hecks/bluebook/dsl/command_builder/operands.rb +121 -0
  68. data/lib/hecks/bluebook/dsl/command_builder.rb +2 -0
  69. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +10 -1
  70. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +45 -2
  71. data/lib/hecks/bluebook/dsl/policy_builder.rb +47 -10
  72. data/lib/hecks/bluebook/dsl/rule_reference.rb +7 -4
  73. data/lib/hecks/bluebook/dsl/world_builder.rb +1 -1
  74. data/lib/hecks/bluebook/expression/ast_json/emitters.rb +6 -0
  75. data/lib/hecks/bluebook/expression/ast_json.rb +9 -6
  76. data/lib/hecks/bluebook/expression/ast_reader.rb +14 -9
  77. data/lib/hecks/bluebook/expression/projection.json +36 -0
  78. data/lib/hecks/bluebook/expression/resolver/operations.rb +31 -0
  79. data/lib/hecks/bluebook/expression/resolver/parsing.rb +38 -5
  80. data/lib/hecks/bluebook/expression/resolver/scanning.rb +22 -5
  81. data/lib/hecks/bluebook/expression/resolver/values.rb +10 -0
  82. data/lib/hecks/bluebook/expression/resolver.rb +20 -1
  83. data/lib/hecks/bluebook/hecksagon.rb +23 -3
  84. data/lib/hecks/bluebook/lifecycle.rb +22 -3
  85. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +13 -1
  86. data/lib/hecks/bluebook/meta_validator/modes.rb +4 -1
  87. data/lib/hecks/bluebook/meta_validator/readings.rb +18 -1
  88. data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +2 -1
  89. data/lib/hecks/bluebook/meta_validator/shapes.rb +5 -0
  90. data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +1 -1
  91. data/lib/hecks/bluebook/meta_validator.rb +12 -12
  92. data/lib/hecks/bluebook/model_check/ask_checks.rb +71 -0
  93. data/lib/hecks/bluebook/model_check/policy_checks.rb +2 -1
  94. data/lib/hecks/bluebook/model_check/reference_checks.rb +70 -0
  95. data/lib/hecks/bluebook/model_check.rb +8 -2
  96. data/lib/hecks/bluebook/policy.rb +4 -2
  97. data/lib/hecks/bluebook/smoke_test.rb +1 -1
  98. data/lib/hecks/bluebook/synthesizer.rb +2 -0
  99. data/lib/hecks/bluebook.rb +1 -0
  100. data/lib/hecks/cli/command_table.rb +1 -1
  101. data/lib/hecks/cli/console.rb +2 -1
  102. data/lib/hecks/cli/document.rb +1 -1
  103. data/lib/hecks/cli/launcher_words.rb +4 -4
  104. data/lib/hecks/cli/mcp.rb +4 -4
  105. data/lib/hecks/cli/project_cli/launcher_source.rb +2 -2
  106. data/lib/hecks/cli/project_cli/templates.rb +5 -5
  107. data/lib/hecks/cli/project_cli.rb +9 -6
  108. data/lib/hecks/cli/run.rb +2 -2
  109. data/lib/hecks/cli/smoke_http/checks.rb +4 -1
  110. data/lib/hecks/cli/smoke_http/transport.rb +3 -3
  111. data/lib/hecks/cli/smoke_http.rb +3 -0
  112. data/lib/hecks/codemod.rb +5 -2
  113. data/lib/hecks/corpus/routes.rb +7 -0
  114. data/lib/hecks/corpus/rust.rb +3 -2
  115. data/lib/hecks/deploy/bluebook/deploy.bluebook +124 -2
  116. data/lib/hecks/deploy/bluebook/deploy.hecksagon +8 -0
  117. data/lib/hecks/deploy/oidc.json +16 -3
  118. data/lib/hecks/doc/reference/rendering.rb +6 -3
  119. data/lib/hecks/forms/app/commands.rb +8 -7
  120. data/lib/hecks/forms/app/queries.rb +2 -1
  121. data/lib/hecks/forms/app.rb +1 -1
  122. data/lib/hecks/forms/record_renderer.rb +1 -1
  123. data/lib/hecks/framework/bluebook/privacy.bluebook +11 -0
  124. data/lib/hecks/fuzzing/concurrent_dispatch.rb +4 -1
  125. data/lib/hecks/fuzzing/failure_triage.rb +2 -1
  126. data/lib/hecks/fuzzing/mutation/run.rb +11 -4
  127. data/lib/hecks/fuzzing/properties/catalog.rb +6 -4
  128. data/lib/hecks/fuzzing/properties/guaranteed_by_construction.rb +18 -11
  129. data/lib/hecks/fuzzing/properties/guards.rb +1 -1
  130. data/lib/hecks/fuzzing/self_consistency/saga_redelivery.rb +1 -1
  131. data/lib/hecks/fuzzing/self_consistency.rb +6 -2
  132. data/lib/hecks/fuzzing/shrinker.rb +3 -1
  133. data/lib/hecks/fuzzing/value_generator.rb +19 -5
  134. data/lib/hecks/gate/stages.yml +4 -10
  135. data/lib/hecks/grammar/evolve.rb +1 -1
  136. data/lib/hecks/grammar/expression_operators.json +372 -0
  137. data/lib/hecks/grammar/operators.rb +3 -1
  138. data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +10 -10
  139. data/lib/hecks/hecks/adapters/codebase/inspection/rubycritic.rb +35 -0
  140. data/lib/hecks/hecks/adapters/codebase/inspection.rb +104 -0
  141. data/lib/hecks/hecks/adapters/codebase/publishing.rb +2 -1
  142. data/lib/hecks/hecks/adapters/codebase/release_facts.rb +12 -2
  143. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +2 -1
  144. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +1 -1
  145. data/lib/hecks/hecks/adapters/cost_explorer.rb +8 -5
  146. data/lib/hecks/hecks/adapters/deploy_toolchain/clearing.rb +51 -0
  147. data/lib/hecks/hecks/adapters/deploy_toolchain/statuses.rb +2 -1
  148. data/lib/hecks/hecks/adapters/deploy_toolchain.rb +2 -0
  149. data/lib/hecks/hecks/adapters/finding_github.rb +13 -6
  150. data/lib/hecks/hecks/adapters/first_admin.rb +2 -2
  151. data/lib/hecks/hecks/adapters/github_rulesets.rb +6 -3
  152. data/lib/hecks/hecks/adapters/in_process_boot.rb +1 -1
  153. data/lib/hecks/hecks/adapters/journal_store/compaction.rb +1 -1
  154. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +10 -20
  155. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +28 -5
  156. data/lib/hecks/hecks/adapters/local_files.rb +2 -2
  157. data/lib/hecks/hecks/adapters/rehearsal/audit_report.rb +107 -0
  158. data/lib/hecks/hecks/adapters/rehearsal/census.rb +71 -0
  159. data/lib/hecks/hecks/adapters/rehearsal/declaration.rb +133 -0
  160. data/lib/hecks/hecks/adapters/rehearsal/environment.rb +83 -0
  161. data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +142 -0
  162. data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +96 -0
  163. data/lib/hecks/hecks/adapters/rehearsal/postgres_census.rb +100 -0
  164. data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +69 -0
  165. data/lib/hecks/hecks/adapters/rehearsal/postgres_store.rb +129 -0
  166. data/lib/hecks/hecks/adapters/rehearsal/rows.rb +41 -0
  167. data/lib/hecks/hecks/adapters/rehearsal/rust_audit.rb +83 -0
  168. data/lib/hecks/hecks/adapters/rehearsal/subject.rb +104 -0
  169. data/lib/hecks/hecks/adapters/rehearsal.rb +54 -0
  170. data/lib/hecks/hecks/adapters/rehearsal_store.adapter +7 -0
  171. data/lib/hecks/hecks/adapters/rehearsal_store.rb +81 -0
  172. data/lib/hecks/hecks/adapters/site_toolchain/role_prober.rb +78 -0
  173. data/lib/hecks/hecks/adapters/site_toolchain.rb +29 -4
  174. data/lib/hecks/hecks/adapters/terminal.rb +13 -11
  175. data/lib/hecks/hecks/adapters/world_clearing.rb +65 -0
  176. data/lib/hecks/hecks/codebase.behaviors +13 -1
  177. data/lib/hecks/hecks/codebase.bluebook +239 -5
  178. data/lib/hecks/hecks/custodian.behaviors +24 -6
  179. data/lib/hecks/hecks/custodian.bluebook +6 -1227
  180. data/lib/hecks/hecks/deploy.behaviors +1 -1
  181. data/lib/hecks/hecks/deploy.world +1 -3
  182. data/lib/hecks/hecks/hecks.behaviors +1 -1
  183. data/lib/hecks/hecks/hecks.hecksagon +61 -18
  184. data/lib/hecks/hecks/hecks.world +11 -10
  185. data/lib/hecks/hecks/rehearsal.bluebook +477 -0
  186. data/lib/hecks/hecks/site.behaviors +1 -1
  187. data/lib/hecks/hecks/site.world +0 -1
  188. data/lib/hecks/hecks/tooling.bluebook +1238 -0
  189. data/lib/hecks/indifferent_key.rb +20 -0
  190. data/lib/hecks/language/adapter.bluebook +13 -3
  191. data/lib/hecks/language/bluebook/aggregate.bluebook +23 -0
  192. data/lib/hecks/language/bluebook/bluebook.bluebook +15 -0
  193. data/lib/hecks/language/bluebook/entity.bluebook +18 -0
  194. data/lib/hecks/language/bluebook/policy.bluebook +9 -1
  195. data/lib/hecks/language/bluebook/query.bluebook +1 -1
  196. data/lib/hecks/language/bluebook/vocabulary.bluebook +11 -4
  197. data/lib/hecks/language/hecksagon/domain_port.bluebook +1 -1
  198. data/lib/hecks/language/hecksagon/hecksagon.bluebook +22 -0
  199. data/lib/hecks/language/oidc.json +10 -0
  200. data/lib/hecks/language/port.bluebook +4 -4
  201. data/lib/hecks/literal.rb +12 -3
  202. data/lib/hecks/ports/key_vault.rb +7 -2
  203. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +21 -10
  204. data/lib/hecks/ports/persistence/plugins/era/postgres_era/boot.rb +4 -2
  205. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +2 -1
  206. data/lib/hecks/ports/persistence/repository_factory.rb +6 -3
  207. data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +29 -0
  208. data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +1 -1
  209. data/lib/hecks/projections/deploy/fargate/settings/tuning.rb +15 -0
  210. data/lib/hecks/projections/deploy/fargate/settings.rb +3 -1
  211. data/lib/hecks/projections/deploy/fargate/stack/readers.rb +1 -0
  212. data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
  213. data/lib/hecks/projections/deploy/shared.rb +5 -2
  214. data/lib/hecks/projections/deploy/templates/fargate/Makefile.tmpl +7 -4
  215. data/lib/hecks/projections/model/deviations.rb +2 -2
  216. data/lib/hecks/projections/model.rb +2 -2
  217. data/lib/hecks/projections/oidc.rb +13 -1
  218. data/lib/hecks/projections/shape.rb +5 -2
  219. data/lib/hecks/projections/site/cms_editor/attributes.rb +95 -0
  220. data/lib/hecks/projections/site/cms_editor/blocks.rb +157 -0
  221. data/lib/hecks/projections/site/cms_editor/checks.rb +77 -0
  222. data/lib/hecks/projections/site/cms_editor/clearing.rb +70 -0
  223. data/lib/hecks/projections/site/cms_editor/color.rb +124 -0
  224. data/lib/hecks/projections/site/cms_editor/composition.rb +42 -0
  225. data/lib/hecks/projections/site/cms_editor/destructive.rb +61 -0
  226. data/lib/hecks/projections/site/cms_editor/drafts.rb +102 -0
  227. data/lib/hecks/projections/site/cms_editor/hints.rb +74 -0
  228. data/lib/hecks/projections/site/cms_editor/icons.rb +86 -0
  229. data/lib/hecks/projections/site/cms_editor/key_kinds.rb +31 -0
  230. data/lib/hecks/projections/site/cms_editor/limits.rb +72 -0
  231. data/lib/hecks/projections/site/cms_editor/media.rb +85 -0
  232. data/lib/hecks/projections/site/cms_editor/moment.rb +34 -0
  233. data/lib/hecks/projections/site/cms_editor/palette.rb +115 -0
  234. data/lib/hecks/projections/site/cms_editor/pickers.rb +85 -0
  235. data/lib/hecks/projections/site/cms_editor/pretty.rb +40 -0
  236. data/lib/hecks/projections/site/cms_editor/preview.rb +91 -0
  237. data/lib/hecks/projections/site/cms_editor/relations.rb +92 -0
  238. data/lib/hecks/projections/site/cms_editor/scale_checks.rb +66 -0
  239. data/lib/hecks/projections/site/cms_editor/scheduling.rb +150 -0
  240. data/lib/hecks/projections/site/cms_editor/schema.rb +161 -0
  241. data/lib/hecks/projections/site/cms_editor/setting.rb +130 -0
  242. data/lib/hecks/projections/site/cms_editor/targets.rb +86 -0
  243. data/lib/hecks/projections/site/cms_editor/templates/package.json.tmpl +36 -0
  244. data/lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl +370 -0
  245. data/lib/hecks/projections/site/cms_editor/templates/src/assets.ts.tmpl +98 -0
  246. data/lib/hecks/projections/site/cms_editor/templates/src/auth/membership.ts.tmpl +87 -0
  247. data/lib/hecks/projections/site/cms_editor/templates/src/auth/session.ts.tmpl +36 -0
  248. data/lib/hecks/projections/site/cms_editor/templates/src/auth/sso.ts.tmpl +20 -0
  249. data/lib/hecks/projections/site/cms_editor/templates/src/browser/app.css.tmpl +412 -0
  250. data/lib/hecks/projections/site/cms_editor/templates/src/browser/autosave.js.tmpl +144 -0
  251. data/lib/hecks/projections/site/cms_editor/templates/src/browser/blocks.js.tmpl +500 -0
  252. data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_doc.js.tmpl +175 -0
  253. data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_editor.js.tmpl +418 -0
  254. data/lib/hecks/projections/site/cms_editor/templates/src/browser/epoch.js.tmpl +61 -0
  255. data/lib/hecks/projections/site/cms_editor/templates/src/browser/forms.js.tmpl +210 -0
  256. data/lib/hecks/projections/site/cms_editor/templates/src/browser/lists.js.tmpl +40 -0
  257. data/lib/hecks/projections/site/cms_editor/templates/src/browser/main.js.tmpl +26 -0
  258. data/lib/hecks/projections/site/cms_editor/templates/src/browser/media_picker.js.tmpl +232 -0
  259. data/lib/hecks/projections/site/cms_editor/templates/src/browser/moments.js.tmpl +73 -0
  260. data/lib/hecks/projections/site/cms_editor/templates/src/browser/pickers.js.tmpl +152 -0
  261. data/lib/hecks/projections/site/cms_editor/templates/src/browser/preview.js.tmpl +98 -0
  262. data/lib/hecks/projections/site/cms_editor/templates/src/browser/shell.js.tmpl +140 -0
  263. data/lib/hecks/projections/site/cms_editor/templates/src/browser/toast.js.tmpl +66 -0
  264. data/lib/hecks/projections/site/cms_editor/templates/src/choices.ts.tmpl +99 -0
  265. data/lib/hecks/projections/site/cms_editor/templates/src/commands.ts.tmpl +133 -0
  266. data/lib/hecks/projections/site/cms_editor/templates/src/config.ts.tmpl +29 -0
  267. data/lib/hecks/projections/site/cms_editor/templates/src/flash.ts.tmpl +52 -0
  268. data/lib/hecks/projections/site/cms_editor/templates/src/host.ts.tmpl +43 -0
  269. data/lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl +177 -0
  270. data/lib/hecks/projections/site/cms_editor/templates/src/media/multipart.ts.tmpl +53 -0
  271. data/lib/hecks/projections/site/cms_editor/templates/src/media/sniff.ts.tmpl +94 -0
  272. data/lib/hecks/projections/site/cms_editor/templates/src/media/storage.ts.tmpl +50 -0
  273. data/lib/hecks/projections/site/cms_editor/templates/src/names.ts.tmpl +36 -0
  274. data/lib/hecks/projections/site/cms_editor/templates/src/schema.ts.tmpl +214 -0
  275. data/lib/hecks/projections/site/cms_editor/templates/src/server.ts.tmpl +65 -0
  276. data/lib/hecks/projections/site/cms_editor/templates/src/ui/availability.ts.tmpl +15 -0
  277. data/lib/hecks/projections/site/cms_editor/templates/src/ui/block_list.js.tmpl +213 -0
  278. data/lib/hecks/projections/site/cms_editor/templates/src/ui/blocks.ts.tmpl +275 -0
  279. data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_model.js.tmpl +123 -0
  280. data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_parse.js.tmpl +320 -0
  281. data/lib/hecks/projections/site/cms_editor/templates/src/ui/detail.ts.tmpl +88 -0
  282. data/lib/hecks/projections/site/cms_editor/templates/src/ui/dialogs.ts.tmpl +43 -0
  283. data/lib/hecks/projections/site/cms_editor/templates/src/ui/fields.ts.tmpl +275 -0
  284. data/lib/hecks/projections/site/cms_editor/templates/src/ui/html.ts.tmpl +61 -0
  285. data/lib/hecks/projections/site/cms_editor/templates/src/ui/icons.ts.tmpl +15 -0
  286. data/lib/hecks/projections/site/cms_editor/templates/src/ui/input.ts.tmpl +92 -0
  287. data/lib/hecks/projections/site/cms_editor/templates/src/ui/links.ts.tmpl +100 -0
  288. data/lib/hecks/projections/site/cms_editor/templates/src/ui/moments.ts.tmpl +44 -0
  289. data/lib/hecks/projections/site/cms_editor/templates/src/ui/outline.ts.tmpl +63 -0
  290. data/lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl +213 -0
  291. data/lib/hecks/projections/site/cms_editor/templates/src/ui/paging.ts.tmpl +82 -0
  292. data/lib/hecks/projections/site/cms_editor/templates/src/ui/pickers.ts.tmpl +110 -0
  293. data/lib/hecks/projections/site/cms_editor/templates/src/ui/preview.ts.tmpl +87 -0
  294. data/lib/hecks/projections/site/cms_editor/templates/src/ui/related.ts.tmpl +97 -0
  295. data/lib/hecks/projections/site/cms_editor/templates/src/ui/schedule.ts.tmpl +160 -0
  296. data/lib/hecks/projections/site/cms_editor/templates/src/ui/shell.ts.tmpl +211 -0
  297. data/lib/hecks/projections/site/cms_editor/templates/src/ui/table.ts.tmpl +151 -0
  298. data/lib/hecks/projections/site/cms_editor/templates/src/ui/theme.js.tmpl +16 -0
  299. data/lib/hecks/projections/site/cms_editor/templates/src/ui/values.ts.tmpl +69 -0
  300. data/lib/hecks/projections/site/cms_editor/templates/src/ui/words.ts.tmpl +97 -0
  301. data/lib/hecks/projections/site/cms_editor/templates/src/ui/world.ts.tmpl +35 -0
  302. data/lib/hecks/projections/site/cms_editor/templates/tsconfig.json.tmpl +17 -0
  303. data/lib/hecks/projections/site/cms_editor/theme.rb +29 -0
  304. data/lib/hecks/projections/site/cms_editor/theme_checks.rb +57 -0
  305. data/lib/hecks/projections/site/cms_editor.rb +133 -0
  306. data/lib/hecks/projections/site/role_probe.rb +74 -0
  307. data/lib/hecks/projector/cli_audience.rb +2 -1
  308. data/lib/hecks/projector/cli_projector/listing.rb +1 -1
  309. data/lib/hecks/projector/cli_projector/option_specs.rb +1 -1
  310. data/lib/hecks/projector/docs_projector/closing.rb +1 -1
  311. data/lib/hecks/projector/docs_projector.rb +1 -1
  312. data/lib/hecks/projector/exporter/bindings.rb +40 -10
  313. data/lib/hecks/projector/exporter/capability_values.rb +55 -0
  314. data/lib/hecks/projector/narrate_projector/reactions.rb +1 -1
  315. data/lib/hecks/projector/target.rb +11 -0
  316. data/lib/hecks/projector.rb +32 -5
  317. data/lib/hecks/quality_control/adapters/github_checks.rb +12 -8
  318. data/lib/hecks/quality_control/adapters/github_issues.rb +8 -4
  319. data/lib/hecks/quality_control/cli/qa_open_pr.rb +2 -2
  320. data/lib/hecks/quality_control/cli/qa_sweep/checks/shrinking.rb +1 -1
  321. data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +1 -1
  322. data/lib/hecks/quality_control/cli/qa_sweep.rb +1 -1
  323. data/lib/hecks/quality_control/quality_control.bluebook +6 -2
  324. data/lib/hecks/release/approval.rb +64 -0
  325. data/lib/hecks/router/{door.rb → aggregate_reader.rb} +5 -4
  326. data/lib/hecks/router/namespace_installer.rb +16 -16
  327. data/lib/hecks/router.rb +1 -1
  328. data/lib/hecks/runtime/best_effort.rb +22 -0
  329. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +12 -2
  330. data/lib/hecks/runtime/command_interpreter.rb +3 -2
  331. data/lib/hecks/runtime/command_rules/emission.rb +1 -1
  332. data/lib/hecks/runtime/dispatcher.rb +4 -4
  333. data/lib/hecks/runtime/entity_element/location.rb +1 -1
  334. data/lib/hecks/runtime/event.rb +5 -0
  335. data/lib/hecks/runtime/identity.rb +7 -6
  336. data/lib/hecks/runtime/interpreting.rb +2 -1
  337. data/lib/hecks/runtime/invocation_builder.rb +1 -1
  338. data/lib/hecks/runtime/loader/boot_steps.rb +8 -5
  339. data/lib/hecks/runtime/loader.rb +10 -10
  340. data/lib/hecks/runtime/policy_interpreter/arguments.rb +7 -4
  341. data/lib/hecks/runtime/policy_interpreter/fan_out.rb +3 -3
  342. data/lib/hecks/runtime/policy_interpreter.rb +6 -6
  343. data/lib/hecks/runtime/port_operation_interpreter.rb +1 -1
  344. data/lib/hecks/runtime/reaction_invocation.rb +1 -1
  345. data/lib/hecks/runtime/rebuild_sweep.rb +11 -1
  346. data/lib/hecks/runtime/registry/ask_verification.rb +35 -0
  347. data/lib/hecks/runtime/registry/hecksagon_rules.rb +10 -0
  348. data/lib/hecks/runtime/registry/merging.rb +1 -1
  349. data/lib/hecks/runtime/registry/providers.rb +16 -0
  350. data/lib/hecks/runtime/registry/read_repository.rb +6 -4
  351. data/lib/hecks/runtime/registry/verification.rb +4 -1
  352. data/lib/hecks/runtime/registry/world_defaults.rb +29 -0
  353. data/lib/hecks/runtime/registry.rb +1 -1
  354. data/lib/hecks/runtime/saga_interpreter/compensation.rb +1 -1
  355. data/lib/hecks/runtime/saga_interpreter/delivery.rb +4 -4
  356. data/lib/hecks/runtime/saga_interpreter/transitions.rb +1 -1
  357. data/lib/hecks/runtime/saga_interpreter.rb +3 -3
  358. data/lib/hecks/runtime/tenant_check.rb +5 -4
  359. data/lib/hecks/runtime/value/coercion.rb +2 -2
  360. data/lib/hecks/runtime/value/validation.rb +16 -4
  361. data/lib/hecks/runtime.rb +9 -9
  362. data/lib/hecks/rust_build/project_rust/target_ir.rb +1 -1
  363. data/lib/hecks/rust_build/wasm.rb +1 -1
  364. data/lib/hecks/rust_build/wasm_browser.rb +1 -1
  365. data/lib/hecks/rust_build.rb +11 -0
  366. data/lib/hecks/served_options.rb +53 -0
  367. data/lib/hecks/site/bluebook/site.bluebook +29 -1
  368. data/lib/hecks/site/bluebook/site.ports.hecksagon +6 -0
  369. data/lib/hecks/storehouse/audit.rb +1 -1
  370. data/lib/hecks/storehouse/dispatching.rb +8 -6
  371. data/lib/hecks/storehouse/introspection.rb +2 -2
  372. data/lib/hecks/storehouse/querying.rb +6 -4
  373. data/lib/hecks/storehouse.rb +4 -4
  374. data/lib/hecks/tools/comment_style/source_file.rb +4 -1
  375. data/lib/hecks/tools/deploy_recipe_lint/fixtures.rb +4 -1
  376. data/lib/hecks/tools/lanes/rows.rb +6 -0
  377. data/lib/hecks/tools/oidc_manifests.rb +4 -5
  378. data/lib/hecks/tools/regeneration_run.rb +11 -4
  379. data/lib/hecks/tools/site_routes/cli.rb +1 -1
  380. data/lib/hecks/tools/site_routes/editor_files.rb +45 -0
  381. data/lib/hecks/tools/site_routes.rb +14 -7
  382. data/lib/hecks/tools/tenant_provisioning.rb +2 -2
  383. data/lib/hecks/tools/tools_doc.rb +4 -4
  384. data/lib/hecks/version.rb +1 -1
  385. data/lib/hecks/vocabulary.rb +4 -4
  386. data/lib/hecks.rb +15 -15
  387. data/lib/rubocop/cop/hecks/env_dump.rb +69 -0
  388. data/lib/rubocop/cop/hecks/monotonic_duration.rb +53 -0
  389. data/lib/rubocop/cop/hecks/no_wall_clock_in_runtime.rb +34 -0
  390. data/lib/rubocop/cop/hecks/raw_shell_interpolation.rb +79 -0
  391. data/lib/rubocop/cop/hecks/sleep_in_spec.rb +34 -0
  392. data/lib/rubocop/cop/hecks/swallowed_rescue.rb +37 -0
  393. data/lib/rubocop/cop/hecks/symbol_string_key_mix.rb +50 -0
  394. data/lib/rubocop/cop/hecks/untyped_raise.rb +37 -0
  395. data/prebuilt/05c358d38d661a3774f813d49c66f5b68939af94432d66257a56f49ee2598994.marshal +0 -0
  396. data/prebuilt/26c40c61f09b09b11651c64668eda3ceb180f83cf2a3802d3033d2fd99ac841b.marshal +0 -0
  397. data/prebuilt/verdicts-230ac18c25abfd3d92ede032bee2661a4c2cd2773ab0cf0e2ae52546ba2f7af9.json +1 -0
  398. data/rust/.gitignore +6 -0
  399. data/rust/Cargo.toml +9 -1
  400. data/rust/build/src/binding_pass.rs +103 -0
  401. data/rust/build/src/cargo_sync.rs +6 -0
  402. data/rust/build/src/lineage_pass.rs +3 -3
  403. data/rust/build/src/main.rs +17 -5
  404. data/rust/build/src/pipeline.rs +48 -5
  405. data/rust/build/src/seams_pass.rs +123 -0
  406. data/rust/build/src/translation_pass.rs +167 -0
  407. data/rust/codegen/src/asks.rs +103 -0
  408. data/rust/codegen/src/bridging.rs +1 -1
  409. data/rust/codegen/src/commands.rs +13 -8
  410. data/rust/codegen/src/constraints.rs +25 -0
  411. data/rust/codegen/src/domain_generator.rs +11 -9
  412. data/rust/codegen/src/expr_emitter.rs +13 -0
  413. data/rust/codegen/src/json_codec.rs +54 -15
  414. data/rust/codegen/src/main.rs +2 -1
  415. data/rust/codegen/src/mutations.rs +174 -4
  416. data/rust/codegen/src/naming.rs +30 -0
  417. data/rust/codegen/src/queries.rs +11 -2
  418. data/rust/codegen/src/reactions.rs +1 -1
  419. data/rust/codegen/src/types.rs +166 -8
  420. data/rust/host/HECKS_RELEASE +1 -1
  421. data/rust/host/src/api.rs +4 -4
  422. data/rust/host/src/bin/validate_harness.rs +43 -0
  423. data/rust/host/src/boundary_fuzz/expr_json.rs +2 -2
  424. data/rust/host/src/boundary_fuzz/ir.rs +1 -0
  425. data/rust/host/src/boundary_fuzz/server.rs +1 -1
  426. data/rust/host/src/checkout.rs +35 -19
  427. data/rust/host/src/commerce_ir.rs +408 -2
  428. data/rust/host/src/expr_json.rs +118 -0
  429. data/rust/host/src/mint.rs +1 -1
  430. data/rust/host/src/payments/tests.rs +27 -1
  431. data/rust/host/src/payments.rs +12 -4
  432. data/rust/host/src/query_step.rs +22 -4
  433. data/rust/host/src/reference_validate.rs +653 -108
  434. data/rust/host/src/resend.rs +2 -0
  435. data/rust/host/src/server.rs +19 -6
  436. data/rust/host/src/ui_schema.rs +132 -5
  437. data/rust/host/src/web/newsletter.rs +7 -8
  438. data/rust/host/src/web/newsletter_send.rs +38 -13
  439. data/rust/host/src/web/registrations.rs +229 -26
  440. data/rust/host/src/web.rs +3 -3
  441. data/rust/parser/src/emit.rs +38 -6
  442. data/rust/parser/src/expr/ast_json.rs +7 -1
  443. data/rust/parser/src/expr/resolver.rs +171 -6
  444. data/rust/parser/src/ir.rs +7 -0
  445. data/rust/parser/src/keywords.rs +24 -0
  446. data/rust/parser/src/main.rs +3 -0
  447. data/rust/parser/src/parse/aggregate.rs +2 -1
  448. data/rust/parser/src/parse/chapter.rs +2 -2
  449. data/rust/parser/src/parse/command.rs +2 -0
  450. data/rust/parser/src/parse/hecksagon.rs +5 -2
  451. data/rust/parser/src/parse/lifecycle.rs +81 -0
  452. data/rust/parser/src/parse/mod.rs +15 -1
  453. data/rust/parser/src/parse/policy.rs +13 -2
  454. data/rust/parser/src/parse/value_object.rs +13 -8
  455. data/rust/parser/src/ruby_value.rs +1 -1
  456. data/rust/src/exemplar/commands.rs +4 -4
  457. data/rust/src/exemplar/constraints.rs +1 -1
  458. data/rust/src/exemplar/json.rs +43 -1
  459. data/rust/src/kernel/cli.rs +7 -5
  460. data/rust/src/kernel/dispatch.rs +2 -2
  461. data/rust/src/kernel/dispatch_guard_tests.rs +1 -1
  462. data/rust/src/kernel/expr.rs +73 -4
  463. data/rust/src/kernel/expression_operators/arithmetic.rs +130 -5
  464. data/rust/src/kernel/expression_operators/presence.rs +41 -3
  465. data/rust/src/kernel/expression_operators/text.rs +26 -2
  466. data/rust/src/kernel/json.rs +15 -0
  467. data/rust/src/kernel/mod.rs +1 -1
  468. data/rust/src/kernel/orchestrate.rs +54 -5
  469. data/rust/src/kernel/orchestrate_guard_tests.rs +67 -0
  470. data/rust/src/kernel/pattern.rs +60 -0
  471. data/rust/src/kernel/reference_lookup.rs +90 -7
  472. metadata +174 -36
  473. data/lib/hecks/doors/cli_door/nesting.rb +0 -34
  474. data/lib/hecks/doors/cli_door/shorthand.rb +0 -85
  475. data/lib/hecks/doors/cli_door.rb +0 -124
  476. data/lib/hecks/doors/cli_runner/answers.rb +0 -138
  477. data/lib/hecks/doors/cli_runner/resolution.rb +0 -146
  478. data/lib/hecks/doors/cli_runner/settling.rb +0 -115
  479. data/lib/hecks/doors/cli_runner/streaming.rb +0 -90
  480. data/lib/hecks/doors/cli_runner/suggestions.rb +0 -43
  481. data/lib/hecks/doors/cli_runner.rb +0 -66
  482. data/lib/hecks/doors/command_request.rb +0 -119
  483. data/lib/hecks/doors/handle.rb +0 -208
  484. data/lib/hecks/doors/json_door.rb +0 -132
  485. data/lib/hecks/doors/launcher_options.rb +0 -247
  486. data/lib/hecks/doors/mcp_door/properties.rb +0 -47
  487. data/lib/hecks/doors/mcp_door/tool_calls.rb +0 -113
  488. data/lib/hecks/doors/mcp_door/tool_definitions/auditing.rb +0 -51
  489. data/lib/hecks/doors/mcp_door/tool_definitions/calling.rb +0 -69
  490. data/lib/hecks/doors/mcp_door/tool_definitions/reading.rb +0 -97
  491. data/lib/hecks/doors/mcp_door/tool_definitions.rb +0 -15
  492. data/lib/hecks/doors/mcp_door.rb +0 -156
  493. data/lib/hecks/doors/mcp_door_scope/argument_policy.rb +0 -92
  494. data/lib/hecks/doors/mcp_door_scope/env_problems.rb +0 -55
  495. data/lib/hecks/doors/mcp_door_scope/presenter.rb +0 -78
  496. data/lib/hecks/doors/mcp_door_scope.rb +0 -201
  497. data/lib/hecks/doors/mcp_guide_cache.rb +0 -75
  498. data/lib/hecks/doors/ruby_door/aggregate_door.rb +0 -162
  499. data/lib/hecks/doors/ruby_door/chapter.rb +0 -89
  500. data/lib/hecks/doors/ruby_door.rb +0 -80
  501. data/lib/hecks/doors/usage_cache.rb +0 -139
  502. data/prebuilt/0ee7f83cba59ce7d1c45c65ba166b071779f70143449f584f33ff7989f64eccb.marshal +0 -0
  503. data/prebuilt/6e4a6bcf0aa880e2e6b056e1846b70e5a768090b9dc998bbadeaf5d6bcfd3db8.marshal +0 -0
  504. data/prebuilt/verdicts-91aaf93ce8981bd9a754948f075d95650dc2ec6435015376f5c60992b36a24b1.json +0 -1
@@ -0,0 +1,267 @@
1
+ require "pathname"
2
+ require "stringio"
3
+ require_relative "../../ports/identity_generation"
4
+ require_relative "../../runtime/errors"
5
+ require_relative "cli"
6
+
7
+ module Hecks
8
+ module Adapters
9
+ module Driving
10
+ # What a domain's world file adds to its generated launcher, all of it opt-in.
11
+ #
12
+ # A `.world` that declares a `launcher` setting switches these on for that chapter; a
13
+ # domain without one keeps the launcher's plain forms exactly:
14
+ #
15
+ # - **run_keys** mints the `run` key of a creating command that was given none.
16
+ # - **settled** lists the commands (`aggregate.command`) that always act as if given `--wait`.
17
+ # - **unknown_runs** lists the questions that refuse a run this process does not hold.
18
+ # - **report** lists the settled commands whose answer is the report they recorded, as text.
19
+ # - **names** maps a launcher name to the command it stands for (see `CliProjector`).
20
+ # - **streams** lists the questions `--stream` may tail, one JSON line per new entry.
21
+ # - **maintainer**, **chapters**, **maintainer_chapters** shape the help for its audience.
22
+ module LauncherOptions
23
+ SETTING = "launcher".freeze
24
+ WAIT = "--wait".freeze
25
+ STREAM = "--stream".freeze
26
+ RUN_KEY = "run.value".freeze
27
+ # The lifecycle mark naming the states `--wait` reports as a failure (exit 1); the lifecycle
28
+ # says so with `mark :failure, "flagged"` (ADR 0097), so no setting lists them.
29
+ FAILURE_MARK = "failure".freeze
30
+ # What makes a directory a hecks checkout: this file stands beside `lib/`, the same test
31
+ # the Codebase aggregate's `Accept` applies before it runs anything.
32
+ CHECKOUT_MARKER = "hecks.gemspec".freeze
33
+ # `HECKS_MAINTAINER=1` shows the maintainer help anywhere, `0` hides it even in a checkout.
34
+ MAINTAINER_VARIABLE = "HECKS_MAINTAINER".freeze
35
+
36
+ module_function
37
+
38
+ # Reads a chapter's `launcher` setting.
39
+ #
40
+ # @param runtime [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted domain
41
+ # @param chapter [String] the chapter the command line speaks to
42
+ # @return [Hash{Symbol => Object}, nil] the setting, or nil when the chapter did not opt in
43
+ def settings(runtime, chapter)
44
+ return unless runtime.respond_to?(:registry)
45
+
46
+ found = runtime.registry.world(chapter)&.for_verb(SETTING)
47
+ found.nil? || found.empty? ? nil : found
48
+ end
49
+
50
+ # The options the launcher's projection is asked for: the program's name, the chapter's
51
+ # launcher names, and whether run keys are minted (so help shows them optional).
52
+ #
53
+ # @param settings [Hash, nil] the chapter's `launcher` setting
54
+ # @param program [String] how the caller was invoked
55
+ # @return [Hash{Symbol => Object}] the options `Projector::CliProjector` reads
56
+ def projection(settings, program)
57
+ { program: program, names: settings && settings[:names], mint_run_keys: settings && settings[:run_keys] }
58
+ end
59
+
60
+ # Whether the person is working on a hecks checkout: `dir` or a directory above it holds
61
+ # `hecks.gemspec` beside `lib/`. `HECKS_MAINTAINER` overrides the look.
62
+ #
63
+ # @param dir [String] where the command line was typed
64
+ # @param env [#[]] the environment
65
+ # @return [Boolean] true for the maintainer's view of the help
66
+ def maintainer?(dir = Dir.pwd, env = ENV)
67
+ forced = env[MAINTAINER_VARIABLE].to_s
68
+ return forced != "0" unless forced.empty?
69
+
70
+ Pathname.new(File.expand_path(dir)).ascend.any? do |root|
71
+ root.join(CHECKOUT_MARKER).exist? && root.join("lib").directory?
72
+ end
73
+ end
74
+
75
+ # The help options one audience gets: the aggregates left out of the lists (`maintainer`,
76
+ # shown only in a hecks checkout or to `--maintainer`) and the chapters pointed at
77
+ # (`chapters`, plus `maintainer_chapters` in a checkout). A chapter that did not opt in
78
+ # gets neither.
79
+ #
80
+ # @param settings [Hash, nil] the chapter's `launcher` setting
81
+ # @param maintainer [Boolean] whether the help is for someone working on a hecks checkout
82
+ # @return [Hash{Symbol => Object}] `:hide` and `:chapters`, to merge into the projection
83
+ def audience(settings, maintainer)
84
+ return {} unless settings
85
+
86
+ chapters = Array(settings[:chapters]) + (maintainer ? Array(settings[:maintainer_chapters]) : [])
87
+ { hide: maintainer ? [] : Array(settings[:maintainer]).map(&:to_s), chapters: chapters.map(&:to_s) }
88
+ end
89
+
90
+ # Runs the block with standard error held back, so the wiring notes hecks prints about its
91
+ # own
92
+ # chapters (a Memory journal loses sagas on restart) do not open a console session. They are
93
+ # for an operator running a stored journal. A raised error still surfaces, unchanged.
94
+ #
95
+ # @param hold [Boolean] whether to hold standard error back; false runs the block as it is
96
+ # @yield the boot
97
+ # @return [Object] the block's value
98
+ def quietly(hold: true)
99
+ return yield unless hold
100
+
101
+ shown = $stderr
102
+ $stderr = StringIO.new
103
+ yield
104
+ ensure
105
+ $stderr = shown if hold
106
+ end
107
+
108
+ # Takes `--wait` out of a command's words, unless it declares a `wait` argument of its own.
109
+ #
110
+ # `--wait=false` (or `no`, `0`, `off`) is a `--wait` that was switched off; a bare `--wait`
111
+ # may be followed by its Boolean word.
112
+ #
113
+ # @param spec [Hash] the command's projected spec
114
+ # @param words [Array<String>] the words after the command
115
+ # @return [Array(Array<String>, Boolean)] the remaining words, and whether `--wait` was
116
+ # given
117
+ # @raise [Runtime::TypeMismatch] if `--wait=` carries something that is not a Boolean word
118
+ def take_wait(spec, words)
119
+ return [words, false] unless words.any? { |word| wait_word?(word) } && !declares_wait?(spec)
120
+
121
+ split_wait(words)
122
+ end
123
+
124
+ # Whether the command declares an argument of its own named `wait`.
125
+ # @api private
126
+ def declares_wait?(spec)
127
+ spec[:arguments].any? { |argument| argument[:path].split(".").first == "wait" }
128
+ end
129
+
130
+ # The words without `--wait`, and whether it was given.
131
+ # @api private
132
+ def split_wait(words)
133
+ wait = false
134
+ rest = []
135
+ queue = words.dup
136
+ until queue.empty?
137
+ word = queue.shift
138
+ wait_word?(word) ? wait ||= Cli.boolean(wait_value(word, queue)) : rest << word
139
+ end
140
+ [rest, wait]
141
+ end
142
+
143
+ # Whether a command always waits for its reactions, as if `--wait` had been given.
144
+ #
145
+ # @param launcher [Hash, nil] the chapter's `launcher` setting
146
+ # @param spec [Hash] the command's projected spec
147
+ # @return [Boolean] true for a command the setting lists under `settled`
148
+ def settled?(launcher, spec)
149
+ return false unless launcher && spec[:kind] == :command
150
+
151
+ Array(launcher[:settled]).map(&:to_s).include?(spec[:short].to_s)
152
+ end
153
+
154
+ # Whether a question about one run refuses a run this process does not hold, instead of
155
+ # answering an empty list.
156
+ #
157
+ # @param launcher [Hash, nil] the chapter's `launcher` setting
158
+ # @param spec [Hash] the question's projected spec
159
+ # @return [Boolean] true for a question the setting lists under `unknown_runs`
160
+ def unknown_run?(launcher, spec)
161
+ return false unless launcher && spec[:kind] == :query
162
+
163
+ Array(launcher[:unknown_runs]).map(&:to_s).include?(spec[:short].to_s)
164
+ end
165
+
166
+ # Whether a command prints the report it recorded instead of its whole record.
167
+ #
168
+ # @param launcher [Hash, nil] the chapter's `launcher` setting
169
+ # @param spec [Hash] the command's projected spec
170
+ # @return [Boolean] true for a command the setting lists under `report`
171
+ def report?(launcher, spec)
172
+ return false unless launcher && spec[:kind] == :command
173
+
174
+ Array(launcher[:report]).map(&:to_s).include?(spec[:short].to_s)
175
+ end
176
+
177
+ # Whether a question may be tailed with `--stream`: the chapter's `launcher` setting lists
178
+ # it
179
+ # under `streams`, by the question's own name.
180
+ #
181
+ # @param launcher [Hash, nil] the chapter's `launcher` setting
182
+ # @param spec [Hash] the question's projected spec
183
+ # @return [Boolean] true for a question the setting names
184
+ def streams?(launcher, spec)
185
+ return false unless launcher && spec[:kind] == :query
186
+
187
+ Array(launcher[:streams]).map(&:to_s).include?(spec[:command].to_s.split(/[.:]+/).last)
188
+ end
189
+
190
+ # Takes `--stream` out of a question's words.
191
+ #
192
+ # @param words [Array<String>] the words after the question
193
+ # @return [Array(Array<String>, Boolean)] the remaining words, and whether `--stream` was
194
+ # given
195
+ def take_stream(words)
196
+ [words.reject { |word| word == STREAM }, words.include?(STREAM)]
197
+ end
198
+
199
+ # @api private
200
+ def wait_word?(word) = word == WAIT || word.start_with?("#{WAIT}=")
201
+
202
+ # The Boolean word a `--wait` carries: after `=`, or the next word when it is one.
203
+ # @api private
204
+ def wait_value(word, queue)
205
+ return word.split("=", 2).last if word.include?("=")
206
+
207
+ Cli::BOOLEAN_WORDS.key?(queue.first.to_s.downcase) ? queue.shift : "true"
208
+ end
209
+
210
+ # Whether a question's text answer reports a gap, which `--wait` turns into a failing exit.
211
+ #
212
+ # The coverage checks end their report with a `GAP (n)` heading; a non-zero count is a
213
+ # finding, and a CI stage that waits on the question fails on it.
214
+ #
215
+ # @param text [String, nil] the question's text answer
216
+ # @return [Boolean] whether a `GAP (n)` heading with n above zero is in the text
217
+ def gap_reported?(text)
218
+ text.is_a?(String) && text.match?(/^GAP \((?!0\))\d+\)/)
219
+ end
220
+
221
+ # Mints the `run` key a creating command was not given, when the domain opted in.
222
+ #
223
+ # An explicit key always wins. Nothing is minted for a command that acts on an existing
224
+ # record. When no identity adapter is bound the run is refused, saying to name a key,
225
+ # rather than sent on without one.
226
+ #
227
+ # @param runtime [Runtime::Dispatcher, Runtime::RemoteDispatcher] the booted domain
228
+ # @param spec [Hash] the command's projected spec
229
+ # @param args [Hash] the parsed arguments
230
+ # @param settings [Hash, nil] the chapter's `launcher` setting
231
+ # @return [Array(Hash, String)] the arguments, and the key minted (nil when none was)
232
+ # @raise [Runtime::NotFound] if a key is owed but no identity adapter is bound
233
+ def run_key(runtime, spec, args, settings)
234
+ return [args, nil] unless key_owed?(runtime, spec, args, settings)
235
+
236
+ key = Ports::IdentityGeneration.uuid(runtime.registry)
237
+ [args.merge(run: { value: key }), key]
238
+ rescue Runtime::WiringError => e
239
+ raise Runtime::NotFound, "cannot mint a run key (#{e.message.lines.first.strip}); name one with run=<key>"
240
+ end
241
+
242
+ # Whether the command is a creating one of an opted-in chapter, takes a run key and was
243
+ # given none.
244
+ # @api private
245
+ def key_owed?(runtime, spec, args, settings)
246
+ return false unless settings && settings[:run_keys] && spec[:creates]
247
+ return false unless spec[:arguments].any? { |argument| argument[:path] == RUN_KEY }
248
+
249
+ !args.key?(:run) && runtime.respond_to?(:registry)
250
+ end
251
+
252
+ # Whether a settled record sits in a state its lifecycle marks as a failure.
253
+ #
254
+ # @param aggregate [Bluebook::Aggregate, nil] the record's aggregate
255
+ # @param state [Hash, nil] the record's state
256
+ # @param settings [Hash, nil] the chapter's `launcher` setting
257
+ # @return [Boolean] false when the aggregate has no lifecycle
258
+ def failed?(aggregate, state, settings)
259
+ field = aggregate&.lifecycle&.field
260
+ return false unless field && state && settings
261
+
262
+ Array(aggregate.lifecycle.marked(FAILURE_MARK)).include?(state[field.to_sym].to_s)
263
+ end
264
+ end
265
+ end
266
+ end
267
+ end
@@ -0,0 +1,49 @@
1
+ require_relative "../../.."
2
+
3
+ module Hecks
4
+ module Adapters
5
+ module Driving
6
+ module Mcp
7
+ # The input-schema properties the MCP server's tools share.
8
+ module Properties
9
+ SUMMARY_PROPERTY = {
10
+ type: "string",
11
+ description: "One line: why this call is happening. Required — it is what makes the audit trail legible later."
12
+ }.freeze
13
+
14
+ DOMAIN_PROPERTY = {
15
+ type: "string",
16
+ description: "The domain directory, containing a .hecksagon (e.g. \"examples/banking\"). The `domains` tool " \
17
+ "lists what's available."
18
+ }.freeze
19
+
20
+ ARGS_PROPERTY = {
21
+ type: "object",
22
+ description: "The command/query's declared arguments, nested value-object literals included " \
23
+ "(e.g. {\"reference\":{\"value\":\"BUG#1\"}})."
24
+ }.freeze
25
+
26
+ SOURCE_PROPERTY = {
27
+ type: "string",
28
+ enum: Hecks::Storehouse::SOURCE_TAGS,
29
+ description: "Optional: who is calling, for the audit log `follow` reads back."
30
+ }.freeze
31
+
32
+ ROLE_PROPERTY = {
33
+ type: "string",
34
+ description: "Bind a caller identity for the call's duration, so a role-gated command's authorization is " \
35
+ "checked rather than merely documented. Required by `dispatch` for any command that declares a " \
36
+ "role — omitting it refuses the call rather than running it unchecked. Also required if " \
37
+ "`actor_id` is given."
38
+ }.freeze
39
+
40
+ ACTOR_ID_PROPERTY = {
41
+ type: "string",
42
+ description: "Optional, alongside `role`: WHO holds that role — once the domain attaches Governance, checked " \
43
+ "against a real Governance::RoleAssignment instead of a bare string match. Requires `role`."
44
+ }.freeze
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,116 @@
1
+ require_relative "../../.."
2
+
3
+ module Hecks
4
+ module Adapters
5
+ module Driving
6
+ module Mcp
7
+ # Answers one `tools/call`: the tool a name stands for, run against the booted domain the
8
+ # call names. A domain refusal is already `{ok: false, ...}` from `Storehouse`.
9
+ module ToolCalls
10
+ # The method that answers each tool.
11
+ HANDLERS = {
12
+ "dispatch" => :dispatch_tool,
13
+ "query" => :query_tool,
14
+ "events" => :events_tool,
15
+ "state" => :state_tool,
16
+ "catalog" => :catalog_tool,
17
+ "describe" => :describe_tool,
18
+ "validate" => :validate_tool,
19
+ "domains" => :domains_tool,
20
+ "history" => :history_tool,
21
+ "behaviors" => :behaviors_tool,
22
+ "follow" => :follow_tool
23
+ }.freeze
24
+
25
+ module_function
26
+
27
+ # Runs the tool `name` with `args`, so the shared `rescue` catches every tool's escape
28
+ # once.
29
+ #
30
+ # @param name [String] the tool's name
31
+ # @param args [Hash{String => Object}] the call's arguments
32
+ # @return [Hash{Symbol => Object}] the tool's answer, or `{ok: false, error: ...}`
33
+ def call(name, args)
34
+ handler = HANDLERS[name]
35
+ return unknown(name) unless handler
36
+
37
+ public_send(handler, args)
38
+ rescue StandardError => e
39
+ # A defect, not a refusal: reaching here means a bad domain path or an
40
+ # argument shape `Adapters::Driving::Json` could not symbolize.
41
+ { ok: false, error: "#{e.class}: #{e.message}" }
42
+ end
43
+
44
+ # The refusal for a tool the server does not have.
45
+ def unknown(name)
46
+ { ok: false, error: "no such tool: #{name.inspect} — known: #{HANDLERS.keys.join(", ")}" }
47
+ end
48
+
49
+ # A question, once the scope has admitted its arguments.
50
+ def query_tool(args)
51
+ Mcp.scope.admit_arguments!(args["args"])
52
+ Storehouse.query(runtime: Mcp.boot(args["domain"]), question: args["question"],
53
+ summary: args["summary"], args: args["args"] || {}, source: args["source"],
54
+ role: args["role"], actor_id: args["actor_id"])
55
+ end
56
+
57
+ # A single command or a batch, once the scope has admitted every command in it.
58
+ def dispatch_tool(args)
59
+ runtime = Mcp.boot(args["domain"])
60
+ return dispatch_steps(runtime, args) if args["steps"]
61
+
62
+ Mcp.scope.admit_command!(runtime, args["command"], args["args"])
63
+ Storehouse.dispatch(runtime: runtime, command: args["command"], summary: args["summary"],
64
+ args: args["args"] || {}, source: args["source"],
65
+ dry_run: args["dry_run"] == true, role: args["role"], actor_id: args["actor_id"])
66
+ end
67
+
68
+ # Several commands in one call.
69
+ def dispatch_steps(runtime, args)
70
+ Mcp.scope.admit_steps!(runtime, args["steps"])
71
+ Storehouse.dispatch_batch(runtime: runtime, steps: args["steps"], summary: args["summary"],
72
+ source: args["source"], role: args["role"], actor_id: args["actor_id"])
73
+ end
74
+
75
+ def events_tool(args)
76
+ Storehouse.events(runtime: Mcp.boot(args["domain"]), aggregate: args["aggregate"], id: args["id"],
77
+ limit: args["limit"])
78
+ end
79
+
80
+ def state_tool(args)
81
+ Storehouse.state(runtime: Mcp.boot(args["domain"]), aggregate: args["aggregate"],
82
+ summary: args["summary"], id: args["id"])
83
+ end
84
+
85
+ def catalog_tool(args)
86
+ Storehouse.catalog(runtime: Mcp.boot(args["domain"]))
87
+ end
88
+
89
+ def describe_tool(args)
90
+ Storehouse.describe(runtime: Mcp.boot(args["domain"]), aggregate: args["aggregate"])
91
+ end
92
+
93
+ def validate_tool(args)
94
+ Storehouse.validate(domain: Mcp.scope.admit_domain!(args["domain"]), deep: args["deep"] == true)
95
+ end
96
+
97
+ def domains_tool(args)
98
+ Storehouse.domains(under: args["under"] || "examples")
99
+ end
100
+
101
+ def history_tool(args)
102
+ Storehouse.history(runtime: Mcp.boot(args["domain"]))
103
+ end
104
+
105
+ def behaviors_tool(args)
106
+ Storehouse.behaviors(target: args["target"])
107
+ end
108
+
109
+ def follow_tool(args)
110
+ Storehouse.follow(runtime: Mcp.boot(args["domain"]), limit: args["limit"] || 20)
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,53 @@
1
+ require_relative "../../mcp/properties"
2
+
3
+ module Hecks
4
+ module Adapters
5
+ module Driving
6
+ module Mcp
7
+ module ToolDefinitions
8
+ # The tools that read what has been recorded: write history, behaviors and the audit log.
9
+ module Auditing
10
+ include Properties
11
+
12
+ LIST = [
13
+ {
14
+ name: "history",
15
+ description: "The full write history for every aggregate in a domain — every operation an append-only " \
16
+ "adapter ever recorded, not just current state. An aggregate on a non-append-only adapter " \
17
+ "answers an empty history honestly.",
18
+ inputSchema: {
19
+ type: "object",
20
+ properties: { domain: DOMAIN_PROPERTY },
21
+ required: %w[domain]
22
+ }
23
+ },
24
+ {
25
+ name: "behaviors",
26
+ description: "Run a domain's hand-curated `.behaviors` example tests and report pass/fail/error per test. " \
27
+ "`target` is a single `.behaviors` file or a directory to sweep.",
28
+ inputSchema: {
29
+ type: "object",
30
+ properties: { target: { type: "string", description: "A .behaviors file, or a directory to sweep." } },
31
+ required: %w[target]
32
+ }
33
+ },
34
+ {
35
+ name: "follow",
36
+ description: "Tail this server's own audit log for a domain — the last `limit` dispatch/query/state/dry-run " \
37
+ "calls made through it, each carrying its summary, source, and outcome.",
38
+ inputSchema: {
39
+ type: "object",
40
+ properties: {
41
+ domain: DOMAIN_PROPERTY,
42
+ limit: { type: "integer", description: "How many recent entries to return. Defaults to 20." }
43
+ },
44
+ required: %w[domain]
45
+ }
46
+ }
47
+ ].freeze
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,71 @@
1
+ require_relative "../../mcp/properties"
2
+
3
+ module Hecks
4
+ module Adapters
5
+ module Driving
6
+ module Mcp
7
+ module ToolDefinitions
8
+ # The tools that issue a command or ask a question.
9
+ module Calling
10
+ include Properties
11
+
12
+ LIST = [
13
+ {
14
+ name: "dispatch",
15
+ description: "Issue a command against a booted domain — or, with `steps`, several in one call. `command` is " \
16
+ "the short or qualified verb name (the catalog/describe tools show what's available). Set " \
17
+ "`dry_run: true` to check whether it WOULD succeed without committing anything. Answers the " \
18
+ "record's id, its resulting state, and the events it announced — or a structured refusal, " \
19
+ "never a crash.",
20
+ inputSchema: {
21
+ type: "object",
22
+ properties: {
23
+ domain: DOMAIN_PROPERTY,
24
+ command: { type: "string", description: "The command's short or qualified name, e.g. \"open_account\". " \
25
+ "Ignored when `steps` is given." },
26
+ args: ARGS_PROPERTY,
27
+ summary: SUMMARY_PROPERTY,
28
+ source: SOURCE_PROPERTY,
29
+ role: ROLE_PROPERTY,
30
+ actor_id: ACTOR_ID_PROPERTY,
31
+ dry_run: { type: "boolean", description: "Preview only — check the command would succeed, commit nothing. " \
32
+ "Ignored when `steps` is given." },
33
+ steps: {
34
+ type: "array",
35
+ description: "Run several commands in one call, in order. Each item: {command, args}. When given, " \
36
+ "`command`/`args`/`dry_run` above are ignored.",
37
+ items: {
38
+ type: "object",
39
+ properties: { command: { type: "string" }, args: ARGS_PROPERTY },
40
+ required: %w[command]
41
+ }
42
+ }
43
+ },
44
+ required: %w[domain summary]
45
+ }
46
+ },
47
+ {
48
+ name: "query",
49
+ description: "Ask a declared question of a booted domain. `question` is the short or qualified query name. " \
50
+ "Answers the row array the query itself declares.",
51
+ inputSchema: {
52
+ type: "object",
53
+ properties: {
54
+ domain: DOMAIN_PROPERTY,
55
+ question: { type: "string", description: "The query's short or qualified name." },
56
+ args: ARGS_PROPERTY,
57
+ summary: SUMMARY_PROPERTY,
58
+ source: SOURCE_PROPERTY,
59
+ role: ROLE_PROPERTY,
60
+ actor_id: ACTOR_ID_PROPERTY
61
+ },
62
+ required: %w[domain question summary]
63
+ }
64
+ }
65
+ ].freeze
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,99 @@
1
+ require_relative "../../mcp/properties"
2
+
3
+ module Hecks
4
+ module Adapters
5
+ module Driving
6
+ module Mcp
7
+ module ToolDefinitions
8
+ # The tools that read a domain: its events, state, shape and wiring.
9
+ module Reading
10
+ include Properties
11
+
12
+ LIST = [
13
+ {
14
+ name: "events",
15
+ description: "What actually HAPPENED, with payloads, to one aggregate/record — events THIS SERVER witnessed " \
16
+ "(every real dispatch ever routed through it, sourced from its own audit log — not a full " \
17
+ "domain-wide event-sourcing replay). Distinct from `state` (what's stored now) and `history` " \
18
+ "(append-only operation snapshots, no payload). Narrow with `aggregate` and (requires " \
19
+ "`aggregate`) `id`; `limit` keeps only the most recent.",
20
+ inputSchema: {
21
+ type: "object",
22
+ properties: {
23
+ domain: DOMAIN_PROPERTY,
24
+ aggregate: { type: "string", description: "Narrow to one aggregate, e.g. \"Account\"." },
25
+ id: { type: "string", description: "Narrow to one record's own events. Requires `aggregate`." },
26
+ limit: { type: "integer", description: "Keep only the most recent N events. Omit for all of them." }
27
+ },
28
+ required: %w[domain]
29
+ }
30
+ },
31
+ {
32
+ name: "state",
33
+ description: "Read what an aggregate actually has stored, no verb involved. Pass `id` for one record; " \
34
+ "omit it to list every record the aggregate currently holds.",
35
+ inputSchema: {
36
+ type: "object",
37
+ properties: {
38
+ domain: DOMAIN_PROPERTY,
39
+ aggregate: { type: "string", description: "The aggregate's name, e.g. \"Account\"." },
40
+ id: { type: "string", description: "A specific record's id. Omit to list every record." },
41
+ summary: SUMMARY_PROPERTY
42
+ },
43
+ required: %w[domain aggregate summary]
44
+ }
45
+ },
46
+ {
47
+ name: "catalog",
48
+ description: "Zoom level one: every aggregate a domain declares, and every command/query name each " \
49
+ "answers to. No summary needed — this changes nothing and commits nothing to any log.",
50
+ inputSchema: {
51
+ type: "object",
52
+ properties: { domain: DOMAIN_PROPERTY },
53
+ required: %w[domain]
54
+ }
55
+ },
56
+ {
57
+ name: "describe",
58
+ description: "Zoom level two: one aggregate's full contract — every command's arguments, the states it " \
59
+ "may be issued from, and every way it can refuse. Omit `aggregate` for the whole domain.",
60
+ inputSchema: {
61
+ type: "object",
62
+ properties: {
63
+ domain: DOMAIN_PROPERTY,
64
+ aggregate: { type: "string", description: "Narrow to one aggregate. Omit for the whole domain." }
65
+ },
66
+ required: %w[domain]
67
+ }
68
+ },
69
+ {
70
+ name: "validate",
71
+ description: "Zoom level three: is this domain's wiring sound — every bind names a declared aggregate, " \
72
+ "every adapter satisfies its port, the default adapter is usable. {valid:false, error:…} " \
73
+ "on a real wiring defect, never a bare crash. Set `deep: true` to also model-check the IR " \
74
+ "for dead lifecycle transitions, unreachable saga states, and dispatches to nowhere.",
75
+ inputSchema: {
76
+ type: "object",
77
+ properties: {
78
+ domain: DOMAIN_PROPERTY,
79
+ deep: { type: "boolean", description: "Also run the static model checker (lifecycle/saga/policy IR)." }
80
+ },
81
+ required: %w[domain]
82
+ }
83
+ },
84
+ {
85
+ name: "domains",
86
+ description: "Zoom level zero: every domain directory found under a root (default \"examples\"), so a " \
87
+ "caller who doesn't already know a path can find one.",
88
+ inputSchema: {
89
+ type: "object",
90
+ properties: { under: { type: "string", description: "Root directory to scan. Defaults to \"examples\"." } }
91
+ }
92
+ }
93
+ ].freeze
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,18 @@
1
+ require_relative "../mcp/tool_definitions/calling"
2
+ require_relative "../mcp/tool_definitions/reading"
3
+ require_relative "../mcp/tool_definitions/auditing"
4
+
5
+ module Hecks
6
+ module Adapters
7
+ module Driving
8
+ module Mcp
9
+ # The tools the MCP server answers: their names, descriptions and input schemas, in the
10
+ # order
11
+ # `tools/list` shows them.
12
+ module ToolDefinitions
13
+ TOOLS = (Calling::LIST + Reading::LIST + Auditing::LIST).freeze
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end