hecks 3.10.0 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (542) hide show
  1. checksums.yaml +4 -4
  2. data/examples/pizzas/bluebook/pizzas.bluebook +29 -0
  3. data/examples/pizzas/bluebook/pizzas.hecksagon +7 -0
  4. data/exe/hecks +4 -4
  5. data/lib/hecks/adapters/driven/d1.rb +2 -10
  6. data/lib/hecks/adapters/driven/heki.adapter +1 -1
  7. data/lib/hecks/adapters/driven/heki.rb +2 -12
  8. data/lib/hecks/adapters/driven/lambda.adapter +1 -1
  9. data/lib/hecks/adapters/driven/lambda.rb +3 -18
  10. data/lib/hecks/adapters/driven/postgres.rb +4 -11
  11. data/lib/hecks/adapters/driven/sqlite.adapter +1 -1
  12. data/lib/hecks/adapters/driven/sqlite.rb +2 -10
  13. data/lib/hecks/adapters/driving/admission.rb +46 -0
  14. data/lib/hecks/adapters/driving/cli/nesting.rb +36 -0
  15. data/lib/hecks/adapters/driving/cli/shorthand.rb +88 -0
  16. data/lib/hecks/adapters/driving/cli.rb +127 -0
  17. data/lib/hecks/adapters/driving/cli_runner/answers.rb +160 -0
  18. data/lib/hecks/adapters/driving/cli_runner/resolution.rb +158 -0
  19. data/lib/hecks/adapters/driving/cli_runner/settling.rb +120 -0
  20. data/lib/hecks/adapters/driving/cli_runner/streaming.rb +93 -0
  21. data/lib/hecks/adapters/driving/cli_runner/suggestions.rb +47 -0
  22. data/lib/hecks/adapters/driving/cli_runner.rb +70 -0
  23. data/lib/hecks/adapters/driving/command_request.rb +121 -0
  24. data/lib/hecks/adapters/driving/handle.rb +214 -0
  25. data/lib/hecks/adapters/driving/json.rb +136 -0
  26. data/lib/hecks/adapters/driving/launcher_options.rb +267 -0
  27. data/lib/hecks/adapters/driving/mcp/properties.rb +49 -0
  28. data/lib/hecks/adapters/driving/mcp/tool_calls.rb +116 -0
  29. data/lib/hecks/adapters/driving/mcp/tool_definitions/auditing.rb +53 -0
  30. data/lib/hecks/adapters/driving/mcp/tool_definitions/calling.rb +71 -0
  31. data/lib/hecks/adapters/driving/mcp/tool_definitions/reading.rb +99 -0
  32. data/lib/hecks/adapters/driving/mcp/tool_definitions.rb +18 -0
  33. data/lib/hecks/adapters/driving/mcp.rb +159 -0
  34. data/lib/hecks/adapters/driving/mcp_guide_cache.rb +78 -0
  35. data/lib/hecks/adapters/driving/mcp_scope/argument_policy.rb +97 -0
  36. data/lib/hecks/adapters/driving/mcp_scope/env_problems.rb +69 -0
  37. data/lib/hecks/adapters/driving/mcp_scope/presenter.rb +83 -0
  38. data/lib/hecks/adapters/driving/mcp_scope.rb +213 -0
  39. data/lib/hecks/adapters/driving/newcomer.rb +50 -0
  40. data/lib/hecks/adapters/driving/ruby/aggregate_module.rb +171 -0
  41. data/lib/hecks/adapters/driving/ruby/chapter.rb +91 -0
  42. data/lib/hecks/adapters/driving/ruby.rb +83 -0
  43. data/lib/hecks/adapters/driving/usage_cache.rb +144 -0
  44. data/lib/hecks/{doors.rb → adapters/driving.rb} +10 -6
  45. data/lib/hecks/behaviors/expectations/boot.rb +1 -1
  46. data/lib/hecks/bench/ruby_runner.rb +1 -1
  47. data/lib/hecks/bluebook/ask_resolution.rb +130 -0
  48. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +8 -2
  49. data/lib/hecks/bluebook/assembly/contracts/read_models.rb +1 -1
  50. data/lib/hecks/bluebook/assembly/contracts/rules.rb +4 -2
  51. data/lib/hecks/bluebook/assembly/contracts/structure.rb +3 -1
  52. data/lib/hecks/bluebook/assembly/marks.rb +4 -15
  53. data/lib/hecks/bluebook/assembly/scalars.rb +39 -0
  54. data/lib/hecks/bluebook/attribute.rb +1 -1
  55. data/lib/hecks/bluebook/behaviour/command.rb +13 -8
  56. data/lib/hecks/bluebook/behaviour/policy.rb +30 -0
  57. data/lib/hecks/bluebook/capabilities/attribute_values.rb +72 -0
  58. data/lib/hecks/bluebook/capabilities.rb +91 -9
  59. data/lib/hecks/bluebook/domain_port.rb +16 -4
  60. data/lib/hecks/bluebook/dsl/adapter_builder.rb +18 -6
  61. data/lib/hecks/bluebook/dsl/binding_proxy.rb +13 -0
  62. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/computed_sources.rb +98 -0
  63. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/fan_out_rows.rb +42 -0
  64. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/projected_fields.rb +14 -2
  65. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/provisions.rb +69 -3
  66. data/lib/hecks/bluebook/dsl/bluebook_builder/validation/with_projections.rb +17 -10
  67. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +5 -0
  68. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -0
  69. data/lib/hecks/bluebook/dsl/command_builder/mutations.rb +8 -1
  70. data/lib/hecks/bluebook/dsl/command_builder/operands.rb +121 -0
  71. data/lib/hecks/bluebook/dsl/command_builder.rb +2 -0
  72. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +10 -1
  73. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +45 -2
  74. data/lib/hecks/bluebook/dsl/policy_builder.rb +47 -10
  75. data/lib/hecks/bluebook/dsl/rule_reference.rb +7 -4
  76. data/lib/hecks/bluebook/dsl/world_builder.rb +1 -1
  77. data/lib/hecks/bluebook/expression/ast_json/emitters.rb +6 -0
  78. data/lib/hecks/bluebook/expression/ast_json.rb +9 -6
  79. data/lib/hecks/bluebook/expression/ast_reader.rb +14 -9
  80. data/lib/hecks/bluebook/expression/projection.json +36 -0
  81. data/lib/hecks/bluebook/expression/resolver/operations.rb +31 -0
  82. data/lib/hecks/bluebook/expression/resolver/parsing.rb +38 -5
  83. data/lib/hecks/bluebook/expression/resolver/scanning.rb +22 -5
  84. data/lib/hecks/bluebook/expression/resolver/values.rb +10 -0
  85. data/lib/hecks/bluebook/expression/resolver.rb +20 -1
  86. data/lib/hecks/bluebook/hecksagon.rb +23 -3
  87. data/lib/hecks/bluebook/lifecycle.rb +22 -3
  88. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +13 -1
  89. data/lib/hecks/bluebook/meta_validator/modes.rb +4 -1
  90. data/lib/hecks/bluebook/meta_validator/readings.rb +24 -1
  91. data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +2 -1
  92. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +6 -3
  93. data/lib/hecks/bluebook/meta_validator/shapes.rb +5 -0
  94. data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +1 -1
  95. data/lib/hecks/bluebook/meta_validator.rb +12 -12
  96. data/lib/hecks/bluebook/model_check/ask_checks.rb +71 -0
  97. data/lib/hecks/bluebook/model_check/policy_checks.rb +2 -1
  98. data/lib/hecks/bluebook/model_check/reference_checks.rb +70 -0
  99. data/lib/hecks/bluebook/model_check.rb +8 -2
  100. data/lib/hecks/bluebook/policy.rb +4 -2
  101. data/lib/hecks/bluebook/smoke_test.rb +1 -1
  102. data/lib/hecks/bluebook/synthesizer.rb +2 -0
  103. data/lib/hecks/bluebook.rb +2 -0
  104. data/lib/hecks/cli/command_table.rb +1 -1
  105. data/lib/hecks/cli/console.rb +2 -1
  106. data/lib/hecks/cli/document.rb +1 -1
  107. data/lib/hecks/cli/launcher_words.rb +4 -4
  108. data/lib/hecks/cli/mcp.rb +4 -4
  109. data/lib/hecks/cli/project_cli/launcher_source.rb +2 -2
  110. data/lib/hecks/cli/project_cli/templates.rb +5 -5
  111. data/lib/hecks/cli/project_cli.rb +9 -6
  112. data/lib/hecks/cli/run.rb +2 -2
  113. data/lib/hecks/cli/smoke_http/checks.rb +4 -1
  114. data/lib/hecks/cli/smoke_http/transport.rb +3 -3
  115. data/lib/hecks/cli/smoke_http.rb +3 -0
  116. data/lib/hecks/codemod.rb +5 -2
  117. data/lib/hecks/corpus/routes.rb +7 -0
  118. data/lib/hecks/corpus/rust.rb +3 -2
  119. data/lib/hecks/deploy/bluebook/deploy.bluebook +34 -4
  120. data/lib/hecks/doc/reference/rendering.rb +6 -3
  121. data/lib/hecks/forms/app/commands.rb +8 -7
  122. data/lib/hecks/forms/app/queries.rb +2 -1
  123. data/lib/hecks/forms/app.rb +1 -1
  124. data/lib/hecks/forms/record_renderer.rb +1 -1
  125. data/lib/hecks/framework/bluebook/privacy.bluebook +11 -0
  126. data/lib/hecks/fuzzing/concurrent_dispatch.rb +4 -1
  127. data/lib/hecks/fuzzing/failure_triage.rb +2 -1
  128. data/lib/hecks/fuzzing/mutation/run.rb +11 -4
  129. data/lib/hecks/fuzzing/properties/catalog.rb +6 -4
  130. data/lib/hecks/fuzzing/properties/guaranteed_by_construction.rb +18 -11
  131. data/lib/hecks/fuzzing/properties/guards.rb +1 -1
  132. data/lib/hecks/fuzzing/self_consistency/saga_redelivery.rb +1 -1
  133. data/lib/hecks/fuzzing/self_consistency.rb +6 -2
  134. data/lib/hecks/fuzzing/shrinker.rb +3 -1
  135. data/lib/hecks/fuzzing/value_generator.rb +19 -5
  136. data/lib/hecks/gate/stages.yml +33 -7
  137. data/lib/hecks/grammar/evolve.rb +1 -1
  138. data/lib/hecks/grammar/expression_operators.json +372 -0
  139. data/lib/hecks/grammar/operators.rb +3 -1
  140. data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +10 -10
  141. data/lib/hecks/hecks/adapters/codebase/inspection/rubycritic.rb +35 -0
  142. data/lib/hecks/hecks/adapters/codebase/inspection.rb +104 -0
  143. data/lib/hecks/hecks/adapters/codebase/publishing.rb +2 -1
  144. data/lib/hecks/hecks/adapters/codebase/release_facts.rb +12 -2
  145. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +2 -1
  146. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +1 -1
  147. data/lib/hecks/hecks/adapters/cost_explorer.rb +8 -5
  148. data/lib/hecks/hecks/adapters/deploy_toolchain/statuses.rb +2 -1
  149. data/lib/hecks/hecks/adapters/finding_github.rb +13 -6
  150. data/lib/hecks/hecks/adapters/first_admin.rb +2 -2
  151. data/lib/hecks/hecks/adapters/github_rulesets.rb +6 -3
  152. data/lib/hecks/hecks/adapters/in_process_boot.rb +1 -1
  153. data/lib/hecks/hecks/adapters/journal_store/compaction.rb +1 -1
  154. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +10 -20
  155. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +28 -5
  156. data/lib/hecks/hecks/adapters/local_files.rb +2 -2
  157. data/lib/hecks/hecks/adapters/rehearsal/audit_report.rb +107 -0
  158. data/lib/hecks/hecks/adapters/rehearsal/census.rb +71 -0
  159. data/lib/hecks/hecks/adapters/rehearsal/declaration.rb +133 -0
  160. data/lib/hecks/hecks/adapters/rehearsal/environment.rb +83 -0
  161. data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +142 -0
  162. data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +96 -0
  163. data/lib/hecks/hecks/adapters/rehearsal/postgres_census.rb +100 -0
  164. data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +69 -0
  165. data/lib/hecks/hecks/adapters/rehearsal/postgres_store.rb +133 -0
  166. data/lib/hecks/hecks/adapters/rehearsal/rows.rb +41 -0
  167. data/lib/hecks/hecks/adapters/rehearsal/rust_audit.rb +83 -0
  168. data/lib/hecks/hecks/adapters/rehearsal/subject.rb +104 -0
  169. data/lib/hecks/hecks/adapters/rehearsal.rb +54 -0
  170. data/lib/hecks/hecks/adapters/rehearsal_store.adapter +7 -0
  171. data/lib/hecks/hecks/adapters/rehearsal_store.rb +81 -0
  172. data/lib/hecks/hecks/adapters/terminal.rb +13 -11
  173. data/lib/hecks/hecks/codebase.behaviors +13 -1
  174. data/lib/hecks/hecks/codebase.bluebook +239 -5
  175. data/lib/hecks/hecks/custodian.behaviors +24 -6
  176. data/lib/hecks/hecks/custodian.bluebook +6 -1227
  177. data/lib/hecks/hecks/deploy.behaviors +1 -1
  178. data/lib/hecks/hecks/deploy.world +1 -3
  179. data/lib/hecks/hecks/hecks.behaviors +1 -1
  180. data/lib/hecks/hecks/hecks.hecksagon +53 -18
  181. data/lib/hecks/hecks/hecks.world +13 -10
  182. data/lib/hecks/hecks/rehearsal.bluebook +477 -0
  183. data/lib/hecks/hecks/site.behaviors +1 -1
  184. data/lib/hecks/hecks/site.world +0 -1
  185. data/lib/hecks/hecks/tooling.bluebook +1238 -0
  186. data/lib/hecks/indifferent_key.rb +20 -0
  187. data/lib/hecks/language/adapter.bluebook +13 -3
  188. data/lib/hecks/language/bluebook/aggregate.bluebook +23 -0
  189. data/lib/hecks/language/bluebook/bluebook.behaviors +23 -0
  190. data/lib/hecks/language/bluebook/bluebook.bluebook +15 -0
  191. data/lib/hecks/language/bluebook/entity.bluebook +18 -0
  192. data/lib/hecks/language/bluebook/policy.behaviors +19 -0
  193. data/lib/hecks/language/bluebook/policy.bluebook +9 -1
  194. data/lib/hecks/language/bluebook/query.bluebook +1 -1
  195. data/lib/hecks/language/bluebook/vocabulary.bluebook +63 -4
  196. data/lib/hecks/language/hecksagon/domain_port.bluebook +1 -1
  197. data/lib/hecks/language/hecksagon/hecksagon.bluebook +22 -0
  198. data/lib/hecks/language/oidc.json +10 -0
  199. data/lib/hecks/language/port.bluebook +4 -4
  200. data/lib/hecks/literal.rb +12 -3
  201. data/lib/hecks/ports/key_vault.rb +7 -2
  202. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +21 -10
  203. data/lib/hecks/ports/persistence/plugins/era/postgres_era/boot.rb +4 -2
  204. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +2 -1
  205. data/lib/hecks/ports/persistence/repository_factory.rb +6 -3
  206. data/lib/hecks/projection_files/expression_tables.rb +7 -2
  207. data/lib/hecks/projections/deploy/box/compose.rb +6 -4
  208. data/lib/hecks/projections/deploy/box/edge.rb +62 -0
  209. data/lib/hecks/projections/deploy/box/logging.rb +99 -0
  210. data/lib/hecks/projections/deploy/box/roll_scripts.rb +16 -8
  211. data/lib/hecks/projections/deploy/box/settings/cdn.rb +40 -0
  212. data/lib/hecks/projections/deploy/box/settings/logs.rb +40 -0
  213. data/lib/hecks/projections/deploy/box/settings/patterns.rb +11 -0
  214. data/lib/hecks/projections/deploy/box/settings/types.rb +16 -1
  215. data/lib/hecks/projections/deploy/box/settings.rb +6 -2
  216. data/lib/hecks/projections/deploy/box/stack_yaml.rb +5 -2
  217. data/lib/hecks/projections/deploy/box/templates/Makefile.tmpl +16 -0
  218. data/lib/hecks/projections/deploy/box/templates/box.yaml.tmpl +8 -4
  219. data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +32 -0
  220. data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +1 -1
  221. data/lib/hecks/projections/deploy/box/templates/edge.mk.tmpl +17 -0
  222. data/lib/hecks/projections/deploy/box/templates/edge.yaml.tmpl +65 -0
  223. data/lib/hecks/projections/deploy/box/templates/log-group.yaml.tmpl +12 -0
  224. data/lib/hecks/projections/deploy/box/templates/log-policy.yaml.tmpl +7 -0
  225. data/lib/hecks/projections/deploy/box/templates/render-compose-taskdef.sh.tmpl +5 -4
  226. data/lib/hecks/projections/deploy/box/templates/render-compose.sh.tmpl +5 -4
  227. data/lib/hecks/projections/deploy/box.rb +15 -3
  228. data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
  229. data/lib/hecks/projections/deploy/shared.rb +5 -2
  230. data/lib/hecks/projections/model/deviations.rb +2 -2
  231. data/lib/hecks/projections/model.rb +2 -2
  232. data/lib/hecks/projections/oidc.rb +13 -1
  233. data/lib/hecks/projections/shape.rb +5 -2
  234. data/lib/hecks/projections/site/cms_editor/attributes.rb +26 -6
  235. data/lib/hecks/projections/site/cms_editor/blocks.rb +157 -0
  236. data/lib/hecks/projections/site/cms_editor/checks.rb +14 -1
  237. data/lib/hecks/projections/site/cms_editor/clearing.rb +70 -0
  238. data/lib/hecks/projections/site/cms_editor/color.rb +124 -0
  239. data/lib/hecks/projections/site/cms_editor/composition.rb +42 -0
  240. data/lib/hecks/projections/site/cms_editor/destructive.rb +61 -0
  241. data/lib/hecks/projections/site/cms_editor/drafts.rb +102 -0
  242. data/lib/hecks/projections/site/cms_editor/hints.rb +74 -0
  243. data/lib/hecks/projections/site/cms_editor/icons.rb +86 -0
  244. data/lib/hecks/projections/site/cms_editor/key_kinds.rb +31 -0
  245. data/lib/hecks/projections/site/cms_editor/limits.rb +72 -0
  246. data/lib/hecks/projections/site/cms_editor/media.rb +1 -1
  247. data/lib/hecks/projections/site/cms_editor/moment.rb +34 -0
  248. data/lib/hecks/projections/site/cms_editor/palette.rb +115 -0
  249. data/lib/hecks/projections/site/cms_editor/pickers.rb +85 -0
  250. data/lib/hecks/projections/site/cms_editor/preview.rb +91 -0
  251. data/lib/hecks/projections/site/cms_editor/relations.rb +92 -0
  252. data/lib/hecks/projections/site/cms_editor/scale_checks.rb +66 -0
  253. data/lib/hecks/projections/site/cms_editor/scheduling.rb +150 -0
  254. data/lib/hecks/projections/site/cms_editor/schema.rb +96 -19
  255. data/lib/hecks/projections/site/cms_editor/setting.rb +52 -9
  256. data/lib/hecks/projections/site/cms_editor/targets.rb +86 -0
  257. data/lib/hecks/projections/site/cms_editor/templates/package.json.tmpl +18 -1
  258. data/lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl +251 -57
  259. data/lib/hecks/projections/site/cms_editor/templates/src/assets.ts.tmpl +98 -0
  260. data/lib/hecks/projections/site/cms_editor/templates/src/auth/membership.ts.tmpl +32 -24
  261. data/lib/hecks/projections/site/cms_editor/templates/src/browser/app.css.tmpl +412 -0
  262. data/lib/hecks/projections/site/cms_editor/templates/src/browser/autosave.js.tmpl +144 -0
  263. data/lib/hecks/projections/site/cms_editor/templates/src/browser/blocks.js.tmpl +500 -0
  264. data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_doc.js.tmpl +175 -0
  265. data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_editor.js.tmpl +418 -0
  266. data/lib/hecks/projections/site/cms_editor/templates/src/browser/epoch.js.tmpl +61 -0
  267. data/lib/hecks/projections/site/cms_editor/templates/src/browser/forms.js.tmpl +210 -0
  268. data/lib/hecks/projections/site/cms_editor/templates/src/browser/lists.js.tmpl +40 -0
  269. data/lib/hecks/projections/site/cms_editor/templates/src/browser/main.js.tmpl +26 -0
  270. data/lib/hecks/projections/site/cms_editor/templates/src/browser/media_picker.js.tmpl +232 -0
  271. data/lib/hecks/projections/site/cms_editor/templates/src/browser/moments.js.tmpl +73 -0
  272. data/lib/hecks/projections/site/cms_editor/templates/src/browser/pickers.js.tmpl +152 -0
  273. data/lib/hecks/projections/site/cms_editor/templates/src/browser/preview.js.tmpl +98 -0
  274. data/lib/hecks/projections/site/cms_editor/templates/src/browser/shell.js.tmpl +140 -0
  275. data/lib/hecks/projections/site/cms_editor/templates/src/browser/toast.js.tmpl +66 -0
  276. data/lib/hecks/projections/site/cms_editor/templates/src/choices.ts.tmpl +99 -0
  277. data/lib/hecks/projections/site/cms_editor/templates/src/commands.ts.tmpl +78 -24
  278. data/lib/hecks/projections/site/cms_editor/templates/src/config.ts.tmpl +6 -0
  279. data/lib/hecks/projections/site/cms_editor/templates/src/flash.ts.tmpl +52 -0
  280. data/lib/hecks/projections/site/cms_editor/templates/src/host.ts.tmpl +19 -2
  281. data/lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl +31 -8
  282. data/lib/hecks/projections/site/cms_editor/templates/src/names.ts.tmpl +36 -0
  283. data/lib/hecks/projections/site/cms_editor/templates/src/schema.ts.tmpl +131 -2
  284. data/lib/hecks/projections/site/cms_editor/templates/src/ui/availability.ts.tmpl +15 -0
  285. data/lib/hecks/projections/site/cms_editor/templates/src/ui/block_list.js.tmpl +213 -0
  286. data/lib/hecks/projections/site/cms_editor/templates/src/ui/blocks.ts.tmpl +275 -0
  287. data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_model.js.tmpl +8 -5
  288. data/lib/hecks/projections/site/cms_editor/templates/src/ui/detail.ts.tmpl +88 -0
  289. data/lib/hecks/projections/site/cms_editor/templates/src/ui/dialogs.ts.tmpl +43 -0
  290. data/lib/hecks/projections/site/cms_editor/templates/src/ui/fields.ts.tmpl +229 -34
  291. data/lib/hecks/projections/site/cms_editor/templates/src/ui/html.ts.tmpl +40 -81
  292. data/lib/hecks/projections/site/cms_editor/templates/src/ui/icons.ts.tmpl +15 -0
  293. data/lib/hecks/projections/site/cms_editor/templates/src/ui/input.ts.tmpl +29 -12
  294. data/lib/hecks/projections/site/cms_editor/templates/src/ui/links.ts.tmpl +100 -0
  295. data/lib/hecks/projections/site/cms_editor/templates/src/ui/moments.ts.tmpl +44 -0
  296. data/lib/hecks/projections/site/cms_editor/templates/src/ui/outline.ts.tmpl +53 -17
  297. data/lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl +178 -88
  298. data/lib/hecks/projections/site/cms_editor/templates/src/ui/paging.ts.tmpl +82 -0
  299. data/lib/hecks/projections/site/cms_editor/templates/src/ui/pickers.ts.tmpl +110 -0
  300. data/lib/hecks/projections/site/cms_editor/templates/src/ui/preview.ts.tmpl +87 -0
  301. data/lib/hecks/projections/site/cms_editor/templates/src/ui/related.ts.tmpl +97 -0
  302. data/lib/hecks/projections/site/cms_editor/templates/src/ui/schedule.ts.tmpl +160 -0
  303. data/lib/hecks/projections/site/cms_editor/templates/src/ui/shell.ts.tmpl +211 -0
  304. data/lib/hecks/projections/site/cms_editor/templates/src/ui/table.ts.tmpl +151 -0
  305. data/lib/hecks/projections/site/cms_editor/templates/src/ui/theme.js.tmpl +16 -0
  306. data/lib/hecks/projections/site/cms_editor/templates/src/ui/values.ts.tmpl +69 -0
  307. data/lib/hecks/projections/site/cms_editor/templates/src/ui/words.ts.tmpl +97 -0
  308. data/lib/hecks/projections/site/cms_editor/templates/src/ui/world.ts.tmpl +35 -0
  309. data/lib/hecks/projections/site/cms_editor/templates/tsconfig.json.tmpl +2 -1
  310. data/lib/hecks/projections/site/cms_editor/theme.rb +29 -0
  311. data/lib/hecks/projections/site/cms_editor/theme_checks.rb +57 -0
  312. data/lib/hecks/projections/site/cms_editor.rb +49 -23
  313. data/lib/hecks/projections/site/role_probe.rb +2 -0
  314. data/lib/hecks/projections/site/site_root/workflow.rb +5 -0
  315. data/lib/hecks/projector/cli_audience.rb +22 -1
  316. data/lib/hecks/projector/cli_projector/listing.rb +1 -1
  317. data/lib/hecks/projector/cli_projector/option_specs.rb +1 -1
  318. data/lib/hecks/projector/cli_projector/usage.rb +15 -4
  319. data/lib/hecks/projector/docs_projector/closing.rb +1 -1
  320. data/lib/hecks/projector/docs_projector.rb +1 -1
  321. data/lib/hecks/projector/exporter/bindings.rb +40 -10
  322. data/lib/hecks/projector/exporter/capability_values.rb +55 -0
  323. data/lib/hecks/projector/narrate_projector/reactions.rb +1 -1
  324. data/lib/hecks/projector/target.rb +11 -0
  325. data/lib/hecks/projector.rb +32 -5
  326. data/lib/hecks/quality_control/adapters/github_checks.rb +12 -8
  327. data/lib/hecks/quality_control/adapters/github_issues.rb +8 -4
  328. data/lib/hecks/quality_control/cli/qa_open_pr.rb +2 -2
  329. data/lib/hecks/quality_control/cli/qa_sweep/checks/shrinking.rb +1 -1
  330. data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +1 -1
  331. data/lib/hecks/quality_control/cli/qa_sweep.rb +1 -1
  332. data/lib/hecks/quality_control/quality_control.bluebook +6 -2
  333. data/lib/hecks/release/approval.rb +64 -0
  334. data/lib/hecks/router/{door.rb → aggregate_reader.rb} +5 -4
  335. data/lib/hecks/router/namespace_installer.rb +16 -16
  336. data/lib/hecks/router.rb +1 -1
  337. data/lib/hecks/runtime/best_effort.rb +22 -0
  338. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +12 -2
  339. data/lib/hecks/runtime/command_interpreter.rb +3 -2
  340. data/lib/hecks/runtime/command_rules/emission.rb +1 -1
  341. data/lib/hecks/runtime/dispatcher.rb +4 -4
  342. data/lib/hecks/runtime/entity_element/location.rb +1 -1
  343. data/lib/hecks/runtime/event.rb +5 -0
  344. data/lib/hecks/runtime/identity.rb +7 -6
  345. data/lib/hecks/runtime/interpreting.rb +2 -1
  346. data/lib/hecks/runtime/invocation_builder.rb +1 -1
  347. data/lib/hecks/runtime/loader/boot_steps.rb +8 -5
  348. data/lib/hecks/runtime/loader.rb +10 -10
  349. data/lib/hecks/runtime/policy_interpreter/arguments.rb +7 -4
  350. data/lib/hecks/runtime/policy_interpreter/fan_out.rb +3 -3
  351. data/lib/hecks/runtime/policy_interpreter.rb +6 -6
  352. data/lib/hecks/runtime/port_operation_interpreter.rb +1 -1
  353. data/lib/hecks/runtime/reaction_invocation.rb +1 -1
  354. data/lib/hecks/runtime/rebuild_sweep.rb +11 -1
  355. data/lib/hecks/runtime/registry/ask_verification.rb +35 -0
  356. data/lib/hecks/runtime/registry/hecksagon_rules.rb +10 -0
  357. data/lib/hecks/runtime/registry/merging.rb +1 -1
  358. data/lib/hecks/runtime/registry/providers.rb +16 -0
  359. data/lib/hecks/runtime/registry/read_repository.rb +6 -4
  360. data/lib/hecks/runtime/registry/verification.rb +4 -1
  361. data/lib/hecks/runtime/registry/world_defaults.rb +29 -0
  362. data/lib/hecks/runtime/registry.rb +1 -1
  363. data/lib/hecks/runtime/saga_interpreter/compensation.rb +1 -1
  364. data/lib/hecks/runtime/saga_interpreter/delivery.rb +4 -4
  365. data/lib/hecks/runtime/saga_interpreter/transitions.rb +1 -1
  366. data/lib/hecks/runtime/saga_interpreter.rb +3 -3
  367. data/lib/hecks/runtime/tenant_check.rb +5 -4
  368. data/lib/hecks/runtime/value/coercion.rb +2 -2
  369. data/lib/hecks/runtime/value/validation.rb +16 -4
  370. data/lib/hecks/runtime.rb +9 -9
  371. data/lib/hecks/rust_build/host.rb +11 -4
  372. data/lib/hecks/rust_build/prebuilt_binary.rb +101 -0
  373. data/lib/hecks/rust_build/project_rust/target_ir.rb +1 -1
  374. data/lib/hecks/rust_build/wasm.rb +1 -1
  375. data/lib/hecks/rust_build/wasm_browser.rb +1 -1
  376. data/lib/hecks/rust_build.rb +11 -0
  377. data/lib/hecks/served_options.rb +53 -0
  378. data/lib/hecks/site/bluebook/site.bluebook +1 -0
  379. data/lib/hecks/storehouse/audit.rb +1 -1
  380. data/lib/hecks/storehouse/dispatching.rb +8 -6
  381. data/lib/hecks/storehouse/introspection.rb +2 -2
  382. data/lib/hecks/storehouse/querying.rb +6 -4
  383. data/lib/hecks/storehouse.rb +4 -4
  384. data/lib/hecks/tools/ci_gate_decision.rb +35 -0
  385. data/lib/hecks/tools/ci_gates.rb +20 -1
  386. data/lib/hecks/tools/comment_style/source_file.rb +4 -1
  387. data/lib/hecks/tools/deploy_recipe_lint/fixtures.rb +4 -1
  388. data/lib/hecks/tools/lanes/files.rb +8 -0
  389. data/lib/hecks/tools/lanes/prebuilt_workflow.rb +81 -0
  390. data/lib/hecks/tools/lanes/rows.rb +6 -0
  391. data/lib/hecks/tools/lanes.rb +1 -0
  392. data/lib/hecks/tools/oidc_manifests.rb +4 -5
  393. data/lib/hecks/tools/regeneration_run.rb +11 -4
  394. data/lib/hecks/tools/release_only.rb +111 -0
  395. data/lib/hecks/tools/site_routes/editor_files.rb +12 -5
  396. data/lib/hecks/tools/tenant_provisioning.rb +2 -2
  397. data/lib/hecks/tools/tools_doc.rb +4 -4
  398. data/lib/hecks/version.rb +1 -1
  399. data/lib/hecks/vocabulary.rb +19 -5
  400. data/lib/hecks.rb +15 -15
  401. data/lib/rubocop/cop/hecks/env_dump.rb +69 -0
  402. data/lib/rubocop/cop/hecks/monotonic_duration.rb +53 -0
  403. data/lib/rubocop/cop/hecks/no_wall_clock_in_runtime.rb +34 -0
  404. data/lib/rubocop/cop/hecks/raw_shell_interpolation.rb +79 -0
  405. data/lib/rubocop/cop/hecks/sleep_in_spec.rb +34 -0
  406. data/lib/rubocop/cop/hecks/swallowed_rescue.rb +37 -0
  407. data/lib/rubocop/cop/hecks/symbol_string_key_mix.rb +50 -0
  408. data/lib/rubocop/cop/hecks/untyped_raise.rb +37 -0
  409. data/prebuilt/9ee54e2f0d4d6d3fe046827779b221e02de665fba911a048ae5dd8b8fbfb7d90.marshal +0 -0
  410. data/prebuilt/d74a00e996222c1d8b676d5959092effc46b4dc59e0555f3bf9554ac58e3094a.marshal +0 -0
  411. data/prebuilt/verdicts-df19f35868d3284a70f55e42dcef87ef4e65e6a678e5135f72e1f6cff4c1357b.json +1 -0
  412. data/rust/.gitignore +6 -0
  413. data/rust/Cargo.toml +6 -0
  414. data/rust/build/src/binding_pass.rs +103 -0
  415. data/rust/build/src/cargo_sync.rs +6 -0
  416. data/rust/build/src/lineage_pass.rs +3 -3
  417. data/rust/build/src/main.rs +17 -5
  418. data/rust/build/src/pipeline.rs +48 -5
  419. data/rust/build/src/seams_pass.rs +123 -0
  420. data/rust/build/src/translation_pass.rs +167 -0
  421. data/rust/codegen/src/asks.rs +103 -0
  422. data/rust/codegen/src/commands.rs +13 -8
  423. data/rust/codegen/src/constraints.rs +25 -0
  424. data/rust/codegen/src/domain_generator.rs +2 -0
  425. data/rust/codegen/src/expr_emitter.rs +13 -0
  426. data/rust/codegen/src/json_codec.rs +54 -15
  427. data/rust/codegen/src/main.rs +1 -0
  428. data/rust/codegen/src/mutations.rs +128 -3
  429. data/rust/codegen/src/queries.rs +11 -2
  430. data/rust/codegen/src/reactions.rs +1 -1
  431. data/rust/codegen/src/types.rs +166 -8
  432. data/rust/host/HECKS_RELEASE +1 -1
  433. data/rust/host/src/api.rs +4 -4
  434. data/rust/host/src/bin/validate_harness.rs +43 -0
  435. data/rust/host/src/boundary_fuzz/expr_json.rs +2 -2
  436. data/rust/host/src/boundary_fuzz/ir.rs +1 -0
  437. data/rust/host/src/boundary_fuzz/server.rs +1 -1
  438. data/rust/host/src/checkout.rs +35 -19
  439. data/rust/host/src/commerce_ir.rs +408 -2
  440. data/rust/host/src/expr_json.rs +118 -0
  441. data/rust/host/src/extension.rs +13 -1
  442. data/rust/host/src/lib.rs +1 -0
  443. data/rust/host/src/mint.rs +1 -1
  444. data/rust/host/src/payments/tests.rs +27 -1
  445. data/rust/host/src/payments.rs +12 -4
  446. data/rust/host/src/platform_signin/attack_tests.rs +1100 -0
  447. data/rust/host/src/platform_signin/config.rs +512 -0
  448. data/rust/host/src/platform_signin/cookie.rs +237 -0
  449. data/rust/host/src/platform_signin/extension.rs +190 -0
  450. data/rust/host/src/platform_signin/fetcher.rs +322 -0
  451. data/rust/host/src/platform_signin/handler.rs +251 -0
  452. data/rust/host/src/platform_signin/handler_tests.rs +554 -0
  453. data/rust/host/src/platform_signin/jti.rs +196 -0
  454. data/rust/host/src/platform_signin/jwks.rs +542 -0
  455. data/rust/host/src/platform_signin/jws.rs +249 -0
  456. data/rust/host/src/platform_signin/known_answer_tests.rs +237 -0
  457. data/rust/host/src/platform_signin/mapping_tests.rs +254 -0
  458. data/rust/host/src/platform_signin/mod.rs +75 -0
  459. data/rust/host/src/platform_signin/mode_tests.rs +382 -0
  460. data/rust/host/src/platform_signin/pages.rs +204 -0
  461. data/rust/host/src/platform_signin/query.rs +233 -0
  462. data/rust/host/src/platform_signin/session.rs +151 -0
  463. data/rust/host/src/platform_signin/settings.rs +385 -0
  464. data/rust/host/src/platform_signin/strict_json.rs +351 -0
  465. data/rust/host/src/platform_signin/test_support.rs +235 -0
  466. data/rust/host/src/platform_signin/ttl_tests.rs +94 -0
  467. data/rust/host/src/platform_signin/verify.rs +604 -0
  468. data/rust/host/src/platform_signin/wiring_support.rs +319 -0
  469. data/rust/host/src/query_step.rs +22 -4
  470. data/rust/host/src/reference_validate.rs +653 -108
  471. data/rust/host/src/resend.rs +2 -0
  472. data/rust/host/src/server.rs +19 -6
  473. data/rust/host/src/ui_schema.rs +132 -5
  474. data/rust/host/src/web/newsletter.rs +7 -8
  475. data/rust/host/src/web/newsletter_send.rs +38 -13
  476. data/rust/host/src/web/registrations.rs +229 -26
  477. data/rust/host/src/web.rs +53 -9
  478. data/rust/parser/src/emit.rs +38 -6
  479. data/rust/parser/src/expr/ast_json.rs +7 -1
  480. data/rust/parser/src/expr/resolver.rs +171 -6
  481. data/rust/parser/src/ir.rs +7 -0
  482. data/rust/parser/src/keywords.rs +24 -0
  483. data/rust/parser/src/main.rs +3 -0
  484. data/rust/parser/src/parse/aggregate.rs +2 -1
  485. data/rust/parser/src/parse/chapter.rs +2 -2
  486. data/rust/parser/src/parse/command.rs +2 -0
  487. data/rust/parser/src/parse/hecksagon.rs +5 -2
  488. data/rust/parser/src/parse/lifecycle.rs +81 -0
  489. data/rust/parser/src/parse/mod.rs +15 -1
  490. data/rust/parser/src/parse/policy.rs +13 -2
  491. data/rust/parser/src/parse/value_object.rs +34 -17
  492. data/rust/parser/src/ruby_value.rs +1 -1
  493. data/rust/src/exemplar/commands.rs +4 -4
  494. data/rust/src/exemplar/constraints.rs +1 -1
  495. data/rust/src/exemplar/json.rs +43 -1
  496. data/rust/src/kernel/cli.rs +7 -5
  497. data/rust/src/kernel/dispatch.rs +2 -2
  498. data/rust/src/kernel/dispatch_guard_tests.rs +1 -1
  499. data/rust/src/kernel/expr.rs +66 -3
  500. data/rust/src/kernel/expression_operators/arithmetic.rs +130 -5
  501. data/rust/src/kernel/expression_operators/text.rs +26 -2
  502. data/rust/src/kernel/json.rs +15 -0
  503. data/rust/src/kernel/mod.rs +1 -1
  504. data/rust/src/kernel/orchestrate.rs +54 -5
  505. data/rust/src/kernel/orchestrate_guard_tests.rs +67 -0
  506. data/rust/src/kernel/pattern.rs +60 -0
  507. data/rust/src/kernel/reference_lookup.rs +90 -7
  508. metadata +178 -38
  509. data/lib/hecks/doors/cli_door/nesting.rb +0 -34
  510. data/lib/hecks/doors/cli_door/shorthand.rb +0 -85
  511. data/lib/hecks/doors/cli_door.rb +0 -124
  512. data/lib/hecks/doors/cli_runner/answers.rb +0 -138
  513. data/lib/hecks/doors/cli_runner/resolution.rb +0 -146
  514. data/lib/hecks/doors/cli_runner/settling.rb +0 -115
  515. data/lib/hecks/doors/cli_runner/streaming.rb +0 -90
  516. data/lib/hecks/doors/cli_runner/suggestions.rb +0 -43
  517. data/lib/hecks/doors/cli_runner.rb +0 -66
  518. data/lib/hecks/doors/command_request.rb +0 -119
  519. data/lib/hecks/doors/handle.rb +0 -208
  520. data/lib/hecks/doors/json_door.rb +0 -132
  521. data/lib/hecks/doors/launcher_options.rb +0 -247
  522. data/lib/hecks/doors/mcp_door/properties.rb +0 -47
  523. data/lib/hecks/doors/mcp_door/tool_calls.rb +0 -113
  524. data/lib/hecks/doors/mcp_door/tool_definitions/auditing.rb +0 -51
  525. data/lib/hecks/doors/mcp_door/tool_definitions/calling.rb +0 -69
  526. data/lib/hecks/doors/mcp_door/tool_definitions/reading.rb +0 -97
  527. data/lib/hecks/doors/mcp_door/tool_definitions.rb +0 -15
  528. data/lib/hecks/doors/mcp_door.rb +0 -156
  529. data/lib/hecks/doors/mcp_door_scope/argument_policy.rb +0 -92
  530. data/lib/hecks/doors/mcp_door_scope/env_problems.rb +0 -55
  531. data/lib/hecks/doors/mcp_door_scope/presenter.rb +0 -78
  532. data/lib/hecks/doors/mcp_door_scope.rb +0 -201
  533. data/lib/hecks/doors/mcp_guide_cache.rb +0 -75
  534. data/lib/hecks/doors/ruby_door/aggregate_door.rb +0 -162
  535. data/lib/hecks/doors/ruby_door/chapter.rb +0 -89
  536. data/lib/hecks/doors/ruby_door.rb +0 -80
  537. data/lib/hecks/doors/usage_cache.rb +0 -139
  538. data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_widget.js.tmpl +0 -282
  539. data/lib/hecks/projections/site/cms_editor/templates/src/ui/media_picker.js.tmpl +0 -109
  540. data/prebuilt/c28d6d9db14eea3e17161e9d9c262efee30b256cf97693a7cfd552bce24b2f7f.marshal +0 -0
  541. data/prebuilt/cb375cba61ca0dbe8ddb9739c306510fe05e5f4b7a9b6955caff8224c63ea0e0.marshal +0 -0
  542. data/prebuilt/verdicts-d6d584ad43b5f3cebf88aafbbdbf024c38574acf18e06adffbc555f7786b1c2f.json +0 -1
