hecks 2.9.0 → 3.0.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 (600) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +51 -6
  3. data/lib/hecks/adapters/driven/heki/journal.rb +1 -1
  4. data/lib/hecks/adapters/driven/lambda/client.rb +1 -1
  5. data/lib/hecks/adapters/driven/lambda.rb +1 -1
  6. data/lib/hecks/adapters/driven/memory.rb +16 -3
  7. data/lib/hecks/adapters/driven/postgres/reconnect.rb +6 -2
  8. data/lib/hecks/adapters/driven/postgres/shared_connection.rb +180 -0
  9. data/lib/hecks/adapters/driven/postgres.rb +4 -2
  10. data/lib/hecks/adapters/driven/prism.rb +41 -8
  11. data/lib/hecks/adapters/driven/tenant_provisioner.rb +73 -16
  12. data/lib/hecks/behaviors/expectations.rb +1 -1
  13. data/lib/hecks/behaviors.rb +1 -1
  14. data/lib/hecks/bench/cli.rb +62 -0
  15. data/lib/hecks/bench/environment.rb +71 -0
  16. data/lib/hecks/bench/postgres_probe.rb +30 -0
  17. data/lib/hecks/bench/report.rb +76 -0
  18. data/lib/hecks/bench/ruby_runner.rb +93 -0
  19. data/lib/hecks/bench/run.rb +55 -0
  20. data/lib/hecks/bench/rust_runner.rb +101 -0
  21. data/lib/hecks/bench/stats.rb +46 -0
  22. data/lib/hecks/bench/suite.rb +98 -0
  23. data/lib/hecks/bench/workload.rb +89 -0
  24. data/lib/hecks/bench.rb +17 -0
  25. data/lib/hecks/bluebook/assembly/contracts.rb +2 -0
  26. data/lib/hecks/bluebook/attribute.rb +1 -1
  27. data/lib/hecks/bluebook/behaviour/aggregate.rb +30 -1
  28. data/lib/hecks/bluebook/behaviour/domain_port.rb +7 -0
  29. data/lib/hecks/bluebook/chapter.rb +6 -2
  30. data/lib/hecks/bluebook/domain_port.rb +36 -5
  31. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +10 -0
  32. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +8 -0
  33. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -1
  34. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +31 -3
  35. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +122 -3
  36. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +1 -1
  37. data/lib/hecks/bluebook/dsl/query_builder.rb +27 -1
  38. data/lib/hecks/bluebook/dsl/rule_reference.rb +1 -1
  39. data/lib/hecks/bluebook/dsl/world_builder.rb +29 -2
  40. data/lib/hecks/bluebook/expression/canonical_form.rb +1 -1
  41. data/lib/hecks/bluebook/expression/resolver.rb +3 -2
  42. data/lib/hecks/bluebook/hexagon.rb +13 -5
  43. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +1 -0
  44. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +4 -1
  45. data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +246 -0
  46. data/lib/hecks/bluebook/meta_validator.rb +9 -4
  47. data/lib/hecks/bluebook/model_check.rb +23 -0
  48. data/lib/hecks/bluebook/pattern_subset.rb +38 -0
  49. data/lib/hecks/bluebook/query.rb +20 -5
  50. data/lib/hecks/bluebook/smoke_test.rb +1 -1
  51. data/lib/hecks/canonical_json.rb +30 -0
  52. data/lib/hecks/chapters.rb +102 -0
  53. data/lib/hecks/cli/behaviors.rb +61 -0
  54. data/lib/hecks/cli/canonicalise.rb +25 -0
  55. data/lib/hecks/cli/check_engine_agreement.rb +32 -0
  56. data/lib/hecks/cli/check_era.rb +88 -0
  57. data/lib/hecks/cli/console.rb +66 -0
  58. data/lib/hecks/cli/deploy_template_diff.rb +40 -0
  59. data/lib/hecks/cli/doc_coverage.rb +32 -0
  60. data/lib/hecks/cli/document.rb +2 -2
  61. data/lib/hecks/cli/expression_projection.rb +41 -0
  62. data/lib/hecks/cli/follow.rb +88 -0
  63. data/lib/hecks/cli/history.rb +44 -0
  64. data/lib/hecks/cli/ir.rb +1 -1
  65. data/lib/hecks/cli/mcp.rb +3 -3
  66. data/lib/hecks/cli/model_check.rb +7 -4
  67. data/lib/hecks/cli/pattern_cases.rb +47 -0
  68. data/lib/hecks/cli/present.rb +39 -0
  69. data/lib/hecks/cli/project_cli.rb +224 -32
  70. data/lib/hecks/cli/project_diagrams.rb +4 -3
  71. data/lib/hecks/cli/project_glossary.rb +44 -0
  72. data/lib/hecks/cli/reference.rb +46 -0
  73. data/lib/hecks/cli/refresh_projections.rb +44 -0
  74. data/lib/hecks/cli/refresh_rspec_runtime_baseline.rb +150 -0
  75. data/lib/hecks/cli/release.rb +70 -0
  76. data/lib/hecks/cli/release_gem.rb +59 -0
  77. data/lib/hecks/cli/rspec_io_parallel_files.rb +137 -0
  78. data/lib/hecks/cli/rspec_shard_files.rb +66 -0
  79. data/lib/hecks/cli/run.rb +3 -3
  80. data/lib/hecks/cli/seed_semantics_corpus.rb +71 -0
  81. data/lib/hecks/cli/serve_query_ir_mcp.rb +30 -0
  82. data/lib/hecks/cli/shape.rb +70 -0
  83. data/lib/hecks/cli/smoke_http.rb +230 -0
  84. data/lib/hecks/cli/smoke_test.rb +5 -3
  85. data/lib/hecks/cli/spec_example.rb +27 -0
  86. data/lib/hecks/cli/statements.rb +32 -0
  87. data/lib/hecks/cli/stores.rb +4 -5
  88. data/lib/hecks/cli/stress_concurrency_specs.rb +177 -0
  89. data/lib/hecks/cli.rb +201 -52
  90. data/lib/hecks/codemod.rb +324 -0
  91. data/lib/hecks/corpus.rb +423 -0
  92. data/lib/hecks/deploy/bluebook/deploy.bluebook +591 -23
  93. data/lib/hecks/deploy/bluebook/deploy.hecksagon +41 -4
  94. data/lib/hecks/deploy/oidc.json +82 -2
  95. data/lib/hecks/doc/reference.rb +351 -0
  96. data/lib/hecks/doors/cli_door.rb +196 -0
  97. data/lib/hecks/doors/cli_runner.rb +297 -0
  98. data/lib/hecks/{facade → doors}/command_request.rb +1 -1
  99. data/lib/hecks/{facade → doors}/handle.rb +2 -2
  100. data/lib/hecks/{facade → doors}/json_door.rb +4 -4
  101. data/lib/hecks/doors/launcher_options.rb +129 -0
  102. data/lib/hecks/{cli → doors}/mcp_door.rb +7 -7
  103. data/lib/hecks/doors/mcp_door_scope.rb +97 -0
  104. data/lib/hecks/{facade/surface → doors/ruby_door}/aggregate_door.rb +8 -3
  105. data/lib/hecks/{facade/surface → doors/ruby_door}/chapter.rb +3 -3
  106. data/lib/hecks/{facade/surface.rb → doors/ruby_door.rb} +36 -5
  107. data/lib/hecks/doors.rb +61 -0
  108. data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +1 -1
  109. data/lib/hecks/embryonaut_bluebook.rb +1 -1
  110. data/lib/hecks/engine_agreement.rb +156 -0
  111. data/lib/hecks/facade.rb +24 -37
  112. data/lib/hecks/forms/app.rb +6 -6
  113. data/lib/hecks/forms/banking_presentation.rb +50 -0
  114. data/lib/hecks/forms/field_shape.rb +2 -1
  115. data/lib/hecks/forms/port_argument.rb +1 -1
  116. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +393 -0
  117. data/lib/hecks/fuzzing/combination_miner.rb +86 -0
  118. data/lib/hecks/fuzzing/concurrent_dispatch.rb +214 -0
  119. data/lib/hecks/fuzzing/coverage_campaign.rb +143 -0
  120. data/lib/hecks/fuzzing/differential.rb +156 -0
  121. data/lib/hecks/fuzzing/domain_generator.rb +615 -0
  122. data/lib/hecks/fuzzing/era_boundary.rb +71 -0
  123. data/lib/hecks/fuzzing/form_census.rb +136 -0
  124. data/lib/hecks/fuzzing/generated_domain_check.rb +93 -0
  125. data/lib/hecks/fuzzing/invalid_value_generator.rb +64 -0
  126. data/lib/hecks/fuzzing/isolated_boot.rb +301 -0
  127. data/lib/hecks/fuzzing/nondeterministic.rb +51 -0
  128. data/lib/hecks/fuzzing/outside_world.rb +45 -0
  129. data/lib/hecks/fuzzing/persistence_parity.rb +102 -0
  130. data/lib/hecks/fuzzing/properties/corrections.rb +88 -0
  131. data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +314 -0
  132. data/lib/hecks/fuzzing/properties/guards.rb +190 -0
  133. data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +300 -0
  134. data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +93 -0
  135. data/lib/hecks/fuzzing/properties/outbox.rb +89 -0
  136. data/lib/hecks/fuzzing/properties/querying.rb +175 -0
  137. data/lib/hecks/fuzzing/properties.rb +162 -0
  138. data/lib/hecks/fuzzing/qa_settings.rb +123 -0
  139. data/lib/hecks/fuzzing/replay.rb +505 -0
  140. data/lib/hecks/fuzzing/rotation_priority.rb +48 -0
  141. data/lib/hecks/fuzzing/rust_gap_manifest.rb +108 -0
  142. data/lib/hecks/fuzzing/self_consistency.rb +339 -0
  143. data/lib/hecks/fuzzing/sequence_generator/adversary.rb +385 -0
  144. data/lib/hecks/fuzzing/sequence_generator/catalog.rb +132 -0
  145. data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +95 -0
  146. data/lib/hecks/fuzzing/sequence_generator/picker.rb +77 -0
  147. data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +109 -0
  148. data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +237 -0
  149. data/lib/hecks/fuzzing/sequence_generator.rb +189 -0
  150. data/lib/hecks/fuzzing/shrinker.rb +166 -0
  151. data/lib/hecks/fuzzing/structural_skips.rb +33 -0
  152. data/lib/hecks/fuzzing/sweep_depth.rb +43 -0
  153. data/lib/hecks/fuzzing/target_capabilities.rb +163 -0
  154. data/lib/hecks/fuzzing/value_generator.rb +216 -0
  155. data/lib/hecks/fuzzing.rb +23 -0
  156. data/lib/hecks/grammar/evolve.rb +336 -0
  157. data/lib/hecks/hecks/adapters/codebase/codemods.rb +45 -0
  158. data/lib/hecks/hecks/adapters/codebase/conformance.rb +71 -0
  159. data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +202 -0
  160. data/lib/hecks/hecks/adapters/codebase/gem_registry.rb +80 -0
  161. data/lib/hecks/hecks/adapters/codebase/kernel_tables.rb +54 -0
  162. data/lib/hecks/hecks/adapters/codebase/language.rb +240 -0
  163. data/lib/hecks/hecks/adapters/codebase/npm_registry.rb +102 -0
  164. data/lib/hecks/hecks/adapters/codebase/publishing.rb +142 -0
  165. data/lib/hecks/hecks/adapters/codebase/regeneration.rb +67 -0
  166. data/lib/hecks/hecks/adapters/codebase/release_facts.rb +90 -0
  167. data/lib/hecks/hecks/adapters/codebase/ruby_child.rb +83 -0
  168. data/lib/hecks/hecks/adapters/codebase/secret_vault.rb +36 -0
  169. data/lib/hecks/hecks/adapters/codebase/source_tree.adapter +7 -0
  170. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +189 -0
  171. data/lib/hecks/hecks/adapters/codebase/sqlite_fixture.rb +71 -0
  172. data/lib/hecks/hecks/adapters/codebase/style.rb +171 -0
  173. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +55 -0
  174. data/lib/hecks/hecks/adapters/codebase/test_suite.rb +165 -0
  175. data/lib/hecks/hecks/adapters/codebase/tree.rb +111 -0
  176. data/lib/hecks/hecks/adapters/console_capture.rb +79 -0
  177. data/lib/hecks/hecks/adapters/deploy_toolchain.adapter +7 -0
  178. data/lib/hecks/hecks/adapters/deploy_toolchain.rb +108 -0
  179. data/lib/hecks/hecks/adapters/git.adapter +7 -0
  180. data/lib/hecks/hecks/adapters/git.rb +102 -0
  181. data/lib/hecks/hecks/adapters/host_http.adapter +7 -0
  182. data/lib/hecks/hecks/adapters/host_http.rb +65 -0
  183. data/lib/hecks/hecks/adapters/in_process_boot.adapter +7 -0
  184. data/lib/hecks/hecks/adapters/in_process_boot.rb +197 -0
  185. data/lib/hecks/hecks/adapters/in_process_operations.rb +202 -0
  186. data/lib/hecks/hecks/adapters/journal_store/changes.rb +143 -0
  187. data/lib/hecks/hecks/adapters/journal_store/compaction.rb +145 -0
  188. data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +132 -0
  189. data/lib/hecks/hecks/adapters/journal_store/examination.rb +135 -0
  190. data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +163 -0
  191. data/lib/hecks/hecks/adapters/journal_store/readings.rb +187 -0
  192. data/lib/hecks/hecks/adapters/journal_store.adapter +7 -0
  193. data/lib/hecks/hecks/adapters/journal_store.rb +64 -0
  194. data/lib/hecks/hecks/adapters/local_files.adapter +7 -0
  195. data/lib/hecks/hecks/adapters/local_files.rb +46 -0
  196. data/lib/hecks/hecks/adapters/pg_admin.adapter +7 -0
  197. data/lib/hecks/hecks/adapters/pg_admin.rb +245 -0
  198. data/lib/hecks/hecks/adapters/process_pool.adapter +7 -0
  199. data/lib/hecks/hecks/adapters/process_pool.rb +119 -0
  200. data/lib/hecks/hecks/adapters/rust_toolchain.adapter +7 -0
  201. data/lib/hecks/hecks/adapters/rust_toolchain.rb +179 -0
  202. data/lib/hecks/hecks/adapters/rust_workspace.rb +150 -0
  203. data/lib/hecks/hecks/adapters/shell.adapter +7 -0
  204. data/lib/hecks/hecks/adapters/shell.rb +49 -0
  205. data/lib/hecks/hecks/adapters/terminal.adapter +7 -0
  206. data/lib/hecks/hecks/adapters/terminal.rb +74 -0
  207. data/lib/hecks/hecks/codebase.behaviors +172 -0
  208. data/lib/hecks/hecks/codebase.bluebook +2453 -0
  209. data/lib/hecks/hecks/context_map.hecksagon +13 -0
  210. data/lib/hecks/hecks/custodian.behaviors +179 -0
  211. data/lib/hecks/hecks/custodian.bluebook +1847 -0
  212. data/lib/hecks/hecks/deploy.behaviors +74 -0
  213. data/lib/hecks/hecks/deploy.world +12 -0
  214. data/lib/hecks/hecks/environments/memory.world +10 -0
  215. data/lib/hecks/hecks/governance.world +7 -0
  216. data/lib/hecks/hecks/hecks.behaviors +62 -0
  217. data/lib/hecks/hecks/hecks.bluebook +124 -0
  218. data/lib/hecks/hecks/hecks.hecksagon +390 -0
  219. data/lib/hecks/hecks/hecks.world +42 -0
  220. data/lib/hecks/kernel_capabilities.rb +194 -0
  221. data/lib/hecks/language/bluebook/bluebook.bluebook +11 -0
  222. data/lib/hecks/language/bluebook/query.bluebook +7 -0
  223. data/lib/hecks/language/bluebook/vocabulary.bluebook +4 -4
  224. data/lib/hecks/language/hecksagon/domain_port.bluebook +10 -0
  225. data/lib/hecks/language/hecksagon/hecksagon.bluebook +20 -0
  226. data/lib/hecks/mcp_stdio_guard.rb +2 -2
  227. data/lib/hecks/persistence_legacy_fixture/regenerate.rb +161 -0
  228. data/lib/hecks/persistence_legacy_fixture.rb +113 -0
  229. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +8 -5
  230. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +4 -1
  231. data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +15 -2
  232. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +1 -1
  233. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +1 -1
  234. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +1 -1
  235. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +32 -15
  236. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +6 -3
  237. data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +227 -0
  238. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +1 -1
  239. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +43 -24
  240. data/lib/hecks/ports/persistence/plugins/era/translation.rb +1 -0
  241. data/lib/hecks/ports/persistence/state_codec.rb +24 -5
  242. data/lib/hecks/projection_files.rb +285 -0
  243. data/lib/hecks/projections/bootstrap_table.rb +1 -1
  244. data/lib/hecks/projections/deploy/fargate.rb +5 -5
  245. data/lib/hecks/projections/deploy/lambda.rb +43 -32
  246. data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
  247. data/lib/hecks/projections/deploy/preview/template.rb +1 -1
  248. data/lib/hecks/projections/deploy/scripts/deploy-service.sh.tmpl +1 -1
  249. data/lib/hecks/projections/deploy/scripts/expected-era.header +1 -1
  250. data/lib/hecks/projections/deploy/scripts/hosting.mk.tmpl +3 -3
  251. data/lib/hecks/projections/deploy/scripts/smoke-after-deploy.sh.tmpl +1 -1
  252. data/lib/hecks/projections/deploy/shared.rb +1 -1
  253. data/lib/hecks/projections/diagrams.rb +3 -3
  254. data/lib/hecks/projections/model/deviations.rb +1 -1
  255. data/lib/hecks/projections/parser_table.rb +4 -4
  256. data/lib/hecks/projections/reference.rb +2 -3
  257. data/lib/hecks/projections/rust_vocabulary.rb +1 -1
  258. data/lib/hecks/projector/cli_projector.rb +106 -37
  259. data/lib/hecks/projector.rb +1 -1
  260. data/lib/hecks/quality_control/adapters/agent.adapter +7 -0
  261. data/lib/hecks/quality_control/adapters/agent.rb +58 -0
  262. data/lib/hecks/quality_control/adapters/angle_tools.adapter +7 -0
  263. data/lib/hecks/quality_control/adapters/angle_tools.rb +15 -0
  264. data/lib/hecks/quality_control/adapters/clearance_recorder.rb +36 -0
  265. data/lib/hecks/quality_control/adapters/clearance_tools.adapter +7 -0
  266. data/lib/hecks/quality_control/adapters/clearance_tools.rb +17 -0
  267. data/lib/hecks/quality_control/adapters/git_pr.adapter +7 -0
  268. data/lib/hecks/quality_control/adapters/git_pr.rb +226 -0
  269. data/lib/hecks/quality_control/adapters/github_checks.adapter +9 -0
  270. data/lib/hecks/quality_control/adapters/github_checks.rb +83 -0
  271. data/lib/hecks/quality_control/adapters/github_ci_webhook.rb +56 -0
  272. data/lib/hecks/quality_control/adapters/github_issues.adapter +7 -0
  273. data/lib/hecks/quality_control/adapters/github_issues.rb +49 -0
  274. data/lib/hecks/quality_control/adapters/qa_tool.rb +59 -0
  275. data/lib/hecks/quality_control/adapters/sweep_tools.adapter +7 -0
  276. data/lib/hecks/quality_control/adapters/sweep_tools.rb +51 -0
  277. data/lib/hecks/quality_control/adapters/target_tools.adapter +7 -0
  278. data/lib/hecks/quality_control/adapters/target_tools.rb +43 -0
  279. data/lib/hecks/quality_control/cli/child.rb +45 -0
  280. data/lib/hecks/quality_control/cli/qa_concurrency_racer.rb +45 -0
  281. data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +248 -0
  282. data/lib/hecks/quality_control/cli/qa_domain_novelty.rb +163 -0
  283. data/lib/hecks/quality_control/cli/qa_generated_domains.rb +450 -0
  284. data/lib/hecks/quality_control/cli/qa_log_bug.rb +195 -0
  285. data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +220 -0
  286. data/lib/hecks/quality_control/cli/qa_open_pr.rb +305 -0
  287. data/lib/hecks/quality_control/cli/qa_postgres_migrate.rb +154 -0
  288. data/lib/hecks/quality_control/cli/qa_postgres_role.rb +159 -0
  289. data/lib/hecks/quality_control/cli/qa_pr_check.rb +232 -0
  290. data/lib/hecks/quality_control/cli/qa_seed_angles.rb +142 -0
  291. data/lib/hecks/quality_control/cli/qa_seed_targets.rb +69 -0
  292. data/lib/hecks/quality_control/cli/qa_sweep/all_mode.rb +280 -0
  293. data/lib/hecks/quality_control/cli/qa_sweep/checks.rb +329 -0
  294. data/lib/hecks/quality_control/cli/qa_sweep/dials.rb +92 -0
  295. data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +117 -0
  296. data/lib/hecks/quality_control/cli/qa_sweep/parsing.rb +175 -0
  297. data/lib/hecks/quality_control/cli/qa_sweep/release_mode.rb +60 -0
  298. data/lib/hecks/quality_control/cli/qa_sweep.rb +611 -0
  299. data/lib/hecks/quality_control/cli/qa_tick.rb +274 -0
  300. data/lib/hecks/quality_control/quality_control.bluebook +2224 -0
  301. data/lib/hecks/quality_control/quality_control.hecksagon +13 -0
  302. data/lib/hecks/quality_control/quality_control.ports.hecksagon +54 -0
  303. data/lib/hecks/query_ir.rb +346 -0
  304. data/lib/hecks/query_ir_mcp.rb +198 -0
  305. data/lib/hecks/release/runner/ci_publisher.rb +2 -2
  306. data/lib/hecks/release/runner/clean_tree.rb +42 -0
  307. data/lib/hecks/release/runner/console.rb +6 -0
  308. data/lib/hecks/release/runner/gem_publisher.rb +14 -7
  309. data/lib/hecks/release/runner/npm_publisher.rb +6 -36
  310. data/lib/hecks/release/runner/preflight.rb +26 -2
  311. data/lib/hecks/release/runner/published.rb +8 -26
  312. data/lib/hecks/release/runner/tagger.rb +30 -15
  313. data/lib/hecks/release/runner.rb +57 -6
  314. data/lib/hecks/router/namespace_installer.rb +3 -3
  315. data/lib/hecks/runtime/adapter_lookup.rb +124 -0
  316. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +4 -0
  317. data/lib/hecks/runtime/dependency_planning.rb +20 -2
  318. data/lib/hecks/runtime/dispatcher.rb +53 -3
  319. data/lib/hecks/runtime/interpreting.rb +3 -0
  320. data/lib/hecks/runtime/loader.rb +65 -12
  321. data/lib/hecks/runtime/outbox.rb +1 -1
  322. data/lib/hecks/runtime/policy_interpreter.rb +5 -2
  323. data/lib/hecks/runtime/port_operation_interpreter.rb +2 -10
  324. data/lib/hecks/runtime/query_interpreter.rb +77 -0
  325. data/lib/hecks/runtime/reaction_outcome.rb +89 -0
  326. data/lib/hecks/runtime/refusal_wording.rb +23 -1
  327. data/lib/hecks/runtime/registry/verification.rb +163 -4
  328. data/lib/hecks/runtime/registry.rb +57 -3
  329. data/lib/hecks/runtime/remote_dispatcher.rb +31 -2
  330. data/lib/hecks/runtime/value/coercion.rb +23 -135
  331. data/lib/hecks/runtime/value/field_checks.rb +172 -0
  332. data/lib/hecks/runtime/value.rb +4 -1
  333. data/lib/hecks/runtime.rb +20 -6
  334. data/lib/hecks/rust_build/conformance.rb +158 -0
  335. data/lib/hecks/rust_build/conformance_fuzz.rb +71 -0
  336. data/lib/hecks/rust_build/coverage.rb +218 -0
  337. data/lib/hecks/rust_build/native_build.rb +124 -0
  338. data/lib/hecks/rust_build/project_rust/root_mod.rb +120 -0
  339. data/lib/hecks/rust_build/project_rust.rb +332 -0
  340. data/lib/hecks/rust_build/wasm.rb +105 -0
  341. data/lib/hecks/rust_build/wasm_browser.rb +113 -0
  342. data/lib/hecks/rust_build.rb +144 -0
  343. data/lib/hecks/storehouse.rb +16 -16
  344. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +2 -2
  345. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +1 -1
  346. data/lib/hecks/three_zero/forms.yml +127 -0
  347. data/lib/hecks/three_zero.rb +12 -0
  348. data/lib/hecks/tools/argument_gate_matrix.rb +316 -0
  349. data/lib/hecks/tools/comment_style.rb +1070 -0
  350. data/lib/hecks/tools/corpus_report.rb +87 -0
  351. data/lib/hecks/tools/deploy_recipe.rb +255 -0
  352. data/lib/hecks/tools/deploy_recipe_lint.rb +282 -0
  353. data/lib/hecks/tools/drop_implicit_append_fields.rb +95 -0
  354. data/lib/hecks/tools/era_projection_backfill.rb +94 -0
  355. data/lib/hecks/tools/era_reattest.rb +146 -0
  356. data/lib/hecks/tools/evolve_run.rb +189 -0
  357. data/lib/hecks/tools/fuzz_sweep.rb +373 -0
  358. data/lib/hecks/tools/heki_compaction.rb +100 -0
  359. data/lib/hecks/tools/hoist_local_givens.rb +246 -0
  360. data/lib/hecks/tools/journal_compaction.rb +89 -0
  361. data/lib/hecks/tools/oidc_manifests.rb +70 -0
  362. data/lib/hecks/tools/query_ir_run.rb +81 -0
  363. data/lib/hecks/tools/regeneration_run.rb +166 -0
  364. data/lib/hecks/tools/rust_comment_style.rb +642 -0
  365. data/lib/hecks/tools/sequence_script.rb +62 -0
  366. data/lib/hecks/tools/tail_merge.rb +117 -0
  367. data/lib/hecks/tools/tenant_provisioning.rb +142 -0
  368. data/lib/hecks/tools/translation_audit.rb +208 -0
  369. data/lib/hecks/tools/translation_scaffold.rb +131 -0
  370. data/lib/hecks/tools.rb +86 -0
  371. data/lib/hecks/version.rb +1 -1
  372. data/lib/hecks.rb +32 -15
  373. data/qa/settings.yml +66 -0
  374. data/rust/.cargo/config.toml +6 -0
  375. data/rust/.gitignore +2 -0
  376. data/rust/Cargo.lock +54 -0
  377. data/rust/Cargo.toml +61 -0
  378. data/rust/build/.cargo/config.toml +3 -0
  379. data/rust/build/.gitignore +1 -0
  380. data/rust/build/Cargo.lock +7 -0
  381. data/rust/build/Cargo.toml +19 -0
  382. data/rust/build/src/build_artifact.rs +47 -0
  383. data/rust/build/src/cargo_sync.rs +248 -0
  384. data/rust/build/src/json.rs +421 -0
  385. data/rust/build/src/lineage_pass.rs +285 -0
  386. data/rust/build/src/main.rs +51 -0
  387. data/rust/build/src/optional_pass.rs +150 -0
  388. data/rust/build/src/pipeline.rs +264 -0
  389. data/rust/build/src/reserved_names.rs +76 -0
  390. data/rust/build/src/resolve.rs +124 -0
  391. data/rust/build/src/root.rs +25 -0
  392. data/rust/build/src/sidecars.rs +73 -0
  393. data/rust/build/src/subprocess.rs +51 -0
  394. data/rust/build/src/tmp.rs +31 -0
  395. data/rust/codegen/.cargo/config.toml +3 -0
  396. data/rust/codegen/.gitignore +1 -0
  397. data/rust/codegen/Cargo.lock +7 -0
  398. data/rust/codegen/Cargo.toml +20 -0
  399. data/rust/codegen/src/attr.rs +32 -0
  400. data/rust/codegen/src/bridging.rs +481 -0
  401. data/rust/codegen/src/commands.rs +1226 -0
  402. data/rust/codegen/src/constraints.rs +109 -0
  403. data/rust/codegen/src/dependency_planning.rs +209 -0
  404. data/rust/codegen/src/domain_generator.rs +1288 -0
  405. data/rust/codegen/src/exemplar.rs +230 -0
  406. data/rust/codegen/src/expr_emitter.rs +87 -0
  407. data/rust/codegen/src/fielded.rs +192 -0
  408. data/rust/codegen/src/hecks_naming.rs +33 -0
  409. data/rust/codegen/src/json.rs +335 -0
  410. data/rust/codegen/src/json_codec.rs +697 -0
  411. data/rust/codegen/src/literal.rs +207 -0
  412. data/rust/codegen/src/main.rs +290 -0
  413. data/rust/codegen/src/manifest.rs +227 -0
  414. data/rust/codegen/src/mutations.rs +784 -0
  415. data/rust/codegen/src/naming.rs +286 -0
  416. data/rust/codegen/src/ports.rs +208 -0
  417. data/rust/codegen/src/prelude.rs +116 -0
  418. data/rust/codegen/src/queries.rs +786 -0
  419. data/rust/codegen/src/reactions.rs +532 -0
  420. data/rust/codegen/src/read_models.rs +697 -0
  421. data/rust/codegen/src/reference_specs.rs +40 -0
  422. data/rust/codegen/src/registry.rs +966 -0
  423. data/rust/codegen/src/reserved_names.rs +76 -0
  424. data/rust/codegen/src/shared.rs +93 -0
  425. data/rust/codegen/src/skip_reason.rs +25 -0
  426. data/rust/codegen/src/types.rs +362 -0
  427. data/rust/host/.cargo/config.toml +3 -0
  428. data/rust/host/.gitignore +1 -0
  429. data/rust/host/Cargo.lock +4297 -0
  430. data/rust/host/Cargo.toml +61 -0
  431. data/rust/host/HECKS_RELEASE +1 -0
  432. data/rust/host/rds-ca-bundle.pem +2736 -0
  433. data/rust/host/src/api.rs +1596 -0
  434. data/rust/host/src/approval.rs +652 -0
  435. data/rust/host/src/auth.rs +1287 -0
  436. data/rust/host/src/bin/expr_harness.rs +46 -0
  437. data/rust/host/src/bin/lineage_harness.rs +119 -0
  438. data/rust/host/src/bin/mint_harness.rs +135 -0
  439. data/rust/host/src/checkout.rs +265 -0
  440. data/rust/host/src/dispatch.rs +1443 -0
  441. data/rust/host/src/expr_json.rs +1117 -0
  442. data/rust/host/src/field_hints.rs +52 -0
  443. data/rust/host/src/ir.rs +733 -0
  444. data/rust/host/src/journal.rs +874 -0
  445. data/rust/host/src/lambda_client.rs +378 -0
  446. data/rust/host/src/log.rs +147 -0
  447. data/rust/host/src/main.rs +474 -0
  448. data/rust/host/src/mint.rs +1865 -0
  449. data/rust/host/src/payments/keystore.rs +330 -0
  450. data/rust/host/src/payments/tests.rs +1400 -0
  451. data/rust/host/src/payments.rs +767 -0
  452. data/rust/host/src/presentation.rs +698 -0
  453. data/rust/host/src/presentation_write.rs +1431 -0
  454. data/rust/host/src/query_step.rs +149 -0
  455. data/rust/host/src/rate_limit.rs +904 -0
  456. data/rust/host/src/reference_transform.rs +241 -0
  457. data/rust/host/src/reference_validate.rs +338 -0
  458. data/rust/host/src/resend.rs +296 -0
  459. data/rust/host/src/secrets.rs +106 -0
  460. data/rust/host/src/server.rs +663 -0
  461. data/rust/host/src/storage_shape.rs +175 -0
  462. data/rust/host/src/test_pg.rs +40 -0
  463. data/rust/host/src/ui_schema.rs +1351 -0
  464. data/rust/host/src/wasm_runner.rs +191 -0
  465. data/rust/host/src/web/newsletter/cooldown.rs +126 -0
  466. data/rust/host/src/web/newsletter/tests.rs +104 -0
  467. data/rust/host/src/web/newsletter.rs +310 -0
  468. data/rust/host/src/web/newsletter_send.rs +357 -0
  469. data/rust/host/src/web/registrations.rs +1505 -0
  470. data/rust/host/src/web.rs +2937 -0
  471. data/rust/lsp/.gitignore +1 -0
  472. data/rust/lsp/Cargo.lock +7 -0
  473. data/rust/lsp/Cargo.toml +16 -0
  474. data/rust/lsp/README.md +133 -0
  475. data/rust/lsp/src/diagnostics.rs +165 -0
  476. data/rust/lsp/src/json.rs +385 -0
  477. data/rust/lsp/src/main.rs +399 -0
  478. data/rust/lsp/src/outline.rs +177 -0
  479. data/rust/lsp/src/rpc.rs +67 -0
  480. data/rust/parser/.cargo/config.toml +5 -0
  481. data/rust/parser/.gitignore +1 -0
  482. data/rust/parser/Cargo.lock +7 -0
  483. data/rust/parser/Cargo.toml +21 -0
  484. data/rust/parser/src/build/closed_sets.rs +27 -0
  485. data/rust/parser/src/build/identity.rs +276 -0
  486. data/rust/parser/src/build/mod.rs +12 -0
  487. data/rust/parser/src/build/naming.rs +141 -0
  488. data/rust/parser/src/build/pattern_subset.rs +161 -0
  489. data/rust/parser/src/build/query_derive.rs +72 -0
  490. data/rust/parser/src/build/query_inference.rs +269 -0
  491. data/rust/parser/src/build/query_options.rs +100 -0
  492. data/rust/parser/src/build/read_model.rs +94 -0
  493. data/rust/parser/src/build/references.rs +32 -0
  494. data/rust/parser/src/canonical.rs +114 -0
  495. data/rust/parser/src/diag.rs +55 -0
  496. data/rust/parser/src/emit.rs +953 -0
  497. data/rust/parser/src/expr/ast_json.rs +147 -0
  498. data/rust/parser/src/expr/evaluator.rs +81 -0
  499. data/rust/parser/src/expr/mod.rs +84 -0
  500. data/rust/parser/src/expr/resolver.rs +497 -0
  501. data/rust/parser/src/ir.rs +387 -0
  502. data/rust/parser/src/keywords.rs +585 -0
  503. data/rust/parser/src/lex.rs +662 -0
  504. data/rust/parser/src/main.rs +252 -0
  505. data/rust/parser/src/parse/aggregate.rs +612 -0
  506. data/rust/parser/src/parse/chapter.rs +517 -0
  507. data/rust/parser/src/parse/command.rs +637 -0
  508. data/rust/parser/src/parse/domain_port.rs +127 -0
  509. data/rust/parser/src/parse/entity.rs +527 -0
  510. data/rust/parser/src/parse/file.rs +67 -0
  511. data/rust/parser/src/parse/hecksagon.rs +231 -0
  512. data/rust/parser/src/parse/lifecycle.rs +162 -0
  513. data/rust/parser/src/parse/mod.rs +1262 -0
  514. data/rust/parser/src/parse/policy.rs +87 -0
  515. data/rust/parser/src/parse/process_manager.rs +305 -0
  516. data/rust/parser/src/parse/query.rs +100 -0
  517. data/rust/parser/src/parse/read_model.rs +214 -0
  518. data/rust/parser/src/parse/value_object.rs +250 -0
  519. data/rust/parser/src/ruby_value.rs +422 -0
  520. data/rust/project/bridging.rb +257 -0
  521. data/rust/project/commands.rb +877 -0
  522. data/rust/project/constraints.rb +86 -0
  523. data/rust/project/dependency_planning.rb +178 -0
  524. data/rust/project/domain_generator.rb +980 -0
  525. data/rust/project/exemplar.rb +148 -0
  526. data/rust/project/expr_emitter.rb +72 -0
  527. data/rust/project/fielded.rb +141 -0
  528. data/rust/project/json_codec.rb +641 -0
  529. data/rust/project/mutations.rb +721 -0
  530. data/rust/project/naming.rb +205 -0
  531. data/rust/project/ports.rb +65 -0
  532. data/rust/project/queries.rb +493 -0
  533. data/rust/project/reactions.rb +317 -0
  534. data/rust/project/read_models.rb +690 -0
  535. data/rust/project/reference_specs.rb +27 -0
  536. data/rust/project/registry.rb +396 -0
  537. data/rust/project/skip_reason.rb +29 -0
  538. data/rust/project/types.rb +225 -0
  539. data/rust/project/write_if_changed.rb +83 -0
  540. data/rust/project.rb +30 -0
  541. data/rust/project_rust_pipeline.rb +383 -0
  542. data/rust/src/exemplar/commands.rs +279 -0
  543. data/rust/src/exemplar/constraints.rs +18 -0
  544. data/rust/src/exemplar/fielded.rs +280 -0
  545. data/rust/src/exemplar/json.rs +277 -0
  546. data/rust/src/exemplar/mod.rs +17 -0
  547. data/rust/src/exemplar/mutations.rs +80 -0
  548. data/rust/src/exemplar/queries.rs +33 -0
  549. data/rust/src/exemplar/reactions.rs +88 -0
  550. data/rust/src/exemplar/read_models.rs +48 -0
  551. data/rust/src/exemplar/registry.rs +166 -0
  552. data/rust/src/exemplar/types.rs +44 -0
  553. data/rust/src/kernel/attribute_shapes/composite.rs +88 -0
  554. data/rust/src/kernel/attribute_shapes/list.rs +18 -0
  555. data/rust/src/kernel/attribute_shapes/mod.rs +44 -0
  556. data/rust/src/kernel/attribute_shapes/optional.rs +9 -0
  557. data/rust/src/kernel/attribute_shapes/scalar.rs +39 -0
  558. data/rust/src/kernel/cli.rs +585 -0
  559. data/rust/src/kernel/dispatch.rs +1090 -0
  560. data/rust/src/kernel/expr.rs +458 -0
  561. data/rust/src/kernel/expression_operators/arithmetic.rs +128 -0
  562. data/rust/src/kernel/expression_operators/comparison.rs +48 -0
  563. data/rust/src/kernel/expression_operators/enumeration.rs +232 -0
  564. data/rust/src/kernel/expression_operators/logical.rs +13 -0
  565. data/rust/src/kernel/expression_operators/membership.rs +18 -0
  566. data/rust/src/kernel/expression_operators/mod.rs +68 -0
  567. data/rust/src/kernel/expression_operators/pattern_match.rs +73 -0
  568. data/rust/src/kernel/expression_operators/positional.rs +126 -0
  569. data/rust/src/kernel/expression_operators/presence.rs +101 -0
  570. data/rust/src/kernel/expression_operators/sign_test.rs +16 -0
  571. data/rust/src/kernel/expression_operators/sized.rs +35 -0
  572. data/rust/src/kernel/expression_operators/text.rs +79 -0
  573. data/rust/src/kernel/expression_operators/to_string.rs +18 -0
  574. data/rust/src/kernel/json.rs +779 -0
  575. data/rust/src/kernel/mod.rs +133 -0
  576. data/rust/src/kernel/named_query.rs +219 -0
  577. data/rust/src/kernel/orchestrate.rs +1810 -0
  578. data/rust/src/kernel/pattern.rs +307 -0
  579. data/rust/src/kernel/query_comparators.rs +206 -0
  580. data/rust/src/kernel/query_ordering.rs +103 -0
  581. data/rust/src/kernel/read_model.rs +914 -0
  582. data/rust/src/kernel/reference_lookup.rs +149 -0
  583. data/rust/src/kernel/repository.rs +468 -0
  584. data/rust/src/kernel/routing.rs +612 -0
  585. data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +118 -0
  586. data/rust/src/kernel/vocab/entity_dispatch_order.rs +114 -0
  587. data/rust/src/kernel/vocab/field_hint.rs +70 -0
  588. data/rust/src/kernel/vocab/mod.rs +20 -0
  589. data/rust/src/kernel/vocab/query_comparator.rs +65 -0
  590. data/rust/src/kernel/vocab/refusal_template.rs +1592 -0
  591. data/rust/src/lib.rs +8 -0
  592. data/rust/src/main.rs +16 -0
  593. data/rust/web/.gitignore +1 -0
  594. data/rust/web/Cargo.lock +119 -0
  595. data/rust/web/Cargo.toml +18 -0
  596. data/rust/web/src/lib.rs +8 -0
  597. metadata +477 -12
  598. data/lib/hecks/facade/cli_door.rb +0 -96
  599. data/lib/hecks/facade/cli_runner.rb +0 -127
  600. data/lib/hecks/mcp_door_scope.rb +0 -95