@@ -0,0 +1,20 @@
1
+ module Hecks
2
+ # Reads a hash by key whichever way its keys are spelled, so the guess about Symbol or String
3
+ # keys is made in one place and `Hecks/SymbolStringKeyMix` can refuse it everywhere else.
4
+ #
5
+ # IndifferentKey.read({ "era" => "a1" }, :era) # => "a1"
6
+ module IndifferentKey
7
+ module_function
8
+
9
+ # Reads `key` as given when present, else by its other spelling. Presence decides, not
10
+ # `||`, so a held `false` is not mistaken for an absent key.
11
+ #
12
+ # @param hash [Hash] a hash keyed by Symbols or by Strings
13
+ # @param key [Symbol, String] the key to read; its own spelling is tried first
14
+ # @return [Object, nil] the held value, or nil when neither spelling is present
15
+ def read(hash, key)
16
+ other = key.is_a?(Symbol) ? key.to_s : key.to_sym
17
+ hash.key?(key) ? hash[key] : hash[other]
18
+ end
19
+ end
20
+ end
@@ -22,10 +22,18 @@ Hecks.bluebook "Adapter" do
22
22
  end
23
23
 
24
24
  value_object "AdapterField" do
25
- attribute :value, String
25
+ attribute :value, String
26
+ attribute :default, String, optional: true
26
27
  invariant("a field names itself") { !value.to_s.empty? }