@@ -1,8 +1,16 @@
1
- # Tooling-internal domain `bin/project_deploy` boots directly; never attached via `uses_framework`.
2
- # It validates the `deployed_to` shape that `world.bluebook`'s untyped `Setting` map leaves open.
1
+ # The Deploy chapter: what `deployed_to(...)` may declare, and the commands that generate, check and
2
+ # compare a deploy recipe, project the OIDC manifests and provision a tenant.
3
+ #
4
+ # `hecks deploy project` and `hecks deploy provision` boot it directly; the Hecks domain attaches it, so
5
+ # each command below is also `hecks deploy <verb>`. The targets validate the `deployed_to` shape
6
+ # that `world.bluebook`'s untyped `Setting` map leaves open. Each run below records that it was
7
+ # requested before its DeployToolchain port is asked, and what came of it after. No command
8
+ # declares a role: the chapter boots standing alone, without Governance to check one against.
3
9
  Hecks.bluebook "Deploy" do
10
+ vision "Generate, check and compare deploy recipes, project OIDC manifests and provision tenants."
11
+
4
12
  aggregate "LambdaTarget" do
5
- description "One domain's validated AWS Lambda deploy target — what deployed_to(\"AwsLambda\") must resolve to before bin/project_deploy generates anything from it."
13
+ description "One domain's validated AWS Lambda deploy target — what deployed_to(\"AwsLambda\") must resolve to before hecks deploy project generates anything from it."
6
14
 