27
28
  end
28
29
 
30
+ # The text of a field's declared default, such as `"data"` or `true`. A `{name}` in a string
31
+ # is filled from the aggregate the adapter is built for, so it names only what the framework
32
+ # can supply.
33
+ value_object "AdapterFieldDefault" do
34
+ attribute :value, String, pattern: '^(?:[^{}]|\{(?:name|storage_name)\})*$'
35
+ end
36
+
29
37
  command "Declare" do
30
38
  role "Deployment"
31
39
  goal "Register a real implementation of one resource port"
@@ -45,9 +53,10 @@ Hecks.bluebook "Adapter" do
45
53
  goal "Name a value this adapter's own world-level wiring must supply"
46
54
 
47
55
  reference_to Adapter
48
- attribute :value, AdapterField
56
+ attribute :value, AdapterField
57
+ attribute :default, AdapterFieldDefault, optional: true
49
58
 
50
- sets :fields, append: { value: :value }
59
+ sets :fields, append: { value: :value, default: :default }
51
60
 
52
61
  emits "AdapterFieldAdded"
53
62
  end
@@ -104,6 +113,7 @@ Hecks.bluebook "Adapter" do
104
113
  member keyword: "adapter", context: "File", at: "1", named: "", kind: "text", required: "true", fills: "name"