7
15
  identified_by :domain
8
16
 
@@ -27,14 +35,14 @@ Hecks.bluebook "Deploy" do
27
35
  # (Serverless v2);
28
36
  # only the emitted CloudFormation resource differs, never the runtime adapter. "Shared" borrows
29
37
  # another domain's instance under its own Postgres schema and needs an `owner` setting, which
30
- # `bin/project_deploy` checks, since the owning domain is a deploy-time fact.
38
+ # `hecks deploy project` checks, since the owning domain is a deploy-time fact.
31
39
  value_object "Database" do
32
40
  attribute :value, String, one_of: ["Postgres", "Aurora", "Shared"]
33
41
  end
34
42
 
35
43
  # "None" (default) or "Rust": the domain's own Lambda (rust/host) also serves a public web UI
36
44
  # in-process (rust/host/src/web.rs). "Ruby" is not a member: a Ruby WebFunction comes from a
37
- # `lambda_handler.rb` file, and `bin/project_deploy` refuses `web "Rust"` alongside one.
45
+ # `lambda_handler.rb` file, and `hecks deploy project` refuses `web "Rust"` alongside one.
38
46
  value_object "Web" do
39
47
  attribute :value, String, one_of: ["None", "Rust"]
40
48
  end
@@ -55,7 +63,7 @@ Hecks.bluebook "Deploy" do
55
63
 