105
114
  member keyword: "port", context: "Adapter", at: "1", named: "", kind: "text", required: "true", fills: "port"
106
115
  member keyword: "field", context: "Adapter", at: "1", named: "", kind: "symbol", required: "true", fills: "fields"
116
+ member keyword: "field", context: "Adapter", at: "", named: "default", kind: "literal", required: "false", fills: "default"
107
117
  member keyword: "secret", context: "Adapter", at: "1", named: "", kind: "symbol", required: "true", fills: "secrets"
108
118
 
109
119
  end
@@ -18,6 +18,9 @@ Hecks.bluebook "Bluebook" do
18
18
  attribute :state_field, IdentityField, optional: true
19
19
  attribute :state_start, IdentityField, optional: true
20
20
  attribute :transitions, list_of(Transition)
21
+ # Named meanings the lifecycle's states carry (`mark :holds_seat, "pending", "paid"`), one
22
+ # row per (mark, state), in declared order.
23
+ attribute :marks, list_of(Mark)
21
24
  # Checked after every command, before save (ADR 0025). The same Rule shape as Command's
22
25
  # givens, declared again because a closed set or value object is aggregate-scoped here.
23
26
  attribute :invariants, list_of(Rule)
@@ -74,6 +77,11 @@ Hecks.bluebook "Bluebook" do
74
77
  attribute :to_state, String
75
78
  end
76
79
 
80
+ value_object "Mark" do
81
+ attribute :name, String
82
+ attribute :state, String
83
+ end
84
+
77
85
  # The same shape as Command's "Rule" (behavior.bluebook), declared again rather than shared.
78
86
  value_object "Rule" do
79
87
  attribute :description, String
@@ -255,6 +263,18 @@ Hecks.bluebook "Bluebook" do
255
263
  emits TransitionAttached
256
264
  end
257
265
 
266
+ command "Mark" do
267
+ role "Language"
268
+ goal "Attach one state to a named meaning of the state machine"
269
+
270
+ attribute :name, FieldName
271
+ attribute :state, FieldName
272
+
273
+ sets :marks, append: { name: :name, state: :state }
274
+
275
+ emits MarkAttached
276
+ end
277
+
258
278
  command "Seal" do
259
279
  role "Language"
260
280
  goal "Close an aggregate — the checks that need every declaration present"
@@ -366,6 +386,7 @@ Hecks.bluebook "Bluebook" do
366
386
  member word: "given", context: "Aggregate", body: "source", inner: "", opens: "", fills: "preconditions", resolves_via: "owner_keyed", disambiguator: "declared_by", calls: "given_impl"
367
387
  member word: "projects", context: "Aggregate", body: "none", inner: "", opens: "", fills: "projected_fields", calls: "projects_impl"
368
388
  member word: "transition", context: "Lifecycle", body: "none", inner: "", opens: "", fills: "transitions", calls: "transition_impl"
389
+ member word: "mark", context: "Lifecycle", body: "none", inner: "", opens: "", fills: "marks", calls: "mark_impl"
369
390
 
370
391
  end
371
392
 
@@ -429,6 +450,8 @@ Hecks.bluebook "Bluebook" do
429
450
  member keyword: "transition", context: "Lifecycle", at: "1", named: "", kind: "pairs", required: "true", fills: "", pair_key_fills: "command", pair_value_fills: "to_state", pairs_shape: "fields"
430
451
  member keyword: "transition", context: "Lifecycle", at: "", named: "from", kind: "text", required: "false", fills: "from_state"
431
452
  member keyword: "transition", context: "Lifecycle", at: "", named: "from", kind: "list", required: "false", fills: "from_state"
453
+ member keyword: "mark", context: "Lifecycle", at: "1", named: "", kind: "symbol", required: "true", fills: "name"
454
+ member keyword: "mark", context: "Lifecycle", at: "2", named: "", kind: "text", required: "true", fills: "state", variadic: "true"
432
455
 
433
456
  end
434
457
  end
@@ -0,0 +1,23 @@
1
+ Hecks.behaviors "Bluebook" do
2
+ vision "A chapter is opened with a name, a vision and a classification, and refuses a classification the language does not admit."
3
+
4
+ loads "bluebook.bluebook", "bluebook.hecksagon"
5
+
6
+ test "Declare opens a chapter" do
7
+ tests "Declare", on: "Bluebook"
8
+ input name: "Pizzas", vision: "Pizzas, built and sold.", classification: "core"
9
+ expect emits: ["ChapterDeclared"]
10
+ end
11
+
12
+ test "Declare refuses a classification that is not core, supporting or generic" do
13
+ tests "Declare", on: "Bluebook"
14
+ input name: "Pizzas", vision: "Pizzas, built and sold.", classification: "huge"
15
+ expect refused: "a chapter is core, supporting, or generic"
16
+ end
17
+
18
+ test "Declare refuses a chapter with no name" do
19
+ tests "Declare", on: "Bluebook"
20
+ input name: "", vision: "Pizzas, built and sold.", classification: "core"
21
+ expect refused: "a chapter is named"
22
+ end
23
+ end
@@ -243,13 +243,24 @@ Hecks.bluebook "Bluebook", version: "1" do
243
243
  member keyword: "provides", context: "Bluebook", at: "", named: "add_name", kind: "text", required: "false", fills: "provides"
244
244
  member keyword: "provides", context: "Bluebook", at: "", named: "confirm", kind: "text", required: "false", fills: "provides"
245
245
  member keyword: "provides", context: "Bluebook", at: "", named: "unsubscribe", kind: "text", required: "false", fills: "provides"
246
+ member keyword: "provides", context: "Bluebook", at: "", named: "awaiting_confirmation", kind: "text", required: "false", fills: "provides"
247
+ member keyword: "provides", context: "Bluebook", at: "", named: "receives_issues", kind: "text", required: "false", fills: "provides"
248
+ member keyword: "provides", context: "Bluebook", at: "", named: "left", kind: "text", required: "false", fills: "provides"
249
+ member keyword: "provides", context: "Bluebook", at: "", named: "confirm_window", kind: "text", required: "false", fills: "provides"
250
+ member keyword: "provides", context: "Bluebook", at: "", named: "unsubscribe_window", kind: "text", required: "false", fills: "provides"
251
+ member keyword: "provides", context: "Bluebook", at: "", named: "webhook_tolerance", kind: "text", required: "false", fills: "provides"
252
+ member keyword: "provides", context: "Bluebook", at: "", named: "session_hold", kind: "text", required: "false", fills: "provides"
246
253
  member keyword: "provides", context: "Bluebook", at: "", named: "initiate", kind: "text", required: "false", fills: "provides"