56
64
  # All required, no `default:`: command-level defaults apply only at the JSON/Rust-codegen
57
65
  # boundary, not Ruby's direct dispatch (interpreting.rb `normalize_args`). Defaults are
58
- # resolved by `bin/project_deploy` before it dispatches.
66
+ # resolved by `hecks deploy project` before it dispatches.
59
67
  command "Declare" do
60
68
  goal "Validate one domain's AwsLambda deploy target before anything is generated from it"
61
69
 
@@ -80,7 +88,7 @@ Hecks.bluebook "Deploy" do
80
88
  # A sibling of `LambdaTarget` with its own value objects, since value objects are not
81
89
  # shared across aggregates.
82
90
  aggregate "FargateTarget" do
83
- description "One domain's validated AWS Fargate deploy target — what deployed_to(\"AwsFargate\") must resolve to before bin/project_deploy generates anything from it."
91
+ description "One domain's validated AWS Fargate deploy target — what deployed_to(\"AwsFargate\") must resolve to before hecks deploy project generates anything from it."
84
92
 
85
93
  identified_by :domain
86
94
 
@@ -135,7 +143,7 @@ Hecks.bluebook "Deploy" do
135
143
  end
136
144
 
137
145
  # All seven required for the same reason as `LambdaTarget.Declare`; this validates a