247
254
  member keyword: "provides", context: "Bluebook", at: "", named: "succeeded", kind: "text", required: "false", fills: "provides"
248
255
  member keyword: "provides", context: "Bluebook", at: "", named: "failed", kind: "text", required: "false", fills: "provides"
256
+ member keyword: "provides", context: "Bluebook", at: "", named: "lapse_reason", kind: "text", required: "false", fills: "provides"
257
+ member keyword: "provides", context: "Bluebook", at: "", named: "holds_seat", kind: "text", required: "false", fills: "provides"
249
258
  member keyword: "provides", context: "Bluebook", at: "", named: "send_issue", kind: "text", required: "false", fills: "provides"
250
259
  member keyword: "provides", context: "Bluebook", at: "", named: "record_delivery", kind: "text", required: "false", fills: "provides"
251
260
  member keyword: "provides", context: "Bluebook", at: "", named: "schedule", kind: "text", required: "false", fills: "provides"
252
261
  member keyword: "provides", context: "Bluebook", at: "", named: "request", kind: "text", required: "false", fills: "provides"
262
+ member keyword: "provides", context: "Bluebook", at: "", named: "registered_at", kind: "text", required: "false", fills: "provides"
263
+ member keyword: "provides", context: "Bluebook", at: "", named: "frees_seat" , kind: "text", required: "false", fills: "provides"
253
264
  member keyword: "provides", context: "Bluebook", at: "", named: "connect", kind: "text", required: "false", fills: "provides"
254
265
  member keyword: "provides", context: "Bluebook", at: "", named: "reconnect", kind: "text", required: "false", fills: "provides"
255
266
  member keyword: "provides", context: "Bluebook", at: "", named: "disconnect", kind: "text", required: "false", fills: "provides"
@@ -257,6 +268,10 @@ Hecks.bluebook "Bluebook", version: "1" do
257
268
  member keyword: "provides", context: "Bluebook", at: "", named: "resume", kind: "text", required: "false", fills: "provides"
258
269
  member keyword: "provides", context: "Bluebook", at: "", named: "enable", kind: "text", required: "false", fills: "provides"
259
270
  member keyword: "provides", context: "Bluebook", at: "", named: "disable", kind: "text", required: "false", fills: "provides"
271
+ member keyword: "provides", context: "Bluebook", at: "", named: "mark_sensitive", kind: "text", required: "false", fills: "provides"
272
+ member keyword: "provides", context: "Bluebook", at: "", named: "markings_for", kind: "text", required: "false", fills: "provides"
273
+ member keyword: "provides", context: "Bluebook", at: "", named: "key_for", kind: "text", required: "false", fills: "provides"
274
+ member keyword: "provides", context: "Bluebook", at: "", named: "shred", kind: "text", required: "false", fills: "provides"
260
275
  member keyword: "aggregate", context: "Bluebook", at: "1", named: "", kind: "text", required: "true", fills: "name"
261
276
  member keyword: "read_model", context: "Bluebook", at: "1", named: "", kind: "text", required: "true", fills: "name"
262
277
  member keyword: "policy", context: "Bluebook", at: "1", named: "", kind: "text", required: "true", fills: "name"
@@ -20,6 +20,7 @@ Hecks.bluebook "Bluebook" do
20
20
  attribute :state_field, EntityText, optional: true
21
21
  attribute :state_start, EntityText, optional: true
22
22
  attribute :transitions, list_of(PieceTransition)
23
+ attribute :marks, list_of(PieceMark)
23
24
 
24
25
  value_object "EntityName" do
25
26
  attribute :value, String
@@ -60,6 +61,11 @@ Hecks.bluebook "Bluebook" do
60
61
  attribute :to_state, String
61
62
  end
62
63
 
64
+ value_object "PieceMark" do
65
+ attribute :name, String
66
+ attribute :state, String
67
+ end
68
+
63
69
  # Declaration order is a fact about the source, so the language holds it, not the store.
64
70
  value_object "Position" do
65
71
  attribute :value, Integer
@@ -233,6 +239,18 @@ Hecks.bluebook "Bluebook" do
233
239
  emits PieceTransitionAttached
234
240
  end
235
241
 
242
+ command "Mark" do
243
+ role "Language"
244
+ goal "Attach one state to a named meaning of the entity's state machine"
245
+
246
+ attribute :name, EntityText
247
+ attribute :state, EntityText
248
+
249
+ sets :marks, append: { name: :name, state: :state }
250
+
251
+ emits PieceMarkAttached
252
+ end
253
+
236
254
  # Keyword rows for this chapter; SyntaxBoot discovers aggregate-local seed tables.
237
255
  value_object "KeywordSeed" do
238
256
  attribute :word, String
@@ -0,0 +1,19 @@
1
+ Hecks.behaviors "Bluebook" do
2
+ vision "A policy hangs off a chapter and names the event it watches; an unnamed policy is refused."
3
+
4
+ loads "bluebook.bluebook", "policy.bluebook", "bluebook.hecksagon"
5
+
6
+ test "Declare puts a policy on a chapter" do
7
+ tests "Declare", on: "Policy"
8
+ setup "Bluebook::Bluebook.Declare", name: "Pizzas", vision: "Pizzas, built and sold.", classification: "core"
9
+ input bluebook: "Pizzas", name: "NotifyKitchen", on_event: "OrderPlaced"
10
+ expect emits: ["ReactionDeclared"]
11
+ end
12
+
13
+ test "Declare refuses a policy with no name" do
14
+ tests "Declare", on: "Policy"
15
+ setup "Bluebook::Bluebook.Declare", name: "Pizzas", vision: "Pizzas, built and sold.", classification: "core"
16
+ input bluebook: "Pizzas", name: "", on_event: "OrderPlaced"
17
+ expect refused: "a policy is named"
18
+ end
19
+ end
@@ -13,6 +13,9 @@ Hecks.bluebook "Bluebook" do
13
13
  attribute :aggregate, PolicyText
14
14
  attribute :on_event, PolicyText
15
15
  attribute :trigger_command, PolicyText
16
+ # The need an `ask` names in the domain's own words, resolved at boot against the hecksagon's
17
+ # declared asks. Present in place of a port-naming `trigger_command`; empty otherwise.
18
+ attribute :ask, PolicyText, optional: true
16
19
  attribute :target_domain, PolicyText
17
20
  # An `across` target this domain expects never to reach. ModelCheck treats the related findings
18
21
  # as expected, and fails a declaration whose target turns out to be known after all.
@@ -63,7 +66,8 @@ Hecks.bluebook "Bluebook" do
63
66
  attribute :name, PolicyName
64
67
  attribute :aggregate, PolicyText, optional: true
65
68
  attribute :on_event, PolicyText
66
- attribute :trigger_command, PolicyText
69
+ attribute :trigger_command, PolicyText, optional: true
70
+ attribute :ask, PolicyText, optional: true
67
71
  attribute :target_domain, PolicyText, optional: true
68
72
  attribute :expect_undelivered, PolicyText, optional: true
69
73
  attribute :where, PolicyText, optional: true
@@ -75,6 +79,7 @@ Hecks.bluebook "Bluebook" do
75
79
  sets :aggregate
76
80
  sets :on_event
77
81
  sets :trigger_command
82
+ sets :ask
78
83
  sets :target_domain
79
84
  sets :expect_undelivered
80
85
  sets :where
@@ -111,6 +116,7 @@ Hecks.bluebook "Bluebook" do
111
116
 
112
117
  member word: "on", context: "Policy", body: "none", inner: "", opens: "", fills: "on_event", calls: "on_impl"
113
118
  member word: "trigger", context: "Policy", body: "none", inner: "", opens: "", fills: "trigger_command", calls: "trigger_impl"
119
+ member word: "ask", context: "Policy", body: "none", inner: "", opens: "", fills: "ask", calls: "ask_impl"
114
120
  member word: "across", context: "Policy", body: "none", inner: "", opens: "", fills: "target_domain", calls: "across_impl"
115
121
  member word: "where", context: "Policy", body: "source", inner: "", opens: "", fills: "where"
116
122
  member word: "for_each", context: "Policy", body: "none", inner: "", opens: "", fills: "for_each"
@@ -138,10 +144,12 @@ Hecks.bluebook "Bluebook" do
138
144
  member keyword: "on", context: "Policy", at: "1", named: "", kind: "text", required: "true", fills: "on_event"
139
145
  member keyword: "trigger", context: "Policy", at: "1", named: "", kind: "constant", required: "true", fills: "trigger_command"
140
146
  member keyword: "trigger", context: "Policy", at: "1", named: "", kind: "text", required: "true", fills: "trigger_command"
147
+ member keyword: "ask", context: "Policy", at: "1", named: "", kind: "symbol", required: "true", fills: "ask"
141
148
  member keyword: "across", context: "Policy", at: "1", named: "", kind: "text", required: "true", fills: "target_domain"
142
149
  member keyword: "across", context: "Policy", at: "", named: "expect_undelivered", kind: "flag", required: "false", fills: "expect_undelivered"
143
150
  member keyword: "for_each", context: "Policy", at: "1", named: "", kind: "text", required: "true", fills: "for_each"
144
151
  member keyword: "trigger", context: "Policy", at: "", named: "with", kind: "pairs", required: "false", fills: "with_spec", pairs_shape: "verbatim"
152
+ member keyword: "ask", context: "Policy", at: "", named: "with", kind: "pairs", required: "false", fills: "with_spec", pairs_shape: "verbatim"
145
153
 
146
154
  end
147
155
  end
@@ -121,7 +121,7 @@ Hecks.bluebook "Bluebook" do
121
121
  goal "Attach one where-clause to the query"
122
122
 
123
123
  attribute :field, QueryText
124
- # The same word at the same door — see Command.Change.op.
124
+ # The same word at the same entry point — see Command.Change.op.
125
125
  attribute :op, QueryText, admits: "Vocabulary::QueryComparator"
126
126
  attribute :value, QueryText
127
127
 
@@ -611,6 +611,10 @@ Hecks.bluebook "Bluebook" do
611
611
  # `mode` is how `pattern` (an extended regex over changed paths) decides:
612
612
  # `touches` runs the job when any changed path matches, `skips_unless` runs it
613
613
  # when any changed path does NOT match (the pattern is the safe-to-skip list).
614
+ # `release_only` answers a different question and ignores `pattern`: `touched` is false only
615
+ # when the change edits nothing but the `ReleaseFile` rows' files and lines and the base it is
616
+ # measured against has every inheritable `RequiredCheck` green (ADR 0107), so the run may
617
+ # inherit that certification.
614
618
  # `push` is what a push event does: `skip` leaves the gate out of push runs,
615
619
  # `before_sha` diffs against the push's `before` commit.
616
620
  value_object "CiGate" do
@@ -624,19 +628,44 @@ Hecks.bluebook "Bluebook" do
624
628
  member name: "runtime_changed", workflow: "ci.yml", mode: "touches",
625
629
  pattern: '^lib/hecks/runtime/', push: "before_sha",
626
630
  label: "does this change touch lib/hecks/runtime/**?"
631
+ member name: "release_only", workflow: "ci.yml", mode: "release_only",
632
+ pattern: "", push: "before_sha",
633
+ label: "is this change only a release bump on a certified base?"
627
634
  member name: "postgres_io_relevant_changed", workflow: "ci-postgres-io-parallel.yml", mode: "skips_unless",
628
635
  pattern: '^(docs/|editors/|release/|deploy/|\.claude/|\.githooks/|rust/(parser|codegen|host|build|lsp|web|tests)/|\.rubocop\.yml$|\.rubocop_todo\.yml$|\.mcp\.json$|\.rspec-local\.example$|README\.md$|CHANGELOG\.md$|CONTRIBUTING\.md$|SECURITY\.md$|LICENSE$|\.gitignore$)',
629
636
  push: "skip",
630
637
  label: "does this change touch anything rspec_postgres_io_parallel covers?"
631
638
  end
632
639
 
640
+ # The files a release bump edits, and the lines of each it may change. A commit whose whole
641
+ # diff against a certified base falls inside these rows inherits the base's certification
642
+ # (`CiGate` `release_only`, ADR 0107): its checks report success without their jobs running,
643
+ # and the `release_consistency` check still runs on it. `path` is the file, exact; `lines` is
644
+ # an extended regex every added or removed line of that file must match, empty for any line.
645
+ value_object "ReleaseFile" do
646
+ attribute :path, String
647
+ attribute :lines, String
648
+
649
+ member path: "lib/hecks/version.rb", lines: "^\\s*VERSION = \"[0-9]+\\.[0-9]+\\.[0-9]+\"\\.freeze$"
650
+ member path: "CHANGELOG.md", lines: ""
651
+ member path: "README.md", lines: "^(\\*\\*Status:\\*\\* )?Current release: `[0-9]+\\.[0-9]+\\.[0-9]+`"
652
+ member path: "Gemfile.lock", lines: "^ hecks \\([0-9]+\\.[0-9]+\\.[0-9]+\\)$"
653
+ member path: "rust/host/HECKS_RELEASE", lines: "^[0-9]+\\.[0-9]+\\.[0-9]+$"
654
+ member path: "packages/hecks-client/package.json", lines: "^\\s*\"version\": \"[0-9]+\\.[0-9]+\\.[0-9]+\",?$"
655
+ member path: "packages/hecks-client/package-lock.json", lines: "^\\s*\"version\": \"[0-9]+\\.[0-9]+\\.[0-9]+\",?$"
656
+ end
657
+
633
658
  # The checks a commit must have passed before a `Promotion` moves it onto a guarded lane. Each
634
659
  # is the name of a job in .github/workflows that reports to a commit as a check run; a check
635
660
  # that a path gate skipped reports `skipped`, which counts as passed. `hecks promote` reads
636
661
  # these rows, and hecks project_lanes writes them into the ruleset of any lane that requires
637
662
  # them, so the list lives here and nowhere else.
663
+ #
664
+ # `runs` is `always` for a check a release bump still runs (it is not inherited from the base);
665
+ # empty for a check a bump may inherit.
638
666
  value_object "RequiredCheck" do
639
667
  attribute :name, String
668
+ attribute :runs, String
640
669
 
641
670
  member name: "rspec"
642
671
  member name: "checks"
@@ -647,6 +676,7 @@ Hecks.bluebook "Bluebook" do
647
676
  member name: "rspec_rust_codegen"
648
677
  member name: "rspec_rust_host"
649
678
  member name: "rspec_fuzzing"
679
+ member name: "release_consistency", runs: "always"
650
680
  end
651
681
 
652
682
  # The branches a change travels along. `main` takes pushes with no gate; `stable` takes only
@@ -660,6 +690,10 @@ Hecks.bluebook "Bluebook" do
660
690
  # empty when none does; `follows` is the lane a promotion draws from, or empty. `alert_after`
661
691
  # is the whole hours the lane may stand behind the lane it follows before `hecks
662
692
  # promotion_run.watch` files a finding, or empty for a lane that is never late.
693
+ # `release_trailer` is the commit-message trailer a commit that sets the version must carry
694
+ # (`Release-Approved-By: <name>`) before a release is cut from this lane, or empty for a lane
695
+ # nothing is released from: the owner decides when a release happens by writing that line in
696
+ # the bump commit, and `release.yml` and `publishing_run.publish` both refuse a bump without it.
663
697
  value_object "Lane" do
664
698
  attribute :name, String
665
699
  attribute :guarded, String
@@ -667,9 +701,34 @@ Hecks.bluebook "Bluebook" do
667
701
  attribute :feeds, String
668
702
  attribute :follows, String
669
703
  attribute :alert_after, String
704
+ attribute :release_trailer, String
670
705
 
671
- member name: "main", guarded: "no", pushers: "anyone", feeds: "", follows: "", alert_after: ""
672
- member name: "stable", guarded: "yes", pushers: "green", feeds: "edge", follows: "main", alert_after: "4"
706
+ member name: "main", guarded: "no", pushers: "anyone", feeds: "", follows: "", alert_after: "",
707
+ release_trailer: ""
708
+ member name: "stable", guarded: "yes", pushers: "green", feeds: "edge", follows: "main", alert_after: "4",
709
+ release_trailer: "Release-Approved-By"
710
+ end
711
+
712
+ # A binary hecks builds once per change to its crate and publishes, so a client that needs the
713
+ # same binary downloads it instead of compiling it (ADR 0110). `hecks regeneration_run.project_lanes`
714
+ # writes .github/workflows/publish-<name>.yml from each row; `Hecks::RustBuild::PrebuiltBinary`
715
+ # reads the same rows to name what to download.
716
+ #
717
+ # `crate` is the directory under the checkout that is built and keyed: the key is a hash of every
718
+ # file in it that goes into the build, so the same bytes in the crate are the same release.
719
+ # `executable` is the Cargo binary and `target` the Rust triple it is built for. `runner` is the
720
+ # GitHub-hosted image it is built on, pinned (never `-latest`) because a binary links the
721
+ # runner's glibc and must run on every host that runs that image or a newer one.
722
+ # The release is tagged `<name>-<key>` and carries `<executable>-<target>` and its `.sha256`.
723
+ value_object "PrebuiltBinary" do
724
+ attribute :name, String
725
+ attribute :crate, String
726
+ attribute :executable, String
727
+ attribute :target, String
728
+ attribute :runner, String
729
+
730
+ member name: "host", crate: "rust/host", executable: "bootstrap", target: "x86_64-unknown-linux-gnu",
731
+ runner: "ubuntu-24.04"
673
732
  end
674
733
 
675
734
  # The dials of the hecks_qa loop: what each is called, the type of value it takes and what it
@@ -791,8 +850,8 @@ Hecks.bluebook "Bluebook" do
791
850
  member script: "compact", section: "Custodian", aggregate: "Era", verb: "compact"
792
851
  member script: "heki_compact", section: "Custodian", aggregate: "Era", verb: "compact_heki"
793
852
  member script: "vendor_bluebook", section: "Custodian", aggregate: "Package", verb: "vendor", note: "waits: a refusal exits 1 with its reason on stderr"
794
- member script: "project_cli", section: "Custodian", aggregate: "Door", verb: "project_cli"
795
- member script: "hecks_mcp_door", section: "Custodian", aggregate: "Door", verb: "serve_mcp"
853
+ member script: "project_cli", section: "Custodian", aggregate: "Launch", verb: "project_cli"
854
+ member script: "hecks_mcp_door", section: "Custodian", aggregate: "Launch", verb: "serve_mcp"
796
855
  member script: "project_rust", section: "Custodian", aggregate: "Build", verb: "project_rust"
797
856
  member script: "project_wasm", section: "Custodian", aggregate: "Build", verb: "build_wasm"
798
857
  member script: "project_host", section: "Custodian", aggregate: "Build", verb: "build_host"
@@ -1,6 +1,6 @@
1
1
  Hecks.bluebook "Hecksagon" do
2
2
  aggregate "DomainPort" do
3
- description "A primary port — the boundary between a domain and its adapters, in hexagonal terms, is exactly what a hecksagon already IS for every other port. Root-level (belongs to the chapter) or aggregate-scoped (reached the same way persisted_by is, through the open Const.verb(...) door). One of two shapes, never both: a list of operations translating an inbound fact into this domain's own events, or a bare verb naming a swappable resource port (the same Hecks.port a project's own .port file declares, reached from inside the hecksagon instead)."
3
+ description "A primary port — the boundary between a domain and its adapters, in hexagonal terms, is exactly what a hecksagon already IS for every other port. Root-level (belongs to the chapter) or aggregate-scoped (reached the same way persisted_by is, through the open Const.verb(...) entry point). One of two shapes, never both: a list of operations translating an inbound fact into this domain's own events, or a bare verb naming a swappable resource port (the same Hecks.port a project's own .port file declares, reached from inside the hecksagon instead)."
4
4
 
5
5
  identified_by PortName, as: :name
6
6
 
@@ -6,6 +6,7 @@ Hecks.bluebook "Hecksagon" do
6
6
 
7
7
  attribute :subscriptions, list_of(Subscription)
8
8
  attribute :attachments, list_of(Attachment)
9
+ attribute :driving, list_of(DrivingAdapter)
9
10
 
10
11
  value_object "HecksagonName" do
11
12
  attribute :value, String
@@ -27,6 +28,14 @@ Hecks.bluebook "Hecksagon" do
27
28
  invariant("an attachment comes from the gem or from vendor") { source == "gem" || source == "vendor" }
28
29
  end
29
30
 