138
- # target already resolved by `bin/project_deploy`'s defaults.
146
+ # target already resolved by `hecks deploy project`'s defaults.
139
147
  command "Declare" do
140
148
  goal "Validate one domain's AwsFargate deploy target before anything is generated from it"
141
149
 
@@ -159,22 +167,27 @@ Hecks.bluebook "Deploy" do
159
167
  end
160
168
  end
161
169
 
162
- # The validated shape of `bin/project_tenant`, which does the generating and provisioning.
170
+ # The validated shape of `hecks deploy provision`, which does the generating and provisioning.
163
171
  # Not a saga: each of its steps is idempotent and local, so there is nothing to resume.
164
172
  aggregate "Tenant" do
165
- description "One tenant's validated identity — which realm and Postgres schema `bin/project_tenant` provisions before booting a domain directory under Runtime.boot's own `environment:` overlay for it."
173
+ description "One tenant's validated identity — which realm and Postgres schema `hecks deploy provision` provisions before booting a domain directory under Runtime.boot's own `environment:` overlay for it."
166
174
 
167
175
  identified_by :slug
168
176
 
169
- attribute :slug, Slug
170
- attribute :domain, DomainName
171
- attribute :realm, Realm
172
- attribute :schema, Schema
177
+ attribute :slug, Slug
178
+ attribute :domain, DomainName
179
+ attribute :realm, Realm
180
+ attribute :schema, Schema
181
+ attribute :database, DatabaseName, optional: true
182
+ attribute :adapter, AdapterName, optional: true
183
+ attribute :directory, DirectoryPath, optional: true
184
+ attribute :output, Report, optional: true
185
+ attribute :refusal, Report, optional: true
173
186
 