31
+ # A driving adapter this hecksagon admits: `value` names one of `Ruby`, `Cli`, `Json` or `Mcp`.
32
+ # A domain that declares none is open to all of them; one that declares any is reached through
33
+ # those and refused by the rest.
34
+ value_object "DrivingAdapter" do
35
+ attribute :value, String
36
+ invariant("a driving adapter is named") { !value.to_s.empty? }
37
+ end
38
+
30
39
  # The name an attachment is asked for by, before its source is known.
31
40
  value_object "ChapterName" do
32
41
  attribute :value, String
@@ -67,6 +76,17 @@ Hecks.bluebook "Hecksagon" do
67
76
  emits "ChapterAttached"
68
77
  end
69
78
 
79
+ command "DrivenBy" do
80
+ role "Deployment"
81
+ goal "Admit a driving adapter to reach this hecksagon's domain; adapters left out refuse it"
82
+
83
+ attribute :adapter, DrivingAdapter
84
+
85
+ sets :driving, append: { value: :adapter }
86
+
87
+ emits "DrivingAdapterAdmitted"
88
+ end
89
+
70
90
  # Keyword rows for File and Hecksagon; SyntaxBoot discovers every aggregate-local seed table.
71
91
  value_object "KeywordSeed" do
72
92
  attribute :word, String
@@ -83,6 +103,7 @@ Hecks.bluebook "Hecksagon" do
83
103
  member word: "hecksagon", context: "File", body: "keywords", inner: "Hecksagon", opens: "Hecksagon", fills: ""
84
104
  member word: "subscribe", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "subscriptions"
85
105
  member word: "attaches", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "attachments"
106
+ member word: "driven_by", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "driving"
86
107
  member word: "port", context: "Hecksagon", body: "keywords", inner: "DomainPort", opens: "DomainPort", fills: "", calls: "port_impl"
87
108
  # A cross-domain reaction wired here rather than in the bluebook; reuses the Policy context.
88
109
  # No `calls:` — HecksagonBuilder#translates is an ordinary method, found before `word_gate`.
@@ -113,6 +134,7 @@ Hecks.bluebook "Hecksagon" do
113
134
  member keyword: "subscribe", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "subscriptions"
114
135
  member keyword: "attaches", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "attachments"
115
136
  member keyword: "attaches", context: "Hecksagon", at: "", named: "from", kind: "symbol", required: "false", fills: "source"
137
+ member keyword: "driven_by", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "driving"
116
138
  member keyword: "port", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "name"
117
139
  member keyword: "translates", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "name"
118
140
 
@@ -31,6 +31,11 @@
31
31
  "verb": "Bluebook::Aggregate.Lifecycle",
32
32
  "role": "Language"
33
33
  },
34
+ {
35
+ "scope": "bluebook:aggregate.mark",
36
+ "verb": "Bluebook::Aggregate.Mark",
37
+ "role": "Language"
38
+ },
34
39
  {
35
40
  "scope": "bluebook:aggregate.precondition",
36
41
  "verb": "Bluebook::Aggregate.Precondition",
@@ -156,6 +161,11 @@
156
161
  "verb": "Bluebook::Entity.Lifecycle",
157
162
  "role": "Language"
158
163
  },
164
+ {
165
+ "scope": "bluebook:entity.mark",
166
+ "verb": "Bluebook::Entity.Mark",
167
+ "role": "Language"
168
+ },
159
169
  {
160
170
  "scope": "bluebook:entity.precondition",
161
171
  "verb": "Bluebook::Entity.Precondition",
@@ -1,9 +1,9 @@
1
1
  Hecks.bluebook "Port" do
2
- vision "The .port language, declared in itself. A port names one resource door a domain's own aggregates call by verb — persisted_by, posted_by, whatever a chapter spells — bound to a real driven adapter at the world level. A sibling artifact to the bluebook, not part of one: the same port name is reused across every domain that needs the same kind of door."
2
+ vision "The .port language, declared in itself. A port names one resource a domain's own aggregates call by verb — persisted_by, posted_by, whatever a chapter spells — bound to a real driven adapter at the world level. A sibling artifact to the bluebook, not part of one: the same port name is reused across every domain that needs the same kind of entry point."
3
3
  core
4
4
 
5
5
  aggregate "Port" do
6
- description "One .port — a resource door a domain's own aggregates call by verb, and whether calling it answers with a value (reply) or fires an effect with nothing to hand back (effect)."
6
+ description "One .port — a resource a domain's own aggregates call by verb, and whether calling it answers with a value (reply) or fires an effect with nothing to hand back (effect)."
7
7
 
8
8
  identified_by PortName, as: :name
9
9
 
@@ -25,7 +25,7 @@ Hecks.bluebook "Port" do
25
25
  attribute :value, String, one_of: ["reply", "effect"]
26
26
  end
27
27
 
28
- # The method contract: what an adapter must `respond_to?` for a dispatch through this door.
28
+ # The method contract: what an adapter must `respond_to?` for a dispatch through this port.
29
29
  # A port that declares none is unchecked beyond `verify!`.
30
30
  value_object "PortAnswer" do
31
31
  attribute :value, String
@@ -34,7 +34,7 @@ Hecks.bluebook "Port" do
34
34
 
35
35
  command "Declare" do
36
36
  role "Deployment"
37
- goal "Open a resource door a domain's own aggregates may call by verb"
37
+ goal "Open a resource a domain's own aggregates may call by verb"
38
38
 
39
39
  attribute :name, PortName
40
40
  # Optional: a port may declare only `signal`; `verb` has no default, unlike `signal`.
data/lib/hecks/literal.rb CHANGED
@@ -7,6 +7,14 @@ module Hecks
7
7
  def to_s = "state(:#{name})"
8
8
  end
9
9
 
10
+ # A mutation source computed from arithmetic over command arguments, state and numbers:
11
+ # `sets :refund, to: paid * rate / 100`. `text` is the canonical expression, read by
12
+ # `Bluebook::Expression::Resolver`; its operands name command arguments first, then the
13
+ # record's own fields.
14
+ Computed = Struct.new(:text) do
15
+ def to_s = "expr(#{text})"
16
+ end
17
+
10
18
  # The one wire spelling for a Ruby literal captured from a bluebook: a symbol wears its
11
19
  # colon, a string its quotes, a hash `{key: value}`, a list brackets; the rest are bare.
12
20
  # Stated here, not left to `inspect`, whose Hash rendering differs between Ruby 3.3 and 3.4.
@@ -15,7 +23,7 @@ module Hecks
15
23
 
16
24
  # Turns a Ruby value into its self-describing wire spelling.
17
25
  #
18
- # @param value [Object] value to render: nil, Symbol, String, StateRef, true,
26
+ # @param value [Object] value to render: nil, Symbol, String, StateRef, Computed, true,
19
27
  # false, Integer, Float, Hash, or Array (recursively)
20
28
  # @return [String] the self-describing spelling `read` can parse back
21
29
  # @raise [ArgumentError] if `value` is a type with no pinned literal spelling
@@ -24,7 +32,7 @@ module Hecks
24
32
  when nil then "nil"
25
33
  when Symbol then ":#{value}"
26
34
  when String then quote(value)
27
- when StateRef, true, false, Integer, Float then value.to_s
35
+ when StateRef, Computed, true, false, Integer, Float then value.to_s
28
36
  when Hash, Array then render_collection(value)
29
37
  else
30
38
  raise ArgumentError, "#{value.class} has no pinned literal spelling — teach Literal.render one " \
@@ -44,7 +52,7 @@ module Hecks
44
52
  # A bare word stays a String, since some fields are stored as plain text, never rendered.
45
53
  #
46
54
  # @param text [String, #to_s] wire spelling produced by `render`, or a bare word
47
- # @return [Object] nil, true, false, Integer, Float, Symbol, StateRef, String,
55
+ # @return [Object] nil, true, false, Integer, Float, Symbol, StateRef, Computed, String,
48
56
  # Hash, or Array — or `text` itself, stripped, when it matches no known spelling
49
57
  def read(text)
50
58
  raw = text.to_s.strip
@@ -65,6 +73,7 @@ module Hecks
65
73
  [->(raw) { raw.match?(/\A-?\d+\.\d+\z/) }, :to_f.to_proc],
66
74
  [->(raw) { raw.start_with?(":") }, ->(raw) { raw[1..].to_sym }],
67
75
  [->(raw) { raw.match?(/\Astate\(:[A-Za-z_][A-Za-z0-9_]*\)\z/) }, ->(raw) { StateRef.new(raw[7..-2].to_sym) }],
76
+ [->(raw) { raw.match?(/\Aexpr\(.+\)\z/m) }, ->(raw) { Computed.new(raw[5..-2]) }],
68
77
  [->(raw) { quoted?(raw) }, ->(raw) { unquote(raw) }],
69
78
  [->(raw) { raw.start_with?("{") && raw.end_with?("}") }, ->(raw) { read_hash(raw) }],
70
79
  [->(raw) { raw.start_with?("[") && raw.end_with?("]") }, ->(raw) { read_array(raw) }]
@@ -20,12 +20,17 @@ module Hecks
20
20
  # reverse, so Shred cannot be dispatched before the key is actually gone. Idempotent:
21
21
  # a subject with no live key, or one already shredded, is left alone and returns false.
22
22
  def shred!(dispatcher, domain:, subject_id:) # rubocop:disable Naming/PredicateMethod
23
- record = dispatcher.query("Privacy::SubjectKey.ForSubject", domain: domain, subject_id: subject_id).first
23
+ provider = dispatcher.registry.provider_of(Bluebook::Capabilities::SUBJECT_KEYS)
24
+ return false unless provider
25
+
26
+ record = dispatcher.query(provider.provided_verb(Bluebook::Capabilities::SUBJECT_KEYS, :key_for),
27
+ domain: domain, subject_id: subject_id).first
24
28
  return false unless record
25
29
  return false if record[:status].to_s == "shredded"
26
30
 
27
31
  destroy(dispatcher.registry, key_reference: record[:key_reference].value)
28
- dispatcher.dispatch_flat("Privacy::SubjectKey.Shred", domain: { value: domain }, subject_id: { value: subject_id })
32
+ shred = provider.provided_verb(Bluebook::Capabilities::SUBJECT_KEYS, :shred)
33
+ dispatcher.dispatch_flat(shred, domain: { value: domain }, subject_id: { value: subject_id })
29
34
  true
30
35
  end
31
36