174
187
  # Lowercase, no spaces: a slug becomes the `environments/<slug>.world` filename and, by
175
188
  # convention only, the schema name (`schema` is separate so a tenant can differ).
176
189
  value_object "Slug" do
177
- attribute :value, String, pattern: '^[a-z][a-z0-9_]*$'
190
+ attribute :value, String, pattern: '\A[a-z][a-z0-9_]*\z'
178
191
  invariant("a tenant slug is named") { !value.to_s.empty? }
179
192
  end
180
193
 
@@ -192,24 +205,579 @@ Hecks.bluebook "Deploy" do
192
205
  # identifier limit is not checked: the invariant expression grammar has no `bytesize`, and
193
206
  # Postgres refuses a too-long identifier itself.
194
207
  value_object "Schema" do
195
- attribute :value, String, pattern: '^[a-z][a-z0-9_]*$'
208
+ attribute :value, String, pattern: '\A[a-z][a-z0-9_]*\z'
196
209
  invariant("a schema is named") { !value.to_s.empty? }
197
210
  end
198
211
 
199
- command "Declare" do
200
- goal "Validate one tenant's shape before bin/project_tenant provisions its schema and overlay world"
212
+ # A database name or a `postgres://` URL, whichever the overlay's `database` setting takes.
213
+ value_object "DatabaseName" do
214
+ attribute :value, String, pattern: '\A[^\t\n\r]+\z'
215
+ end
216
+
217
+ # The persistence adapter the overlay binds; PostgresEra when a request names none.
218
+ value_object "AdapterName" do
219
+ attribute :value, String, pattern: '\A[A-Z][A-Za-z0-9]*\z'
220
+ end
221
+
222
+ # The domain's own directory on disk, where `environments/<slug>.world` is written.
223
+ value_object "DirectoryPath" do
224
+ attribute :value, String, pattern: '[^\t\n\r]'
225
+ end
201
226
 
202
- attribute :slug, Slug
203
- attribute :domain, DomainName
204
- attribute :realm, Realm
205
- attribute :schema, Schema
227
+ value_object "Report" do
228
+ attribute :value, String
229
+ end
230
+
231
+ lifecycle :status, default: "requested" do
232
+ transition "Reprovision" => "requested", from: %w[provisioned refused]
233
+ transition "Complete" => "provisioned", from: "requested"
234
+ transition "Abandon" => "refused", from: "requested"
235
+ end
206
236
 
237
+ # `hecks deploy provision <directory> slug=s domain= realm= schema= database= [adapter=]`.
238
+ # The only command that creates a tenant: its slug, schema and realm are validated by the value
239
+ # objects' patterns and invariants, then the overlay is written through the TenantProvisioning
240
+ # port; the adapter answers PostgresEra when `adapter` is left out. `dry_run?` on this verb
241
+ # validates a declaration without recording it.
242
+ command "Provision" do
243
+ goal "Validate one tenant, write its environment overlay world, and register it"
244
+
245
+ attribute :directory, DirectoryPath
246
+ attribute :slug, Slug
247
+ attribute :domain, DomainName
248
+ attribute :realm, Realm
249
+ attribute :schema, Schema
250
+ attribute :database, DatabaseName
251
+ attribute :adapter, AdapterName, optional: true
252
+
253
+ sets :directory
207
254
  sets :slug
208
255
  sets :domain
209
256
  sets :realm
210
257
  sets :schema
258
+ sets :database
259
+ sets :adapter
260
+
261
+ emits "TenantProvisionRequested"
262
+ end
263
+
264
+ # A tenant's slug names its record, so provisioning it again is its own command; the overlay
265
+ # is rewritten with the database and adapter given now.
266
+ command "Reprovision" do
267
+ goal "Write a provisioned or refused tenant's environment overlay world again"
268
+
269
+ reference_to Tenant
270
+ attribute :directory, DirectoryPath
271
+ attribute :database, DatabaseName
272
+ attribute :adapter, AdapterName, optional: true
273
+
274
+ sets :directory
275
+ sets :database
276
+ sets :adapter
277
+
278
+ emits "TenantReprovisionRequested"
279
+ end
280
+
281
+ command "Complete" do
282
+ goal "Record that the tenant's overlay was written, and where"
283
+
284
+ reference_to Tenant
285
+ attribute :output, Report
286
+
287
+ sets :output
288
+
289
+ emits "TenantRecorded"
290
+ end
291
+
292
+ command "Abandon" do
293
+ goal "Record that the tenant could not be provisioned, and why"
294
+
295
+ reference_to Tenant
296
+ attribute :refusal, Report
297
+
298
+ sets :refusal
299
+
300
+ emits "ProvisioningAbandoned"
301
+ end
302
+
303
+ query "Provisioning" do
304
+ description "What provisioning one tenant did: its status, and the reason when it was refused."
305
+ attribute :slug, Slug
306
+ where(slug: :slug)
307
+ order_by :slug
308
+ end
309
+
310
+ query "Unprovisioned" do
311
+ description "Every tenant whose provisioning was refused."
312
+ where(status: "refused")
313
+ order_by :slug
314
+ end
315
+ end
316
+
317
+ # `TenantProvisioned` also reaches Tenancy's `RegisterProvisionedTenant` where that chapter is
318
+ # attached, so a provisioned tenant becomes a fact there.
319
+ policy "ProvisionWhenRequested" do
320
+ on "Tenant.TenantProvisionRequested"
321
+ trigger Tenant::TenantProvisioning::WriteOverlay, with: { database: :database, directory: :directory }
322
+ end
323
+
324
+ policy "ReprovisionWhenRequested" do
325
+ on "Tenant.TenantReprovisionRequested"
326
+ trigger Tenant::TenantProvisioning::WriteOverlay, with: { database: :database, directory: :directory }
327
+ end
328
+
329
+ policy "RecordTheTenant" do
330
+ on "Tenant.TenantProvisioned"
331
+ trigger Tenant::Complete, with: { output: :output }
332
+ end
333
+
334
+ policy "RecordTheRefusedTenant" do
335
+ on "Tenant.ProvisioningRefused"
336
+ trigger Tenant::Abandon, with: { refusal: :refusal }
337
+ end
338
+
339
+ aggregate "Recipe" do
340
+ description "One generation of a domain's deploy recipe: the template, scripts and Makefile written from its deployed_to target."
341
+
342
+ attribute :domain, DomainPath
343
+ attribute :run, RunKey
344
+ attribute :tenant, TenantSlug, optional: true
345
+ attribute :schema, SchemaName, optional: true
346
+ attribute :out, Location, optional: true
347
+ attribute :environment, EnvironmentName, optional: true
348
+ attribute :output, Report, optional: true
349
+ attribute :refusal, Report, optional: true
350
+ identified_by :run
351
+
352
+ value_object "RunKey" do
353
+ attribute :value, String, pattern: '[^ \t\n\r]'
354
+
355
+ invariant("a run is named") { !value.to_s.empty? }
356
+ end
357
+
358
+ # A domain directory, whose `bluebook/` holds the `.world` that declares `deployed_to`.
359
+ value_object "DomainPath" do
360
+ attribute :value, String, pattern: '[^\t\n\r]'
361
+
362
+ invariant("a domain is named by its path") { !value.to_s.empty? }
363
+ end
364
+
365
+ # A tenant of a shared-database domain: its stack is the domain's own, suffixed with the slug.
366
+ value_object "TenantSlug" do
367
+ attribute :value, String, pattern: '\A[a-z][a-z0-9_]*\z'
368
+ end
369
+
370
+ value_object "SchemaName" do
371
+ attribute :value, String, pattern: '\A[a-z][a-z0-9_]*\z'
372
+ end
373
+
374
+ # Where the recipe is written, for a domain that lives in a client's repository.
375
+ value_object "Location" do
376
+ attribute :value, String, pattern: '[^\t\n\r]'
377
+ end
378
+
379
+ # An `environments/<name>.world` overlay of the domain, which must exist.
380
+ value_object "EnvironmentName" do
381
+ attribute :value, String, pattern: '\A[A-Za-z][A-Za-z0-9_]*\z'
382
+ end
383
+
384
+ value_object "Report" do
385
+ attribute :value, String
386
+ end
387
+
388
+ lifecycle :status, default: "requested" do
389
+ transition "Complete" => "projected", from: "requested"
390
+ transition "Fault" => "faulted", from: "requested"
391
+ end
392
+
393
+ # `hecks deploy project <domain> [tenant=] [schema=] [out=] [environment=]`. A schema override
394
+ # needs its tenant; the generator says so, and a domain with no `deployed_to` target, or one
395
+ # whose settings conflict, is faulted with the generator's own sentence.
396
+ command "Project" do
397
+ goal "Generate a domain's AWS deploy recipe from its declared deployed_to target"
398
+
399
+ attribute :domain, DomainPath
400
+ attribute :run, RunKey
401
+ attribute :tenant, TenantSlug, optional: true
402
+ attribute :schema, SchemaName, optional: true
403
+ attribute :out, Location, optional: true
404
+ attribute :environment, EnvironmentName, optional: true
405
+
406
+ sets :domain
407
+ sets :run
408
+ sets :tenant
409
+ sets :schema
410
+ sets :out
411
+ sets :environment
412
+
413
+ emits "ProjectionRequested"
414
+ end
415
+
416
+ command "Complete" do
417
+ goal "Record that the recipe was written, and where"
418
+
419
+ reference_to Recipe
420
+ attribute :output, Report
421
+
422
+ sets :output
423
+
424
+ emits "RecipeProjected"
425
+ end
426
+
427
+ command "Fault" do
428
+ goal "Record that the recipe could not be generated, and why"
429
+
430
+ reference_to Recipe
431
+ attribute :refusal, Report
432
+
433
+ sets :refusal
434
+
435
+ emits "RecipeFaulted"
436
+ end
211
437
 
212
- emits "TenantDeclared"
438
+ query "Outcome" do
439
+ description "What one generation did: its status, and the files written or the reason it stopped."
440
+ attribute :run, RunKey
441
+ where(run: :run)
442
+ order_by :run
213
443
  end
444
+
445
+ query "Faulted" do
446
+ description "Every generation that could not write its recipe."
447
+ where(status: "faulted")
448
+ order_by :run
449
+ end
450
+ end
451
+
452
+ policy "GenerateWhenRequested" do
453
+ on "Recipe.ProjectionRequested"
454
+ trigger Recipe::DeployToolchain::Generate, with: { run: :run }
455
+ end
456
+
457
+ policy "RecordTheRecipe" do
458
+ on "Recipe.RecipeAnswered"
459
+ trigger Recipe::Complete, with: { output: :output }
460
+ end
461
+
462
+ policy "RecordTheFaultedRecipe" do
463
+ on "Recipe.RecipeRefused"
464
+ trigger Recipe::Fault, with: { refusal: :refusal }
465
+ end
466
+
467
+ aggregate "MakefileCheck" do
468
+ description "One lint of generated deploy Makefiles for prod-touching recipes that hide failure."
469
+
470
+ attribute :run, RunKey
471
+ attribute :makefiles, PathList, optional: true
472
+ attribute :report, Report, optional: true
473
+ attribute :refusal, Report, optional: true
474
+ identified_by :run
475
+
476
+ value_object "RunKey" do
477
+ attribute :value, String, pattern: '[^ \t\n\r]'
478
+
479
+ invariant("a run is named") { !value.to_s.empty? }
480
+ end
481
+
482
+ # Makefile paths, comma separated; three generated fixture domains when absent.
483
+ value_object "PathList" do
484
+ attribute :value, String, pattern: '[^\t\n\r]'
485
+ end
486
+
487
+ value_object "Report" do
488
+ attribute :value, String
489
+ end
490
+
491
+ lifecycle :status, default: "requested" do
492
+ transition "Pass" => "clean", from: "requested"
493
+ transition "Flag" => "flagged", from: "requested"
494
+ end
495
+
496
+ # A pattern match over Make and shell text, not a static analyzer: the findings are the
497
+ # linter's own sentences, one per violation, and a run that finds any is flagged.
498
+ command "Lint" do
499
+ goal "Lint generated deploy Makefiles for recipes that hide the failure of a command that touches prod"
500
+
501
+ attribute :makefiles, PathList, optional: true
502
+ attribute :run, RunKey
503
+
504
+ sets :makefiles
505
+ sets :run
506
+
507
+ emits "LintRequested"
508
+ end
509
+
510
+ command "Pass" do
511
+ goal "Record that no recipe hides a failure"
512
+
513
+ reference_to MakefileCheck
514
+ attribute :report, Report
515
+
516
+ sets :report
517
+
518
+ emits "LintPassed"
519
+ end
520
+
521
+ command "Flag" do
522
+ goal "Record that a recipe hides a failure, or that the lint could not run, and what it said"
523
+
524
+ reference_to MakefileCheck
525
+ attribute :refusal, Report
526
+
527
+ sets :refusal
528
+
529
+ emits "LintFlagged"
530
+ end
531
+
532
+ query "Verdict" do
533
+ description "What one lint found: its status, and the report or the violations."
534
+ attribute :run, RunKey
535
+ where(run: :run)
536
+ order_by :run
537
+ end
538
+
539
+ query "Flagged" do
540
+ description "Every lint that left a violation or could not run."
541
+ where(status: "flagged")
542
+ order_by :run
543
+ end
544
+ end
545
+
546
+ policy "LintWhenRequested" do
547
+ on "MakefileCheck.LintRequested"
548
+ trigger MakefileCheck::DeployToolchain::Scan, with: { run: :run }
549
+ end
550
+
551
+ policy "RecordTheCleanLint" do
552
+ on "MakefileCheck.LintAnswered"
553
+ trigger MakefileCheck::Pass, with: { report: :report }
554
+ end
555
+
556
+ policy "RecordTheFlaggedLint" do
557
+ on "MakefileCheck.LintRefused"
558
+ trigger MakefileCheck::Flag, with: { refusal: :refusal }
559
+ end
560
+
561
+ aggregate "TemplateComparison" do
562
+ description "One offline comparison of two CloudFormation templates, by logical id."
563
+
564
+ attribute :before, Location
565
+ attribute :after, Location
566
+ attribute :run, RunKey
567
+ attribute :json, Switch, optional: true
568
+ attribute :strict, Switch, optional: true
569
+ attribute :report, Report, optional: true
570
+ attribute :refusal, Report, optional: true
571
+ identified_by :run
572
+
573
+ value_object "RunKey" do
574
+ attribute :value, String, pattern: '[^ \t\n\r]'
575
+
576
+ invariant("a run is named") { !value.to_s.empty? }
577
+ end
578
+
579
+ value_object "Location" do
580
+ attribute :value, String, pattern: '[^\t\n\r]'
581
+
582
+ invariant("a template is named by its path") { !value.to_s.empty? }
583
+ end
584
+
585
+ value_object "Switch" do
586
+ attribute :value, Boolean
587
+ end
588
+
589
+ value_object "Report" do
590
+ attribute :value, String
591
+ end
592
+
593
+ lifecycle :status, default: "requested" do
594
+ transition "Match" => "matching", from: "requested"
595
+ transition "Drift" => "drifted", from: "requested"
596
+ transition "Refuse" => "refused", from: "requested"
597
+ end
598
+
599
+ # `hecks deploy diff <before> after=<template> [--json] [--strict]`. `--strict` also counts
600
+ # cosmetic differences (comments, key order); `--json` writes the report as JSON.
601
+ command "Diff" do
602
+ goal "Compare two CloudFormation templates and report what differs by logical id"
603
+
604
+ attribute :before, Location
605
+ attribute :after, Location
606
+ attribute :run, RunKey
607
+ attribute :json, Switch, optional: true
608
+ attribute :strict, Switch, optional: true
609
+
610
+ sets :before
611
+ sets :after
612
+ sets :run
613
+ sets :json
614
+ sets :strict
615
+
616
+ emits "ComparisonRequested"
617
+ end
618
+
619
+ command "Match" do
620
+ goal "Record that the templates agree"
621
+
622
+ reference_to TemplateComparison
623
+ attribute :report, Report
624
+ attribute :different, Switch
625
+
626
+ given("the templates agree") { !different.value }
627
+
628
+ sets :report
629
+
630
+ emits "TemplatesMatched"
631
+ end
632
+
633
+ command "Drift" do
634
+ goal "Record that the templates differ, and how"
635
+
636
+ reference_to TemplateComparison
637
+ attribute :report, Report
638
+ attribute :different, Switch
639
+
640
+ given("the templates differ") { different.value }
641
+
642
+ sets :report
643
+
644
+ emits "TemplatesDrifted"
645
+ end
646
+
647
+ command "Refuse" do
648
+ goal "Record that a template could not be read, and why"
649
+
650
+ reference_to TemplateComparison
651
+ attribute :refusal, Report
652
+
653
+ sets :refusal
654
+
655
+ emits "ComparisonRefused"
656
+ end
657
+
658
+ query "Verdict" do
659
+ description "What one comparison found: its status, and the report or the reason it could not run."
660
+ attribute :run, RunKey
661
+ where(run: :run)
662
+ order_by :run
663
+ end
664
+
665
+ query "Drifted" do
666
+ description "Every comparison in which the templates differ."
667
+ where(status: "drifted")
668
+ order_by :run
669
+ end
670
+ end
671
+
672
+ policy "CompareWhenRequested" do
673
+ on "TemplateComparison.ComparisonRequested"
674
+ trigger TemplateComparison::DeployToolchain::Compare, with: { run: :run }
675
+ end
676
+
677
+ policy "RecordTheMatch" do
678
+ on "TemplateComparison.ComparisonAnswered"
679
+ trigger TemplateComparison::Match, with: { report: :report, different: :different }
680
+ end
681
+
682
+ policy "RecordTheDrift" do
683
+ on "TemplateComparison.ComparisonAnswered"
684
+ trigger TemplateComparison::Drift, with: { report: :report, different: :different }
685
+ end
686
+
687
+ policy "RecordTheRefusedComparison" do
688
+ on "TemplateComparison.ComparisonUnreadable"
689
+ trigger TemplateComparison::Refuse, with: { refusal: :refusal }
690
+ end
691
+
692
+ aggregate "OidcManifest" do
693
+ description "One projection of each domain's OIDC client and scope manifest into its oidc.json."
694
+
695
+ attribute :run, RunKey
696
+ attribute :domains, DomainList, optional: true
697
+ attribute :output, Report, optional: true
698
+ attribute :refusal, Report, optional: true
699
+ identified_by :run
700
+
701
+ value_object "RunKey" do
702
+ attribute :value, String, pattern: '[^ \t\n\r]'
703
+
704
+ invariant("a run is named") { !value.to_s.empty? }
705
+ end
706
+
707
+ # Domain directories, comma separated; every domain of the checkout when absent.
708
+ value_object "DomainList" do
709
+ attribute :value, String, pattern: '[^\t\n\r]'
710
+ end
711
+
712
+ value_object "Report" do
713
+ attribute :value, String
714
+ end
715
+
716
+ lifecycle :status, default: "requested" do
717
+ transition "Complete" => "projected", from: "requested"
718
+ transition "Fault" => "faulted", from: "requested"
719
+ end
720
+
721
+ command "ProjectOidc" do
722
+ goal "Write each domain's OIDC client and scope manifest beside it as oidc.json"
723
+
724
+ attribute :domains, DomainList, optional: true
725
+ attribute :run, RunKey
726
+
727
+ sets :domains
728
+ sets :run
729
+
730
+ emits "OidcProjectionRequested"
731
+ end
732
+
733
+ command "Complete" do
734
+ goal "Record which manifests were written"
735
+
736
+ reference_to OidcManifest
737
+ attribute :output, Report
738
+
739
+ sets :output
740
+
741
+ emits "OidcProjected"
742
+ end
743
+
744
+ command "Fault" do
745
+ goal "Record that the manifests could not be projected, and why"
746
+
747
+ reference_to OidcManifest
748
+ attribute :refusal, Report
749
+
750
+ sets :refusal
751
+
752
+ emits "OidcFaulted"
753
+ end
754
+
755
+ query "Outcome" do
756
+ description "What one projection did: its status, and the manifests written or the reason it stopped."
757
+ attribute :run, RunKey
758
+ where(run: :run)
759
+ order_by :run
760
+ end
761
+
762
+ query "Faulted" do
763
+ description "Every projection that could not write its manifests."
764
+ where(status: "faulted")
765
+ order_by :run
766
+ end
767
+ end
768
+
769
+ policy "ProjectWhenRequested" do
770
+ on "OidcManifest.OidcProjectionRequested"
771
+ trigger OidcManifest::DeployToolchain::Manifest, with: { run: :run }
772
+ end
773
+
774
+ policy "RecordTheManifests" do
775
+ on "OidcManifest.ManifestAnswered"
776
+ trigger OidcManifest::Complete, with: { output: :output }
777
+ end
778
+
779
+ policy "RecordTheFaultedManifests" do
780
+ on "OidcManifest.ManifestRefused"
781
+ trigger OidcManifest::Fault, with: { refusal: :refusal }
214
782
  end
215
783
  end